From ce090830863f05f06020c76985436e7b3c7e46b4 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Fri, 21 Jun 2024 20:32:18 +0800 Subject: [PATCH 01/22] implement WENO limiter for DG method --- include/aspect/parameters.h | 42 +- .../visualization/kxrcf_indicator.h | 80 ++ include/aspect/simulator.h | 23 +- include/aspect/simulator_access.h | 8 + .../visualization/kxrcf_indicator.cc | 123 +++ source/simulator/core.cc | 12 +- source/simulator/helper_functions.cc | 243 ----- source/simulator/limiters.cc | 870 ++++++++++++++++++ source/simulator/parameters.cc | 121 ++- source/simulator/simulator_access.cc | 13 + source/simulator/solver.cc | 41 +- 11 files changed, 1271 insertions(+), 305 deletions(-) create mode 100644 include/aspect/postprocess/visualization/kxrcf_indicator.h create mode 100644 source/postprocess/visualization/kxrcf_indicator.cc create mode 100644 source/simulator/limiters.cc diff --git a/include/aspect/parameters.h b/include/aspect/parameters.h index 201fb425efa..f4205dc8d1b 100644 --- a/include/aspect/parameters.h +++ b/include/aspect/parameters.h @@ -313,6 +313,41 @@ namespace aspect } }; + /** + * A struct to provide the different choices of limiters for + * the discontinuous Galerkin method. + */ + struct DGLimiterType + { + enum Kind + { + boundary_preserving, + WENO, + none + }; + + static + Kind + parse(const std::string &input) + { + if (input == "boundary preserving") + return boundary_preserving; + else if (input == "WENO") + return WENO; + else if (input == "none") + return none; + else + AssertThrow(false, ExcNotImplemented()); + + return Kind(); + } + + static const std::string pattern() + { + return "boundary preserving|WENO|none"; + } + }; + /** * This enum represents the different choices for the linear solver * for the Stoke system. See @p stokes_solver_type. @@ -656,12 +691,15 @@ namespace aspect std::vector stabilization_beta; double stabilization_gamma; double discontinuous_penalty; - bool use_limiter_for_discontinuous_temperature_solution; - std::vector use_limiter_for_discontinuous_composition_solution; + typename DGLimiterType::Kind limiter_for_discontinuous_temperature_solution; + std::vector limiter_for_discontinuous_composition_solution; double global_temperature_max_preset; double global_temperature_min_preset; std::vector global_composition_max_preset; std::vector global_composition_min_preset; + double temperature_KXRCF_indicator_threshold; + std::vector composition_KXRCF_indicator_threshold; + double WENO_linear_weight; std::vector compositional_fields_with_disabled_boundary_entropy_viscosity; /** diff --git a/include/aspect/postprocess/visualization/kxrcf_indicator.h b/include/aspect/postprocess/visualization/kxrcf_indicator.h new file mode 100644 index 00000000000..bcd4022612d --- /dev/null +++ b/include/aspect/postprocess/visualization/kxrcf_indicator.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_kxrcf_indicator_h +#define _aspect_postprocess_visualization_kxrcf_indicator_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived that implements a function that provides the + * KXRCF indicator for a given advection field on each cell for + * graphical output. + */ + template + class KXRCFIndicator : public CellDataVectorCreator, + public SimulatorAccess + { + public: + /** + * Constructor. + */ + KXRCFIndicator(); + + /** + * @copydoc CellDataVectorCreator::execute() + */ + std::pair>> + execute () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A parameter that tells us for which advection field the + * KXRCF indicator should be visualized. + */ + unsigned int field_index; + }; + } + } +} + +#endif diff --git a/include/aspect/simulator.h b/include/aspect/simulator.h index 3df4a6752a9..e21f85c6284 100644 --- a/include/aspect/simulator.h +++ b/include/aspect/simulator.h @@ -1373,10 +1373,29 @@ namespace aspect * the discontinuous Galerkin solution will stay in the prescribed bounds. * * This function is implemented in - * source/simulator/helper_functions.cc. + * source/simulator/limiters.cc. + */ + void apply_BP_limiter_to_dg_solutions (const AdvectionField &advection_field); + + /** + * Apply the WENO limiter to the discontinuous Galerkin solutions. + * The WENO scheme implemented in this function is proposed by Zhong and Shu, 2013. + * + * This function is implemented in + * source/simulator/limiters.cc. */ - void apply_limiter_to_dg_solutions (const AdvectionField &advection_field); + void apply_WENO_limiter_to_dg_solutions (const AdvectionField &advection_field); + /** + * Compute the KXRCF indicator that detect shocks in the advection field. + * The KXRCF indicator is used by the WENO limiter. + * + * This function is implemented in + * source/simulator/limiters.cc. + */ + template + void compute_KXRCF_indicators(Vector &KXRCF_indicators, + const AdvectionField &advection_field) const; /** * Compute the reactions in case of operator splitting: diff --git a/include/aspect/simulator_access.h b/include/aspect/simulator_access.h index a65c0cf4879..999a22a6980 100644 --- a/include/aspect/simulator_access.h +++ b/include/aspect/simulator_access.h @@ -427,6 +427,14 @@ namespace aspect void get_artificial_viscosity_composition(Vector &viscosity_per_cell, const unsigned int compositional_variable) const; + + /** + * Compute the KXRCF indicator on each locally owned cell for a specific + * advection field. + */ + void + compute_KXRCF_indicators(Vector &KXRCF_indicators, + const unsigned int field_index) const; /** @} */ diff --git a/source/postprocess/visualization/kxrcf_indicator.cc b/source/postprocess/visualization/kxrcf_indicator.cc new file mode 100644 index 00000000000..5403aa477f0 --- /dev/null +++ b/source/postprocess/visualization/kxrcf_indicator.cc @@ -0,0 +1,123 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + template + KXRCFIndicator::KXRCFIndicator() + : + CellDataVectorCreator("") + {} + + + template + std::pair>> + KXRCFIndicator::execute() const + { + std::pair>> + return_value ("KXRCF_indicator", + std::make_unique>(this->get_triangulation().n_active_cells())); + this->compute_KXRCF_indicators(*return_value.second, field_index); + return return_value; + } + + + template + void + KXRCFIndicator::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Visualization"); + { + prm.enter_subsection("KXRCF indicator"); + { + prm.declare_entry ("Name of advection field", "", + Patterns::Anything(), + "The name of the advection field whose output " + "should be visualized. "); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + KXRCFIndicator::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Visualization"); + { + prm.enter_subsection("KXRCF indicator"); + { + const std::string field_name = prm.get("Name of advection field"); + + if (field_name == "temperature") + field_index = 0; + else + { + AssertThrow(this->introspection().compositional_name_exists(field_name), + ExcMessage("No compositional field with name <" + + field_name + + "> exists for which you want to visualize the KXRCF indicator.")); + + field_index = this->introspection().compositional_index_for_name(field_name) + 1; + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + ASPECT_REGISTER_VISUALIZATION_POSTPROCESSOR(KXRCFIndicator, + "kxrcf indicator", + "A visualization output object that generates output " + "showing the value of the KXRCF indicator on each " + "cell." + "\n\n" + "Physical units: none.") + } + } +} diff --git a/source/simulator/core.cc b/source/simulator/core.cc index d74c564d1ea..e0226cf8034 100644 --- a/source/simulator/core.cc +++ b/source/simulator/core.cc @@ -485,14 +485,16 @@ namespace aspect if (MappingQCache *map = dynamic_cast*>(&(*mapping))) map->initialize(MappingQGeneric(4), triangulation); - bool dg_limiter_enabled = parameters.use_limiter_for_discontinuous_temperature_solution; + bool bp_limiter_enabled = (parameters.limiter_for_discontinuous_temperature_solution + == Parameters::DGLimiterType::boundary_preserving); for (unsigned int c=0; c::DGLimiterType::boundary_preserving); - // Check that DG limiters are only used with cartesian mapping - if (dg_limiter_enabled) + // Check that BP limiters are only used with cartesian mapping + if (bp_limiter_enabled) AssertThrow(geometry_model->natural_coordinate_system() == Utilities::Coordinates::CoordinateSystem::cartesian, - ExcMessage("The limiter for the discontinuous temperature and composition solutions " + ExcMessage("The boundary preserving limiter for the discontinuous temperature and composition solutions " "has not been tested in non-Cartesian geometries and currently requires " "the use of a Cartesian geometry model.")); diff --git a/source/simulator/helper_functions.cc b/source/simulator/helper_functions.cc index 0450a1de14d..bd84cabf160 100644 --- a/source/simulator/helper_functions.cc +++ b/source/simulator/helper_functions.cc @@ -1392,248 +1392,6 @@ namespace aspect - template - void Simulator::apply_limiter_to_dg_solutions (const AdvectionField &advection_field) - { - // TODO: Modify to more robust method - // Skip if this composition field is being set from the volume_of_fluid handler - if (!advection_field.is_temperature() && - parameters.volume_of_fluid_tracking_enabled) - if (volume_of_fluid_handler->field_index_for_name(introspection.name_for_compositional_index(advection_field.compositional_variable)) - != volume_of_fluid_handler->get_n_fields()) - return; - - /* - * First setup the quadrature points which are used to find the maximum and minimum solution values at those points. - * A quadrature formula that combines all quadrature points constructed as all tensor products of - * 1) one dimensional Gauss points; 2) one dimensional Gauss-Lobatto points. - * We require that the Gauss-Lobatto points (2) appear in only one direction. - * Therefore, possible combination - * in 2d: the combinations are 21, 12 - * in 3d: the combinations are 211, 121, 112 - */ - const QGauss<1> quadrature_formula_1 (advection_field.polynomial_degree(introspection)+1); - const QGaussLobatto<1> quadrature_formula_2 (advection_field.polynomial_degree(introspection)+1); - - const unsigned int n_q_points_1 = quadrature_formula_1.size(); - const unsigned int n_q_points_2 = quadrature_formula_2.size(); - const unsigned int n_q_points = dim * n_q_points_2 * static_cast(std::pow(n_q_points_1, dim-1)); - - std::vector> quadrature_points; - quadrature_points.reserve(n_q_points); - - switch (dim) - { - case 2: - { - // append quadrature points combination 12 - for (unsigned int i=0; i < n_q_points_1 ; ++i) - { - const double x = quadrature_formula_1.point(i)(0); - for (unsigned int j=0; j < n_q_points_2 ; ++j) - { - const double y = quadrature_formula_2.point(j)(0); - quadrature_points.push_back(Point(x,y)); - } - } - // append quadrature points combination 21 - for (unsigned int i=0; i < n_q_points_2 ; ++i) - { - const double x = quadrature_formula_2.point(i)(0); - for (unsigned int j=0; j < n_q_points_1 ; ++j) - { - const double y = quadrature_formula_1.point(j)(0); - quadrature_points.push_back(Point(x,y)); - } - } - break; - } - - case 3: - { - // append quadrature points combination 121 - for ( unsigned int i=0; i < n_q_points_1 ; ++i) - { - const double x = quadrature_formula_1.point(i)(0); - for ( unsigned int j=0; j < n_q_points_2 ; ++j) - { - const double y = quadrature_formula_2.point(j)(0); - for ( unsigned int k=0; k < n_q_points_1 ; ++k) - { - const double z = quadrature_formula_1.point(k)(0); - quadrature_points.push_back(Point(x,y,z)); - } - } - } - // append quadrature points combination 112 - for (unsigned int i=0; i < n_q_points_1 ; ++i) - { - const double x = quadrature_formula_1.point(i)(0); - for (unsigned int j=0; j < n_q_points_1 ; ++j) - { - const double y = quadrature_formula_1.point(j)(0); - for (unsigned int k=0; k < n_q_points_2 ; ++k) - { - const double z = quadrature_formula_2.point(k)(0); - quadrature_points.push_back(Point(x,y,z)); - } - } - } - // append quadrature points combination 211 - for (unsigned int i=0; i < n_q_points_2 ; ++i) - { - const double x = quadrature_formula_2.point(i)(0); - for ( unsigned int j=0; j < n_q_points_1 ; ++j) - { - const double y = quadrature_formula_1.point(j)(0); - for ( unsigned int k=0; k < n_q_points_1 ; ++k) - { - const double z = quadrature_formula_1.point(k)(0); - quadrature_points.push_back(Point(x,y,z)); - } - } - } - break; - } - - default: - Assert (false, ExcNotImplemented()); - } - - Assert (quadrature_points.size() == n_q_points, ExcInternalError()); - const Quadrature quadrature_formula(quadrature_points); - - // Quadrature rules only used for the numerical integration for better accuracy - const Quadrature &quadrature_formula_0 - = (advection_field.is_temperature() ? - introspection.quadratures.temperature : - introspection.quadratures.compositional_fields); - const unsigned int n_q_points_0 = quadrature_formula_0.size(); - - // fe values for points evaluation - FEValues fe_values (*mapping, - finite_element, - quadrature_formula, - update_values | - update_quadrature_points); - std::vector values (n_q_points); - // fe values for numerical integration, with a number of quadrature points - // that is equal to 1/dim times the number of total points above - FEValues fe_values_0 (*mapping, - finite_element, - quadrature_formula_0, - update_values | - update_quadrature_points | - update_JxW_values); - std::vector values_0 (n_q_points_0); - - const FEValuesExtractors::Scalar field - = (advection_field.is_temperature() - ? - introspection.extractors.temperature - : - introspection.extractors.compositional_fields[advection_field.compositional_variable] - ); - - const double max_solution_exact_global = (advection_field.is_temperature() - ? - parameters.global_temperature_max_preset - : - parameters.global_composition_max_preset[advection_field.compositional_variable] - ); - const double min_solution_exact_global = (advection_field.is_temperature() - ? - parameters.global_temperature_min_preset - : - parameters.global_composition_min_preset[advection_field.compositional_variable] - ); - - LinearAlgebra::BlockVector distributed_solution (introspection.index_sets.system_partitioning, - mpi_communicator); - const unsigned int block_idx = advection_field.block_index(introspection); - distributed_solution.block(block_idx) = solution.block(block_idx); - - std::vector local_dof_indices (finite_element.dofs_per_cell); - - for (const auto &cell : dof_handler.active_cell_iterators()) - if (cell->is_locally_owned()) - { - cell->get_dof_indices (local_dof_indices); - // used to find the maximum, minimum - fe_values.reinit (cell); - fe_values[field].get_function_values(solution, values); - // used for the numerical integration - fe_values_0.reinit (cell); - fe_values_0[field].get_function_values(solution, values_0); - - // Find the local max and local min - const double min_solution_local = *std::min_element (values.begin(), values.end()); - const double max_solution_local = *std::max_element (values.begin(), values.end()); - // Find the trouble cell - if (min_solution_local < min_solution_exact_global - || max_solution_local > max_solution_exact_global) - { - // Compute the cell area and cell solution average - double local_area = 0.0; - double local_solution_average = 0.0; - for (unsigned int q = 0; q < n_q_points_0; ++q) - { - local_area += fe_values_0.JxW(q); - local_solution_average += values_0[q]*fe_values_0.JxW(q); - } - local_solution_average /= local_area; - - /* - * Define theta: a scaling constant used to correct the old solution by the formula - * new_value = theta * (old_value-old_solution_cell_average)+old_solution_cell_average - * where theta \in [0,1] defined as below. - * After the correction, the new solution does not exceed the user-given - * exact global maximum/minimum values. Meanwhile, the new solution's cell average - * equals to the old solution's cell average. - */ - double theta = 1.0; - if (std::abs(max_solution_local-local_solution_average) > std::numeric_limits::min()) - { - theta = std::min(theta, std::abs((max_solution_exact_global-local_solution_average) - / (max_solution_local-local_solution_average))); - } - if (std::abs(min_solution_local-local_solution_average) > std::numeric_limits::min()) - { - theta = std::min(theta, std::abs((min_solution_exact_global-local_solution_average) - / (min_solution_local-local_solution_average))); - } - - /* Modify the advection degrees of freedom of the numerical solution. - * Note that we are using DG elements, so every DoF on a locally owned cell is locally owned; - * this means that we do not need to check whether the 'distributed_solution' vector actually - * stores the element we read from/write to here. - */ - for (unsigned int j = 0; - j < finite_element.base_element(advection_field.base_element(introspection)).dofs_per_cell; - ++j) - { - const unsigned int support_point_index = finite_element.component_to_system_index( - (advection_field.is_temperature() - ? - introspection.component_indices.temperature - : - introspection.component_indices.compositional_fields[advection_field.compositional_variable] - ), - /*dof index within component=*/ j); - const double solution_value = solution(local_dof_indices[support_point_index]); - const double limited_solution_value = theta * (solution_value-local_solution_average) + local_solution_average; - distributed_solution(local_dof_indices[support_point_index]) = limited_solution_value; - } - } - } - - distributed_solution.compress(VectorOperation::insert); - // now get back to the original vector - solution.block(block_idx) = distributed_solution.block(block_idx); - } - - - template void Simulator::update_solution_vectors_with_reaction_results (const unsigned int block_index, const LinearAlgebra::BlockVector &distributed_vector, @@ -2740,7 +2498,6 @@ namespace aspect template bool Simulator::stokes_matrix_depends_on_solution() const; \ template bool Simulator::stokes_A_block_is_symmetric() const; \ template void Simulator::interpolate_onto_velocity_system(const TensorFunction<1,dim> &func, LinearAlgebra::Vector &vec);\ - template void Simulator::apply_limiter_to_dg_solutions(const AdvectionField &advection_field); \ template void Simulator::compute_reactions(); \ template void Simulator::initialize_current_linearization_point (); \ template void Simulator::interpolate_material_output_into_advection_field(const AdvectionField &adv_field); \ diff --git a/source/simulator/limiters.cc b/source/simulator/limiters.cc new file mode 100644 index 00000000000..eb1ec577785 --- /dev/null +++ b/source/simulator/limiters.cc @@ -0,0 +1,870 @@ +#include + +namespace aspect +{ + template + void + Simulator::apply_BP_limiter_to_dg_solutions(const AdvectionField &advection_field) + { + // TODO: Modify to more robust method + // Skip if this composition field is being set from the volume_of_fluid handler + if (!advection_field.is_temperature() && + parameters.volume_of_fluid_tracking_enabled) + if (volume_of_fluid_handler->field_index_for_name(introspection.name_for_compositional_index(advection_field.compositional_variable)) + != volume_of_fluid_handler->get_n_fields()) + return; + + /* + * First setup the quadrature points which are used to find the maximum and minimum solution values at those points. + * A quadrature formula that combines all quadrature points constructed as all tensor products of + * 1) one dimensional Gauss points; 2) one dimensional Gauss-Lobatto points. + * We require that the Gauss-Lobatto points (2) appear in only one direction. + * Therefore, possible combination + * in 2d: the combinations are 21, 12 + * in 3d: the combinations are 211, 121, 112 + */ + const QGauss<1> quadrature_formula_1 (advection_field.polynomial_degree(introspection)+1); + const QGaussLobatto<1> quadrature_formula_2 (advection_field.polynomial_degree(introspection)+1); + + const unsigned int n_q_points_1 = quadrature_formula_1.size(); + const unsigned int n_q_points_2 = quadrature_formula_2.size(); + const unsigned int n_q_points = dim * n_q_points_2 * static_cast(std::pow(n_q_points_1, dim-1)); + + std::vector> quadrature_points; + quadrature_points.reserve(n_q_points); + + switch (dim) + { + case 2: + { + // append quadrature points combination 12 + for (unsigned int i=0; i < n_q_points_1 ; ++i) + { + const double x = quadrature_formula_1.point(i)(0); + for (unsigned int j=0; j < n_q_points_2 ; ++j) + { + const double y = quadrature_formula_2.point(j)(0); + quadrature_points.push_back(Point(x,y)); + } + } + // append quadrature points combination 21 + for (unsigned int i=0; i < n_q_points_2 ; ++i) + { + const double x = quadrature_formula_2.point(i)(0); + for (unsigned int j=0; j < n_q_points_1 ; ++j) + { + const double y = quadrature_formula_1.point(j)(0); + quadrature_points.push_back(Point(x,y)); + } + } + break; + } + + case 3: + { + // append quadrature points combination 121 + for ( unsigned int i=0; i < n_q_points_1 ; ++i) + { + const double x = quadrature_formula_1.point(i)(0); + for ( unsigned int j=0; j < n_q_points_2 ; ++j) + { + const double y = quadrature_formula_2.point(j)(0); + for ( unsigned int k=0; k < n_q_points_1 ; ++k) + { + const double z = quadrature_formula_1.point(k)(0); + quadrature_points.push_back(Point(x,y,z)); + } + } + } + // append quadrature points combination 112 + for (unsigned int i=0; i < n_q_points_1 ; ++i) + { + const double x = quadrature_formula_1.point(i)(0); + for (unsigned int j=0; j < n_q_points_1 ; ++j) + { + const double y = quadrature_formula_1.point(j)(0); + for (unsigned int k=0; k < n_q_points_2 ; ++k) + { + const double z = quadrature_formula_2.point(k)(0); + quadrature_points.push_back(Point(x,y,z)); + } + } + } + // append quadrature points combination 211 + for (unsigned int i=0; i < n_q_points_2 ; ++i) + { + const double x = quadrature_formula_2.point(i)(0); + for ( unsigned int j=0; j < n_q_points_1 ; ++j) + { + const double y = quadrature_formula_1.point(j)(0); + for ( unsigned int k=0; k < n_q_points_1 ; ++k) + { + const double z = quadrature_formula_1.point(k)(0); + quadrature_points.push_back(Point(x,y,z)); + } + } + } + break; + } + + default: + Assert (false, ExcNotImplemented()); + } + + Assert (quadrature_points.size() == n_q_points, ExcInternalError()); + const Quadrature quadrature_formula(quadrature_points); + + // Quadrature rules only used for the numerical integration for better accuracy + const Quadrature &quadrature_formula_0 + = (advection_field.is_temperature() ? + introspection.quadratures.temperature : + introspection.quadratures.compositional_fields); + const unsigned int n_q_points_0 = quadrature_formula_0.size(); + + // fe values for points evaluation + FEValues fe_values (*mapping, + finite_element, + quadrature_formula, + update_values | + update_quadrature_points); + std::vector values (n_q_points); + // fe values for numerical integration, with a number of quadrature points + // that is equal to 1/dim times the number of total points above + FEValues fe_values_0 (*mapping, + finite_element, + quadrature_formula_0, + update_values | + update_quadrature_points | + update_JxW_values); + std::vector values_0 (n_q_points_0); + + const FEValuesExtractors::Scalar field + = (advection_field.is_temperature() + ? + introspection.extractors.temperature + : + introspection.extractors.compositional_fields[advection_field.compositional_variable] + ); + + const double max_solution_exact_global = (advection_field.is_temperature() + ? + parameters.global_temperature_max_preset + : + parameters.global_composition_max_preset[advection_field.compositional_variable] + ); + const double min_solution_exact_global = (advection_field.is_temperature() + ? + parameters.global_temperature_min_preset + : + parameters.global_composition_min_preset[advection_field.compositional_variable] + ); + + LinearAlgebra::BlockVector distributed_solution (introspection.index_sets.system_partitioning, + mpi_communicator); + const unsigned int block_idx = advection_field.block_index(introspection); + distributed_solution.block(block_idx) = solution.block(block_idx); + + std::vector local_dof_indices (finite_element.dofs_per_cell); + + for (const auto &cell : dof_handler.active_cell_iterators()) + if (cell->is_locally_owned()) + { + cell->get_dof_indices (local_dof_indices); + // used to find the maximum, minimum + fe_values.reinit (cell); + fe_values[field].get_function_values(solution, values); + // used for the numerical integration + fe_values_0.reinit (cell); + fe_values_0[field].get_function_values(solution, values_0); + + // Find the local max and local min + const double min_solution_local = *std::min_element (values.begin(), values.end()); + const double max_solution_local = *std::max_element (values.begin(), values.end()); + // Find the trouble cell + if (min_solution_local < min_solution_exact_global + || max_solution_local > max_solution_exact_global) + { + // Compute the cell area and cell solution average + double local_area = 0.0; + double local_solution_average = 0.0; + for (unsigned int q = 0; q < n_q_points_0; ++q) + { + local_area += fe_values_0.JxW(q); + local_solution_average += values_0[q]*fe_values_0.JxW(q); + } + local_solution_average /= local_area; + + /* + * Define theta: a scaling constant used to correct the old solution by the formula + * new_value = theta * (old_value-old_solution_cell_average)+old_solution_cell_average + * where theta \in [0,1] defined as below. + * After the correction, the new solution does not exceed the user-given + * exact global maximum/minimum values. Meanwhile, the new solution's cell average + * equals to the old solution's cell average. + */ + double theta = 1.0; + if (std::abs(max_solution_local-local_solution_average) > std::numeric_limits::min()) + { + theta = std::min(theta, std::abs((max_solution_exact_global-local_solution_average) + / (max_solution_local-local_solution_average))); + } + if (std::abs(min_solution_local-local_solution_average) > std::numeric_limits::min()) + { + theta = std::min(theta, std::abs((min_solution_exact_global-local_solution_average) + / (min_solution_local-local_solution_average))); + } + + /* Modify the advection degrees of freedom of the numerical solution. + * Note that we are using DG elements, so every DoF on a locally owned cell is locally owned; + * this means that we do not need to check whether the 'distributed_solution' vector actually + * stores the element we read from/write to here. + */ + for (unsigned int j = 0; + j < finite_element.base_element(advection_field.base_element(introspection)).dofs_per_cell; + ++j) + { + const unsigned int support_point_index = finite_element.component_to_system_index( + (advection_field.is_temperature() + ? + introspection.component_indices.temperature + : + introspection.component_indices.compositional_fields[advection_field.compositional_variable] + ), + /*dof index within component=*/ j); + const double solution_value = solution(local_dof_indices[support_point_index]); + const double limited_solution_value = theta * (solution_value-local_solution_average) + local_solution_average; + distributed_solution(local_dof_indices[support_point_index]) = limited_solution_value; + } + } + } + + distributed_solution.compress(VectorOperation::insert); + // now get back to the original vector + solution.block(block_idx) = distributed_solution.block(block_idx); + } + + + + namespace internal + { + struct KXRCFCellData + { + double cell_norm; + double inflow_face_jump; + double inflow_face_area; + + KXRCFCellData() + : cell_norm(0.0) + , inflow_face_jump(0.0) + , inflow_face_area(0.0) + {} + }; + } + + + template + template + void + Simulator::compute_KXRCF_indicators(Vector &KXRCF_indicators, + const AdvectionField &advection_field) const + { + // stuff for computing the integrals in cells and cell faces + QGauss quadrature(2); + QGauss face_quadrature(2); + + FEValues fe_values(*mapping, + finite_element, + quadrature, + update_values); + + FEFaceValues fe_face_values(*mapping, + finite_element, + face_quadrature, + update_values | + update_normal_vectors | + update_JxW_values); + + FESubfaceValues fe_subface_values(*mapping, + finite_element, + face_quadrature, + update_values | + update_normal_vectors | + update_JxW_values); + + FEFaceValues neighbor_fe_face_values(*mapping, + finite_element, + face_quadrature, + update_values | + update_JxW_values); + + const FEValuesExtractors::Scalar &field_extractor = advection_field.scalar_extractor(introspection); + + const unsigned int n_q_points = fe_values.n_quadrature_points; + const unsigned int n_face_q_points = fe_face_values.n_quadrature_points; + + std::vector field_values(n_q_points); + std::vector face_field_values(n_face_q_points); + std::vector neighbor_face_field_values(n_face_q_points); + + std::vector> face_velocity_values(n_face_q_points); + std::vector> face_mesh_velocity_values(n_face_q_points); + + // KXRCF indicator requires the computation of (1) cell maximum norm; + // (2) integration of the jump over inflow faces of each field. To + // avoid doing integration twice on each cell face, we set up a map + // to store the cell data and then loop over the cells using the same + // strategy as in Assemblers::AdvectionSystemInteriorFace::execute(). + std::map data; + for (const auto &cell : dof_handler.active_cell_iterators()) + if (cell->is_locally_owned()) + data.insert(std::make_pair(cell->active_cell_index(), + internal::KXRCFCellData())); + + // Now loop over locally owned cells and compute the maximum norm + // and the jump over inflow faces. + for (const auto &cell : dof_handler.active_cell_iterators()) + if (cell->is_locally_owned()) + { + auto cell_data = data.find(cell->active_cell_index()); + + // Compute the maximum norm of field values in this cell. + fe_values.reinit(cell); + fe_values[field_extractor].get_function_values(solution, field_values); + + double cell_norm = 0.0; + for (unsigned int q = 0; q < n_q_points; ++q) + cell_norm = std::max(cell_norm, std::abs(field_values[q])); + + cell_data->second.cell_norm = cell_norm; + + // Compute the jump of field values over inflow faces. + for (const unsigned int face_no : cell->face_indices()) + { + if (!cell->at_boundary(face_no) || cell->has_periodic_neighbor(face_no)) + { + const typename DoFHandler::cell_iterator + neighbor = cell->neighbor_or_periodic_neighbor(face_no); + + const bool cell_has_periodic_neighbor = cell->has_periodic_neighbor(face_no); + + // 'neighbor' defined above is NOT active_cell_iterator, this includes cells + // that are refined + if (!neighbor->has_children()) + { + if (neighbor->level() == cell->level() && + neighbor->is_active() && + (((neighbor->is_locally_owned()) && (cell->index() < neighbor->index())) + || + ((!neighbor->is_locally_owned()) && (cell->subdomain_id() < neighbor->subdomain_id())))) + { + // cell and neighbor are equal-sized, and cell has been chosen to + // assemble this face, so calculate from cell + const unsigned int neighbor2 = + (cell_has_periodic_neighbor + ? + cell->periodic_neighbor_of_periodic_neighbor(face_no) + : + cell->neighbor_of_neighbor(face_no)); + + auto neighbor_data = data.find(neighbor->active_cell_index()); + + // Set up face values. + fe_face_values.reinit(cell, face_no); + fe_face_values[field_extractor].get_function_values(solution, face_field_values); + + fe_face_values[introspection.extractors.velocities].get_function_values( + solution, face_velocity_values); + if (parameters.mesh_deformation_enabled) + fe_face_values[introspection.extractors.velocities].get_function_values( + mesh_deformation->mesh_velocity, face_mesh_velocity_values); + + // Set up neighbor face values. + neighbor_fe_face_values.reinit(neighbor, neighbor2); + neighbor_fe_face_values[field_extractor].get_function_values(solution, neighbor_face_field_values); + + const double face_area = cell->face(face_no)->measure(); + + double v_n = 0.0; + double face_jump = 0.0; + for (unsigned int q = 0; q < n_face_q_points; ++q) + { + Tensor<1,dim> current_u = face_velocity_values[q]; + if (parameters.mesh_deformation_enabled) + current_u -= face_mesh_velocity_values[q]; + + v_n += (current_u * fe_face_values.normal_vector(q)) * fe_face_values.JxW(q); + + face_jump += (face_field_values[q] - neighbor_face_field_values[q]) * fe_face_values.JxW(q); + } + + if (v_n < 0.0) // inflow + { + cell_data->second.inflow_face_jump += face_jump; + cell_data->second.inflow_face_area += face_area; + } + else // outflow + { + if (neighbor_data != data.end()) + { + neighbor_data->second.inflow_face_jump -= face_jump; + neighbor_data->second.inflow_face_area += face_area; + } + } + + } + else + { + // Neighbor is taking responsibility for assembly of this face, bacause + // either (1) neighbor is coarser, or + // (2) neighbor is equally-sized and + // (a) neighbor is on a different subdomain, with lower subdomain_id(), or + // (b) nieghbor is on the same subdomain and has lower index(). + } + } + else + { + // Neighbor has children, so always assemble from here. + const unsigned int neighbor2 = + (cell_has_periodic_neighbor + ? + cell->periodic_neighbor_face_no(face_no) + : + cell->neighbor_face_no(face_no)); + + // Loop over subfaces. We know that the neighbor is finer, so we could loop over the subfaces of the current + // face. but if we are at a periodic boundary, then the face of the current cell has no children, so instead use + // the children of the periodic neighbor's corresponding face since we know that the letter does indeed have + // children (because we know that the neighbor is refined). + typename DoFHandler::face_iterator neighbor_face = neighbor->face(neighbor2); + for (unsigned int subface_no = 0; subface_no < neighbor_face->n_children(); ++subface_no) + { + const typename DoFHandler::active_cell_iterator neighbor_child = + (cell_has_periodic_neighbor + ? + cell->periodic_neighbor_child_on_subface(face_no, subface_no) + : + cell->neighbor_child_on_subface(face_no, subface_no)); + + auto neighbor_data = data.find(neighbor_child->active_cell_index()); + + // Set up subface values. + fe_subface_values.reinit(cell, face_no, subface_no); + fe_subface_values[field_extractor].get_function_values(solution, face_field_values); + + fe_subface_values[introspection.extractors.velocities].get_function_values( + solution, face_velocity_values); + if (parameters.mesh_deformation_enabled) + fe_subface_values[introspection.extractors.velocities].get_function_values( + mesh_deformation->mesh_velocity, face_mesh_velocity_values); + + neighbor_fe_face_values.reinit(neighbor_child, neighbor2); + neighbor_fe_face_values[field_extractor].get_function_values(solution, neighbor_face_field_values); + + const double face_area = neighbor_child->face(neighbor2)->measure(); + + double v_n = 0.0; + double face_jump = 0.0; + for (unsigned int q = 0; q < n_face_q_points; ++q) + { + Tensor<1,dim> current_u = face_velocity_values[q]; + if (parameters.mesh_deformation_enabled) + current_u -= face_mesh_velocity_values[q]; + + v_n += (current_u * fe_subface_values.normal_vector(q)) * fe_subface_values.JxW(q); + + face_jump += (face_field_values[q] - neighbor_face_field_values[q]) * fe_subface_values.JxW(q); + } + + if (v_n < 0.0) // inflow + { + cell_data->second.inflow_face_jump += face_jump; + cell_data->second.inflow_face_area += face_area; + } + else // outflow + { + if (neighbor_data != data.end()) + { + neighbor_data->second.inflow_face_jump -= face_jump; + neighbor_data->second.inflow_face_area += face_area; + } + } + } + } + } + else + { + // The current face is a boundary face. + } + } + } + + // Finally, compute the KXRCF indicator and pick the largest one as + // troubled cell indicator. + const unsigned int degree = advection_field.polynomial_degree(introspection); + const double power = (degree + 1.0) / 2.0; + + const unsigned int block_idx = advection_field.block_index(introspection); + const double epsilon = std::max(1e-20, + 1e-3 * (solution.block(block_idx).max() - solution.block(block_idx).min())); + + KXRCF_indicators.reinit(triangulation.n_active_cells()); + for (const auto &cell : dof_handler.active_cell_iterators()) + if (cell->is_locally_owned()) + { + const double h_pow = std::pow(cell->diameter(), power); + const auto cell_data = data.find(cell->active_cell_index()); + if (cell_data->second.inflow_face_area == 0.0) + KXRCF_indicators[cell->active_cell_index()] = 0.0; + else + KXRCF_indicators[cell->active_cell_index()] = + std::abs(cell_data->second.inflow_face_jump) / + (h_pow * cell_data->second.inflow_face_area * (cell_data->second.cell_norm + epsilon)); + } + } + + + template + void + Simulator::apply_WENO_limiter_to_dg_solutions(const AdvectionField &advection_field) + { + // Skip if this composition field is being set from the volume_of_fluid handler + if (!advection_field.is_temperature() && + parameters.volume_of_fluid_tracking_enabled) + if (volume_of_fluid_handler->field_index_for_name(introspection.name_for_compositional_index(advection_field.compositional_variable)) + != volume_of_fluid_handler->get_n_fields()) + return; + + const unsigned int degree = advection_field.polynomial_degree(introspection); + AssertThrow(degree < 3, + ExcMessage("Currently, WENO limiter has only been implemented for " + "advection fields with polynomial degree 1 or 2.")); + + // We need two objects of FEValues in the following computation: + // fe_values: computes the cell average and smoothness indicator of the target cell, + // and provides the coordinates and JxWs of the quadrature points of the target + // cell when computing the smoothness indicators of neighbor cells; + // neighbor_fe_values: computes the cell averages and field derivatives of + // neighbor cells at quadrature points of the target cell. With the derivatives + // at hand, we can use the JxWs provided by fe_values to compute the smoothness + // indicators of neighbor cells. + // The coordinates of quadrature points of neighbor_fe_values change from cell to + // cell since the mesh may not be Cartesian, hence neighbor_fe_values has to be + // reconstructed in each cell. + Quadrature quadrature(advection_field.is_temperature() ? + introspection.quadratures.temperature : + introspection.quadratures.compositional_fields); + + UpdateFlags update_flags = update_values | update_gradients | + update_quadrature_points | update_JxW_values | + (degree > 1 ? update_hessians : update_default); + + UpdateFlags neighbor_update_flags = update_values | update_gradients | + (degree > 1 ? update_hessians : update_default); + + FEValues fe_values(*mapping, finite_element, quadrature, update_flags); + + const unsigned int n_q_points = fe_values.n_quadrature_points; + const unsigned int field_dofs_per_cell = finite_element.base_element(advection_field.base_element(introspection)).dofs_per_cell; + const unsigned int field_component = advection_field.component_index(introspection); + + const FEValuesExtractors::Scalar &field_extractor = advection_field.scalar_extractor(introspection); + + std::vector field_values(n_q_points); + std::vector> field_gradients(n_q_points); + std::vector> field_hessians(n_q_points); + + std::vector> neighbor_quadrature_points(n_q_points); + + std::vector reconstructed_values(n_q_points); + + std::vector cell_averages; + std::vector smoothness_indicators; + std::vector linear_weights; + std::vector nonlinear_weights; + std::vector> field_values_in_target_cell; + + // stuff for projecting the reconstructed polynomial onto grid nodes + FullMatrix cell_matrix(field_dofs_per_cell, field_dofs_per_cell); + Vector cell_rhs(field_dofs_per_cell); + Vector cell_solution(field_dofs_per_cell); + std::vector phi_field(field_dofs_per_cell); + std::vector cell_dof_indices(finite_element.dofs_per_cell); + + // Detect troubled cells with KXRCF indicator. + Vector KXRCF_indicators; + compute_KXRCF_indicators(KXRCF_indicators, advection_field); + + TrilinosWrappers::MPI::BlockVector distributed_solution(introspection.index_sets.system_partitioning, + mpi_communicator); + + const unsigned int block_idx = advection_field.block_index(introspection); + distributed_solution.block(block_idx) = solution.block(block_idx); + + const double KXRCF_indicator_threshold = (advection_field.is_temperature() ? + parameters.temperature_KXRCF_indicator_threshold : + parameters.composition_KXRCF_indicator_threshold[advection_field.compositional_variable]); + for (const auto &cell : dof_handler.active_cell_iterators()) + if (cell->is_locally_owned()) + { + // If the KXRCF indicator of the present cell is lower than the threshold, + // then we do not have to do WENO reconstruction for the cell. + if (KXRCF_indicators[cell->active_cell_index()] < KXRCF_indicator_threshold) + continue; + + cell_averages.clear(); + smoothness_indicators.clear(); + field_values_in_target_cell.clear(); + linear_weights.clear(); + + // Compute the field values and derivatives at quadrature points. + fe_values.reinit(cell); + fe_values[field_extractor].get_function_values(solution, field_values); + fe_values[field_extractor].get_function_gradients(solution, field_gradients); + if (degree > 1) + fe_values[field_extractor].get_function_hessians(solution, field_hessians); + + // Compute the cell average and the smoothness indicator. + double cell_measure = 0.0; + double field_integral = 0.0; + double field_gradient_square_integral = 0.0; + double field_hessian_square_integral = 0.0; + for (unsigned int q = 0; q < n_q_points; ++q) + { + cell_measure += fe_values.JxW(q); + field_integral += field_values[q] * fe_values.JxW(q); + + field_gradient_square_integral += field_gradients[q].norm_square() * fe_values.JxW(q); + if (degree > 1) + field_hessian_square_integral += field_hessians[q].norm_square() * fe_values.JxW(q); + } + + double beta = field_gradient_square_integral; + if (degree > 1) + beta += field_hessian_square_integral * cell_measure; + + cell_averages.push_back(field_integral / cell_measure); + smoothness_indicators.push_back(beta); + field_values_in_target_cell.push_back(field_values); + // Linear weight of the target cell cannot be determined at present time + // (because we don't know how many neighbors the target cell has). Fill in + // the position with an invalid value. + linear_weights.push_back(numbers::signaling_nan()); + + // Loop over the neighbor cells. + for (const unsigned int face_no : cell->face_indices()) + { + if (cell->face(face_no)->at_boundary()) + continue; + + const typename DoFHandler::cell_iterator + neighbor = cell->neighbor_or_periodic_neighbor(face_no); + + // 'neighbor' defined above is NOT active_cell_iterator, this includes cells + // that are refined + if (!neighbor->has_children()) + { + // Compute the field values at quadrature points of the neighbor. + + // Compute the field derivatives at quadrature points of the target cell. + // To do so, we need to transform the quadrature points of the target cell + // to the 'unit cell' defined by the neighbor. + mapping->transform_points_real_to_unit_cell(neighbor, + fe_values.get_quadrature_points(), + neighbor_quadrature_points); + + Quadrature neighbor_quadrature(neighbor_quadrature_points, + quadrature.get_weights()); + + FEValues neighbor_fe_values(*mapping, + finite_element, + neighbor_quadrature, + neighbor_update_flags); + + neighbor_fe_values.reinit(neighbor); + neighbor_fe_values[field_extractor].get_function_values(solution, field_values); + neighbor_fe_values[field_extractor].get_function_gradients(solution, field_gradients); + if (degree > 1) + neighbor_fe_values[field_extractor].get_function_hessians(solution, field_hessians); + + // Compute the cell average and the smoothness indicator. + double field_integral = 0.0; + double field_gradient_square_integral = 0.0; + double field_hessian_square_integral = 0.0; + for (unsigned int q = 0; q < n_q_points; ++q) + { + field_integral += field_values[q] * fe_values.JxW(q); + field_gradient_square_integral += field_gradients[q].norm_square() * fe_values.JxW(q); + if (degree > 1) + field_hessian_square_integral += field_hessians[q].norm_square() * fe_values.JxW(q); + } + + double beta = field_gradient_square_integral; + if (degree > 1) + beta += field_hessian_square_integral * cell_measure; + + cell_averages.push_back(field_integral / cell_measure); + smoothness_indicators.push_back(beta); + field_values_in_target_cell.push_back(field_values); + linear_weights.push_back(parameters.WENO_linear_weight); + } + else + { + // Neighbor has children. We use a half of the children that are adjacent to + // the target cell (i.e., children that share a face with the target cell) to + // compute the cell average and smoothness indicator. + const unsigned int neighbor_face_no = + (cell->has_periodic_neighbor(face_no) + ? + cell->periodic_neighbor_face_no(face_no) + : + cell->neighbor_face_no(face_no)); + + typename DoFHandler::face_iterator neighbor_face = neighbor->face(neighbor_face_no); + for (unsigned int subface_no = 0; subface_no < neighbor_face->n_children(); ++subface_no) + { + const unsigned int child_no = + GeometryInfo::child_cell_on_face(RefinementCase::isotropic_refinement, + neighbor_face_no, + subface_no, + neighbor->face_orientation(face_no), + neighbor->face_flip(face_no), + neighbor->face_rotation(face_no)); + + typename DoFHandler::active_cell_iterator + neighbor_child = neighbor->child(child_no); + + // Compute the field derivatives at quadrature points of the target cell. + // To do so, we need to transform the quadrature points of the target cell + // to the 'unit cell' defined by the neighbor. + mapping->transform_points_real_to_unit_cell(neighbor_child, + fe_values.get_quadrature_points(), + neighbor_quadrature_points); + + Quadrature neighbor_quadrature(neighbor_quadrature_points, + quadrature.get_weights()); + + FEValues neighbor_fe_values(*mapping, + finite_element, + neighbor_quadrature, + neighbor_update_flags); + + neighbor_fe_values.reinit(neighbor_child); + neighbor_fe_values[field_extractor].get_function_values(solution, field_values); + neighbor_fe_values[field_extractor].get_function_gradients(solution, field_gradients); + if (degree > 1) + neighbor_fe_values[field_extractor].get_function_hessians(solution, field_hessians); + + // Compute the cell average and the smoothness indicator. + double field_integral = 0.0; + double field_gradient_square_integral = 0.0; + double field_hessian_square_integral = 0.0; + for (unsigned int q = 0; q < n_q_points; ++q) + { + field_integral += field_values[q] * fe_values.JxW(q); + field_gradient_square_integral += field_gradients[q].norm_square() * fe_values.JxW(q); + if (degree > 1) + field_hessian_square_integral += field_hessians[q].norm_square() * fe_values.JxW(q); + } + + double beta = field_gradient_square_integral; + if (degree > 1) + beta += field_hessian_square_integral * cell_measure; + + cell_averages.push_back(field_integral / cell_measure); + smoothness_indicators.push_back(beta); + field_values_in_target_cell.push_back(field_values); + linear_weights.push_back(parameters.WENO_linear_weight / neighbor_face->n_children()); + } + } + } + + // Compute the linear weights of the target cell. + linear_weights[0] = 1.0; + for (unsigned int i = 1; i < linear_weights.size(); ++i) + linear_weights[0] -= linear_weights[i]; + + // Compute the nonlinear weights. + const double epsilon = 1e-6 * std::accumulate(smoothness_indicators.begin(), + smoothness_indicators.end(), + 0.0); + nonlinear_weights.clear(); + for (unsigned int i = 0; i < linear_weights.size(); ++i) + nonlinear_weights.push_back(linear_weights[i] / + Utilities::fixed_power<2,double>(smoothness_indicators[i] + epsilon)); + + // Normalize the nonlinear weights. + const double sum = std::accumulate(nonlinear_weights.begin(), + nonlinear_weights.end(), + 0.0); + + for (unsigned int i = 0; i < nonlinear_weights.size(); ++i) + nonlinear_weights[i] /= sum; + + // Compute the values of the reconstructed polynomial at quadrature points. + std::fill(reconstructed_values.begin(), reconstructed_values.end(), 0.0); + for (unsigned int q = 0; q < n_q_points; ++q) + for (unsigned int i = 0; i < nonlinear_weights.size(); ++i) + reconstructed_values[q] += (field_values_in_target_cell[i][q] - cell_averages[i] + cell_averages[0]) * nonlinear_weights[i]; + + // Project the reconstructed polynomial onto grid nodes. + cell_matrix = 0; + cell_rhs = 0; + for (unsigned int q = 0; q < n_q_points; ++q) + { + for (unsigned int i = 0, i_field = 0; i_field < field_dofs_per_cell; /*increment at end of loop*/) + { + if (finite_element.system_to_component_index(i).first == field_component) + { + phi_field[i_field] = fe_values[field_extractor].value(i, q); + ++i_field; + } + ++i; + } + + for (unsigned int i = 0; i < field_dofs_per_cell; ++i) + { + cell_rhs(i) += phi_field[i] * reconstructed_values[q] * fe_values.JxW(q); + + for (unsigned int j = 0; j < field_dofs_per_cell; ++j) + cell_matrix(i, j) += phi_field[i] * phi_field[j] * fe_values.JxW(q); + } + } + + cell_matrix.gauss_jordan(); + cell_matrix.vmult(cell_solution, cell_rhs); + + // Copy the results to the distributed solution vector. + cell->get_dof_indices(cell_dof_indices); + for (unsigned int i = 0, i_field = 0; i_field < field_dofs_per_cell; /*increment at end of loop*/) + { + if (finite_element.system_to_component_index(i).first == field_component) + { + distributed_solution[cell_dof_indices[i]] = cell_solution(i_field); + ++i_field; + } + ++i; + } + } + + // Update the solution vector. + distributed_solution.compress(VectorOperation::insert); + solution.block(block_idx) = distributed_solution.block(block_idx); + } +} + +// explicit instantiations +namespace aspect +{ + +#define INSTANTIATE(dim) \ + template void Simulator::apply_BP_limiter_to_dg_solutions(const AdvectionField &advection_field); \ + template void Simulator::compute_KXRCF_indicators(Vector &, \ + const AdvectionField &) const; \ + template void Simulator::compute_KXRCF_indicators(Vector &, \ + const AdvectionField &) const; \ + template void Simulator::apply_WENO_limiter_to_dg_solutions(const AdvectionField &advection_field); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE +} diff --git a/source/simulator/parameters.cc b/source/simulator/parameters.cc index 630301c8fce..465a60ae821 100644 --- a/source/simulator/parameters.cc +++ b/source/simulator/parameters.cc @@ -1139,47 +1139,51 @@ namespace aspect "is largely empirically decided -- it must be large enough to ensure " "the bilinear form is coercive, but not so large as to penalize " "discontinuity at all costs."); - prm.declare_entry ("Use limiter for discontinuous temperature solution", "false", - Patterns::Bool (), - "Whether to apply the bound preserving limiter as a correction after computing " - "the discontinuous temperature solution. The limiter will only have an " - "effect if the 'Global temperature maximum' and " - "'Global temperature minimum' parameters are defined in the .prm file. " - "This limiter keeps the discontinuous solution in the range given by " - "'Global temperature maximum' and 'Global temperature minimum'. " - "Because this limiter modifies the solution it no longer " - "satisfies the assembled equation. Therefore, " - "the nonlinear residual for this field is meaningless, and in nonlinear " - "solvers we will ignore the residual for this field to evaluate " + prm.declare_entry ("Limiter for discontinuous temperature solution", "none", + Patterns::Selection(DGLimiterType::pattern()), + "The type of limiter to apply to the discontinuous temperature solution. " + "Available options are:\n" + " * `boundary preserving': a limiter that keeps the discontinuous solution " + "in the range given by `Global temperature maximum' and `Global temperature " + "minimum'.\n" + " * `WENO': a limiter that eliminates spurious oscillations by reconstructing " + "a polynomial function in places where shocks are detected.\n" + " * `none`: if chosen, no limiter is applied to the discontinuous solution.\n" + "Note that if this entry is not set to `none', then the limiter will modify " + "the solution, so the nonlinear residual for this field is meaning less, and " + "in nonlinear solvers we will ignore the residual for this field to evaluate " "if the nonlinear solver has converged."); - prm.declare_entry ("Use limiter for discontinuous composition solution", "false", - Patterns::List(Patterns::Bool()), - "Whether to apply the bound preserving limiter as a correction after having " - "the discontinuous composition solution. The limiter will only have an " - "effect if the 'Global composition maximum' and " - "'Global composition minimum' parameters are defined in the .prm file. " - "This limiter keeps the discontinuous solution in the range given by " - "Global composition maximum' and 'Global composition minimum'. " - "The number of input values in this parameter separated by ',' has to be " - "one or the number of the compositional fields. When only one value " - "is supplied, this same value is assumed for all compositional fields, otherwise " - "each value represents if the limiter should be applied to the respective " - "compositional field. " - "Because this limiter modifies the solution it no longer " - "satisfies the assembled equation. Therefore, " - "the nonlinear residual for this field is meaningless, and in nonlinear " - "solvers we will ignore the residual for this field to evaluate " + prm.declare_entry ("Limiter for discontinuous composition solution", "none", + Patterns::List(Patterns::Selection(DGLimiterType::pattern())), + "The type of limiter to apply to the discontinuous composition solution. The " + "number of the input values separated by ',' has to be one or the same as the " + "number of the compositional fields. When only one value is supplied, this " + "same value is assumed for all compositional fields.\n" + "Available options are:\n" + " * `boundary preserving': a limiter that keeps the discontinuous solution " + "in the range given by `Global temperature maximum' and `Global temperature " + "minimum'.\n" + " * `WENO': a limiter that eliminates spurious oscillations by reconstructing " + "a polynomial function in places where shocks are detected.\n" + " * `none`: if chosen, no limiter is applied to the discontinuous solution.\n" + "Note that if this entry is not set to `none', then the limiter will modify " + "the solution, so the nonlinear residual for this field is meaning less, and " + "in nonlinear solvers we will ignore the residual for this field to evaluate " "if the nonlinear solver has converged."); prm.declare_entry ("Global temperature maximum", boost::lexical_cast(std::numeric_limits::max()), Patterns::Double (), "The maximum global temperature value that will be used in the bound preserving " - "limiter for the discontinuous solutions from temperature advection fields."); + "limiter for the discontinuous solutions from temperature advection fields. " + "The input value is active only when `Limiter for discontinuous temperature " + "solution' is set to `boundary preserving'."); prm.declare_entry ("Global temperature minimum", boost::lexical_cast(std::numeric_limits::lowest()), Patterns::Double (), "The minimum global temperature value that will be used in the bound preserving " - "limiter for the discontinuous solutions from temperature advection fields."); + "limiter for the discontinuous solutions from temperature advection fields." + "The input value is active only when `Limiter for discontinuous temperature " + "solution' is set to `boundary preserving'."); prm.declare_entry ("Global composition maximum", boost::lexical_cast(std::numeric_limits::max()), Patterns::List(Patterns::Double ()), @@ -1187,7 +1191,9 @@ namespace aspect "limiter for the discontinuous solutions from composition advection fields. " "The number of the input 'Global composition maximum' values separated by ',' has to be " "one or the same as the number of the compositional fields. When only one value " - "is supplied, this same value is assumed for all compositional fields."); + "is supplied, this same value is assumed for all compositional fields. " + "The input value is active only when `Limiter for discontinuous composition " + "solution' is set to `boundary preserving'."); prm.declare_entry ("Global composition minimum", boost::lexical_cast(std::numeric_limits::lowest()), Patterns::List(Patterns::Double ()), @@ -1195,7 +1201,31 @@ namespace aspect "limiter for the discontinuous solutions from composition advection fields. " "The number of the input 'Global composition minimum' values separated by ',' has to be " "one or the same as the number of the compositional fields. When only one value " - "is supplied, this same value is assumed for all compositional fields."); + "is supplied, this same value is assumed for all compositional fields. " + "The input value is active only when `Limiter for discontinuous composition " + "solution' is set to `boundary preserving'."); + prm.declare_entry ("Temperature KXRCF indicator threshold", "1.0", + Patterns::Double(0.0), + "The threshold of KXRCF indicator for the temperature field. If the KXRCF indicator " + "of a cell is greater than the threshold, then the cell is marked as 'troubled' " + "and will be smoothed by the WENO limiter. " + "The input value is active only when `Limiter for discontinuous temperature " + "solution' is set to `WENO'."); + prm.declare_entry ("Composition KXRCF indicator threshold", "1.0", + Patterns::Double(0.0), + "The threshold of KXRCF indicator for the temperature field. If the KXRCF indicator " + "of a cell is greater than the threshold, then the cell is marked as 'troubled' " + "and will be smoothed by the WENO limiter. The number of the input values " + "separated by ',' has to be one or the same as the number of the compositional " + "fields. When only one value is supplied, this same value is assumed for all " + "compositional fields. " + "The input value is active only when `Limiter for discontinuous composition " + "solution' is set to `WENO'."); + prm.declare_entry ("WENO linear weight of neighbor cells", "0.001", + Patterns::Double(0.0, 1.0), + "The liear weight of neighbor cells in WENO scheme. The larger this value is, " + "the more information of neighbor cells will be involved in the polynomial " + "reconstruction."); } prm.leave_subsection (); } @@ -1787,13 +1817,16 @@ namespace aspect stabilization_gamma = prm.get_double ("gamma"); discontinuous_penalty = prm.get_double ("Discontinuous penalty"); - use_limiter_for_discontinuous_temperature_solution - = prm.get_bool("Use limiter for discontinuous temperature solution"); - use_limiter_for_discontinuous_composition_solution - = Utilities::possibly_extend_from_1_to_N(Utilities::string_to_bool - (Utilities::split_string_list(prm.get("Use limiter for discontinuous composition solution"))), - n_compositional_fields, - "Use limiter for discontinuous composition solution"); + + limiter_for_discontinuous_temperature_solution = DGLimiterType::parse(prm.get("Limiter for discontinuous temperature solution")); + std::vector x_limiter_for_discontinuous_composition_solution = + Utilities::possibly_extend_from_1_to_N(Utilities::split_string_list(prm.get("Limiter for discontinuous composition solution")), + n_compositional_fields, + "Limiter for discontinuous composition solution"); + limiter_for_discontinuous_composition_solution.resize(n_compositional_fields); + for (unsigned int c = 0; c < n_compositional_fields; ++c) + limiter_for_discontinuous_composition_solution[c] = DGLimiterType::parse(x_limiter_for_discontinuous_composition_solution[c]); + global_temperature_max_preset = prm.get_double ("Global temperature maximum"); global_temperature_min_preset = prm.get_double ("Global temperature minimum"); global_composition_max_preset = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double @@ -1804,6 +1837,14 @@ namespace aspect (Utilities::split_string_list(prm.get ("Global composition minimum"))), n_compositional_fields, "Global composition minimum"); + + temperature_KXRCF_indicator_threshold = prm.get_double ("Temperature KXRCF indicator threshold"); + composition_KXRCF_indicator_threshold = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double + (Utilities::split_string_list(prm.get("Composition KXRCF indicator threshold"))), + n_compositional_fields, + "Composition KXRCF indicator threshold"); + WENO_linear_weight = prm.get_double("WENO linear weight of neighbor cells"); + compositional_fields_with_disabled_boundary_entropy_viscosity = Utilities::split_string_list(prm.get("List of compositional fields with disabled boundary entropy viscosity")); diff --git a/source/simulator/simulator_access.cc b/source/simulator/simulator_access.cc index 990c55a8564..12b4a3affeb 100644 --- a/source/simulator/simulator_access.cc +++ b/source/simulator/simulator_access.cc @@ -321,6 +321,19 @@ namespace aspect + template + void + SimulatorAccess::compute_KXRCF_indicators(Vector &KXRCF_indicators, + const unsigned int field_index) const + { + const typename Simulator::AdvectionField advection_field = + (field_index == 0 ? Simulator::AdvectionField::temperature() + : Simulator::AdvectionField::composition(field_index-1)); + simulator->compute_KXRCF_indicators(KXRCF_indicators, advection_field); + } + + + template const LinearAlgebra::BlockVector & SimulatorAccess::get_current_linearization_point () const diff --git a/source/simulator/solver.cc b/source/simulator/solver.cc index bb9ba0227da..fb737a7ecd7 100644 --- a/source/simulator/solver.cc +++ b/source/simulator/solver.cc @@ -736,20 +736,35 @@ namespace aspect pcout << solver_control.last_step() << " iterations." << std::endl; - if ((advection_field.is_discontinuous(introspection) - && - ( - (advection_field.is_temperature() && parameters.use_limiter_for_discontinuous_temperature_solution) - || - (!advection_field.is_temperature() && parameters.use_limiter_for_discontinuous_composition_solution[advection_field.compositional_variable]) - ))) + if (advection_field.is_discontinuous(introspection)) { - apply_limiter_to_dg_solutions(advection_field); - // by applying the limiter we have modified the solution to no longer - // satisfy the equation. Therefore the residual is meaningless and cannot - // converge to zero in nonlinear iterations. Disable residual computation - // for this field. - return 0.0; + const typename Parameters::DGLimiterType::Kind + limiter = (advection_field.is_temperature() ? + parameters.limiter_for_discontinuous_temperature_solution : + parameters.limiter_for_discontinuous_composition_solution[advection_field.compositional_variable]); + + switch (limiter) + { + case Parameters::DGLimiterType::boundary_preserving: + apply_BP_limiter_to_dg_solutions(advection_field); + break; + case Parameters::DGLimiterType::WENO: + apply_WENO_limiter_to_dg_solutions(advection_field); + break; + case Parameters::DGLimiterType::none: + break; + default: + AssertThrow(false, ExcNotImplemented()); + } + + if (limiter != Parameters::DGLimiterType::none) + // by applying the limiter we have modified the solution to no longer + // satisfy the equation. Therefore the residual is meaningless and cannot + // converge to zero in nonlinear iterations. Disable residual computation + // for this field. + return 0.0; + else + return initial_residual; } return initial_residual; From b6aaaca5adb452d8081b0cbe93d0f82a7135b760 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Sat, 22 Jun 2024 15:20:49 +0800 Subject: [PATCH 02/22] correct spelling mistakes --- source/simulator/limiters.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/simulator/limiters.cc b/source/simulator/limiters.cc index eb1ec577785..c8094e91267 100644 --- a/source/simulator/limiters.cc +++ b/source/simulator/limiters.cc @@ -414,11 +414,11 @@ namespace aspect } else { - // Neighbor is taking responsibility for assembly of this face, bacause + // Neighbor is taking responsibility for assembly of this face, because // either (1) neighbor is coarser, or // (2) neighbor is equally-sized and // (a) neighbor is on a different subdomain, with lower subdomain_id(), or - // (b) nieghbor is on the same subdomain and has lower index(). + // (b) neighbor is on the same subdomain and has lower index(). } } else From 68e633c2a14c06c1db5c4252796f3b42f2d15a24 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Thu, 4 Jul 2024 11:47:09 +0800 Subject: [PATCH 03/22] add necessary headers for compilation without unity build --- source/simulator/limiters.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/simulator/limiters.cc b/source/simulator/limiters.cc index c8094e91267..20109ca5f60 100644 --- a/source/simulator/limiters.cc +++ b/source/simulator/limiters.cc @@ -1,4 +1,6 @@ #include +#include +#include namespace aspect { From 4bfb4a8d20f159e106796e8f1c9670d45c4e84d7 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Thu, 4 Jul 2024 11:54:14 +0800 Subject: [PATCH 04/22] reformat the .prm file for limiter settings --- .../prm_files/reformat_limiter_settings.py | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 contrib/utilities/update_scripts/prm_files/reformat_limiter_settings.py diff --git a/contrib/utilities/update_scripts/prm_files/reformat_limiter_settings.py b/contrib/utilities/update_scripts/prm_files/reformat_limiter_settings.py new file mode 100644 index 00000000000..27b26b11627 --- /dev/null +++ b/contrib/utilities/update_scripts/prm_files/reformat_limiter_settings.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" This script changes 'Use limiter for discontinuous temperature/composition solution' +to 'limiter for discontinuous temperature/composition solution' in order to allow users +to specify different limiters for different fields +""" + + +import sys +import os +import re +import argparse + +__author__ = 'The authors of the ASPECT code' +__copyright__ = 'Copyright 2024, ASPECT' +__license__ = 'GNU GPL 2 or later' + +# Add the ASPECT root directory to the path so we can import from the aspect_data module +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..')) +import python.scripts.aspect_input as aspect + + + +def reformat_limiter_settings(parameters): + """change 'Use limiter for discontinuous temperature/composition solution' + to 'limiter for discontinuous temperature/composition solution' in order to allow users + to specify different limiters for different fields + """ + + old_entries = ["Use limiter for discontinuous temperature solution", + "Use limiter for discontinuous composition solution"] + new_entries = ["Limiter for discontinuous temperature solution", + "Limiter for discontinuous composition solution"] + + # go to the subsection + if "Discretization" in parameters: + if "Stabilization parameters" in parameters["Discretization"]["value"]: + subsection = parameters["Discretization"]["value"]["Stabilization parameters"]["value"] + + for i in range(0,2): + if old_entries[i] in subsection: + + # Delete the old entry + use_limiter = subsection[old_entries[i]]["value"] + del subsection[old_entries[i]] + + # If limiter is used, then set the value of the new entry to "boundary preserving" + if use_limiter == "true": + subsection[new_entries[i]] = {"comment" : "", + "value" : "boundary preserving", + "type" : "parameter", + "alignment spaces": 1} + + return parameters + + + +def main(input_file, output_file): + """Echo the input arguments to standard output""" + parameters = aspect.read_parameter_file(input_file) + parameters = reformat_limiter_settings(parameters) + aspect.write_parameter_file(parameters, output_file) + + + +if __name__ == '__main__': + parser = argparse.ArgumentParser( + prog='ASPECT .prm file reformatter', + description='Reformats ASPECT .prm files to follow our general formatting guidelines. See the documentation of this script for details.') + parser.add_argument('input_file', type=str, help='The .prm file to reformat') + parser.add_argument('output_file', type=str, help='The .prm file to write the reformatted file to') + args = parser.parse_args() + + sys.exit(main(args.input_file, args.output_file)) From 13ed3c4f5e57a9b92f0a676fc79b45566b2c1ef8 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Thu, 4 Jul 2024 11:57:53 +0800 Subject: [PATCH 05/22] Update source/simulator/parameters.cc Co-authored-by: Rene Gassmoeller --- source/simulator/parameters.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/simulator/parameters.cc b/source/simulator/parameters.cc index 465a60ae821..26bf5025993 100644 --- a/source/simulator/parameters.cc +++ b/source/simulator/parameters.cc @@ -1223,7 +1223,7 @@ namespace aspect "solution' is set to `WENO'."); prm.declare_entry ("WENO linear weight of neighbor cells", "0.001", Patterns::Double(0.0, 1.0), - "The liear weight of neighbor cells in WENO scheme. The larger this value is, " + "The linear weight of neighbor cells in WENO scheme. The larger this value is, " "the more information of neighbor cells will be involved in the polynomial " "reconstruction."); } From 95edb8a732f500227946231df74264d998885a34 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Thu, 4 Jul 2024 12:07:01 +0800 Subject: [PATCH 06/22] change boundary_preserving to bound_preserving --- include/aspect/parameters.h | 8 ++++---- source/simulator/core.cc | 6 +++--- source/simulator/parameters.cc | 12 ++++++------ source/simulator/solver.cc | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/aspect/parameters.h b/include/aspect/parameters.h index f4205dc8d1b..4890ac4c987 100644 --- a/include/aspect/parameters.h +++ b/include/aspect/parameters.h @@ -321,7 +321,7 @@ namespace aspect { enum Kind { - boundary_preserving, + bound_preserving, WENO, none }; @@ -330,8 +330,8 @@ namespace aspect Kind parse(const std::string &input) { - if (input == "boundary preserving") - return boundary_preserving; + if (input == "bound preserving") + return bound_preserving; else if (input == "WENO") return WENO; else if (input == "none") @@ -344,7 +344,7 @@ namespace aspect static const std::string pattern() { - return "boundary preserving|WENO|none"; + return "bound preserving|WENO|none"; } }; diff --git a/source/simulator/core.cc b/source/simulator/core.cc index e0226cf8034..76cac919a8f 100644 --- a/source/simulator/core.cc +++ b/source/simulator/core.cc @@ -486,15 +486,15 @@ namespace aspect map->initialize(MappingQGeneric(4), triangulation); bool bp_limiter_enabled = (parameters.limiter_for_discontinuous_temperature_solution - == Parameters::DGLimiterType::boundary_preserving); + == Parameters::DGLimiterType::bound_preserving); for (unsigned int c=0; c::DGLimiterType::boundary_preserving); + == Parameters::DGLimiterType::bound_preserving); // Check that BP limiters are only used with cartesian mapping if (bp_limiter_enabled) AssertThrow(geometry_model->natural_coordinate_system() == Utilities::Coordinates::CoordinateSystem::cartesian, - ExcMessage("The boundary preserving limiter for the discontinuous temperature and composition solutions " + ExcMessage("The bound preserving limiter for the discontinuous temperature and composition solutions " "has not been tested in non-Cartesian geometries and currently requires " "the use of a Cartesian geometry model.")); diff --git a/source/simulator/parameters.cc b/source/simulator/parameters.cc index 26bf5025993..29b7f832f8e 100644 --- a/source/simulator/parameters.cc +++ b/source/simulator/parameters.cc @@ -1143,7 +1143,7 @@ namespace aspect Patterns::Selection(DGLimiterType::pattern()), "The type of limiter to apply to the discontinuous temperature solution. " "Available options are:\n" - " * `boundary preserving': a limiter that keeps the discontinuous solution " + " * `bound preserving': a limiter that keeps the discontinuous solution " "in the range given by `Global temperature maximum' and `Global temperature " "minimum'.\n" " * `WENO': a limiter that eliminates spurious oscillations by reconstructing " @@ -1160,7 +1160,7 @@ namespace aspect "number of the compositional fields. When only one value is supplied, this " "same value is assumed for all compositional fields.\n" "Available options are:\n" - " * `boundary preserving': a limiter that keeps the discontinuous solution " + " * `bound preserving': a limiter that keeps the discontinuous solution " "in the range given by `Global temperature maximum' and `Global temperature " "minimum'.\n" " * `WENO': a limiter that eliminates spurious oscillations by reconstructing " @@ -1176,14 +1176,14 @@ namespace aspect "The maximum global temperature value that will be used in the bound preserving " "limiter for the discontinuous solutions from temperature advection fields. " "The input value is active only when `Limiter for discontinuous temperature " - "solution' is set to `boundary preserving'."); + "solution' is set to `bound preserving'."); prm.declare_entry ("Global temperature minimum", boost::lexical_cast(std::numeric_limits::lowest()), Patterns::Double (), "The minimum global temperature value that will be used in the bound preserving " "limiter for the discontinuous solutions from temperature advection fields." "The input value is active only when `Limiter for discontinuous temperature " - "solution' is set to `boundary preserving'."); + "solution' is set to `bound preserving'."); prm.declare_entry ("Global composition maximum", boost::lexical_cast(std::numeric_limits::max()), Patterns::List(Patterns::Double ()), @@ -1193,7 +1193,7 @@ namespace aspect "one or the same as the number of the compositional fields. When only one value " "is supplied, this same value is assumed for all compositional fields. " "The input value is active only when `Limiter for discontinuous composition " - "solution' is set to `boundary preserving'."); + "solution' is set to `bound preserving'."); prm.declare_entry ("Global composition minimum", boost::lexical_cast(std::numeric_limits::lowest()), Patterns::List(Patterns::Double ()), @@ -1203,7 +1203,7 @@ namespace aspect "one or the same as the number of the compositional fields. When only one value " "is supplied, this same value is assumed for all compositional fields. " "The input value is active only when `Limiter for discontinuous composition " - "solution' is set to `boundary preserving'."); + "solution' is set to `bound preserving'."); prm.declare_entry ("Temperature KXRCF indicator threshold", "1.0", Patterns::Double(0.0), "The threshold of KXRCF indicator for the temperature field. If the KXRCF indicator " diff --git a/source/simulator/solver.cc b/source/simulator/solver.cc index fb737a7ecd7..c91409716bb 100644 --- a/source/simulator/solver.cc +++ b/source/simulator/solver.cc @@ -745,7 +745,7 @@ namespace aspect switch (limiter) { - case Parameters::DGLimiterType::boundary_preserving: + case Parameters::DGLimiterType::bound_preserving: apply_BP_limiter_to_dg_solutions(advection_field); break; case Parameters::DGLimiterType::WENO: From b0c4e8f332fb9cfbd1c668c5f6ad3c5148ba2d35 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Fri, 5 Jul 2024 11:03:38 +0800 Subject: [PATCH 07/22] replace 'boundary preserving' by 'bound preserving' --- .../update_scripts/prm_files/reformat_limiter_settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/utilities/update_scripts/prm_files/reformat_limiter_settings.py b/contrib/utilities/update_scripts/prm_files/reformat_limiter_settings.py index 27b26b11627..f9a401d4281 100644 --- a/contrib/utilities/update_scripts/prm_files/reformat_limiter_settings.py +++ b/contrib/utilities/update_scripts/prm_files/reformat_limiter_settings.py @@ -45,10 +45,10 @@ def reformat_limiter_settings(parameters): use_limiter = subsection[old_entries[i]]["value"] del subsection[old_entries[i]] - # If limiter is used, then set the value of the new entry to "boundary preserving" + # If limiter is used, then set the value of the new entry to "bound preserving" if use_limiter == "true": subsection[new_entries[i]] = {"comment" : "", - "value" : "boundary preserving", + "value" : "bound preserving", "type" : "parameter", "alignment spaces": 1} From a53c298fce094dbd4397585018d8262d3d50c93b Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Mon, 8 Jul 2024 15:48:16 +0800 Subject: [PATCH 08/22] add citations for WENO limiter and KXRCF indicator --- doc/manual/citing_aspect.bib | 28 ++++++++++++++++++++++++++++ source/simulator/parameters.cc | 29 ++++++++++++++++------------- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/doc/manual/citing_aspect.bib b/doc/manual/citing_aspect.bib index 1ef12192db7..f332ea06521 100644 --- a/doc/manual/citing_aspect.bib +++ b/doc/manual/citing_aspect.bib @@ -2068,4 +2068,32 @@ @article{SAKI2024107212 keywords = {Mantle transition zone discontinuities, PP and SS precursors, Caribbean subduction, Plume-slab interaction} } +@article{zhong2013, +title = {A simple weighted essentially nonoscillatory limiter for {Runge}–{Kutta} discontinuous {Galerkin} methods}, +volume = {232}, +issn = {0021-9991}, +doi = {10.1016/j.jcp.2012.08.028}, +language = {en}, +number = {1}, +journal = {Journal of Computational Physics}, +author = {Zhong, Xinghui and Shu, Chi-Wang}, +month = jan, +year = {2013}, +keywords = {Discontinuous Galerkin method, WENO limiter}, +pages = {397--415} +} +@article{krivodonova2004, +series = {Workshop on {Innovative} {Time} {Integrators} for {PDEs}}, +title = {Shock detection and limiting with discontinuous {Galerkin} methods for hyperbolic conservation laws}, +volume = {48}, +issn = {0168-9274}, +doi = {10.1016/j.apnum.2003.11.002}, +language = {en}, +number = {3}, +journal = {Applied Numerical Mathematics}, +author = {Krivodonova, L. and Xin, J. and Remacle, J. -F. and Chevaugeon, N. and Flaherty, J. E.}, +month = mar, +year = {2004}, +pages = {323--338} +} diff --git a/source/simulator/parameters.cc b/source/simulator/parameters.cc index 29b7f832f8e..ddfc8eae121 100644 --- a/source/simulator/parameters.cc +++ b/source/simulator/parameters.cc @@ -1147,7 +1147,8 @@ namespace aspect "in the range given by `Global temperature maximum' and `Global temperature " "minimum'.\n" " * `WENO': a limiter that eliminates spurious oscillations by reconstructing " - "a polynomial function in places where shocks are detected.\n" + "a polynomial function in places where shocks are detected, as described in " + "\\cite{zhong:etal:2013}.\n" " * `none`: if chosen, no limiter is applied to the discontinuous solution.\n" "Note that if this entry is not set to `none', then the limiter will modify " "the solution, so the nonlinear residual for this field is meaning less, and " @@ -1164,7 +1165,8 @@ namespace aspect "in the range given by `Global temperature maximum' and `Global temperature " "minimum'.\n" " * `WENO': a limiter that eliminates spurious oscillations by reconstructing " - "a polynomial function in places where shocks are detected.\n" + "a polynomial function in places where shocks are detected, as described in " + "\\cite{zhong:etal:2013}.\n" " * `none`: if chosen, no limiter is applied to the discontinuous solution.\n" "Note that if this entry is not set to `none', then the limiter will modify " "the solution, so the nonlinear residual for this field is meaning less, and " @@ -1201,31 +1203,32 @@ namespace aspect "limiter for the discontinuous solutions from composition advection fields. " "The number of the input 'Global composition minimum' values separated by ',' has to be " "one or the same as the number of the compositional fields. When only one value " - "is supplied, this same value is assumed for all compositional fields. " + "is supplied, this same value is assumed for all compositional fields.\n" "The input value is active only when `Limiter for discontinuous composition " "solution' is set to `bound preserving'."); prm.declare_entry ("Temperature KXRCF indicator threshold", "1.0", Patterns::Double(0.0), - "The threshold of KXRCF indicator for the temperature field. If the KXRCF indicator " - "of a cell is greater than the threshold, then the cell is marked as 'troubled' " - "and will be smoothed by the WENO limiter. " + "The threshold of KXRCF indicator for the temperature field, as described in " + "\\cite{Krivodonova:etal:2004}. If the KXRCF indicator of a cell is greater than " + "the threshold, then the cell is marked as 'troubled' and will be smoothed by " + "the WENO limiter.\n" "The input value is active only when `Limiter for discontinuous temperature " "solution' is set to `WENO'."); prm.declare_entry ("Composition KXRCF indicator threshold", "1.0", Patterns::Double(0.0), - "The threshold of KXRCF indicator for the temperature field. If the KXRCF indicator " - "of a cell is greater than the threshold, then the cell is marked as 'troubled' " - "and will be smoothed by the WENO limiter. The number of the input values " - "separated by ',' has to be one or the same as the number of the compositional " - "fields. When only one value is supplied, this same value is assumed for all " - "compositional fields. " + "The threshold of KXRCF indicator for the temperature field, as described in " + "\\cite{Krivodonova:etal:2004}. If the KXRCF indicator of a cell is greater than " + "the threshold, then the cell is marked as 'troubled' and will be smoothed by " + "the WENO limiter. The number of the input values separated by ',' has to be one " + "or the same as the number of the compositional fields. When only one value is " + "supplied, this same value is assumed for all compositional fields.\n" "The input value is active only when `Limiter for discontinuous composition " "solution' is set to `WENO'."); prm.declare_entry ("WENO linear weight of neighbor cells", "0.001", Patterns::Double(0.0, 1.0), "The linear weight of neighbor cells in WENO scheme. The larger this value is, " "the more information of neighbor cells will be involved in the polynomial " - "reconstruction."); + "reconstruction. See \\cite{zhong:etal:2013} for detail."); } prm.leave_subsection (); } From 9d46a6266ae0030b447d85eec79fe9bfb412b20d Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Mon, 8 Jul 2024 15:48:56 +0800 Subject: [PATCH 09/22] scale the characteristic mesh spacing by the diameter of Omega --- source/simulator/limiters.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/simulator/limiters.cc b/source/simulator/limiters.cc index 20109ca5f60..bce8fba5b4a 100644 --- a/source/simulator/limiters.cc +++ b/source/simulator/limiters.cc @@ -504,6 +504,7 @@ namespace aspect // troubled cell indicator. const unsigned int degree = advection_field.polynomial_degree(introspection); const double power = (degree + 1.0) / 2.0; + const double scaling_factor = 1. / global_Omega_diameter; const unsigned int block_idx = advection_field.block_index(introspection); const double epsilon = std::max(1e-20, @@ -513,7 +514,10 @@ namespace aspect for (const auto &cell : dof_handler.active_cell_iterators()) if (cell->is_locally_owned()) { - const double h_pow = std::pow(cell->diameter(), power); + // The characteristic mesh spacing is calculated by d/D, where + // d and D are the diameters of the present cell and the geometry + // model, respectively. + const double h_pow = std::pow(cell->diameter() * scaling_factor, power); const auto cell_data = data.find(cell->active_cell_index()); if (cell_data->second.inflow_face_area == 0.0) KXRCF_indicators[cell->active_cell_index()] = 0.0; From 06e7cb8134123d4d91da4dd118eeb36f5cc42fac Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Mon, 8 Jul 2024 17:00:09 +0800 Subject: [PATCH 10/22] add viscoelastic_beam_modified benchmark with WENO limiter --- .../20km_opentopbot_weno.prm | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 benchmarks/viscoelastic_beam_modified/20km_opentopbot_weno.prm diff --git a/benchmarks/viscoelastic_beam_modified/20km_opentopbot_weno.prm b/benchmarks/viscoelastic_beam_modified/20km_opentopbot_weno.prm new file mode 100644 index 00000000000..3eab684ad1d --- /dev/null +++ b/benchmarks/viscoelastic_beam_modified/20km_opentopbot_weno.prm @@ -0,0 +1,33 @@ +# This parameter file modifies the benchmark 20kmh_05drho.prm to use the WENO limiter +# for viscoelastic stress components. + +include $ASPECT_SOURCE_DIR/benchmarks/viscoelastic_bending_beam/20km_opentopbot.prm + +set Output directory = 20kmh_05drho_weno + + +subsection Discretization + subsection Stabilization parameters + # Use WENO limiter for viscoelastic stress components, while using the + # bound-preserving limiter for the chemical field + set Limiter for discontinuous composition solution = WENO, WENO, WENO, bound preserving + # In this benchmark, the spurious oscillations at the boundaries of the beam + # are extremely serious, so we set the linear weight of neighbor cells one + # magnitude greater than the default value to make the reconstructed solution + # smoother. + set WENO linear weight of neighbor cells = 0.01 + # The global maximum and minimum values are only used by the chemical field. + set Global composition maximum = 1.0 + set Global composition minimum = 0.0 + end +end + +# Visualize the KXRCF indicator for ve_stress_xy +subsection Postprocess + subsection Visualization + set List of output variables = material properties, strain rate, kxrcf indicator + subsection KXRCF indicator + set Name of advection field = ve_stress_xy + end + end +end From 36ff89126c07e7621380c913d8b0a71bcc0f2386 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Mon, 8 Jul 2024 17:01:45 +0800 Subject: [PATCH 11/22] add viscoelastic_bending_beam benchmark with WENO limiter --- .../viscoelastic_bending_beam_weno.prm | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_weno.prm diff --git a/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_weno.prm b/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_weno.prm new file mode 100644 index 00000000000..d6a698d676f --- /dev/null +++ b/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_weno.prm @@ -0,0 +1,32 @@ +# This parameter file modifies the benchmark viscoealastic_bending_beam.prm +# to use the WENO limiter for viscoelastic stress components. + +include $ASPECT_SOURCE_DIR/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam.prm + +set Output directory = output_viscoelastic_bending_beam_weno + +subsection Discretization + subsection Stabilization parameters + # Use WENO limiter for viscoelastic stress components, while using the + # bound-preserving limiter for the chemical field + set Limiter for discontinuous composition solution = WENO, WENO, WENO, bound preserving + # In this benchmark, the spurious oscillations at the boundaries of the beam + # are extremely serious, so we set the linear weight of neighbor cells one + # magnitude greater than the default value to make the reconstructed solution + # smoother. + set WENO linear weight of neighbor cells = 0.01 + # The global maximum and minimum values are only used by the chemical field. + set Global composition maximum = 1.0 + set Global composition minimum = 0.0 + end +end + +# Visualize the KXRCF indicator for ve_stress_xy +subsection Postprocess + subsection Visualization + set List of output variables = material properties, strain rate, kxrcf indicator + subsection KXRCF indicator + set Name of advection field = ve_stress_xy + end + end +end From 0a25a71f8efaf0a625eabc924c1424356b8cb185 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Mon, 8 Jul 2024 17:02:20 +0800 Subject: [PATCH 12/22] add rotate_shape benchmark with WENO limiter --- benchmarks/advection/rotate_shape_dg_weno.prm | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 benchmarks/advection/rotate_shape_dg_weno.prm diff --git a/benchmarks/advection/rotate_shape_dg_weno.prm b/benchmarks/advection/rotate_shape_dg_weno.prm new file mode 100644 index 00000000000..895cf0ccdb3 --- /dev/null +++ b/benchmarks/advection/rotate_shape_dg_weno.prm @@ -0,0 +1,26 @@ +# Like rotate_shape_supg but with discontinuous Galerkin method +# and WENO limiter + +set Dimension = 2 + +include rotate_shape_supg.prm + +set Output directory = output-rotate-shape-dg-weno + +subsection Discretization + set Use discontinuous temperature discretization = true + set Use discontinuous composition discretization = true + subsection Stabilization parameters + set Limiter for discontinuous temperature solution = WENO + set Limiter for discontinuous composition solution = WENO + end +end + +subsection Postprocess + subsection Visualization + set List of output variables = kxrcf indicator + subsection KXRCF indicator + set Name of advection field = C_1 + end + end +end From 7103a42cb7cb20455281da97e5618dd893794a1c Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Mon, 8 Jul 2024 17:02:31 +0800 Subject: [PATCH 13/22] add rotate_shape benchmark with bound-preserving limiter --- benchmarks/advection/rotate_shape_dg_bp.prm | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 benchmarks/advection/rotate_shape_dg_bp.prm diff --git a/benchmarks/advection/rotate_shape_dg_bp.prm b/benchmarks/advection/rotate_shape_dg_bp.prm new file mode 100644 index 00000000000..bf877a98975 --- /dev/null +++ b/benchmarks/advection/rotate_shape_dg_bp.prm @@ -0,0 +1,21 @@ +# Like rotate_shape_supg but with discontinuous Galerkin method +# and bound-preserving limiter + +set Dimension = 2 + +include rotate_shape_supg.prm + +set Output directory = output-rotate-shape-dg-bp + +subsection Discretization + set Use discontinuous temperature discretization = true + set Use discontinuous composition discretization = true + subsection Stabilization parameters + set Limiter for discontinuous temperature solution = bound preserving + set Limiter for discontinuous composition solution = bound preserving + set Global temperature maximum = 1 + set Global temperature minimum = 0 + set Global composition maximum = 1 + set Global composition minimum = 0 + end +end From 59f361bcfbbe9189c92ccd25d0a4a2abd5a5a1f1 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Thu, 11 Jul 2024 23:14:33 +0800 Subject: [PATCH 14/22] replace Patterns::Double() by Patterns::List(Patterns::Double()) for Composition KXRCF indicator threshold --- source/simulator/parameters.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/simulator/parameters.cc b/source/simulator/parameters.cc index ddfc8eae121..0388951e6a0 100644 --- a/source/simulator/parameters.cc +++ b/source/simulator/parameters.cc @@ -1215,7 +1215,7 @@ namespace aspect "The input value is active only when `Limiter for discontinuous temperature " "solution' is set to `WENO'."); prm.declare_entry ("Composition KXRCF indicator threshold", "1.0", - Patterns::Double(0.0), + Patterns::List(Double(0.0)), "The threshold of KXRCF indicator for the temperature field, as described in " "\\cite{Krivodonova:etal:2004}. If the KXRCF indicator of a cell is greater than " "the threshold, then the cell is marked as 'troubled' and will be smoothed by " From d6a1a0e971102af3c56adb6c7acb096c07a7dae1 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Thu, 11 Jul 2024 23:16:09 +0800 Subject: [PATCH 15/22] supplement comments for KXRCF indicator and WENO limiter --- include/aspect/simulator.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/include/aspect/simulator.h b/include/aspect/simulator.h index e21f85c6284..0c7fbd1630f 100644 --- a/include/aspect/simulator.h +++ b/include/aspect/simulator.h @@ -1379,7 +1379,13 @@ namespace aspect /** * Apply the WENO limiter to the discontinuous Galerkin solutions. - * The WENO scheme implemented in this function is proposed by Zhong and Shu, 2013. + * WENO is short for Weighted Essentially Non-Oscillatory, which is + * a class of high-resolution schemes used in the numerical solution + * of hyperbolic conservation laws. The basic idea of WENO limiter is + * to replace the solution in troubled cells (cells with oscillation) + * by a polynomial reconstruction that takes the neighbor cells into + * account. The WENO scheme implemented in the program is a simple + * variant proposed by Zhong and Shu, 2013. * * This function is implemented in * source/simulator/limiters.cc. @@ -1387,8 +1393,10 @@ namespace aspect void apply_WENO_limiter_to_dg_solutions (const AdvectionField &advection_field); /** - * Compute the KXRCF indicator that detect shocks in the advection field. - * The KXRCF indicator is used by the WENO limiter. + * Fills a vector with the KXRCF indicator for a given advection field + * on each local cell. The KXRCF indicator is a metric of discontinuity + * for hyperbolic conservation laws. Cells with high KXRCF values are + * identified as "troubled cells" and will be smoothed by the WENO limiter. * * This function is implemented in * source/simulator/limiters.cc. From 92b5d90c96838cd7975025469fddfaaa24da175a Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Thu, 11 Jul 2024 23:16:28 +0800 Subject: [PATCH 16/22] supplement the documentation for KXRCF indicator --- .../postprocess/visualization/kxrcf_indicator.cc | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/source/postprocess/visualization/kxrcf_indicator.cc b/source/postprocess/visualization/kxrcf_indicator.cc index 5403aa477f0..b932f96d09f 100644 --- a/source/postprocess/visualization/kxrcf_indicator.cc +++ b/source/postprocess/visualization/kxrcf_indicator.cc @@ -114,8 +114,20 @@ namespace aspect ASPECT_REGISTER_VISUALIZATION_POSTPROCESSOR(KXRCFIndicator, "kxrcf indicator", "A visualization output object that generates output " - "showing the value of the KXRCF indicator on each " - "cell." + "showing the value of the KXRCF indicator for a given " + "advection field (either temperature or compositional " + "field) on each cell. The KXRCF indicator is a metric " + "of discontinuity for hyperbolic conservation laws. " + "If the KXRCF value of a cell is higher than the value of " + "``Temperature/Composition KXRCF indicator threshold'' " + "of the corresponding field in the input parameter file, " + "the cell will be identified as a ``troubled-cell'' that " + "should be smoothed by the WENO limiter. For details, see " + "\\cite{Krivodonova:etal:2004}." + "\n\n" + "This postprocessor should only be used for discontinuous " + "advection fields. Otherwise, the postprocessor will produce " + "a meaningless visualization output." "\n\n" "Physical units: none.") } From e3057763e375413aeb83b86016b2b18d3bfad90e Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Thu, 11 Jul 2024 23:18:31 +0800 Subject: [PATCH 17/22] Update source/simulator/parameters.cc Co-authored-by: Rene Gassmoeller --- source/simulator/parameters.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/simulator/parameters.cc b/source/simulator/parameters.cc index 0388951e6a0..559d3912529 100644 --- a/source/simulator/parameters.cc +++ b/source/simulator/parameters.cc @@ -1151,7 +1151,7 @@ namespace aspect "\\cite{zhong:etal:2013}.\n" " * `none`: if chosen, no limiter is applied to the discontinuous solution.\n" "Note that if this entry is not set to `none', then the limiter will modify " - "the solution, so the nonlinear residual for this field is meaning less, and " + "the solution, so the nonlinear residual for this field is meaningless, and " "in nonlinear solvers we will ignore the residual for this field to evaluate " "if the nonlinear solver has converged."); prm.declare_entry ("Limiter for discontinuous composition solution", "none", From f5cbc1cb05f73165dc1c93a05c82fb43b9deaf67 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Thu, 11 Jul 2024 23:19:45 +0800 Subject: [PATCH 18/22] Update source/simulator/parameters.cc Co-authored-by: Rene Gassmoeller --- source/simulator/parameters.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/simulator/parameters.cc b/source/simulator/parameters.cc index 559d3912529..9738cb515aa 100644 --- a/source/simulator/parameters.cc +++ b/source/simulator/parameters.cc @@ -1227,7 +1227,7 @@ namespace aspect prm.declare_entry ("WENO linear weight of neighbor cells", "0.001", Patterns::Double(0.0, 1.0), "The linear weight of neighbor cells in WENO scheme. The larger this value is, " - "the more information of neighbor cells will be involved in the polynomial " + "the more weight is given to information from neighbor cells when reconstructing the polynomial " "reconstruction. See \\cite{zhong:etal:2013} for detail."); } prm.leave_subsection (); From 4667dbcad9e02dfe8f87b19662c0d29fdb21c728 Mon Sep 17 00:00:00 2001 From: Yimin Jin Date: Thu, 11 Jul 2024 23:29:43 +0800 Subject: [PATCH 19/22] reformat the .prm file for limiter settings --- benchmarks/advection/drop_ev.prm.bak | 13 + benchmarks/advection/drop_supg.prm.bak | 123 + benchmarks/advection/rotate_shape_dg_bp.prm | 1 + .../advection/rotate_shape_dg_bp.prm.bak | 21 + benchmarks/advection/rotate_shape_dg_weno.prm | 2 + .../advection/rotate_shape_dg_weno.prm.bak | 26 + benchmarks/advection/rotate_shape_ev.prm.bak | 13 + .../advection/rotate_shape_supg.prm.bak | 119 + .../advection_in_annulus.cc.bak | 162 + .../advection_in_annulus.prm.bak | 120 + .../annulus/instantaneous/annulus.prm.bak | 90 + benchmarks/annulus/plugin/annulus.cc.bak | 837 ++ .../transient/transient_annulus.prm.bak | 89 + benchmarks/blankenbach/base_case1a.prm.bak | 111 + benchmarks/blankenbach/base_case1b.prm.bak | 18 + benchmarks/blankenbach/base_case1c.prm.bak | 18 + benchmarks/blankenbach/base_case2a.prm.bak | 111 + benchmarks/blankenbach/base_case2b.prm.bak | 118 + benchmarks/blankenbach/plugin/code.cc.bak | 167 + .../heat_flux_statistics_gradient.cc.bak | 198 + .../heat_flux_statistics_gradient.h.bak | 53 + .../buiter_et_al_2008_jgr/figure_6_1e20.prm | 1 - .../figure_6_1e20.prm.bak | 179 + .../figure_6_1e22.prm.bak | 12 + .../doc/convergence.part.prm | 2 +- .../doc/convergence.part.prm.bak | 44 + .../doc/velocity_bc.part.prm.bak | 37 + benchmarks/buiter_et_al_2016_jsg/exp_1.prm | 3 +- .../buiter_et_al_2016_jsg/exp_1.prm.bak | 191 + .../exp_2_high_resolution.prm | 2 +- .../exp_2_high_resolution.prm.bak | 224 + .../exp_2_low_resolution.prm.bak | 32 + benchmarks/burstedde/burstedde.cc.bak | 517 ++ benchmarks/burstedde/burstedde.prm.bak | 104 + benchmarks/burstedde/doc/burstedde.prm.bak | 32 + .../lateral_pipe/adiabatic.prm.bak | 8 + .../lateral_pipe/ala.prm.bak | 14 + .../lateral_pipe/hydrostatic.prm.bak | 4 + .../lateral_pipe/isentropic.prm.bak | 4 + .../lateral_pipe/lateral_pipe.prm.bak | 125 + .../lateral_pipe/projected_density.prm.bak | 10 + .../lateral_pipe/sub_adiabatic.prm.bak | 8 + .../lateral_pipe_advect/ala.prm.bak | 12 + .../lateral_pipe_advect/hydrostatic.prm.bak | 4 + .../lateral_pipe_advect/isentropic.prm.bak | 4 + .../lateral_pipe_advect/lateral_pipe.prm.bak | 135 + .../projected_density.prm.bak | 10 + .../ala.prm.bak | 12 + .../hydrostatic.prm.bak | 4 + .../isentropic.prm.bak | 4 + .../lateral_pipe.prm.bak | 147 + .../projected_density.prm.bak | 10 + .../projected_density_full_pressure.prm.bak | 10 + .../lateral_pipe_transient/ala.prm.bak | 12 + .../hydrostatic.prm.bak | 4 + .../lateral_pipe_transient/isentropic.prm.bak | 4 + .../lateral_pipe.prm.bak | 138 + .../projected_density.prm.bak | 10 + .../lateral_pipe_transient/timestep.prm.bak | 1 + .../compressibility_formulations.cc.bak | 265 + .../vertical_pipe/adiabatic.prm.bak | 8 + .../vertical_pipe/ala.prm.bak | 4 + .../vertical_pipe/hydrostatic.prm.bak | 4 + .../vertical_pipe/isentropic.prm.bak | 4 + .../vertical_pipe/projected_density.prm.bak | 10 + .../vertical_pipe/sub_adiabatic.prm.bak | 8 + .../vertical_pipe/vertical_pipe.prm.bak | 133 + .../case_1/crameri_benchmark_1.cc.bak | 179 + .../case_1/crameri_benchmark_1.prm.bak | 139 + .../case_1/crameri_benchmark_1_gmg.prm.bak | 27 + .../case_2/crameri_benchmark_2.prm.bak | 134 + .../doc/crameri_benchmark_1.prm.bak | 18 + .../doc/crameri_benchmark_2.prm.bak | 22 + benchmarks/davies_et_al/case-1.1.prm.bak | 109 + benchmarks/davies_et_al/case-2.1.prm.bak | 120 + benchmarks/davies_et_al/case-2.2.prm.bak | 119 + .../davies_et_al/case-2.3-plugin/VoT.cc.bak | 202 + benchmarks/davies_et_al/case-2.3.prm.bak | 121 + benchmarks/davies_et_al/doc/case-1.1.prm.bak | 51 + benchmarks/davies_et_al/doc/case-2.1.prm.bak | 11 + benchmarks/davies_et_al/doc/case-2.2.prm.bak | 9 + benchmarks/davies_et_al/doc/case-2.3.prm.bak | 14 + .../1_sine_zero_flux.prm.bak | 125 + .../2_sine_constant_h.prm.bak | 124 + .../analytical_topography.cc.bak | 369 + .../analytical_topography.h.bak | 113 + benchmarks/doneahuerta/doneahuerta.cc.bak | 362 + benchmarks/doneahuerta/doneahuerta.prm.bak | 88 + .../entropy_adiabat/entropy_adiabat.prm.bak | 184 + .../entropy_adiabat/entropy_combined.prm.bak | 42 + .../entropy_conduction.prm.bak | 147 + .../entropy_half_space.prm.bak | 155 + .../plugins/entropy_advection.cc.bak | 312 + .../plugins/entropy_advection.h.bak | 58 + benchmarks/finite_strain/finite_strain.cc.bak | 20 + benchmarks/finite_strain/pure_shear.prm.bak | 145 + benchmarks/finite_strain/simple_shear.prm.bak | 133 + ...ree_surface_VE_cylinder_2D_loading.prm.bak | 169 + ...linder_2D_loading_fixed_elastic_dt.prm.bak | 21 + ...e_VE_cylinder_2D_loading_unloading.prm.bak | 27 + ...ree_surface_VE_cylinder_3D_loading.prm.bak | 170 + ...linder_3D_loading_fixed_elastic_dt.prm.bak | 21 + ...urface_viscous_cylinder_2D_loading.prm.bak | 22 + ...urface_viscous_cylinder_3D_loading.prm.bak | 22 + .../spectral-comparison.prm.bak | 124 + .../grain_size_plunge.prm.bak | 162 + .../gravity_mantle/mantle_gravity.prm.bak | 76 + .../doc/thick_shell.prm.bak | 11 + .../gravity_thick_shell/thick_shell.prm.bak | 72 + .../doc/thinshell_a.prm.bak | 11 + .../doc/thinshell_b.prm.bak | 1 + .../doc/thinshell_c.prm.bak | 15 + .../gravity_thin_shell.prm.bak | 88 + benchmarks/hollow_sphere/hollow_sphere.cc.bak | 682 ++ .../hollow_sphere/hollow_sphere.prm.bak | 103 + benchmarks/inclusion/adaptive.prm.base.bak | 72 + .../inclusion_compositional_fields.cc.bak | 51 + .../inclusion_compositional_fields.h.bak | 34 + .../inclusion_compositional_fields.prm.bak | 91 + .../inclusion_particles.prm.bak | 119 + benchmarks/inclusion/doc/inclusion.prm.bak | 62 + benchmarks/inclusion/global.prm.base.bak | 63 + benchmarks/inclusion/inclusion.cc.bak | 50 + benchmarks/inclusion/inclusion.h.bak | 356 + benchmarks/infill_density/infill_ascii.prm | 2 +- .../infill_density/infill_ascii.prm.bak | 217 + .../infill_density/infill_ascii_data.cc.bak | 267 + benchmarks/king2dcompressible/ala.prm.bak | 184 + .../king2dcompressible/plugin/code.cc.bak | 250 + benchmarks/layeredflow/layeredflow.cc.bak | 404 + benchmarks/layeredflow/layeredflow.prm.bak | 94 + .../nonlinear_channel_flow/input_t.prm.bak | 134 + .../input_t_gmg.prm.bak | 21 + .../nonlinear_channel_flow/input_v.prm | 2 +- .../nonlinear_channel_flow/input_v.prm.bak | 133 + .../input_v_gmg.prm.bak | 21 + .../simple_nonlinear.cc.bak | 404 + .../drucker_prager_compositions.cc.bak | 671 ++ .../spiegelman_et_al_2016/input.prm.bak | 137 + .../tosi_et_al_2015/input.prm | 6 +- .../tosi_et_al_2015/input.prm.bak | 168 + .../tosi_et_al_2015/input_gmg.prm.bak | 23 + benchmarks/nsinker/nsinker.cc.bak | 352 + benchmarks/nsinker/nsinker.prm | 4 +- benchmarks/nsinker/nsinker.prm.bak | 84 + benchmarks/nsinker/nsinker_2d.prm.bak | 72 + benchmarks/nsinker/nsinker_bfbt.prm | 6 +- benchmarks/nsinker/nsinker_bfbt.prm.bak | 85 + benchmarks/nsinker/nsinker_gmg.prm.bak | 92 + .../nsinker_spherical_shell/amg.prm.bak | 20 + .../nsinker_spherical_shell/gmg.prm.bak | 86 + .../nsinker_spherical_shell/nsinker.cc.bak | 349 + .../convection-box-base.prm.bak | 94 + .../advection_reaction.base.prm.bak | 149 + .../advection_reaction.cc.bak | 502 ++ .../doc/exponential_decay.part.1.prm.bak | 15 + .../doc/exponential_decay.part.2.prm.bak | 38 + .../exponential_decay.base.prm.bak | 121 + .../exponential_decay.cc.bak | 402 + .../particle_integration_scheme/circle.prm | 2 +- .../circle.prm.bak | 78 + .../euler.part.prm.bak | 6 + .../rk2.part.prm.bak | 6 + .../rk4.part.prm.bak | 6 + benchmarks/polydiapirs/polydiapirs.prm.bak | 96 + .../rayleigh_taylor_instability/blank.prm.bak | 52 + .../rayleigh_taylor_instability.cc.bak | 199 + .../rayleigh_taylor_instability.prm.bak | 75 + .../kaus_rayleigh_taylor_instability.prm | 2 +- .../kaus_rayleigh_taylor_instability.prm.bak | 158 + .../rose_rayleigh_taylor_instability.prm.bak | 49 + .../instantaneous/rigid_shear.prm.bak | 87 + .../rigid_shear/plugin/rigid_shear.cc.bak | 378 + .../steady-state/rigid_shear.prm.bak | 110 + .../rigid_shear/transient/rigid_shear.prm.bak | 134 + .../shear_bands/magmatic_shear_bands.prm.bak | 146 + benchmarks/shear_bands/shear_bands.cc.bak | 846 ++ benchmarks/shear_bands/shear_bands.prm.bak | 130 + benchmarks/sinking_block/blank.prm.bak | 58 + benchmarks/sinking_block/sinking_block.cc.bak | 232 + .../sinking_block/sinking_block.prm.bak | 71 + .../slab_detachment/slab_detachment.prm.bak | 152 + .../solcx_compositional_fields.cc.bak | 46 + .../solcx_compositional_fields.h.bak | 34 + .../solcx_compositional_fields.prm | 1 - .../solcx_compositional_fields.prm.bak | 95 + .../compositional_fields/solcx_particles.prm | 1 - .../solcx_particles.prm.bak | 128 + benchmarks/solcx/doc/solcx.prm.bak | 60 + benchmarks/solcx/solcx.cc.bak | 44 + benchmarks/solcx/solcx.h.bak | 3189 +++++++ benchmarks/solcx/solcx.prm.bak | 66 + .../solitary_wave/doc/solitary_wave.prm.bak | 103 + benchmarks/solitary_wave/solitary_wave.cc.bak | 1025 +++ .../solitary_wave/solitary_wave.prm.bak | 170 + .../solkz_compositional_fields.cc.bak | 45 + .../solkz_compositional_fields.h.bak | 33 + .../solkz_compositional_fields.prm.bak | 93 + .../solkz_particles.prm.bak | 117 + benchmarks/solkz/doc/solkz.prm.bak | 60 + benchmarks/solkz/solkz.cc.bak | 44 + benchmarks/solkz/solkz.h.bak | 799 ++ benchmarks/solkz/solkz.prm.bak | 62 + benchmarks/solubility/plugin/solubility.cc | 4 +- .../solubility/plugin/solubility.cc.bak | 424 + benchmarks/solubility/solubility.prm.bak | 162 + benchmarks/tangurnis/ba/tan.prm.bak | 130 + benchmarks/tangurnis/code/tangurnis.cc.bak | 461 + benchmarks/tangurnis/tala/tan.prm.bak | 140 + benchmarks/tangurnis/tala_c/tan.prm.bak | 139 + .../plugin/time_dependent_annulus.cc.bak | 55 + .../plugin/time_dependent_annulus.h.bak | 377 + .../time_dependent_annulus.prm.bak | 179 + .../tosi_et_al_2015_gcubed/Tosi_Case1.prm.bak | 21 + .../tosi_et_al_2015_gcubed/Tosi_Case2.prm.bak | 20 + .../tosi_et_al_2015_gcubed/Tosi_Case3.prm.bak | 21 + .../tosi_et_al_2015_gcubed/Tosi_Case4.prm.bak | 22 + .../tosi_et_al_2015_gcubed/Tosi_Case5.prm.bak | 21 + .../tosi_et_al_2015_gcubed/Tosi_base.prm.bak | 175 + .../doc/tosi_benchmark_2.prm.bak | 8 + benchmarks/tosi_et_al_2015_gcubed/tosi.cc.bak | 722 ++ .../20km_opentopbot.prm.bak | 96 + .../20km_opentopbot_weno.prm | 4 +- .../20km_opentopbot_weno.prm.bak | 33 + .../viscoelastic_bending_beam.prm | 2 +- .../viscoelastic_bending_beam.prm.bak | 185 + ...iscoelastic_bending_beam_particles.prm.bak | 41 + .../viscoelastic_bending_beam_weno.prm | 3 + .../viscoelastic_bending_beam_weno.prm.bak | 32 + .../gerya_2019/gerya_2019_vep.prm.bak | 61 + .../gerya_2019/gerya_2019_vp.prm.bak | 190 + .../gerya_2019/gerya_2019_vp_damper.prm.bak | 20 + .../kaus_2010/kaus_2010_extension.prm.bak | 238 + .../viscoelastic_plastic_simple_shear.prm.bak | 146 + .../viscoelastic_plate_flexure.prm | 2 +- .../viscoelastic_plate_flexure.prm.bak | 177 + .../viscoelastic_sheared_torsion.prm.bak | 172 + .../viscoelastic_stress_build-up.prm.bak | 191 + ...oelastic_stress_build-up_particles.prm.bak | 43 + ...viscoelastic_stress_build-up_yield.prm.bak | 43 + ...ic_stress_build-up_yield_particles.prm.bak | 74 + .../viscosity_grooves.cc.bak | 473 + .../viscosity_grooves.prm.bak | 82 + .../anelasticity_temperature.cc.bak | 402 + .../anelasticity_temperature.h.bak | 135 + .../yamauchi_takei_2016_anelasticity.prm.bak | 79 + benchmarks/zhong_et_al_93/zhong_case1.prm.bak | 105 + contrib/opendap/prm_files/aspect_test.prm.bak | 82 + .../opendap/prm_files/aspect_url_test.prm.bak | 78 + .../perplex_lookup_composition.prm.bak | 84 + .../read_output_files/convection-box.prm.bak | 10 + .../__pycache__/aspect_input.cpython-312.pyc | Bin 0 -> 8883 bytes contrib/world_builder/include/app/main.h.bak | 27 + contrib/world_builder/include/glm/glm.h.bak | 248 + .../include/rapidjson/allocators.h.bak | 308 + .../rapidjson/cursorstreamwrapper.h.bak | 89 + .../include/rapidjson/encodedstream.h.bak | 485 + .../include/rapidjson/encodings.h.bak | 855 ++ .../include/rapidjson/error/en.h.bak | 95 + .../include/rapidjson/error/error.h.bak | 200 + .../include/rapidjson/filereadstream.h.bak | 130 + .../include/rapidjson/filewritestream.h.bak | 134 + .../world_builder/include/rapidjson/fwd.h.bak | 151 + .../rapidjson/internal/biginteger.h.bak | 340 + .../include/rapidjson/internal/diyfp.h.bak | 293 + .../include/rapidjson/internal/dtoa.h.bak | 301 + .../include/rapidjson/internal/ieee754.h.bak | 122 + .../include/rapidjson/internal/itoa.h.bak | 329 + .../include/rapidjson/internal/meta.h.bak | 229 + .../include/rapidjson/internal/pow10.h.bak | 58 + .../include/rapidjson/internal/regex.h.bak | 820 ++ .../include/rapidjson/internal/stack.h.bak | 277 + .../include/rapidjson/internal/strfunc.h.bak | 75 + .../include/rapidjson/internal/strtod.h.bak | 317 + .../include/rapidjson/internal/swap.h.bak | 48 + .../include/rapidjson/istreamwrapper.h.bak | 137 + .../include/rapidjson/latexwriter.h.bak | 468 + .../include/rapidjson/memorybuffer.h.bak | 91 + .../include/rapidjson/memorystream.h.bak | 96 + .../rapidjson/msinttypes/inttypes.h.bak | 320 + .../include/rapidjson/msinttypes/stdint.h.bak | 300 + .../include/rapidjson/mystwriter.h.bak | 528 ++ .../include/rapidjson/ostreamwrapper.h.bak | 104 + .../include/rapidjson/pointer.h.bak | 1532 ++++ .../include/rapidjson/prettywriter.h.bak | 340 + .../include/rapidjson/rapidjson.h.bak | 660 ++ .../include/rapidjson/reader.h.bak | 2574 ++++++ .../include/rapidjson/schema.h.bak | 2927 +++++++ .../include/rapidjson/stream.h.bak | 312 + .../include/rapidjson/stringbuffer.h.bak | 155 + .../include/rapidjson/writer.h.bak | 867 ++ .../include/visualization/main.h.bak | 39 + .../include/world_builder/assert.h.bak | 63 + .../include/world_builder/bounding_box.h.bak | 513 ++ .../include/world_builder/consts.h.bak | 35 + .../world_builder/coordinate_system.h.bak | 68 + .../coordinate_systems/cartesian.h.bak | 114 + .../coordinate_systems/interface.h.bak | 184 + .../coordinate_systems/invalid.h.bak | 110 + .../coordinate_systems/spherical.h.bak | 130 + .../include/world_builder/deprecate.h.bak | 13 + .../features/continental_plate.h.bak | 162 + .../composition/interface.h.bak | 164 + .../composition/random.h.bak | 100 + .../composition/uniform.h.bak | 99 + .../grains/interface.h.bak | 170 + .../grains/random_uniform_distribution.h.bak | 115 + ...andom_uniform_distribution_deflected.h.bak | 115 + .../grains/uniform.h.bak | 113 + .../temperature/adiabatic.h.bak | 113 + .../temperature/interface.h.bak | 169 + .../temperature/linear.h.bak | 99 + .../temperature/uniform.h.bak | 98 + .../world_builder/features/fault.h.bak | 229 + .../fault_models/composition/interface.h.bak | 172 + .../fault_models/composition/smooth.h.bak | 97 + .../fault_models/composition/uniform.h.bak | 95 + .../fault_models/grains/interface.h.bak | 173 + .../grains/random_uniform_distribution.h.bak | 113 + ...andom_uniform_distribution_deflected.h.bak | 113 + .../fault_models/grains/uniform.h.bak | 112 + .../fault_models/temperature/adiabatic.h.bak | 110 + .../fault_models/temperature/interface.h.bak | 173 + .../fault_models/temperature/linear.h.bak | 95 + .../fault_models/temperature/uniform.h.bak | 95 + .../features/feature_utilities.h.bak | 101 + .../world_builder/features/interface.h.bak | 228 + .../world_builder/features/mantle_layer.h.bak | 161 + .../composition/interface.h.bak | 168 + .../composition/uniform.h.bak | 98 + .../grains/interface.h.bak | 170 + .../grains/random_uniform_distribution.h.bak | 114 + ...andom_uniform_distribution_deflected.h.bak | 114 + .../mantle_layer_models/grains/uniform.h.bak | 114 + .../temperature/adiabatic.h.bak | 113 + .../temperature/interface.h.bak | 169 + .../temperature/linear.h.bak | 98 + .../temperature/uniform.h.bak | 97 + .../features/oceanic_plate.h.bak | 158 + .../composition/interface.h.bak | 168 + .../composition/uniform.h.bak | 98 + .../grains/interface.h.bak | 166 + .../grains/random_uniform_distribution.h.bak | 114 + ...andom_uniform_distribution_deflected.h.bak | 114 + .../oceanic_plate_models/grains/uniform.h.bak | 114 + .../temperature/adiabatic.h.bak | 112 + .../temperature/half_space_model.h.bak | 103 + .../temperature/interface.h.bak | 169 + .../temperature/linear.h.bak | 98 + .../temperature/plate_model.h.bak | 107 + .../plate_model_constant_age.h.bak | 105 + .../temperature/uniform.h.bak | 97 + .../world_builder/features/plume.h.bak | 164 + .../plume_models/composition/interface.h.bak | 164 + .../plume_models/composition/uniform.h.bak | 97 + .../plume_models/grains/interface.h.bak | 170 + .../plume_models/grains/uniform.h.bak | 111 + .../plume_models/temperature/gaussian.h.bak | 96 + .../plume_models/temperature/interface.h.bak | 173 + .../plume_models/temperature/uniform.h.bak | 98 + .../features/subducting_plate.h.bak | 230 + .../composition/interface.h.bak | 173 + .../composition/smooth.h.bak | 98 + .../composition/uniform.h.bak | 95 + .../grains/interface.h.bak | 173 + .../grains/random_uniform_distribution.h.bak | 112 + ...andom_uniform_distribution_deflected.h.bak | 113 + .../grains/uniform.h.bak | 112 + .../temperature/adiabatic.h.bak | 110 + .../temperature/interface.h.bak | 174 + .../temperature/linear.h.bak | 96 + .../temperature/mass_conserving.h.bak | 143 + .../temperature/plate_model.h.bak | 102 + .../temperature/uniform.h.bak | 95 + .../include/world_builder/grains.h.bak | 68 + .../gravity_model/interface.h.bak | 149 + .../world_builder/gravity_model/uniform.h.bak | 96 + .../include/world_builder/kd_tree.h.bak | 161 + .../include/world_builder/nan.h.bak | 50 + .../world_builder/objects/bezier_curve.h.bak | 89 + .../objects/closest_point_on_curve.h.bak | 56 + .../objects/distance_from_surface.h.bak | 64 + .../objects/natural_coordinate.h.bak | 125 + .../world_builder/objects/segment.h.bak | 79 + .../world_builder/objects/surface.h.bak | 112 + .../include/world_builder/parameters.h.bak | 332 + .../include/world_builder/point.h.bak | 473 + .../include/world_builder/types/array.h.bak | 119 + .../include/world_builder/types/bool.h.bak | 77 + .../include/world_builder/types/double.h.bak | 76 + .../include/world_builder/types/int.h.bak | 80 + .../world_builder/types/interface.h.bak | 93 + .../include/world_builder/types/object.h.bak | 87 + .../include/world_builder/types/one_of.h.bak | 89 + .../world_builder/types/plugin_system.h.bak | 85 + .../include/world_builder/types/point.h.bak | 132 + .../include/world_builder/types/segment.h.bak | 100 + .../include/world_builder/types/string.h.bak | 103 + .../world_builder/types/unsigned_int.h.bak | 80 + .../world_builder/types/value_at_points.h.bak | 80 + .../include/world_builder/utilities.h.bak | 494 ++ .../include/world_builder/world.h.bak | 316 + .../include/world_builder/wrapper_c.h.bak | 71 + .../include/world_builder/wrapper_cpp.h.bak | 94 + .../world_builder/source/gwb-dat/main.cc.bak | 343 + .../world_builder/source/gwb-grid/main.cc.bak | 1672 ++++ .../coordinate_systems/cartesian.cc.bak | 103 + .../coordinate_systems/interface.cc.bak | 100 + .../coordinate_systems/invalid.cc.bak | 88 + .../coordinate_systems/spherical.cc.bak | 146 + .../features/continental_plate.cc.bak | 270 + .../composition/interface.cc.bak | 80 + .../composition/random.cc.bak | 144 + .../composition/uniform.cc.bak | 136 + .../grains/interface.cc.bak | 81 + .../grains/random_uniform_distribution.cc.bak | 225 + ...ndom_uniform_distribution_deflected.cc.bak | 231 + .../grains/uniform.cc.bak | 177 + .../temperature/adiabatic.cc.bak | 171 + .../temperature/interface.cc.bak | 94 + .../temperature/linear.cc.bak | 157 + .../temperature/uniform.cc.bak | 114 + .../world_builder/features/fault.cc.bak | 730 ++ .../fault_models/composition/interface.cc.bak | 81 + .../fault_models/composition/smooth.cc.bak | 129 + .../fault_models/composition/uniform.cc.bak | 124 + .../fault_models/grains/interface.cc.bak | 111 + .../grains/random_uniform_distribution.cc.bak | 217 + ...ndom_uniform_distribution_deflected.cc.bak | 223 + .../fault_models/grains/uniform.cc.bak | 169 + .../fault_models/temperature/adiabatic.cc.bak | 164 + .../fault_models/temperature/interface.cc.bak | 95 + .../fault_models/temperature/linear.cc.bak | 140 + .../fault_models/temperature/uniform.cc.bak | 107 + .../features/feature_utilities.cc.bak | 56 + .../world_builder/features/interface.cc.bak | 209 + .../features/mantle_layer.cc.bak | 264 + .../composition/interface.cc.bak | 81 + .../composition/uniform.cc.bak | 131 + .../grains/interface.cc.bak | 111 + .../grains/random_uniform_distribution.cc.bak | 224 + ...ndom_uniform_distribution_deflected.cc.bak | 231 + .../mantle_layer_models/grains/uniform.cc.bak | 176 + .../temperature/adiabatic.cc.bak | 172 + .../temperature/interface.cc.bak | 94 + .../temperature/linear.cc.bak | 147 + .../temperature/uniform.cc.bak | 117 + .../features/oceanic_plate.cc.bak | 285 + .../composition/interface.cc.bak | 81 + .../composition/uniform.cc.bak | 129 + .../grains/interface.cc.bak | 111 + .../grains/random_uniform_distribution.cc.bak | 224 + ...ndom_uniform_distribution_deflected.cc.bak | 230 + .../grains/uniform.cc.bak | 177 + .../temperature/adiabatic.cc.bak | 173 + .../temperature/half_space_model.cc.bak | 210 + .../temperature/interface.cc.bak | 94 + .../temperature/linear.cc.bak | 145 + .../temperature/plate_model.cc.bak | 214 + .../plate_model_constant_age.cc.bak | 161 + .../temperature/uniform.cc.bak | 116 + .../world_builder/features/plume.cc.bak | 403 + .../plume_models/composition/interface.cc.bak | 80 + .../plume_models/composition/uniform.cc.bak | 129 + .../plume_models/grains/interface.cc.bak | 81 + .../plume_models/grains/uniform.cc.bak | 169 + .../plume_models/temperature/gaussian.cc.bak | 166 + .../plume_models/temperature/interface.cc.bak | 94 + .../plume_models/temperature/uniform.cc.bak | 106 + .../features/subducting_plate.cc.bak | 762 ++ .../composition/interface.cc.bak | 82 + .../composition/smooth.cc.bak | 131 + .../composition/uniform.cc.bak | 123 + .../grains/interface.cc.bak | 111 + .../grains/random_uniform_distribution.cc.bak | 217 + ...ndom_uniform_distribution_deflected.cc.bak | 223 + .../grains/uniform.cc.bak | 169 + .../temperature/adiabatic.cc.bak | 166 + .../temperature/interface.cc.bak | 94 + .../temperature/linear.cc.bak | 138 + .../temperature/mass_conserving.cc.bak | 639 ++ .../temperature/plate_model.cc.bak | 214 + .../temperature/uniform.cc.bak | 109 + .../source/world_builder/grains.cc.bak | 80 + .../gravity_model/interface.cc.bak | 99 + .../gravity_model/uniform.cc.bak | 94 + .../source/world_builder/kd_tree.cc.bak | 211 + .../world_builder/objects/bezier_curve.cc.bak | 550 ++ .../objects/distance_from_surface.cc.bak | 36 + .../objects/natural_coordinate.cc.bak | 121 + .../world_builder/objects/segment.cc.bak | 126 + .../world_builder/objects/surface.cc.bak | 227 + .../source/world_builder/parameters.cc.bak | 2229 +++++ .../source/world_builder/point.cc.bak | 108 + .../source/world_builder/types/array.cc.bak | 84 + .../source/world_builder/types/bool.cc.bak | 62 + .../source/world_builder/types/double.cc.bak | 68 + .../source/world_builder/types/int.cc.bak | 64 + .../world_builder/types/interface.cc.bak | 45 + .../source/world_builder/types/object.cc.bak | 91 + .../source/world_builder/types/one_of.cc.bak | 77 + .../world_builder/types/plugin_system.cc.bak | 95 + .../source/world_builder/types/point.cc.bak | 185 + .../source/world_builder/types/segment.cc.bak | 170 + .../source/world_builder/types/string.cc.bak | 120 + .../world_builder/types/unsigned_int.cc.bak | 64 + .../types/value_at_points.cc.bak | 96 + .../source/world_builder/utilities.cc.bak | 1510 ++++ .../source/world_builder/world.cc.bak | 498 ++ .../source/world_builder/wrapper_c.cc.bak | 108 + .../source/world_builder/wrapper_cpp.cc.bak | 77 + .../tests/unit_tests/bounding_box.cc.bak | 87 + .../tests/unit_tests/gwb_gravity.cc.bak | 68 + .../tests/unit_tests/kd_tree.cc.bak | 214 + .../tests/unit_tests/main.cc.bak | 25 + .../tests/unit_tests/unit_test_wb_glm.cc.bak | 253 + .../unit_tests/unit_test_world_builder.cc.bak | 7780 +++++++++++++++++ .../2d_annulus_example.prm.bak | 89 + .../allken.prm | 2 +- .../allken.prm.bak | 155 + .../AV_Rayleigh_Taylor.prm.bak | 100 + .../anisotropic_viscosity/av_material.cc.bak | 831 ++ .../bunge_et_al.prm.bak | 104 + cookbooks/burnman/burnman.prm.bak | 143 + .../doc/adiabatic_conditions.part.prm.bak | 8 + .../burnman/doc/formulation.part.prm.bak | 3 + .../burnman/doc/formulation_ica.part.prm.bak | 3 + .../burnman/doc/gravity_model.part.prm.bak | 3 + .../burnman/doc/material_model.part.prm.bak | 14 + cookbooks/burnman/doc/tala.part.prm.bak | 5 + .../christensen_yuen_phase_function.prm.bak | 172 + .../doc/material.part.prm.bak | 35 + .../composition-reaction.prm.bak | 113 + .../doc/initial.part.prm.bak | 8 + .../doc/material.part.prm.bak | 12 + .../composition_active.prm.bak | 106 + .../doc/active.part.prm.bak | 12 + .../doc/postprocess.part.prm.bak | 8 + .../composition_active_particles.prm.bak | 127 + .../doc/composition.part.prm.bak | 6 + .../doc/particles.part.prm.bak | 18 + .../composition_passive.prm.bak | 99 + .../doc/passive.part.prm.bak | 18 + .../doc/postprocess.part.prm.bak | 3 + .../composition_passive_particles.prm.bak | 114 + ...ition_passive_particles_properties.prm.bak | 121 + .../doc/particle-properties.part.prm.bak | 17 + .../doc/particles.part.prm.bak | 20 + .../continental_extension.prm.bak | 314 + ...ntal_extension_boundary_conditions.prm.bak | 36 + .../continental_extension_composition.prm.bak | 16 + ...ontinental_extension_geometry_mesh.prm.bak | 23 + ...ntinental_extension_material_model.prm.bak | 6 + .../convection-box-particles.prm.bak | 170 + .../convection-box/convection-box.prm.bak | 160 + .../convection-box/doc/disc.part.prm.bak | 4 + .../convection-box/doc/gravity.part.prm.bak | 5 + .../convection-box/doc/refine.part.prm.bak | 5 + .../convection-box/doc/refine2.part.prm.bak | 8 + .../model_input/convection-box.prm.bak | 160 + .../model_input/convection-box2.prm.bak | 161 + .../model_input/tutorial.prm | 35 +- .../model_input/tutorial.prm.bak | 157 + .../convection_box_3d.prm.bak | 152 + .../convection_box_3d/doc/amr.part.prm.bak | 6 + .../doc/checkpoint.part.prm.bak | 3 + .../doc/gravity.part.prm.bak | 7 + .../doc/initial.part.prm.bak | 9 + .../doc/postprocess.part.prm.bak | 8 + .../convection_box_3d/doc/start.part.prm.bak | 25 + .../crustal_model_2D.prm.bak | 134 + .../crustal_model_3D.prm.bak | 128 + .../doc/crustal_model_2D_part1.prm.bak | 15 + .../doc/crustal_model_2D_part2.prm.bak | 7 + .../doc/crustal_model_2D_part3.prm.bak | 3 + .../doc/crustal_model_2D_part4.prm.bak | 9 + .../doc/crustal_model_3D_part1.prm.bak | 7 + .../fastscape_eroding_box.prm.bak | 177 + .../doc/finite_strain.part.prm.bak | 14 + cookbooks/finite_strain/finite_strain.cc.bak | 128 + cookbooks/finite_strain/finite_strain.prm.bak | 119 + .../doc/free_surface.part.prm.bak | 41 + cookbooks/free_surface/free_surface.prm.bak | 141 + .../doc/free_surface_with_crust.part1.prm.bak | 4 + .../doc/free_surface_with_crust.part2.prm.bak | 19 + .../free_surface_with_crust.prm.bak | 112 + .../plugin/simpler_with_crust.cc.bak | 220 + cookbooks/future/mantle_setup_restart.prm.bak | 30 + cookbooks/future/mantle_setup_start.prm | 4 +- cookbooks/future/mantle_setup_start.prm.bak | 192 + cookbooks/future/net_rotation.prm.bak | 78 + cookbooks/future/periodic_box.prm.bak | 106 + cookbooks/future/radiogenic_heating.prm.bak | 104 + .../radiogenic_heating_function.prm.bak | 108 + cookbooks/future/sphere.prm.bak | 74 + cookbooks/geomio/doc/geomIO.prm.bak | 40 + cookbooks/geomio/geomIO.prm.bak | 96 + cookbooks/global_melt/doc/global_melt.prm.bak | 248 + .../global_melt/doc/global_no_melt.prm.bak | 211 + cookbooks/global_melt/global_melt.prm.bak | 371 + cookbooks/global_melt/global_no_melt.prm.bak | 211 + cookbooks/gplates/doc/gplates.part.prm.bak | 17 + cookbooks/gplates/doc/slice1.part.prm.bak | 2 + cookbooks/gplates/doc/slice2.part.prm.bak | 2 + cookbooks/gplates/gplates_2d.prm.bak | 88 + cookbooks/gplates/gplates_3d.prm.bak | 88 + .../grain_size_ridge/doc/fields.part.prm.bak | 11 + .../doc/material_model.part.prm.bak | 48 + .../doc/particles.part.prm.bak | 30 + .../grain_size_ridge/grain_size_ridge.prm.bak | 310 + cookbooks/heat_flow/heat-flow-plume.prm.bak | 154 + cookbooks/heat_flow/heat-flow-terms.prm.bak | 40 + cookbooks/heat_flow/heat-flow.prm.bak | 143 + .../inclusions/ellipse_pure_shear.prm.bak | 13 + .../ellipse_pure_shear_nonlinear.prm.bak | 129 + cookbooks/inclusions/ellipse_ref.prm.bak | 94 + .../inclusions/ellipse_simple_shear.prm.bak | 13 + .../inclusions/rectangle_pure_shear.prm.bak | 13 + cookbooks/inclusions/rectangle_ref.prm.bak | 94 + .../inclusions/rectangle_simple_shear.prm.bak | 13 + .../initial-condition-S20RTS/S20RTS.prm.bak | 152 + .../doc/S20RTS.part.prm.bak | 13 + .../doc/inner_core_traction.part.1.prm.bak | 15 + .../doc/inner_core_traction.part.2.prm.bak | 13 + .../doc/inner_core_traction.part.3.prm.bak | 11 + .../inner_core_assembly.cc.bak | 140 + .../inner_core_convection.cc.bak | 488 ++ .../inner_core_traction.prm | 2 +- .../inner_core_traction.prm.bak | 136 + .../composition_trms_statistics.cc.bak | 227 + .../composition_trms_statistics.h.bak | 75 + .../doc/Case1_compositions.prm.bak | 39 + .../doc/Case1_materialmodel.prm.bak | 15 + .../doc/Case1_meshrefinement.prm.bak | 23 + .../doc/Case1_postprocessing.prm | 2 +- .../doc/Case1_postprocessing.prm.bak | 16 + .../doc/Case1_velocity.prm.bak | 13 + .../doc/Case2a_materialmodel.prm.bak | 13 + .../doc/Case2a_postprocessing.prm | 2 +- .../doc/Case2a_postprocessing.prm.bak | 20 + .../doc/Case2a_temperatures.prm.bak | 21 + .../doc/Case2b_materialmodel.prm.bak | 25 + .../isotherm_depth.cc.bak | 152 + .../isotherm_depth.h.bak | 74 + ...nematically_driven_subduction_2d_case1.prm | 2 +- ...tically_driven_subduction_2d_case1.prm.bak | 202 + ...ematically_driven_subduction_2d_case2a.prm | 2 +- ...ically_driven_subduction_2d_case2a.prm.bak | 107 + ...ically_driven_subduction_2d_case2b.prm.bak | 38 + .../subduction_plate_cooling.cc.bak | 100 + .../subduction_plate_cooling.h.bak | 52 + .../trench_location.cc.bak | 157 + .../trench_location.h.bak | 75 + .../latent-heat/doc/material.part.prm.bak | 41 + cookbooks/latent-heat/latent-heat.prm.bak | 145 + .../lower_crustal_flow_obstacle.prm.bak | 116 + .../magnetic_stripes/magnetic_stripes.cc | 2 +- .../magnetic_stripes/magnetic_stripes.cc.bak | 153 + .../magnetic_stripes/magnetic_stripes.prm | 4 +- .../magnetic_stripes/magnetic_stripes.prm.bak | 241 + .../modelR.prm.bak | 210 + .../doc/boundary_conditions.part.prm.bak | 34 + .../doc/compaction_length.part.prm.bak | 23 + .../doc/melting_and_freezing.part.prm.bak | 38 + .../doc/mesh_refinement.part.prm.bak | 28 + .../mid_ocean_ridge/mid_ocean_ridge.prm.bak | 254 + .../doc/morency_doin.part.prm.bak | 59 + .../morency_doin_2004/morency_doin.cc.bak | 302 + .../morency_doin_2004/morency_doin.h.bak | 125 + cookbooks/morency_doin_2004/morency_doin.prm | 2 +- .../morency_doin_2004/morency_doin.prm.bak | 113 + .../doc/comp.field.prm.bak | 5 + .../doc/comp.setup.prm.bak | 12 + .../doc/conductivity.setup.prm.bak | 7 + .../doc/lookup.part.prm.bak | 10 + .../doc/temperature.setup.prm.bak | 26 + .../steinberger_thermochemical_plume.prm.bak | 166 + .../doc/check-initial-condition.part.prm.bak | 18 + .../doc/mesh-refinement.part.prm.bak | 23 + .../doc/repetitions.part.prm.bak | 15 + .../doc/temperature.part.prm.bak | 39 + .../muparser-temperature-example.prm.bak | 159 + .../onset_of_convection.prm.bak | 93 + .../doc/boundary.part.prm.bak | 10 + .../platelike-boundary/doc/platelike.prm.bak | 91 + .../platelike-boundary.prm.bak | 96 + .../opening_angle_45degrees.prm.bak | 11 + .../opening_angle_90degrees.prm.bak | 11 + cookbooks/plume_2D_chunk/plume2D.prm.bak | 104 + .../strongly_temperature_dependent.prm.bak | 11 + .../weakly_temperature_dependent.prm.bak | 11 + cookbooks/prescribed_velocity/circle.prm.bak | 62 + .../prescribed_velocity/corner_flow.prm.bak | 62 + .../prescribed_velocity/doc/minimal.prm.bak | 24 + .../prescribed_velocity.cc.bak | 301 + ...escribed_velocity_ascii_data.prm.0.out.bak | 2 + ...escribed_velocity_ascii_data.prm.1.out.bak | 18 + ...escribed_velocity_ascii_data.prm.2.out.bak | 8 + .../prescribed_velocity_ascii_data.cc.bak | 311 + .../prescribed_velocity_ascii_data.prm.bak | 152 + .../doc/shell_3d_postprocess.part.prm.bak | 9 + .../shell_3d_postprocess.prm.bak | 108 + .../doc/shearheat.part.prm.bak | 3 + cookbooks/shell_simple_2d/doc/shell.prm.bak | 72 + .../shell_simple_2d/shell_simple_2d.prm.bak | 82 + .../shell_simple_2d_smoothing.part.prm.bak | 20 + .../shell_simple_2d_smoothing.prm.bak | 95 + .../shell_simple_3d/doc/amr.part.prm.bak | 6 + .../doc/checkpoint.part.prm.bak | 3 + .../shell_simple_3d/doc/part1.part.prm.bak | 13 + .../shell_simple_3d/doc/part2.part.prm.bak | 13 + .../shell_simple_3d/doc/part3.part.prm.bak | 9 + .../shell_simple_3d/doc/part4.part.prm.bak | 11 + .../doc/postprocess.part.prm.bak | 16 + .../shell_simple_3d/shell_simple_3d.prm.bak | 79 + .../doc/conservative.prm.bak | 3 + .../sinker-with-averaging/doc/full.prm.bak | 86 + .../doc/harmonic.prm.bak | 3 + .../sinker-with-averaging.prm.bak | 86 + .../steinberger/doc/geometry.part.prm.bak | 10 + cookbooks/steinberger/doc/lookup.part.prm.bak | 11 + .../steinberger/doc/nullspace.part.prm.bak | 3 + .../doc/projected_density.part.prm.bak | 11 + .../steinberger/doc/rheology.part.prm.bak | 11 + .../steinberger/doc/rheology2.part.prm.bak | 5 + cookbooks/steinberger/steinberger.prm.bak | 215 + cookbooks/stokes/doc/stokeslaw.prm.bak | 118 + cookbooks/stokes/stokes.prm.bak | 121 + .../subduction_initiation.prm.base.bak | 51 + ...on_initiation_compositional_fields.prm.bak | 50 + ...uction_initiation_particle_in_cell.prm.bak | 66 + ...an-parameterization-kinematic-slab.prm.bak | 303 + ...an-parameterization-kinematic-slab.prm.bak | 36 + .../2D_slice_with_faults_and_cratons.prm.bak | 246 + ...omography_based_plate_motions.part.prm.bak | 53 + .../plugins/reference_profile.cc.bak | 457 + .../plugins/reference_profile.h.bak | 214 + .../plugins/tomography_based_plate_motions.cc | 12 +- .../tomography_based_plate_motions.cc.bak | 1726 ++++ .../tomography_based_plate_motions.h.bak | 513 ++ .../doc/material.part.prm.bak | 12 + .../doc/temperature.part.prm.bak | 28 + .../temperature_dependent.prm.bak | 24 + .../transform_fault_behn_2007.prm.bak | 203 + cookbooks/van-keken-vof/doc/amr.part.prm.bak | 8 + cookbooks/van-keken-vof/doc/main.part.prm.bak | 19 + .../doc/postprocess.part.prm.bak | 13 + .../van-keken-vof/doc/variation.part.prm.bak | 10 + cookbooks/van-keken-vof/van-keken-vof.prm.bak | 108 + cookbooks/van-keken/doc/main.part.prm.bak | 19 + .../van-keken/doc/postprocess.part.prm.bak | 3 + cookbooks/van-keken/doc/smooth.part.prm.bak | 9 + .../van-keken/van-keken-discontinuous.prm.bak | 93 + cookbooks/van-keken/van-keken-smooth.prm.bak | 94 + .../plugin/van_Keken_mesh.cc.bak | 367 + .../vankeken_corner_flow.prm.bak | 157 + .../doc/harzburgite.prm.bak | 9 + .../doc/material_model.prm.bak | 15 + .../doc/steinberg.prm.bak | 17 + .../visualizing_phase_diagram.prm.bak | 131 + doc/logo/logo.prm.bak | 111 + .../doc/boundary-conditions.part.prm.bak | 7 + .../cookbooks/overview/doc/dim.part.prm.bak | 1 + .../overview/doc/geometry.part.prm.bak | 10 + .../overview/doc/gmg-average.part.prm.bak | 3 + .../overview/doc/gmg-enable.part.prm.bak | 5 + .../cookbooks/overview/doc/simple.prm.bak | 16 + .../overview/doc/structure.part.prm.bak | 20 + doc/manual/empty.prm.bak | 32 + .../adiabatic_conditions/ascii_data.h.bak | 130 + .../compute_entropy_profile.h.bak | 147 + .../compute_profile.h.bak | 200 + .../adiabatic_conditions/function.h.bak | 107 + .../adiabatic_conditions/interface.h.bak | 226 + .../boundary_composition/ascii_data.h.bak | 99 + include/aspect/boundary_composition/box.h.bak | 84 + .../boundary_composition/function.h.bak | 96 + .../initial_composition.h.bak | 114 + .../boundary_composition/interface.h.bak | 323 + .../spherical_constant.h.bak | 95 + .../two_merged_boxes.h.bak | 84 + .../boundary_fluid_pressure/density.h.bak | 92 + .../boundary_fluid_pressure/interface.h.bak | 166 + .../aspect/boundary_heat_flux/function.h.bak | 99 + .../aspect/boundary_heat_flux/interface.h.bak | 158 + .../boundary_temperature/ascii_data.h.bak | 115 + include/aspect/boundary_temperature/box.h.bak | 91 + .../boundary_temperature/constant.h.bak | 97 + .../boundary_temperature/dynamic_core.h.bak | 517 ++ .../boundary_temperature/function.h.bak | 129 + .../initial_temperature.h.bak | 115 + .../boundary_temperature/interface.h.bak | 355 + .../spherical_constant.h.bak | 109 + .../two_merged_boxes.h.bak | 96 + .../aspect/boundary_traction/ascii_data.h.bak | 105 + .../aspect/boundary_traction/function.h.bak | 112 + .../initial_lithostatic_pressure.h.bak | 126 + .../aspect/boundary_traction/interface.h.bak | 286 + .../boundary_traction/zero_traction.h.bak | 61 + .../aspect/boundary_velocity/ascii_data.h.bak | 110 + .../aspect/boundary_velocity/function.h.bak | 115 + .../aspect/boundary_velocity/gplates.h.bak | 347 + .../aspect/boundary_velocity/interface.h.bak | 349 + .../boundary_velocity/zero_velocity.h.bak | 59 + include/aspect/citation_info.h.bak | 62 + include/aspect/compat.h.bak | 216 + include/aspect/coordinate_systems.h.bak | 52 + include/aspect/fe_variable_collection.h.bak | 288 + include/aspect/geometry_model/box.h.bak | 255 + include/aspect/geometry_model/chunk.h.bak | 428 + .../geometry_model/ellipsoidal_chunk.h.bak | 346 + .../initial_topography_model/ascii_data.h.bak | 103 + .../initial_topography_model/function.h.bak | 93 + .../initial_topography_model/interface.h.bak | 163 + .../prm_polygon.h.bak | 87 + .../zero_topography.h.bak | 60 + include/aspect/geometry_model/interface.h.bak | 447 + include/aspect/geometry_model/sphere.h.bak | 164 + .../geometry_model/spherical_shell.h.bak | 454 + .../geometry_model/two_merged_boxes.h.bak | 265 + .../geometry_model/two_merged_chunks.h.bak | 325 + include/aspect/global.h.bak | 312 + include/aspect/gravity_model/ascii_data.h.bak | 99 + include/aspect/gravity_model/function.h.bak | 100 + include/aspect/gravity_model/interface.h.bak | 143 + include/aspect/gravity_model/radial.h.bak | 143 + include/aspect/gravity_model/vertical.h.bak | 72 + .../heating_model/adiabatic_heating.h.bak | 104 + .../adiabatic_heating_of_melt.h.bak | 108 + .../heating_model/compositional_heating.h.bak | 94 + .../heating_model/constant_heating.h.bak | 79 + include/aspect/heating_model/function.h.bak | 97 + include/aspect/heating_model/interface.h.bak | 384 + .../aspect/heating_model/latent_heat.h.bak | 74 + .../heating_model/latent_heat_melt.h.bak | 91 + .../heating_model/radioactive_decay.h.bak | 119 + .../aspect/heating_model/shear_heating.h.bak | 119 + .../shear_heating_with_melt.h.bak | 78 + .../adiabatic_density.h.bak | 58 + .../initial_composition/ascii_data.h.bak | 90 + .../ascii_data_layered.h.bak | 87 + .../entropy_table_lookup.h.bak | 111 + .../aspect/initial_composition/function.h.bak | 89 + .../initial_composition/interface.h.bak | 280 + .../aspect/initial_composition/porosity.h.bak | 84 + .../initial_composition/slab_model.h.bak | 109 + .../initial_composition/world_builder.h.bak | 105 + .../S40RTS_perturbation.h.bak | 233 + .../SAVANI_perturbation.h.bak | 196 + .../initial_temperature/adiabatic.h.bak | 187 + .../adiabatic_boundary.h.bak | 89 + .../initial_temperature/ascii_data.h.bak | 85 + .../ascii_data_layered.h.bak | 85 + .../initial_temperature/ascii_profile.h.bak | 90 + include/aspect/initial_temperature/box.h.bak | 122 + .../continental_geotherm.h.bak | 114 + .../aspect/initial_temperature/function.h.bak | 93 + .../harmonic_perturbation.h.bak | 107 + .../initial_temperature/interface.h.bak | 277 + .../lithosphere_mask.h.bak | 168 + .../initial_temperature/patch_on_S40RTS.h.bak | 122 + .../prescribed_temperature.h.bak | 73 + .../random_gaussian_perturbation.h.bak | 99 + .../initial_temperature/spherical_shell.h.bak | 147 + .../initial_temperature/world_builder.h.bak | 84 + include/aspect/introspection.h.bak | 676 ++ include/aspect/lateral_averaging.h.bak | 326 + .../ascii_reference_profile.h.bak | 167 + include/aspect/material_model/averaging.h.bak | 168 + .../aspect/material_model/compositing.h.bak | 136 + .../material_model/composition_reaction.h.bak | 125 + .../material_model/depth_dependent.h.bak | 151 + .../diffusion_dislocation.h.bak | 128 + .../material_model/drucker_prager.h.bak | 170 + .../aspect/material_model/entropy_model.h.bak | 187 + .../equation_of_state/interface.h.bak | 125 + .../linearized_incompressible.h.bak | 140 + .../multicomponent_compressible.h.bak | 143 + .../multicomponent_incompressible.h.bak | 127 + .../thermodynamic_table_lookup.h.bak | 236 + .../aspect/material_model/grain_size.h.bak | 490 ++ include/aspect/material_model/interface.h.bak | 1534 ++++ .../aspect/material_model/latent_heat.h.bak | 127 + .../material_model/latent_heat_melt.h.bak | 205 + .../aspect/material_model/melt_boukare.h.bak | 355 + .../aspect/material_model/melt_global.h.bak | 149 + .../aspect/material_model/melt_simple.h.bak | 144 + .../aspect/material_model/modified_tait.h.bak | 166 + .../material_model/multicomponent.h.bak | 139 + .../multicomponent_compressible.h.bak | 133 + .../material_model/nondimensional.h.bak | 132 + .../material_model/perplex_lookup.h.bak | 113 + .../material_model/prescribed_viscosity.h.bak | 110 + .../katz2003_mantle_melting.h.bak | 168 + .../reactive_fluid_transport.h.bak | 262 + .../replace_lithosphere_viscosity.h.bak | 102 + .../rheology/ascii_depth_profile.h.bak | 96 + .../rheology/composite_visco_plastic.h.bak | 147 + .../compositional_viscosity_prefactors.h.bak | 122 + .../rheology/constant_viscosity.h.bak | 73 + .../constant_viscosity_prefactors.h.bak | 85 + .../rheology/diffusion_creep.h.bak | 167 + .../rheology/diffusion_dislocation.h.bak | 139 + .../rheology/dislocation_creep.h.bak | 155 + .../rheology/drucker_prager.h.bak | 161 + .../material_model/rheology/elasticity.h.bak | 197 + .../rheology/frank_kamenetskii.h.bak | 98 + .../rheology/friction_models.h.bak | 135 + .../rheology/peierls_creep.h.bak | 275 + .../rheology/strain_dependent.h.bak | 274 + .../rheology/visco_plastic.h.bak | 339 + include/aspect/material_model/simple.h.bak | 109 + .../material_model/simple_compressible.h.bak | 137 + include/aspect/material_model/simpler.h.bak | 86 + .../aspect/material_model/steinberger.h.bak | 335 + include/aspect/material_model/utilities.h.bak | 680 ++ .../aspect/material_model/visco_plastic.h.bak | 283 + .../aspect/material_model/viscoelastic.h.bak | 220 + include/aspect/melt.h.bak | 571 ++ .../aspect/mesh_deformation/ascii_data.h.bak | 96 + .../aspect/mesh_deformation/diffusion.h.bak | 138 + .../aspect/mesh_deformation/fastscape.h.bak | 597 ++ .../mesh_deformation/free_surface.h.bak | 116 + .../aspect/mesh_deformation/function.h.bak | 87 + .../aspect/mesh_deformation/interface.h.bak | 649 ++ .../artificial_viscosity.h.bak | 78 + include/aspect/mesh_refinement/boundary.h.bak | 81 + .../mesh_refinement/compaction_length.h.bak | 79 + .../aspect/mesh_refinement/composition.h.bak | 78 + .../composition_approximate_gradient.h.bak | 78 + .../composition_gradient.h.bak | 78 + .../composition_threshold.h.bak | 76 + include/aspect/mesh_refinement/density.h.bak | 60 + .../aspect/mesh_refinement/interface.h.bak | 318 + .../aspect/mesh_refinement/isosurfaces.h.bak | 145 + .../maximum_refinement_function.h.bak | 94 + .../minimum_refinement_function.h.bak | 95 + .../nonadiabatic_temperature.h.bak | 58 + .../nonadiabatic_temperature_threshold.h.bak | 90 + .../mesh_refinement/particle_density.h.bak | 69 + include/aspect/mesh_refinement/slope.h.bak | 62 + .../aspect/mesh_refinement/strain_rate.h.bak | 58 + .../aspect/mesh_refinement/temperature.h.bak | 58 + .../thermal_energy_density.h.bak | 59 + .../aspect/mesh_refinement/topography.h.bak | 59 + include/aspect/mesh_refinement/velocity.h.bak | 58 + .../aspect/mesh_refinement/viscosity.h.bak | 60 + .../volume_of_fluid_interface.h.bak | 73 + include/aspect/newton.h.bak | 358 + include/aspect/parameters.h | 2 +- include/aspect/parameters.h.bak | 802 ++ .../particle/generator/ascii_file.h.bak | 80 + .../aspect/particle/generator/interface.h.bak | 251 + .../probability_density_function.h.bak | 128 + .../generator/quadrature_points.h.bak | 63 + .../particle/generator/random_uniform.h.bak | 98 + .../particle/generator/reference_cell.h.bak | 94 + .../particle/generator/uniform_box.h.bak | 99 + .../particle/generator/uniform_radial.h.bak | 124 + .../aspect/particle/integrator/euler.h.bak | 101 + .../particle/integrator/interface.h.bak | 242 + include/aspect/particle/integrator/rk_2.h.bak | 155 + include/aspect/particle/integrator/rk_4.h.bak | 135 + include/aspect/particle/interface.h.bak | 63 + .../interpolator/bilinear_least_squares.h.bak | 103 + .../particle/interpolator/cell_average.h.bak | 80 + .../interpolator/harmonic_average.h.bak | 80 + .../particle/interpolator/interface.h.bak | 179 + .../interpolator/nearest_neighbor.h.bak | 81 + .../quadratic_least_squares.h.bak | 117 + .../particle/property/composition.h.bak | 98 + .../property/cpo_bingham_average.h.bak | 224 + .../property/cpo_elastic_tensor.h.bak | 206 + .../property/crystal_preferred_orientation.h | 2 +- .../crystal_preferred_orientation.h.bak | 649 ++ .../particle/property/elastic_stress.h.bak | 104 + .../elastic_tensor_decomposition.h.bak | 274 + .../aspect/particle/property/function.h.bak | 101 + .../aspect/particle/property/grain_size.h.bak | 123 + .../property/initial_composition.h.bak | 83 + .../particle/property/initial_position.h.bak | 71 + .../particle/property/integrated_strain.h.bak | 99 + .../integrated_strain_invariant.h.bak | 98 + .../aspect/particle/property/interface.h.bak | 816 ++ .../particle/property/melt_particle.h.bak | 115 + .../aspect/particle/property/pT_path.h.bak | 119 + .../aspect/particle/property/position.h.bak | 87 + .../property/reference_position.h.bak | 87 + .../particle/property/strain_rate.h.bak | 97 + .../aspect/particle/property/velocity.h.bak | 96 + .../viscoplastic_strain_invariants.h.bak | 109 + include/aspect/particle/world.h.bak | 531 ++ include/aspect/plugins.h.bak | 808 ++ .../aspect/postprocess/ODE_statistics.h.bak | 82 + .../aspect/postprocess/basic_statistics.h.bak | 62 + .../postprocess/boundary_densities.h.bak | 79 + .../postprocess/boundary_pressures.h.bak | 79 + ...dary_strain_rate_residual_statistics.h.bak | 106 + ...oundary_velocity_residual_statistics.h.bak | 128 + include/aspect/postprocess/command.h.bak | 72 + .../postprocess/composition_statistics.h.bak | 53 + .../composition_velocity_statistics.h.bak | 75 + .../aspect/postprocess/core_statistics.h.bak | 106 + .../crystal_preferred_orientation.h.bak | 279 + .../aspect/postprocess/depth_average.h.bak | 156 + .../domain_volume_statistics.h.bak | 54 + .../postprocess/dynamic_topography.h.bak | 136 + .../entropy_viscosity_statistics.h.bak | 52 + include/aspect/postprocess/geoid.h.bak | 188 + .../postprocess/global_statistics.h.bak | 153 + .../postprocess/gravity_point_values.h.bak | 291 + .../postprocess/heat_flux_densities.h.bak | 54 + .../aspect/postprocess/heat_flux_map.h.bak | 109 + .../postprocess/heat_flux_statistics.h.bak | 53 + .../postprocess/heating_statistics.h.bak | 56 + include/aspect/postprocess/interface.h.bak | 380 + .../postprocess/load_balance_statistics.h.bak | 66 + .../postprocess/mass_flux_statistics.h.bak | 54 + .../postprocess/material_statistics.h.bak | 54 + .../postprocess/matrix_statistics.h.bak | 52 + .../aspect/postprocess/max_depth_field.h.bak | 52 + .../aspect/postprocess/melt_statistics.h.bak | 57 + .../postprocess/memory_statistics.h.bak | 68 + .../postprocess/mobility_statistics.h.bak | 52 + .../particle_count_statistics.h.bak | 60 + include/aspect/postprocess/particles.h.bak | 319 + include/aspect/postprocess/point_values.h.bak | 128 + .../postprocess/pressure_statistics.h.bak | 52 + .../postprocess/rotation_statistics.h.bak | 85 + include/aspect/postprocess/sea_level.h.bak | 178 + .../spherical_velocity_statistics.h.bak | 54 + .../aspect/postprocess/stokes_residual.h.bak | 108 + .../postprocess/temperature_statistics.h.bak | 52 + include/aspect/postprocess/topography.h.bak | 91 + .../velocity_boundary_statistics.h.bak | 55 + .../postprocess/velocity_statistics.h.bak | 52 + .../viscous_dissipation_statistics.h.bak | 54 + .../aspect/postprocess/visualization.h.bak | 747 ++ .../ISA_rotation_timescale.h.bak | 72 + .../postprocess/visualization/adiabat.h.bak | 68 + .../visualization/artificial_viscosity.h.bak | 60 + .../artificial_viscosity_composition.h.bak | 80 + .../visualization/boundary_indicator.h.bak | 65 + .../boundary_strain_rate_residual.h.bak | 87 + .../boundary_velocity_residual.h.bak | 84 + .../visualization/compositional_vector.h.bak | 86 + .../postprocess/visualization/depth.h.bak | 58 + .../visualization/dynamic_topography.h.bak | 75 + .../visualization/error_indicator.h.bak | 59 + .../postprocess/visualization/geoid.h.bak | 84 + .../visualization/grain_lag_angle.h.bak | 79 + .../postprocess/visualization/gravity.h.bak | 58 + .../visualization/heat_flux_map.h.bak | 105 + .../postprocess/visualization/heating.h.bak | 74 + .../visualization/kxrcf_indicator.h.bak | 80 + .../visualization/material_properties.h.bak | 92 + ...aximum_horizontal_compressive_stress.h.bak | 92 + .../postprocess/visualization/melt.h.bak | 84 + .../visualization/melt_fraction.h.bak | 116 + .../named_additional_outputs.h.bak | 79 + .../visualization/nonadiabatic_pressure.h.bak | 62 + .../nonadiabatic_temperature.h.bak | 62 + .../visualization/particle_count.h.bak | 71 + .../postprocess/visualization/partition.h.bak | 62 + .../visualization/principal_stress.h.bak | 82 + .../visualization/seismic_anomalies.h.bak | 156 + .../visualization/shear_stress.h.bak | 72 + .../visualization/spd_factor.h.bak | 71 + .../spherical_velocity_components.h.bak | 76 + .../visualization/strain_rate.h.bak | 67 + .../visualization/strain_rate_tensor.h.bak | 65 + .../postprocess/visualization/stress.h.bak | 71 + .../stress_second_invariant.h.bak | 67 + .../surface_dynamic_topography.h.bak | 72 + .../visualization/surface_elevation.h.bak | 68 + .../surface_strain_rate_tensor.h.bak | 68 + .../visualization/surface_stress.h.bak | 73 + .../visualization/temperature_anomaly.h.bak | 93 + .../visualization/vertical_heat_flux.h.bak | 67 + .../volume_of_fluid_values.h.bak | 116 + .../volumetric_strain_rate.h.bak | 62 + .../volume_of_fluid_statistics.h.bak | 53 + .../ascii_data.h.bak | 85 + .../prescribed_stokes_solution/circle.h.bak | 51 + .../prescribed_stokes_solution/function.h.bak | 105 + .../interface.h.bak | 159 + include/aspect/simulator.h.bak | 2203 +++++ .../simulator/assemblers/advection.h.bak | 136 + .../simulator/assemblers/interface.h.bak | 818 ++ .../aspect/simulator/assemblers/stokes.h.bak | 224 + include/aspect/simulator_access.h.bak | 1002 +++ include/aspect/simulator_signals.h.bak | 420 + include/aspect/stokes_matrix_free.h.bak | 702 ++ include/aspect/structured_data.h.bak | 778 ++ .../termination_criteria/end_step.h.bak | 70 + .../termination_criteria/end_time.h.bak | 77 + .../termination_criteria/end_walltime.h.bak | 84 + .../termination_criteria/interface.h.bak | 244 + .../steady_heat_flux.h.bak | 94 + .../steady_rms_velocity.h.bak | 79 + .../steady_temperature.h.bak | 78 + .../termination_criteria/user_request.h.bak | 72 + .../time_stepping/conduction_time_step.h.bak | 61 + .../time_stepping/convection_time_step.h.bak | 62 + include/aspect/time_stepping/function.h.bak | 72 + include/aspect/time_stepping/interface.h.bak | 284 + .../time_stepping/repeat_on_cutback.h.bak | 85 + include/aspect/utilities.h.bak | 1392 +++ include/aspect/volume_of_fluid/assembly.h | 4 +- include/aspect/volume_of_fluid/assembly.h.bak | 231 + include/aspect/volume_of_fluid/field.h.bak | 96 + include/aspect/volume_of_fluid/handler.h | 2 +- include/aspect/volume_of_fluid/handler.h.bak | 226 + .../aspect/volume_of_fluid/utilities.h.bak | 171 + source/adiabatic_conditions/ascii_data.cc.bak | 168 + .../compute_entropy_profile.cc.bak | 315 + .../compute_profile.cc.bak | 427 + source/adiabatic_conditions/function.cc.bak | 148 + source/adiabatic_conditions/interface.cc.bak | 222 + source/boundary_composition/ascii_data.cc.bak | 131 + source/boundary_composition/box.cc.bak | 180 + source/boundary_composition/function.cc.bak | 146 + .../initial_composition.cc.bak | 135 + source/boundary_composition/interface.cc.bak | 376 + .../spherical_constant.cc.bak | 143 + .../two_merged_boxes.cc.bak | 207 + source/boundary_fluid_pressure/density.cc.bak | 154 + .../boundary_fluid_pressure/interface.cc.bak | 155 + source/boundary_heat_flux/function.cc.bak | 179 + source/boundary_heat_flux/interface.cc.bak | 155 + source/boundary_temperature/ascii_data.cc.bak | 144 + source/boundary_temperature/box.cc.bak | 173 + source/boundary_temperature/constant.cc.bak | 189 + .../boundary_temperature/dynamic_core.cc.bak | 986 +++ source/boundary_temperature/function.cc.bak | 186 + .../initial_temperature.cc.bak | 134 + source/boundary_temperature/interface.cc.bak | 390 + .../spherical_constant.cc.bak | 149 + .../two_merged_boxes.cc.bak | 191 + source/boundary_traction/ascii_data.cc.bak | 140 + source/boundary_traction/function.cc.bak | 158 + .../initial_lithostatic_pressure.cc.bak | 442 + source/boundary_traction/interface.cc.bak | 321 + source/boundary_traction/zero_traction.cc.bak | 62 + source/boundary_velocity/ascii_data.cc.bak | 177 + source/boundary_velocity/function.cc.bak | 185 + source/boundary_velocity/gplates.cc.bak | 870 ++ source/boundary_velocity/interface.cc.bak | 414 + source/boundary_velocity/zero_velocity.cc.bak | 54 + source/citation_info.cc.bak | 55 + source/compat.cc.bak | 800 ++ source/fe_variable_collection.cc.bak | 268 + source/geometry_model/box.cc.bak | 524 ++ source/geometry_model/chunk.cc.bak | 949 ++ .../geometry_model/ellipsoidal_chunk.cc.bak | 833 ++ .../ascii_data.cc.bak | 204 + .../initial_topography_model/function.cc.bak | 190 + .../initial_topography_model/interface.cc.bak | 176 + .../prm_polygon.cc.bak | 172 + .../zero_topography.cc.bak | 58 + source/geometry_model/interface.cc.bak | 368 + source/geometry_model/sphere.cc.bak | 238 + source/geometry_model/spherical_shell.cc.bak | 1074 +++ source/geometry_model/two_merged_boxes.cc.bak | 570 ++ .../geometry_model/two_merged_chunks.cc.bak | 635 ++ source/global.cc.bak | 112 + source/gravity_model/ascii_data.cc.bak | 126 + source/gravity_model/function.cc.bak | 138 + source/gravity_model/interface.cc.bak | 167 + source/gravity_model/radial.cc.bak | 211 + source/gravity_model/vertical.cc.bak | 98 + source/heating_model/adiabatic_heating.cc.bak | 112 + .../adiabatic_heating_of_melt.cc.bak | 160 + .../compositional_heating.cc.bak | 141 + source/heating_model/constant_heating.cc.bak | 96 + source/heating_model/function.cc.bak | 157 + source/heating_model/interface.cc.bak | 324 + source/heating_model/latent_heat.cc.bak | 63 + source/heating_model/latent_heat_melt.cc.bak | 187 + source/heating_model/radioactive_decay.cc.bak | 206 + source/heating_model/shear_heating.cc.bak | 203 + .../shear_heating_with_melt.cc.bak | 122 + .../adiabatic_density.cc.bak | 54 + source/initial_composition/ascii_data.cc.bak | 118 + .../ascii_data_layered.cc.bak | 123 + .../entropy_table_lookup.cc.bak | 138 + source/initial_composition/function.cc.bak | 125 + source/initial_composition/interface.cc.bak | 275 + source/initial_composition/porosity.cc.bak | 116 + source/initial_composition/slab_model.cc.bak | 147 + .../initial_composition/world_builder.cc.bak | 136 + .../S40RTS_perturbation.cc.bak | 530 ++ .../SAVANI_perturbation.cc.bak | 537 ++ source/initial_temperature/adiabatic.cc.bak | 572 ++ .../adiabatic_boundary.cc.bak | 136 + source/initial_temperature/ascii_data.cc.bak | 112 + .../ascii_data_layered.cc.bak | 124 + .../initial_temperature/ascii_profile.cc.bak | 112 + source/initial_temperature/box.cc.bak | 276 + .../continental_geotherm.cc.bak | 269 + source/initial_temperature/function.cc.bak | 129 + .../harmonic_perturbation.cc.bak | 234 + source/initial_temperature/interface.cc.bak | 264 + .../lithosphere_mask.cc.bak | 223 + .../patch_on_S40RTS.cc.bak | 212 + .../prescribed_temperature.cc.bak | 97 + .../random_gaussian_perturbation.cc.bak | 211 + .../spherical_shell.cc.bak | 378 + .../initial_temperature/world_builder.cc.bak | 84 + source/main.cc.bak | 892 ++ .../ascii_reference_profile.cc.bak | 280 + source/material_model/averaging.cc.bak | 464 + source/material_model/compositing.cc.bak | 259 + .../composition_reaction.cc.bak | 250 + source/material_model/depth_dependent.cc.bak | 350 + .../diffusion_dislocation.cc.bak | 219 + source/material_model/drucker_prager.cc.bak | 323 + source/material_model/entropy_model.cc.bak | 577 ++ .../equation_of_state/interface.cc.bak | 85 + .../linearized_incompressible.cc.bak | 160 + .../multicomponent_compressible.cc.bak | 177 + .../multicomponent_incompressible.cc.bak | 156 + .../thermodynamic_table_lookup.cc.bak | 579 ++ source/material_model/grain_size.cc.bak | 1687 ++++ source/material_model/interface.cc.bak | 1239 +++ source/material_model/latent_heat.cc.bak | 422 + source/material_model/latent_heat_melt.cc.bak | 660 ++ source/material_model/melt_boukare.cc | 4 +- source/material_model/melt_boukare.cc.bak | 1314 +++ source/material_model/melt_global.cc.bak | 556 ++ source/material_model/melt_simple.cc.bak | 284 + source/material_model/modified_tait.cc.bak | 271 + source/material_model/multicomponent.cc.bak | 179 + .../multicomponent_compressible.cc.bak | 184 + source/material_model/nondimensional.cc.bak | 216 + source/material_model/perplex_lookup.cc.bak | 230 + .../prescribed_viscosity.cc.bak | 210 + .../katz2003_mantle_melting.cc.bak | 651 ++ .../reactive_fluid_transport.cc | 2 +- .../reactive_fluid_transport.cc.bak | 585 ++ .../replace_lithosphere_viscosity.cc.bak | 172 + .../rheology/ascii_depth_profile.cc.bak | 99 + .../rheology/composite_visco_plastic.cc.bak | 458 + .../compositional_viscosity_prefactors.cc.bak | 178 + .../rheology/constant_viscosity.cc.bak | 67 + .../constant_viscosity_prefactors.cc.bak | 105 + .../rheology/diffusion_creep.cc.bak | 303 + .../rheology/diffusion_dislocation.cc.bak | 386 + .../rheology/dislocation_creep.cc.bak | 285 + .../rheology/drucker_prager.cc.bak | 294 + .../material_model/rheology/elasticity.cc.bak | 529 ++ .../rheology/frank_kamenetskii.cc.bak | 156 + .../rheology/friction_models.cc.bak | 312 + .../rheology/peierls_creep.cc.bak | 679 ++ .../rheology/strain_dependent.cc.bak | 917 ++ .../rheology/visco_plastic.cc.bak | 855 ++ source/material_model/simple.cc.bak | 265 + .../material_model/simple_compressible.cc.bak | 170 + source/material_model/simpler.cc.bak | 131 + source/material_model/steinberger.cc.bak | 631 ++ source/material_model/utilities.cc.bak | 1546 ++++ source/material_model/visco_plastic.cc.bak | 678 ++ source/material_model/viscoelastic.cc.bak | 313 + source/mesh_deformation/ascii_data.cc.bak | 151 + source/mesh_deformation/diffusion.cc.bak | 582 ++ source/mesh_deformation/fastscape.cc.bak | 1997 +++++ source/mesh_deformation/free_surface.cc.bak | 336 + source/mesh_deformation/function.cc.bak | 149 + source/mesh_deformation/interface.cc.bak | 1605 ++++ .../artificial_viscosity.cc.bak | 132 + source/mesh_refinement/boundary.cc.bak | 122 + .../mesh_refinement/compaction_length.cc.bak | 158 + source/mesh_refinement/composition.cc.bak | 152 + .../composition_approximate_gradient.cc.bak | 153 + .../composition_gradient.cc.bak | 185 + .../composition_threshold.cc.bak | 137 + source/mesh_refinement/density.cc.bak | 143 + source/mesh_refinement/interface.cc.bak | 519 ++ source/mesh_refinement/isosurfaces.cc.bak | 404 + .../maximum_refinement_function.cc.bak | 193 + .../minimum_refinement_function.cc.bak | 192 + .../nonadiabatic_temperature.cc.bak | 127 + .../nonadiabatic_temperature_threshold.cc.bak | 158 + .../mesh_refinement/particle_density.cc.bak | 75 + source/mesh_refinement/slope.cc.bak | 103 + source/mesh_refinement/strain_rate.cc.bak | 75 + source/mesh_refinement/temperature.cc.bak | 83 + .../thermal_energy_density.cc.bak | 144 + source/mesh_refinement/topography.cc.bak | 87 + source/mesh_refinement/velocity.cc.bak | 83 + source/mesh_refinement/viscosity.cc.bak | 148 + .../volume_of_fluid_interface.cc.bak | 345 + source/particle/generator/ascii_file.cc.bak | 133 + source/particle/generator/interface.cc.bak | 306 + .../probability_density_function.cc.bak | 149 + .../generator/quadrature_points.cc.bak | 63 + .../particle/generator/random_uniform.cc.bak | 123 + .../particle/generator/reference_cell.cc.bak | 148 + source/particle/generator/uniform_box.cc.bak | 175 + .../particle/generator/uniform_radial.cc.bak | 254 + source/particle/integrator/euler.cc.bak | 103 + source/particle/integrator/interface.cc.bak | 248 + source/particle/integrator/rk_2.cc.bak | 242 + source/particle/integrator/rk_4.cc.bak | 281 + source/particle/interface.cc.bak | 42 + .../bilinear_least_squares.cc.bak | 364 + .../particle/interpolator/cell_average.cc.bak | 161 + .../interpolator/harmonic_average.cc.bak | 169 + source/particle/interpolator/interface.cc.bak | 149 + .../interpolator/nearest_neighbor.cc.bak | 161 + .../quadratic_least_squares.cc.bak | 640 ++ source/particle/property/composition.cc.bak | 110 + .../property/cpo_bingham_average.cc.bak | 284 + .../property/cpo_elastic_tensor.cc.bak | 261 + .../property/crystal_preferred_orientation.cc | 2 +- .../crystal_preferred_orientation.cc.bak | 1275 +++ .../particle/property/elastic_stress.cc.bak | 199 + .../elastic_tensor_decomposition.cc.bak | 468 + source/particle/property/function.cc.bak | 113 + source/particle/property/grain_size.cc.bak | 173 + .../property/initial_composition.cc.bak | 91 + .../particle/property/initial_position.cc.bak | 72 + .../property/integrated_strain.cc.bak | 124 + .../integrated_strain_invariant.cc.bak | 118 + source/particle/property/interface.cc.bak | 820 ++ source/particle/property/melt_particle.cc.bak | 126 + source/particle/property/pT_path.cc.bak | 123 + source/particle/property/position.cc.bak | 80 + .../property/reference_position.cc.bak | 80 + source/particle/property/strain_rate.cc.bak | 102 + source/particle/property/velocity.cc.bak | 88 + .../viscoplastic_strain_invariants.cc.bak | 243 + source/particle/world.cc.bak | 1384 +++ source/plugins.cc.bak | 50 + source/postprocess/ODE_statistics.cc.bak | 108 + source/postprocess/basic_statistics.cc.bak | 165 + source/postprocess/boundary_densities.cc.bak | 177 + source/postprocess/boundary_pressures.cc.bak | 156 + ...ary_strain_rate_residual_statistics.cc.bak | 332 + ...undary_velocity_residual_statistics.cc.bak | 376 + source/postprocess/command.cc.bak | 131 + .../postprocess/composition_statistics.cc.bak | 168 + .../composition_velocity_statistics.cc.bak | 205 + source/postprocess/core_statistics.cc.bak | 236 + .../crystal_preferred_orientation.cc.bak | 870 ++ source/postprocess/depth_average.cc.bak | 517 ++ .../domain_volume_statistics.cc.bak | 69 + source/postprocess/dynamic_topography.cc.bak | 548 ++ .../entropy_viscosity_statistics.cc.bak | 118 + source/postprocess/geoid.cc.bak | 1060 +++ source/postprocess/global_statistics.cc.bak | 324 + .../postprocess/gravity_point_values.cc.bak | 850 ++ source/postprocess/heat_flux_densities.cc.bak | 157 + source/postprocess/heat_flux_map.cc.bak | 565 ++ .../postprocess/heat_flux_statistics.cc.bak | 160 + source/postprocess/heating_statistics.cc.bak | 166 + source/postprocess/interface.cc.bak | 414 + .../load_balance_statistics.cc.bak | 111 + .../postprocess/mass_flux_statistics.cc.bak | 188 + source/postprocess/material_statistics.cc.bak | 128 + source/postprocess/matrix_statistics.cc.bak | 119 + source/postprocess/max_depth_field.cc.bak | 131 + source/postprocess/melt_statistics.cc.bak | 152 + source/postprocess/memory_statistics.cc.bak | 141 + source/postprocess/mobility_statistics.cc.bak | 156 + .../particle_count_statistics.cc.bak | 97 + source/postprocess/particles.cc.bak | 758 ++ source/postprocess/point_values.cc.bak | 369 + source/postprocess/pressure_statistics.cc.bak | 144 + source/postprocess/rotation_statistics.cc.bak | 202 + source/postprocess/sea_level.cc.bak | 618 ++ .../spherical_velocity_statistics.cc.bak | 170 + source/postprocess/stokes_residual.cc.bak | 179 + .../postprocess/temperature_statistics.cc.bak | 172 + source/postprocess/topography.cc.bak | 250 + .../velocity_boundary_statistics.cc.bak | 217 + source/postprocess/velocity_statistics.cc.bak | 118 + .../viscous_dissipation_statistics.cc.bak | 168 + source/postprocess/visualization.cc.bak | 1688 ++++ .../ISA_rotation_timescale.cc.bak | 116 + .../postprocess/visualization/adiabat.cc.bak | 120 + .../visualization/artificial_viscosity.cc.bak | 84 + .../artificial_viscosity_composition.cc.bak | 135 + .../visualization/boundary_indicator.cc.bak | 112 + .../boundary_strain_rate_residual.cc.bak | 148 + .../boundary_velocity_residual.cc.bak | 126 + .../visualization/compositional_vector.cc.bak | 196 + source/postprocess/visualization/depth.cc.bak | 93 + .../visualization/dynamic_topography.cc.bak | 142 + .../visualization/error_indicator.cc.bak | 78 + source/postprocess/visualization/geoid.cc.bak | 113 + .../visualization/grain_lag_angle.cc.bak | 180 + .../postprocess/visualization/gravity.cc.bak | 80 + .../visualization/heat_flux_map.cc.bak | 208 + .../postprocess/visualization/heating.cc.bak | 188 + .../visualization/kxrcf_indicator.cc.bak | 135 + .../visualization/material_properties.cc.bak | 306 + ...ximum_horizontal_compressive_stress.cc.bak | 366 + source/postprocess/visualization/melt.cc.bak | 278 + .../visualization/melt_fraction.cc.bak | 354 + .../named_additional_outputs.cc.bak | 184 + .../nonadiabatic_pressure.cc.bak | 91 + .../nonadiabatic_temperature.cc.bak | 81 + .../visualization/particle_count.cc.bak | 90 + .../visualization/partition.cc.bak | 81 + .../visualization/principal_stress.cc.bak | 242 + .../visualization/seismic_anomalies.cc.bak | 566 ++ .../visualization/shear_stress.cc.bak | 148 + .../visualization/spd_factor.cc.bak | 109 + .../spherical_velocity_components.cc.bak | 145 + .../visualization/strain_rate.cc.bak | 97 + .../visualization/strain_rate_tensor.cc.bak | 105 + .../postprocess/visualization/stress.cc.bak | 147 + .../stress_second_invariant.cc.bak | 137 + .../surface_dynamic_topography.cc.bak | 135 + .../visualization/surface_elevation.cc.bak | 110 + .../surface_strain_rate_tensor.cc.bak | 109 + .../visualization/surface_stress.cc.bak | 143 + .../visualization/temperature_anomaly.cc.bak | 190 + .../visualization/vertical_heat_flux.cc.bak | 106 + .../volume_of_fluid_values.cc.bak | 209 + .../volumetric_strain_rate.cc.bak | 95 + .../volume_of_fluid_statistics.cc.bak | 117 + .../ascii_data.cc.bak | 121 + .../prescribed_stokes_solution/circle.cc.bak | 70 + .../function.cc.bak | 246 + .../interface.cc.bak | 156 + source/simulator/assemblers/advection.cc.bak | 1634 ++++ source/simulator/assemblers/interface.cc.bak | 656 ++ .../simulator/assemblers/newton_stokes.cc.bak | 972 ++ source/simulator/assemblers/stokes.cc.bak | 994 +++ source/simulator/assembly.cc.bak | 1301 +++ source/simulator/checkpoint_restart.cc.bak | 650 ++ source/simulator/core.cc | 2 +- source/simulator/core.cc.bak | 2199 +++++ source/simulator/entropy_viscosity.cc.bak | 710 ++ source/simulator/helper_functions.cc.bak | 2521 ++++++ source/simulator/initial_conditions.cc.bak | 545 ++ source/simulator/introspection.cc.bak | 615 ++ source/simulator/lateral_averaging.cc.bak | 972 ++ source/simulator/limiters.cc.bak | 876 ++ source/simulator/melt.cc.bak | 1960 +++++ source/simulator/newton.cc.bak | 318 + source/simulator/nullspace.cc.bak | 522 ++ source/simulator/parameters.cc | 6 +- source/simulator/parameters.cc.bak | 2329 +++++ source/simulator/simulator_access.cc.bak | 901 ++ source/simulator/simulator_signals.cc.bak | 102 + source/simulator/solver.cc.bak | 1270 +++ source/simulator/solver_schemes.cc.bak | 1411 +++ source/simulator/stokes_matrix_free.cc.bak | 2798 ++++++ source/structured_data.cc.bak | 1952 +++++ source/termination_criteria/end_step.cc.bak | 71 + source/termination_criteria/end_time.cc.bak | 95 + .../termination_criteria/end_walltime.cc.bak | 80 + source/termination_criteria/interface.cc.bak | 284 + .../steady_heat_flux.cc.bak | 233 + .../steady_rms_velocity.cc.bak | 172 + .../steady_temperature.cc.bak | 199 + .../termination_criteria/user_request.cc.bak | 95 + .../time_stepping/conduction_time_step.cc.bak | 131 + .../time_stepping/convection_time_step.cc.bak | 109 + source/time_stepping/function.cc.bak | 106 + source/time_stepping/interface.cc.bak | 380 + source/time_stepping/repeat_on_cutback.cc.bak | 115 + source/utilities.cc.bak | 3601 ++++++++ source/volume_of_fluid/assembler.cc | 2 +- source/volume_of_fluid/assembler.cc.bak | 650 ++ source/volume_of_fluid/handler.cc.bak | 647 ++ source/volume_of_fluid/reconstruct.cc.bak | 519 ++ .../setup_initial_conditions.cc.bak | 245 + source/volume_of_fluid/solver.cc.bak | 106 + source/volume_of_fluid/utilities.cc.bak | 694 ++ tests/2d_annulus_pyvista_cookbook.prm.bak | 90 + tests/ISA_rotation_timescale.prm.bak | 102 + tests/Picard_compressible.prm.bak | 249 + tests/additional_outputs_02.cc.bak | 171 + tests/additional_outputs_02.prm.bak | 77 + tests/additional_outputs_03.cc.bak | 185 + tests/additional_outputs_03.prm.bak | 78 + tests/adiabatic_boundary.prm.bak | 66 + tests/adiabatic_conditions.prm.bak | 75 + ...ic_conditions_composition_function.prm.bak | 83 + tests/adiabatic_conditions_function.prm.bak | 83 + .../adiabatic_conditions_time_change.prm.bak | 88 + tests/adiabatic_heating.prm.bak | 124 + tests/adiabatic_heating_simplified.prm.bak | 130 + tests/adiabatic_heating_with_melt.prm.bak | 146 + tests/adiabatic_initial_conditions.prm.bak | 99 + ...adiabatic_initial_conditions_chunk.prm.bak | 94 + ...abatic_initial_conditions_chunk_3d.prm.bak | 98 + ...ic_initial_conditions_compressible.prm.bak | 95 + ...abatic_initial_conditions_constant.prm.bak | 89 + ...diabatic_initial_conditions_points.prm.bak | 105 + ...initial_conditions_subadiabaticity.prm.bak | 93 + ...nitial_conditions_without_boundary.prm.bak | 66 + tests/adiabatic_plate_cooling.prm.bak | 81 + tests/adiabatic_plate_function.prm.bak | 86 + tests/advect_field_with_melt_velocity.cc.bak | 21 + tests/advect_field_with_melt_velocity.prm.bak | 142 + tests/advect_mesh_vertically.prm.bak | 128 + tests/advection_reaction.cc.bak | 21 + tests/advection_reaction.prm.bak | 152 + tests/advection_solver_fail.prm.bak | 12 + tests/airy_isostasy.prm.bak | 140 + tests/airy_isostasy_initial_topo.cc.bak | 77 + tests/airy_isostasy_initial_topo.prm.bak | 37 + ..._initial_topo_lithostatic_pressure.prm.bak | 41 + tests/always_refine.prm.bak | 107 + tests/analytic_artificial_viscosity_0.prm.bak | 93 + tests/anisotropic_viscosity.cc.bak | 830 ++ tests/anisotropic_viscosity.prm.bak | 91 + tests/annulus.cc.bak | 21 + tests/annulus.prm.bak | 10 + tests/annulus_transient.cc.bak | 21 + tests/annulus_transient.prm.bak | 96 + tests/artificial_postprocess.cc.bak | 83 + tests/artificial_postprocess.prm.bak | 112 + tests/artificial_viscosity.prm.bak | 124 + ...ial_viscosity_dirichlet_boundaries.prm.bak | 110 + tests/artificial_viscosity_list.prm.bak | 93 + tests/ascii_boundary_member.cc.bak | 212 + tests/ascii_boundary_member.prm.bak | 67 + tests/ascii_data_adiabatic_conditions.prm.bak | 78 + ...a_boundary_composition_2d_box_time.prm.bak | 89 + ...i_data_boundary_composition_3d_box.prm.bak | 78 + ...a_boundary_temperature_2d_box_time.prm.bak | 71 + ...i_data_boundary_temperature_3d_box.prm.bak | 68 + ...scii_data_boundary_velocity_2d_box.prm.bak | 67 + ...data_boundary_velocity_2d_box_list.prm.bak | 73 + ...data_boundary_velocity_2d_box_time.prm.bak | 74 + ...dary_velocity_2d_box_time_backward.prm.bak | 77 + ...locity_2d_box_time_non_equidistant.prm.bak | 73 + ...ii_data_boundary_velocity_2d_chunk.prm.bak | 72 + ...ii_data_boundary_velocity_2d_shell.prm.bak | 72 + ...undary_velocity_2d_shell_spherical.prm.bak | 73 + ...scii_data_boundary_velocity_3d_box.prm.bak | 74 + ...ii_data_boundary_velocity_3d_chunk.prm.bak | 75 + ...ii_data_boundary_velocity_3d_shell.prm.bak | 72 + ...undary_velocity_3d_shell_spherical.prm.bak | 73 + ...i_data_boundary_velocity_3d_sphere.prm.bak | 70 + ...a_boundary_velocity_residual_shell.prm.bak | 84 + tests/ascii_data_fail_1.prm.bak | 71 + tests/ascii_data_fail_2.prm.bak | 71 + tests/ascii_data_fail_3.prm.bak | 71 + tests/ascii_data_fail_4.prm.bak | 71 + tests/ascii_data_gravity.prm.bak | 79 + ...ii_data_initial_composition_2d_box.prm.bak | 77 + ...data_initial_composition_2d_box_gz.prm.bak | 79 + ..._data_initial_composition_3d_chunk.prm.bak | 85 + ..._data_initial_composition_3d_shell.prm.bak | 83 + ...ii_data_initial_temperature_2d_box.prm.bak | 59 + ..._data_initial_temperature_3d_chunk.prm.bak | 63 + ...l_temperature_3d_ellipsoidal_chunk.prm.bak | 62 + ..._data_initial_temperature_3d_shell.prm.bak | 60 + ..._initial_temperature_3d_two_chunks.prm.bak | 66 + ...layered_initial_composition_2d_box.prm.bak | 77 + ...layered_initial_temperature_2d_box.prm.bak | 65 + ...yered_initial_temperature_2d_chunk.prm.bak | 67 + ...layered_initial_temperature_3d_box.prm.bak | 67 + ...yered_initial_temperature_3d_chunk.prm.bak | 74 + ...perature_piecewise_constant_3d_box.prm.bak | 66 + ...uniform_initial_composition_2d_box.prm.bak | 87 + ...scii_data_prescribed_stokes_2d_box.prm.bak | 73 + tests/ascii_data_slice.prm.bak | 111 + tests/ascii_data_slice_temperature.prm.bak | 64 + tests/average_arithmetic.prm.bak | 95 + ...ge_density_boundary_fluid_pressure.prm.bak | 280 + tests/average_geometric.prm.bak | 95 + tests/average_harmonic.prm.bak | 95 + tests/average_log.prm.bak | 95 + tests/average_none.prm.bak | 96 + tests/average_nwd_arithmetic.prm.bak | 100 + tests/average_nwd_geometric.prm.bak | 100 + tests/average_nwd_harmonic.prm.bak | 100 + tests/average_pick_largest.prm.bak | 95 + tests/average_project_to_q1.prm.bak | 96 + tests/background_output_writer.prm.bak | 14 + tests/backward_advection.prm.bak | 84 + tests/benchmark_layeredflow.cc.bak | 21 + tests/benchmark_layeredflow.prm.bak | 13 + ...chmark_particle_integration_scheme.prm.bak | 7 + tests/blankenbach.prm.bak | 80 + tests/blankenbach_approximation.prm.bak | 93 + tests/blankenbach_case1a.cc.bak | 22 + tests/blankenbach_case1a.prm.bak | 20 + tests/blankenbach_case1b.cc.bak | 22 + tests/blankenbach_case1b.prm.bak | 26 + tests/blankenbach_case1c.cc.bak | 22 + tests/blankenbach_case1c.prm.bak | 26 + tests/blankenbach_case2a.cc.bak | 22 + tests/blankenbach_case2a.prm.bak | 20 + tests/blankenbach_case2b.cc.bak | 22 + tests/blankenbach_case2b.prm.bak | 20 + tests/boukare_bulk_composition.prm | 4 +- tests/boukare_bulk_composition.prm.bak | 211 + tests/boukare_conserve_mass.prm | 4 +- tests/boukare_conserve_mass.prm.bak | 159 + tests/boukare_latent_heat.prm | 2 +- tests/boukare_latent_heat.prm.bak | 166 + tests/boukare_melting_diagram.prm.bak | 162 + tests/boundary_composition_list.prm.bak | 103 + ...dary_composition_passive_cartesian.prm.bak | 102 + ...boundary_composition_passive_depth.prm.bak | 102 + ...oundary_composition_passive_sphere.prm.bak | 102 + tests/boundary_heatflux.prm.bak | 124 + tests/boundary_heatflux_update.cc.bak | 108 + tests/boundary_heatflux_update.prm.bak | 102 + tests/boundary_temperature_function.prm.bak | 70 + tests/boundary_temperature_list.prm.bak | 74 + ...on_function_cartesian_free_surface.prm.bak | 143 + ...on_function_spherical_free_surface.prm.bak | 144 + ...undary_velocity_function_spherical.prm.bak | 74 + tests/box_end_time_1e7_terminate.prm.bak | 67 + tests/box_first_time_step.prm.bak | 58 + .../box_first_time_step_alternate_bc.prm.bak | 64 + tests/box_initial_mesh_deformation.cc.bak | 68 + tests/box_initial_mesh_deformation.prm.bak | 81 + ...nitial_mesh_deformation_ascii_data.prm.bak | 102 + ...x_initial_mesh_deformation_periodic.cc.bak | 21 + ..._initial_mesh_deformation_periodic.prm.bak | 25 + .../box_initial_topography_ascii_data.prm.bak | 99 + ...topography_ascii_data_moved_origin.prm.bak | 101 + tests/box_initial_topography_function.prm.bak | 98 + ...box_initial_topography_prm_polygon.prm.bak | 91 + tests/box_lithostatic_pressure_2d.prm.bak | 142 + tests/box_lithostatic_pressure_3d.prm.bak | 140 + tests/box_origin.prm.bak | 68 + tests/box_repetitions.prm.bak | 65 + ...simple_log_viscosity_depth_average.prm.bak | 104 + ...ox_simple_surface_strain_rate_residual.prm | 6 +- ...imple_surface_strain_rate_residual.prm.bak | 99 + tests/box_steady_state_terminate.prm.bak | 63 + .../box_steady_temperature_terminate.prm.bak | 73 + tests/box_surface_base_variables.prm | 4 - tests/box_surface_base_variables.prm.bak | 105 + tests/bunge_cookbook.prm.bak | 17 + tests/burnman_seismic_test.prm.bak | 151 + tests/burnman_test.prm.bak | 128 + tests/burstedde.cc.bak | 21 + tests/burstedde.prm.bak | 94 + tests/burstedde_stokes_rhs.cc.bak | 472 + tests/burstedde_stokes_rhs.prm.bak | 99 + tests/cell_reference.cc.bak | 61 + tests/cell_reference.prm.bak | 68 + tests/cells_in_circumference.prm.bak | 91 + ...check_compositional_field_functions.cc.bak | 71 + ...heck_compositional_field_functions.prm.bak | 13 + tests/check_compositional_field_names.cc.bak | 76 + tests/check_compositional_field_names.prm.bak | 14 + tests/checkpoint_01.cc.bak | 100 + tests/checkpoint_01.prm.bak | 87 + tests/checkpoint_01_check_parameters.cc.bak | 112 + tests/checkpoint_01_check_parameters.prm.bak | 85 + tests/checkpoint_02.cc.bak | 97 + tests/checkpoint_02.prm.bak | 86 + tests/checkpoint_02_direct.cc.bak | 97 + tests/checkpoint_02_direct.prm.bak | 81 + tests/checkpoint_03_particles.cc.bak | 98 + tests/checkpoint_03_particles.prm.bak | 97 + .../checkpoint_04_particles_no_output.cc.bak | 96 + .../checkpoint_04_particles_no_output.prm.bak | 97 + tests/checkpoint_05_mpi_create.prm.bak | 5 + tests/checkpoint_05_mpi_resume.cc.bak | 55 + tests/checkpoint_05_mpi_resume.prm.bak | 12 + tests/checkpoint_06_spherical_shell.cc.bak | 98 + tests/checkpoint_06_spherical_shell.prm.bak | 66 + ...oint_07_enable_free_surface_create.prm.bak | 74 + ...point_07_enable_free_surface_resume.cc.bak | 55 + ...oint_07_enable_free_surface_resume.prm.bak | 31 + tests/chunk_ascii_initial_temperature.prm.bak | 75 + tests/chunk_conditions.prm.bak | 77 + tests/chunk_cross_hemisphere.prm.bak | 74 + tests/chunk_first_time_step_2d.prm.bak | 74 + tests/chunk_first_time_step_3d.prm.bak | 74 + ...hunk_initial_topography_ascii_data.prm.bak | 83 + ...k_initial_topography_ascii_data_3d.prm.bak | 88 + ...opography_ascii_data_3d_colatitude.prm.bak | 19 + tests/chunk_lithostatic_pressure_2d.prm.bak | 132 + ...tic_pressure_2d_initial_topography.prm.bak | 46 + tests/chunk_tangential_velocity.prm.bak | 92 + tests/chunk_topography_postprocessor.prm.bak | 115 + tests/command_postprocessor.prm.bak | 40 + tests/compaction_length_refinement.prm.bak | 128 + tests/compaction_length_visualization.prm.bak | 123 + tests/composite_viscous_outputs.cc.bak | 208 + tests/composite_viscous_outputs.prm.bak | 80 + tests/compositing_02.prm.bak | 119 + tests/compositing_named_outputs.prm.bak | 92 + tests/composition_active.prm.bak | 107 + tests/composition_active_nans.prm.bak | 21 + tests/composition_active_with_melt.cc.bak | 158 + tests/composition_active_with_melt.prm.bak | 106 + tests/composition_active_without_melt.cc.bak | 21 + tests/composition_active_without_melt.prm.bak | 100 + tests/composition_cg_dg_fem.prm.bak | 96 + tests/composition_names.prm.bak | 117 + tests/composition_names_duplicates.prm.bak | 95 + ...ion_passive_discontinuous_constant.prm.bak | 99 + tests/composition_passive_particles.prm.bak | 111 + ...on_passive_quarter_shell_cartesian.prm.bak | 108 + ...sition_passive_quarter_shell_depth.prm.bak | 108 + ...on_passive_quarter_shell_spherical.prm.bak | 108 + tests/composition_passive_static.prm.bak | 95 + tests/composition_reaction.prm.bak | 110 + ...composition_reaction_iterated_IMPES.cc.bak | 91 + ...omposition_reaction_iterated_IMPES.prm.bak | 121 + tests/composition_stabilization.prm.bak | 113 + tests/compositional_boundary_values.prm.bak | 101 + .../compositional_boundary_values_02.prm.bak | 102 + .../compositional_boundary_values_03.prm.bak | 100 + tests/compositional_heating.prm.bak | 166 + ...itional_heating_exclude_background.prm.bak | 113 + tests/compositional_vectors.prm.bak | 60 + tests/compositional_vectors_3d.prm.bak | 60 + tests/compressibility.cc.bak | 215 + tests/compressibility.prm.bak | 110 + tests/compressibility_iterated_stokes.cc.bak | 89 + tests/compressibility_iterated_stokes.prm.bak | 99 + ...ility_iterated_stokes_direct_solver.cc.bak | 21 + ...lity_iterated_stokes_direct_solver.prm.bak | 86 + tests/compressibility_lateral_pipe.cc.bak | 21 + tests/compressibility_lateral_pipe.prm.bak | 5 + ...compressibility_lateral_pipe_advect.cc.bak | 21 + ...ompressibility_lateral_pipe_advect.prm.bak | 5 + ...teral_pipe_advect_projected_density.cc.bak | 21 + ...eral_pipe_advect_projected_density.prm.bak | 8 + ...lity_lateral_pipe_increase_pressure.cc.bak | 21 + ...ity_lateral_pipe_increase_pressure.prm.bak | 5 + ...increase_pressure_projected_density.cc.bak | 21 + ...ncrease_pressure_projected_density.prm.bak | 8 + ...lity_lateral_pipe_projected_density.cc.bak | 21 + ...ity_lateral_pipe_projected_density.prm.bak | 8 + ...pressibility_lateral_pipe_transient.cc.bak | 21 + ...ressibility_lateral_pipe_transient.prm.bak | 5 + ...al_pipe_transient_projected_density.cc.bak | 21 + ...l_pipe_transient_projected_density.prm.bak | 8 + tests/compressibility_vertical_pipe.cc.bak | 21 + tests/compressibility_vertical_pipe.prm.bak | 5 + ...ity_vertical_pipe_projected_density.cc.bak | 21 + ...ty_vertical_pipe_projected_density.prm.bak | 8 + ...pressibility_volumetric_strain_rate.cc.bak | 21 + ...ressibility_volumetric_strain_rate.prm.bak | 87 + tests/compressible_forsterite_box.prm.bak | 87 + tests/compression_heating.cc.bak | 69 + tests/compression_heating.prm.bak | 141 + ...compute-no-normal-flux-constraints.prm.bak | 146 + tests/conservative_with_mpi.cc.bak | 21 + tests/conservative_with_mpi.prm.bak | 81 + ...t_boundary_flux_adjacent_dirichlet.prm.bak | 90 + .../consistent_boundary_flux_neumann.prm.bak | 84 + ...istent_boundary_flux_open_boundary.prm.bak | 88 + .../constant_composition_convergence.prm.bak | 77 + ...nt_temperature_boundary_conditions.prm.bak | 70 + tests/continental_extension.prm.bak | 51 + tests/convection_box_particles.prm.bak | 4 + tests/convection_box_phase_function.prm.bak | 143 + ...cookbook_mantle_convection_annulus.prm.bak | 36 + tests/cookbook_simpler_with_crust.cc.bak | 208 + tests/coordinate_transformation.cc.bak | 94 + tests/coordinate_transformation.prm.bak | 80 + ...an_parameterization_kinematic_slab.prm.bak | 59 + tests/cpo_simple_shearbox.prm.bak | 154 + tests/crameri_benchmark_1_gmg.cc.bak | 21 + tests/crameri_benchmark_1_gmg.prm.bak | 52 + tests/crustal_model_3D.prm.bak | 124 + tests/custom_spherical_shell_2d_list.prm.bak | 82 + .../custom_spherical_shell_2d_slices.prm.bak | 82 + tests/custom_spherical_shell_3d_list.prm.bak | 82 + .../custom_spherical_shell_3d_slices.prm.bak | 82 + .../damped_viscoelastic_bending_beam.prm.bak | 49 + tests/darcy_velocity.cc.bak | 21 + tests/darcy_velocity.prm.bak | 145 + tests/darcy_velocity_vertical.cc.bak | 21 + tests/darcy_velocity_vertical.prm.bak | 37 + tests/dash_dash.cc.bak | 50 + tests/dash_dash.prm.bak | 8 + tests/dc_Picard_compressible.prm | 4 +- tests/dc_Picard_compressible.prm.bak | 263 + tests/density_boundary.prm.bak | 95 + tests/depth_average_01.prm.bak | 90 + tests/depth_average_02.prm.bak | 88 + tests/depth_average_03.prm.bak | 93 + tests/depth_average_04.prm.bak | 91 + tests/depth_average_05.prm.bak | 91 + tests/depth_average_06.prm.bak | 79 + tests/depth_average_rounding_bug.prm.bak | 85 + tests/depth_average_txt_output.prm.bak | 90 + tests/depth_average_underres.prm.bak | 92 + ...pth_dependent_3d_shell_list_simple.prm.bak | 83 + ...depth_dependent_additional_outputs.prm.bak | 34 + tests/depth_dependent_box_file_simple.prm.bak | 159 + ...epth_dependent_box_function_simple.prm.bak | 161 + ...endent_box_function_time_dependent.prm.bak | 164 + tests/depth_dependent_box_none_simple.prm.bak | 157 + ...th_dependent_initialize_base_model.prm.bak | 133 + tests/depth_postprocessor_box.prm.bak | 64 + tests/depth_postprocessor_chunk.prm.bak | 70 + ...th_postprocessor_ellipsoidal_chunk.prm.bak | 78 + tests/depth_postprocessor_sphere.prm.bak | 68 + ...epth_postprocessor_spherical_shell.prm.bak | 67 + ...pth_postprocessor_two_merged_boxes.prm.bak | 68 + ...rivative_of_weighted_p_norm_average.cc.bak | 41 + ...ivative_of_weighted_p_norm_average.prm.bak | 1 + tests/diffusion.prm.bak | 304 + tests/diffusion_dislocation.prm.bak | 122 + ...sion_dislocation_fixed_strain_rate.prm.bak | 92 + ...ion_dislocation_fixed_strain_rate2.prm.bak | 88 + ...location_reference_density_profile.prm.bak | 124 + tests/diffusion_velocity.prm.bak | 303 + tests/direct_solver_1.prm.bak | 152 + tests/direct_solver_2.prm.bak | 150 + tests/discontinuous_composition_1.prm.bak | 95 + ...s_composition_bound_preserving_limiter.prm | 1 - ...mposition_bound_preserving_limiter.prm.bak | 100 + ...omposition_bound_preserving_limiter_3d.prm | 1 - ...sition_bound_preserving_limiter_3d.prm.bak | 101 + ...und_preserving_limiter_selected_fields.prm | 2 - ...preserving_limiter_selected_fields.prm.bak | 88 + ...us_composition_serial_periodic_amr.prm.bak | 80 + tests/discontinuous_temperature.prm.bak | 95 + ...scontinuous_temperature_blankenbach.cc.bak | 21 + ...continuous_temperature_blankenbach.prm.bak | 119 + ...ous_temperature_spherical_shell_3d.prm.bak | 94 + tests/doneahuerta_3.cc.bak | 21 + tests/doneahuerta_3.prm.bak | 88 + tests/drucker_prager_compression.prm.bak | 124 + tests/drucker_prager_derivatives_2d.cc.bak | 247 + tests/drucker_prager_derivatives_2d.prm.bak | 108 + tests/drucker_prager_derivatives_3d.cc.bak | 262 + tests/drucker_prager_derivatives_3d.prm.bak | 108 + tests/drucker_prager_extension.prm.bak | 124 + tests/dynamic_core.prm.bak | 101 + tests/dynamic_friction.prm.bak | 141 + tests/dynamic_topography.prm.bak | 101 + tests/dynamic_topography2.prm.bak | 102 + tests/dynamic_topography3.prm.bak | 79 + tests/dynamic_topography_back.prm.bak | 101 + ...aphy_vs_surface_dynamic_topography.prm.bak | 103 + tests/edit_parameters.cc.bak | 98 + tests/edit_parameters.prm.bak | 72 + ...ic_stabilization_time_scale_factor.prm.bak | 38 + ...ipsoidal_chunk_coordinate_parallel.prm.bak | 86 + tests/ellipsoidal_chunk_geometry.cc.bak | 121 + tests/ellipsoidal_chunk_geometry.prm.bak | 78 + ...oidal_chunk_noncoordinate_parallel.prm.bak | 87 + tests/ellipsoidal_chunk_topography.prm.bak | 93 + tests/entropy_adiabat.cc.bak | 21 + tests/entropy_adiabat.prm.bak | 13 + tests/entropy_conduction.cc.bak | 21 + tests/entropy_conduction.prm.bak | 7 + tests/entropy_half_space.cc.bak | 21 + tests/entropy_half_space.prm.bak | 13 + tests/entropy_initial_lookup.cc.bak | 21 + tests/entropy_initial_lookup.prm.bak | 136 + tests/entropy_initial_lookup_wb.cc.bak | 21 + tests/entropy_initial_lookup_wb.prm.bak | 141 + tests/entropy_plasticity.cc.bak | 21 + tests/entropy_plasticity.prm.bak | 152 + tests/entropy_read_multi_table.cc.bak | 21 + tests/entropy_read_multi_table.prm.bak | 116 + tests/entropy_viscosity_statistics.prm.bak | 11 + tests/exponential_decay.cc.bak | 21 + tests/exponential_decay.prm.bak | 124 + tests/fail.prm.bak | 5 + tests/find_boundary_composition_model.cc.bak | 88 + tests/find_boundary_composition_model.prm.bak | 75 + ...d_boundary_composition_model_fail_1.cc.bak | 61 + ..._boundary_composition_model_fail_1.prm.bak | 81 + tests/find_mesh_refinement.cc.bak | 88 + tests/find_mesh_refinement.prm.bak | 61 + tests/find_mesh_refinement_fail_1.cc.bak | 60 + tests/find_mesh_refinement_fail_1.prm.bak | 65 + tests/find_postprocess.cc.bak | 88 + tests/find_postprocess.prm.bak | 58 + tests/find_postprocess_fail_1.cc.bak | 61 + tests/find_postprocess_fail_1.prm.bak | 64 + ...er_2D_loading_fixed_elastic_dt_gmg.prm.bak | 33 + tests/free_surface_adaptive_blob.prm.bak | 115 + tests/free_surface_blob.prm.bak | 114 + tests/free_surface_blob_gmg.prm.bak | 17 + tests/free_surface_blob_melt.cc.bak | 326 + tests/free_surface_blob_melt.prm.bak | 135 + tests/free_surface_blob_nonzero_melt.cc.bak | 21 + tests/free_surface_blob_nonzero_melt.prm.bak | 153 + tests/free_surface_iterated_IMPES.prm.bak | 121 + tests/free_surface_iterated_stokes.prm.bak | 120 + tests/free_surface_iterated_stokes_gmg.prm | 2 +- .../free_surface_iterated_stokes_gmg.prm.bak | 21 + tests/free_surface_relaxation.cc.bak | 178 + tests/free_surface_relaxation.prm.bak | 121 + ...e_surface_tangential_mesh_velocity.prm.bak | 86 + ...surface_tangential_mesh_velocity_2.prm.bak | 83 + tests/free_surface_timestep_repeat.prm.bak | 176 + ...formation_tangential_mesh_velocity.prm.bak | 86 + tests/gaussian_initial_temperature.prm.bak | 81 + tests/geoid.prm.bak | 101 + tests/geoid_freesurface.prm.bak | 116 + tests/geoid_no_topo.prm.bak | 89 + tests/geoid_visualization.prm.bak | 104 + tests/geometric_average_crash.prm.bak | 59 + .../geometric_average_only_viscosity.prm.bak | 80 + tests/global_latent_heat.prm.bak | 159 + tests/global_melt.prm.bak | 216 + tests/global_melt_parallel.prm.bak | 214 + tests/global_refine_amr.cc.bak | 105 + tests/global_refine_amr.prm.bak | 59 + tests/global_refine_bug.prm.bak | 74 + tests/gmg_mesh_deform.prm.bak | 18 + tests/gmg_mesh_deform_adaptive.prm.bak | 21 + tests/gmg_mesh_deform_adaptive_bug.prm.bak | 25 + tests/gmg_mesh_deform_adaptive_bug2.prm.bak | 139 + tests/gmg_mesh_deform_function.prm.bak | 17 + tests/gmg_mesh_deform_ghost_entries.prm.bak | 38 + tests/gmg_mesh_deform_prescribed.cc.bak | 21 + tests/gmg_mesh_deform_prescribed.prm.bak | 17 + tests/gmg_mesh_deform_topo.prm.bak | 109 + tests/gmg_no_normal_flux_only.prm.bak | 87 + tests/gmg_test_project_q1.prm.bak | 102 + ...g_velocity_boundary_2d_box_no_flux.prm.bak | 100 + ...ity_boundary_2d_box_no_normal_flux.prm.bak | 99 + ...velocity_boundary_2d_chunk_no_flux.prm.bak | 103 + ...y_boundary_2d_chunk_no_normal_flux.prm.bak | 102 + ...g_velocity_boundary_3d_box_no_flux.prm.bak | 103 + ...ity_boundary_3d_box_no_normal_flux.prm.bak | 102 + ...velocity_boundary_3d_chunk_no_flux.prm.bak | 106 + ...y_boundary_3d_chunk_no_normal_flux.prm.bak | 105 + tests/gmg_velocity_boundary_component.prm.bak | 20 + tests/gplates_1_3.prm.bak | 78 + tests/gplates_1_4.prm.bak | 81 + tests/gplates_3d.prm.bak | 77 + tests/gplates_rotation.prm.bak | 77 + tests/gplates_scale_factor.prm.bak | 84 + tests/grain_lag_angle.prm.bak | 102 + tests/grain_size_additional_outputs.prm.bak | 24 + tests/grain_size_averaging.prm.bak | 16 + tests/grain_size_crossed_transition.prm.bak | 172 + tests/grain_size_friction_heating.prm.bak | 131 + tests/grain_size_growth.prm.bak | 159 + tests/grain_size_growth_one_cell.prm.bak | 144 + ...ain_size_growth_one_cell_particles.prm.bak | 43 + tests/grain_size_growth_particles.prm.bak | 49 + tests/grain_size_growth_pinned.prm.bak | 34 + tests/grain_size_latent_heat.cc.bak | 237 + tests/grain_size_latent_heat.prm.bak | 131 + tests/grain_size_phase_function.prm.bak | 149 + tests/grain_size_plunge.prm.bak | 10 + tests/grain_size_ridge.prm.bak | 23 + tests/grain_size_ridge_traction.prm.bak | 112 + tests/grain_size_strain.prm.bak | 130 + tests/grain_size_strain_pinned.prm.bak | 77 + tests/grain_size_strain_pinned_state.prm.bak | 58 + tests/grain_size_yield.prm.bak | 55 + tests/graphical_output.cc.bak | 21 + tests/graphical_output.prm.bak | 74 + tests/graphical_output_02.prm.bak | 76 + tests/graphical_output_hdf5.cc.bak | 21 + tests/graphical_output_hdf5.prm.bak | 78 + tests/gravity_function.prm.bak | 71 + tests/gravity_function_time.prm.bak | 72 + tests/gravity_model_cartesian.prm.bak | 99 + tests/gravity_model_depth.prm.bak | 89 + tests/gravity_model_spherical.prm.bak | 99 + tests/gravity_point_values_list.prm.bak | 69 + tests/gravity_point_values_map.prm.bak | 69 + tests/gravity_point_values_spiral.prm.bak | 68 + ...avity_point_values_spiral_parallel.prm.bak | 9 + tests/gravity_prem.prm.bak | 72 + ...gravity_quadrature_degree_increase.prm.bak | 70 + tests/gs_drucker_prager.prm.bak | 131 + tests/gs_drucker_prager_extension.prm.bak | 93 + ...drucker_prager_extension_adiabatic.prm.bak | 92 + tests/heat_advection_by_melt.cc.bak | 127 + tests/heat_advection_by_melt.prm.bak | 143 + ...dvection_by_melt_operator_splitting.cc.bak | 21 + ...vection_by_melt_operator_splitting.prm.bak | 134 + tests/heat_flow.prm.bak | 4 + tests/heat_flow_plume.prm.bak | 4 + tests/heat_flux_densities.prm.bak | 110 + tests/heat_flux_map.prm.bak | 72 + tests/heat_flux_map_vis.prm.bak | 79 + tests/heat_flux_map_vis_point_wise.prm.bak | 20 + tests/heating_function.prm.bak | 67 + tests/heating_function_depth.prm.bak | 16 + tests/heating_function_spherical.prm.bak | 17 + tests/hexagonal_initial_temperature.prm.bak | 84 + tests/hill_diffusion.prm.bak | 115 + tests/hill_diffusion_3D.prm.bak | 116 + ...vine_composite_hydration_prefactor.prm.bak | 144 + ...mposite_hydration_prefactor_cutoff.prm.bak | 23 + ...vine_diffusion_hydration_prefactor.prm.bak | 131 + ...ne_dislocation_hydration_prefactor.prm.bak | 128 + tests/hollow_sphere.cc.bak | 21 + tests/hollow_sphere.prm.bak | 99 + tests/hollow_sphere_gmg.cc.bak | 21 + tests/hollow_sphere_gmg.prm.bak | 101 + tests/hollow_sphere_gmg_project_q1.cc.bak | 21 + tests/hollow_sphere_gmg_project_q1.prm.bak | 29 + tests/hollow_sphere_gmg_q3.cc.bak | 21 + tests/hollow_sphere_gmg_q3.prm.bak | 105 + tests/hydrostatic_compression.cc.bak | 313 + tests/hydrostatic_compression.prm.bak | 113 + tests/inclusion_2.cc.bak | 21 + tests/inclusion_2.prm.bak | 86 + tests/inclusion_4.cc.bak | 21 + tests/inclusion_4.prm.bak | 86 + tests/inclusion_adaptive.cc.bak | 21 + tests/inclusion_adaptive.prm.bak | 89 + tests/infill_density_flexure.cc.bak | 21 + tests/infill_density_flexure.prm.bak | 10 + tests/initial_composition_list.prm.bak | 81 + ...ial_composition_list_using_maximum.prm.bak | 82 + ...ial_composition_list_using_minimum.prm.bak | 82 + ...al_composition_list_using_subtract.prm.bak | 82 + tests/initial_condition_S20RTS.prm.bak | 70 + tests/initial_condition_S20RTS_2D.prm.bak | 10 + tests/initial_condition_S20RTS_dgp.prm.bak | 75 + tests/initial_condition_S40RTS.prm.bak | 71 + tests/initial_condition_SAVANI.prm.bak | 74 + ...initial_condition_lithosphere_mask.prm.bak | 62 + .../initial_condition_patch_on_S40RTS.prm.bak | 62 + tests/initial_condition_vs_to_density.prm.bak | 77 + ...ial_condition_vs_to_density_SAVANI.prm.bak | 77 + tests/initial_global_refinement.prm.bak | 88 + tests/initial_porosity.prm.bak | 216 + tests/initial_temperature_list.prm.bak | 63 + ...ial_temperature_list_using_maximum.prm.bak | 64 + ...ial_temperature_list_using_minimum.prm.bak | 64 + ...al_temperature_list_using_subtract.prm.bak | 64 + tests/initial_temperature_profile.prm.bak | 69 + tests/inner_core.cc.bak | 21 + tests/inner_core.prm.bak | 142 + tests/internal_heating_statistics.prm.bak | 100 + .../interpolor_particles_harmonic_average.prm | 1 - ...erpolor_particles_harmonic_average.prm.bak | 21 + ...erpolor_particles_nearest_neighbor.prm.bak | 8 + ..._particles_quadratic_least_squares.prm.bak | 8 + tests/isosurfaces_simple_box_2D.prm.bak | 96 + ...es_simple_box_2D_custom_fieldnames.prm.bak | 21 + ...mple_box_2D_custom_fieldnames_fail.prm.bak | 21 + ...sosurfaces_simple_box_2D_min_max_1.prm.bak | 14 + ...sosurfaces_simple_box_2D_min_max_2.prm.bak | 14 + tests/isosurfaces_simple_box_3D.prm.bak | 56 + tests/isosurfaces_slab_2D.prm.bak | 102 + tests/isosurfaces_slab_3D.prm.bak | 67 + ...ction_and_defect_correction_Stokes.prm.bak | 127 + tests/iterated_advection_and_stokes.prm.bak | 127 + tests/iterated_advection_and_stokes_DG.prm | 1 - .../iterated_advection_and_stokes_DG.prm.bak | 128 + ...erated_advection_and_stokes_DG_limiter.prm | 3 +- ...ed_advection_and_stokes_DG_limiter.prm.bak | 135 + ...advection_and_stokes_direct_solver.prm.bak | 130 + ...ated_advection_and_stokes_residual.prm.bak | 127 + .../kaus_rayleigh_taylor_instability.prm.bak | 41 + ...nematically_driven_subduction_2d_case1.prm | 2 +- ...tically_driven_subduction_2d_case1.prm.bak | 177 + ...tically_driven_subduction_2d_case2a.cc.bak | 4 + ...ematically_driven_subduction_2d_case2a.prm | 2 +- ...ically_driven_subduction_2d_case2a.prm.bak | 176 + ...tically_driven_subduction_2d_case2b.cc.bak | 4 + ...ematically_driven_subduction_2d_case2b.prm | 2 +- ...ically_driven_subduction_2d_case2b.prm.bak | 195 + tests/king_ala.cc.bak | 22 + tests/king_ala.prm.bak | 11 + tests/king_ala_nondim.prm.bak | 163 + tests/latent_heat.prm.bak | 132 + tests/latent_heat_composition.prm.bak | 164 + tests/latent_heat_enthalpy.cc.bak | 188 + tests/latent_heat_enthalpy.prm.bak | 115 + tests/latent_heat_melt.prm.bak | 145 + tests/latent_heat_melt_operator_split.prm.bak | 172 + tests/latent_heat_melt_statistics.prm.bak | 127 + tests/latent_heat_melt_transport.prm.bak | 162 + tests/latent_heat_pressure.prm.bak | 126 + tests/latent_heat_viscosity.prm.bak | 113 + tests/latent_heat_viscosity_adiabatic.prm.bak | 102 + tests/lithosphere_boundary_indicator.prm.bak | 130 + .../lithosphere_boundary_indicator_3d.prm.bak | 133 + ...ere_boundary_indicator_3d_one_grid.prm.bak | 13 + ...ere_boundary_indicator_3d_periodic.prm.bak | 152 + ...sphere_boundary_indicator_one_grid.prm.bak | 13 + ...hosphere_boundary_indicator_origin.prm.bak | 15 + tests/logo.prm.bak | 14 + tests/magnetic_stripes.cc.bak | 21 + tests/magnetic_stripes.prm.bak | 8 + tests/mass_flux_statistics.prm.bak | 44 + tests/mass_reaction_term.prm.bak | 173 + tests/material_model_dependencies.cc.bak | 132 + ...terial_model_dependencies_burstedde.cc.bak | 22 + ...erial_model_dependencies_burstedde.prm.bak | 86 + ...l_dependencies_composition_reaction.cc.bak | 21 + ..._dependencies_composition_reaction.prm.bak | 67 + ...es_cookbooks_freesurface_with_crust.cc.bak | 22 + ...s_cookbooks_freesurface_with_crust.prm.bak | 67 + ..._dependencies_diffusion_dislocation.cc.bak | 21 + ...dependencies_diffusion_dislocation.prm.bak | 73 + ...rial_model_dependencies_inclusion_2.cc.bak | 22 + ...ial_model_dependencies_inclusion_2.prm.bak | 67 + ...rial_model_dependencies_latent_heat.cc.bak | 21 + ...ial_model_dependencies_latent_heat.prm.bak | 104 + ...model_dependencies_latent_heat_melt.cc.bak | 21 + ...odel_dependencies_latent_heat_melt.prm.bak | 67 + ...ial_model_dependencies_morency_doin.cc.bak | 23 + ...al_model_dependencies_morency_doin.prm.bak | 67 + ...l_model_dependencies_multicomponent.cc.bak | 21 + ..._model_dependencies_multicomponent.prm.bak | 67 + ...l_model_dependencies_shear_thinning.cc.bak | 22 + ..._model_dependencies_shear_thinning.prm.bak | 76 + .../material_model_dependencies_simple.cc.bak | 21 + ...material_model_dependencies_simple.prm.bak | 67 + ...el_dependencies_simple_compressible.cc.bak | 21 + ...l_dependencies_simple_compressible.prm.bak | 67 + ...material_model_dependencies_simpler.cc.bak | 21 + ...aterial_model_dependencies_simpler.prm.bak | 67 + .../material_model_dependencies_solcx.cc.bak | 22 + .../material_model_dependencies_solcx.prm.bak | 67 + .../material_model_dependencies_solkz.cc.bak | 22 + .../material_model_dependencies_solkz.prm.bak | 67 + ...rial_model_dependencies_steinberger.cc.bak | 21 + ...ial_model_dependencies_steinberger.prm.bak | 85 + ...terial_model_dependencies_tangurnis.cc.bak | 22 + ...erial_model_dependencies_tangurnis.prm.bak | 86 + tests/material_statistics.prm.bak | 80 + tests/matrix_nonzeros_1.prm.bak | 85 + tests/matrix_nonzeros_2.prm.bak | 100 + tests/matrix_nonzeros_3.prm.bak | 106 + tests/matrix_nonzeros_4.prm.bak | 114 + tests/matrix_nonzeros_5.prm.bak | 110 + tests/matrix_nonzeros_6.prm.bak | 111 + tests/matrix_nonzeros_7.prm.bak | 117 + tests/max_timesteps_btwn_output.prm.bak | 168 + ...zontal_compressive_stress_case_one.prm.bak | 108 + ...zontal_compressive_stress_case_two.prm.bak | 110 + tests/maximum_refinement_function.prm.bak | 154 + ...imum_refinement_function_cartesian.prm.bak | 144 + ...imum_refinement_function_spherical.prm.bak | 136 + tests/maxtimestep.prm.bak | 64 + tests/melt_and_traction.prm.bak | 276 + tests/melt_boukare_EOS.prm | 2 +- tests/melt_boukare_EOS.prm.bak | 157 + tests/melt_boukare_averaging.prm | 2 +- tests/melt_boukare_averaging.prm.bak | 157 + tests/melt_boundary_heat_flux.cc.bak | 21 + tests/melt_boundary_heat_flux.prm.bak | 127 + tests/melt_compressible_advection.cc.bak | 213 + tests/melt_compressible_advection.prm.bak | 132 + tests/melt_force_vector.cc.bak | 338 + tests/melt_force_vector.prm.bak | 160 + tests/melt_fraction_postprocessor.prm.bak | 126 + tests/melt_introspection.cc.bak | 138 + tests/melt_introspection.prm.bak | 95 + tests/melt_material_1.cc.bak | 102 + tests/melt_material_1.prm.bak | 109 + tests/melt_material_2.cc.bak | 129 + tests/melt_material_2.prm.bak | 132 + tests/melt_material_3.cc.bak | 129 + tests/melt_material_3.prm.bak | 132 + tests/melt_material_4.cc.bak | 240 + tests/melt_material_4.prm.bak | 143 + tests/melt_postprocessor_peridotite.prm.bak | 121 + tests/melt_postprocessor_pyroxenite.prm.bak | 140 + tests/melt_property_visualization.cc.bak | 21 + tests/melt_property_visualization.prm.bak | 139 + tests/melt_restart.cc.bak | 96 + tests/melt_restart.prm.bak | 223 + tests/melt_statistics.prm.bak | 141 + tests/melt_track.cc.bak | 21 + tests/melt_track.prm.bak | 189 + tests/melt_transport.prm.bak | 151 + tests/melt_transport_adaptive.cc.bak | 518 ++ tests/melt_transport_adaptive.prm.bak | 135 + tests/melt_transport_compressible.cc.bak | 370 + tests/melt_transport_compressible.prm.bak | 142 + ...lt_transport_compressible_iterative.cc.bak | 21 + ...t_transport_compressible_iterative.prm.bak | 135 + .../melt_transport_convergence_simple.cc.bak | 326 + .../melt_transport_convergence_simple.prm.bak | 135 + tests/melt_transport_convergence_test.cc.bak | 330 + tests/melt_transport_convergence_test.prm.bak | 136 + .../melt_velocity_boundary_conditions.cc.bak | 21 + .../melt_velocity_boundary_conditions.prm.bak | 154 + tests/melt_visco_plastic.cc.bak | 1038 +++ ...isco_plastic_mohr_circle_compaction.cc.bak | 21 + ...t_visco_plastic_mohr_circle_compaction.prm | 1 - ...sco_plastic_mohr_circle_compaction.prm.bak | 163 + ...elt_visco_plastic_mohr_circle_shear.cc.bak | 21 + .../melt_visco_plastic_mohr_circle_shear.prm | 1 - ...lt_visco_plastic_mohr_circle_shear.prm.bak | 162 + tests/melting_rate.cc.bak | 126 + tests/melting_rate.prm.bak | 138 + tests/melting_rate_operator_splitting.prm.bak | 154 + .../melting_rate_operator_splitting2.prm.bak | 144 + tests/melting_rate_test.prm.bak | 156 + tests/memory_statistics_1.prm.bak | 69 + tests/merged_chunks_2D.prm.bak | 132 + tests/merged_chunks_2D_one_grid.prm.bak | 13 + tests/merged_chunks_3D.prm.bak | 140 + tests/merged_chunks_3D_one_grid.prm.bak | 13 + ...deformation_gmg_2d_spherical_shell.prm.bak | 96 + tests/mesh_deformation_particles.cc.bak | 71 + tests/mesh_deformation_particles.prm.bak | 85 + tests/mesh_velocity_output.prm.bak | 121 + tests/mid_ocean_ridge.prm.bak | 26 + tests/minimum_refinement_function.prm.bak | 154 + ...imum_refinement_function_cartesian.prm.bak | 144 + ...imum_refinement_function_spherical.prm.bak | 136 + ...refinement_function_time_dependent.prm.bak | 154 + tests/modified_tait_forsterite_box.prm.bak | 101 + tests/morency_doin.cc.bak | 22 + tests/morency_doin.prm.bak | 100 + tests/multicomponent_arithmetic.prm.bak | 128 + ...ticomponent_compressible_averaging.prm.bak | 129 + tests/multicomponent_geometric.prm.bak | 128 + tests/multicomponent_harmonic.prm.bak | 128 + tests/multicomponent_max_composition.prm.bak | 128 + tests/multicomponent_steinberger.prm.bak | 121 + .../multiple_named_additional_outputs.cc.bak | 112 + .../multiple_named_additional_outputs.prm.bak | 99 + tests/muparser-temperature-example.prm.bak | 149 + tests/n_expensive_stokes_solver_steps.prm.bak | 160 + tests/natural_coordinates_conversion.cc.bak | 217 + tests/natural_coordinates_conversion.prm.bak | 1 + tests/netcdf_boundary_velocity_2d_box.prm.bak | 71 + tests/newton_postprocess_nonlinear.prm.bak | 175 + ..._iterated_defect_correction_Stokes.prm.bak | 127 + tests/no_adiabatic_heating.cc.bak | 57 + tests/no_adiabatic_heating.prm.bak | 82 + tests/no_adiabatic_heating_02.cc.bak | 65 + tests/no_adiabatic_heating_02.prm.bak | 82 + tests/no_adiabatic_heating_03.cc.bak | 57 + tests/no_adiabatic_heating_03.prm.bak | 115 + tests/no_cheap_gmg.cc.bak | 21 + tests/no_cheap_gmg.prm.bak | 83 + tests/no_conduction_timestep.prm.bak | 80 + tests/no_dirichlet_on_outflow.prm.bak | 168 + tests/no_dirichlet_on_outflow_C.prm.bak | 172 + .../no_dirichlet_on_outflow_adaptive.prm.bak | 172 + tests/no_dirichlet_on_outflow_melt.cc.bak | 21 + tests/no_dirichlet_on_outflow_melt.prm.bak | 144 + ...et_on_outflow_only_new_constraints.prm.bak | 168 + tests/no_dirichlet_on_outflow_refine.prm | 2 +- tests/no_dirichlet_on_outflow_refine.prm.bak | 123 + tests/no_flow.prm.bak | 85 + tests/non_conservative_with_mpi.cc.bak | 21 + tests/non_conservative_with_mpi.prm.bak | 79 + ...hannel_flow_tractions_Newton_Stokes.cc.bak | 21 + ...annel_flow_tractions_Newton_Stokes.prm.bak | 131 + ...el_flow_tractions_Newton_Stokes_GMG.cc.bak | 21 + ...l_flow_tractions_Newton_Stokes_GMG.prm.bak | 17 + ...tractions_Newton_Stokes_no_deviator.cc.bak | 21 + ...ractions_Newton_Stokes_no_deviator.prm.bak | 132 + ...ctions_Newton_Stokes_no_line_search.cc.bak | 21 + ...tions_Newton_Stokes_no_line_search.prm.bak | 8 + ...w_tractions_Newton_Stokes_particles.cc.bak | 21 + ..._tractions_Newton_Stokes_particles.prm.bak | 38 + ...flow_tractions_dc_picard_Stokes_GMG.cc.bak | 1 + ...low_tractions_dc_picard_Stokes_GMG.prm.bak | 17 + ...annel_flow_tractions_iterated_IMPES.cc.bak | 21 + ...nnel_flow_tractions_iterated_IMPES.prm.bak | 129 + ...annel_flow_velocities_Newton_Stokes.cc.bak | 21 + ...nnel_flow_velocities_Newton_Stokes.prm.bak | 134 + ...l_flow_velocities_Newton_Stokes_GMG.cc.bak | 21 + ..._flow_velocities_Newton_Stokes_GMG.prm.bak | 23 + ...ocities_Newton_Stokes_no_derivative.cc.bak | 21 + ...cities_Newton_Stokes_no_derivative.prm.bak | 21 + ...ties_Newton_Stokes_no_derivative_EW.cc.bak | 21 + ...ies_Newton_Stokes_no_derivative_EW.prm.bak | 21 + ...elocities_Newton_Stokes_no_deviator.cc.bak | 21 + ...locities_Newton_Stokes_no_deviator.prm.bak | 17 + ...cities_Newton_Stokes_no_line_search.cc.bak | 21 + ...ities_Newton_Stokes_no_line_search.prm.bak | 8 + ...nnel_flow_velocities_iterated_IMPES.cc.bak | 21 + ...nel_flow_velocities_iterated_IMPES.prm.bak | 128 + ...ties_single_advection_Newton_Stokes.cc.bak | 21 + ...ies_single_advection_Newton_Stokes.prm.bak | 9 + ...r_convergence_for_small_composition.cc.bak | 71 + ..._convergence_for_small_composition.prm.bak | 162 + tests/nonlinear_solver_history.cc.bak | 46 + tests/nonlinear_solver_history.prm.bak | 69 + tests/normalize_initial_composition.prm.bak | 62 + tests/normalize_pressure_volume.prm.bak | 70 + tests/nsinker.cc.bak | 21 + tests/nsinker.prm.bak | 9 + tests/nsinker_2d.cc.bak | 21 + tests/nsinker_2d.prm.bak | 8 + tests/nsinker_bfbt.cc.bak | 21 + tests/nsinker_bfbt.prm.bak | 9 + tests/nsinker_gmg_idr.cc.bak | 21 + tests/nsinker_gmg_idr.prm.bak | 24 + tests/octagonal_initial_temperature.prm.bak | 90 + ...tial_temperature_ellipsoidal_chunk.prm.bak | 94 + ...agonal_initial_temperature_rotated.prm.bak | 91 + tests/onset_of_convection.prm.bak | 4 + tests/original_prm.prm.bak | 10 + tests/original_prm/original.prm | 1 - tests/original_prm/original.prm.bak | 13 + tests/output_averaging_arithmetic.cc.bak | 21 + tests/output_averaging_arithmetic.prm.bak | 82 + tests/output_averaging_harmonic.cc.bak | 21 + tests/output_averaging_harmonic.prm.bak | 82 + tests/own_gravity.cc.bak | 44 + tests/own_gravity.prm.bak | 77 + tests/parallel_output_group_0.prm.bak | 76 + tests/parallel_output_group_1.prm.bak | 76 + tests/parallel_output_group_2.prm.bak | 76 + tests/parallel_refine_crash.prm.bak | 112 + tests/particle_count_statistics.cc.bak | 21 + tests/particle_count_statistics.prm.bak | 91 + tests/particle_exclude_all_properties.prm.bak | 117 + tests/particle_exclude_one_property.prm.bak | 117 + .../particle_exclude_one_property_vtu.prm.bak | 117 + ...ticle_exclude_three_properties_vtu.prm.bak | 117 + ...article_exclude_two_properties_vtu.prm.bak | 117 + ...le_fast_evaluate_many_compositions.prm.bak | 116 + ...ast_evaluate_multiple_compositions.prm.bak | 116 + tests/particle_free_surface.prm.bak | 114 + tests/particle_generator_ascii.prm.bak | 108 + tests/particle_generator_box.prm.bak | 113 + tests/particle_generator_box_3d.prm.bak | 118 + ...rticle_generator_quadrature_points.prm.bak | 108 + tests/particle_generator_radial.prm.bak | 116 + .../particle_generator_random_uniform.prm.bak | 109 + ...ator_random_uniform_3mpi_1particle.prm.bak | 109 + ...ator_random_uniform_3mpi_2particle.prm.bak | 109 + ...ator_random_uniform_3mpi_3particle.prm.bak | 109 + ...ator_random_uniform_3mpi_4particle.prm.bak | 109 + ..._random_uniform_deterministic_cell.prm.bak | 110 + ...enerator_random_uniform_empty_rank.prm.bak | 109 + .../particle_generator_reference_cell.prm.bak | 111 + tests/particle_handler_copy.cc.bak | 83 + tests/particle_handler_copy.prm.bak | 96 + .../particle_initial_adaptive_output.prm.bak | 107 + ...rticle_initial_adaptive_refinement.prm.bak | 107 + tests/particle_integrator_euler.prm.bak | 109 + ...le_integrator_rk2_first_order_time.prm.bak | 26 + tests/particle_integrator_rk4.prm.bak | 109 + .../particle_interpolator_bilinear_3d.prm.bak | 118 + ...rpolator_bilinear_3d_add_particles.prm.bak | 113 + ...interpolator_bilinear_add_particles.cc.bak | 21 + ...nterpolator_bilinear_add_particles.prm.bak | 118 + ...olator_bilinear_least_squares_solkz.cc.bak | 21 + ...lator_bilinear_least_squares_solkz.prm.bak | 115 + ...icle_interpolator_bilinear_limiter.prm.bak | 120 + ...particle_interpolator_cell_average.prm.bak | 125 + ...rticle_interpolator_cell_average_2.prm.bak | 119 + .../particle_interpolator_empty_cells.prm.bak | 100 + ...icle_interpolator_from_ghost_cells.prm.bak | 102 + ...interpolator_harmonic_average_solkz.cc.bak | 21 + ...nterpolator_harmonic_average_solkz.prm.bak | 119 + ...icle_interpolator_nearest_neighbor.prm.bak | 127 + ...atic_least_squares_2d_add_particles.cc.bak | 21 + ...tic_least_squares_2d_add_particles.prm.bak | 120 + ..._quadratic_least_squares_2d_limiter.cc.bak | 21 + ...quadratic_least_squares_2d_limiter.prm.bak | 28 + ...uadratic_least_squares_2d_periodic.prm.bak | 41 + ...polator_quadratic_least_squares_3d.prm.bak | 119 + ...ticle_interpolator_time_dependence.prm.bak | 109 + ...rticle_linear_accelerated_flow_rk2.prm.bak | 86 + tests/particle_load_balancing_none.prm.bak | 106 + ...particle_load_balancing_refinement.prm.bak | 105 + ...ticle_load_balancing_refinement_02.prm.bak | 105 + tests/particle_load_balancing_removal.prm.bak | 103 + ...le_load_balancing_removal_addition.prm.bak | 106 + ...ancing_removal_addition_properties.prm.bak | 107 + ...article_load_balancing_repartition.prm.bak | 19 + ...le_load_balancing_repartition_1000.prm.bak | 20 + tests/particle_melt_advection.cc.bak | 21 + tests/particle_melt_advection.prm.bak | 166 + tests/particle_output_gnuplot.prm.bak | 107 + tests/particle_output_hdf5.prm.bak | 107 + .../particle_output_multiple_formats.prm.bak | 106 + tests/particle_output_none.prm.bak | 109 + tests/particle_output_vtu.prm.bak | 107 + tests/particle_output_vtu_group.prm.bak | 110 + tests/particle_output_vtu_temp.prm.bak | 109 + tests/particle_periodic_boundaries.prm.bak | 114 + tests/particle_periodic_boundaries_dc.prm.bak | 35 + .../particle_periodic_boundaries_rk4.prm.bak | 113 + tests/particle_periodic_quarter_shell.prm.bak | 112 + .../particle_periodic_quarter_shell_2.prm.bak | 122 + tests/particle_property_composition.cc.bak | 21 + tests/particle_property_composition.prm.bak | 188 + tests/particle_property_function.prm.bak | 113 + ...ticle_property_initial_composition.prm.bak | 106 + ...perty_initial_composition_boundary.prm.bak | 103 + ...operty_integrated_strain_invariant.prm.bak | 112 + ...perty_integrated_strain_pure_shear.prm.bak | 92 + ...rty_integrated_strain_simple_shear.prm.bak | 91 + ...rticle_property_multiple_functions.prm.bak | 115 + ...tiple_functions_with_interpolation.prm.bak | 118 + ...e_property_post_initialize_function.cc.bak | 86 + ..._property_post_initialize_function.prm.bak | 105 + tests/particle_timing_information.prm.bak | 109 + ...ticle_visualization_particle_count.prm.bak | 110 + tests/particles_with_AMR_on.prm.bak | 124 + tests/passive_comp.prm.bak | 280 + tests/periodic_box.prm.bak | 108 + tests/periodic_box2.prm.bak | 97 + tests/periodic_box_freesurface.prm.bak | 116 + tests/periodic_box_gmg.prm | 2 +- tests/periodic_box_gmg.prm.bak | 124 + tests/periodic_box_mpi4.prm.bak | 99 + tests/periodic_compressible.prm.bak | 84 + tests/periodic_linear_momentum.prm.bak | 112 + tests/periodic_quarter_shell.prm.bak | 77 + tests/plugin.cc.bak | 41 + tests/plugin.prm.bak | 80 + tests/plugin_dependency.cc.bak | 56 + tests/plugin_dependency.prm.bak | 78 + tests/plugin_dependency_redundant.cc.bak | 23 + tests/plugin_dependency_redundant.prm.bak | 80 + tests/plugin_dependency_redundant_02.cc.bak | 23 + tests/plugin_dependency_redundant_02.prm.bak | 79 + tests/point_value_01.prm.bak | 102 + tests/point_value_02.prm.bak | 109 + tests/point_value_02_mpi.prm.bak | 107 + tests/point_value_03.prm.bak | 103 + tests/point_value_natural_coordinates.prm.bak | 86 + ...nt_value_natural_coordinates_shell.prm.bak | 86 + .../point_value_specific_output_times.prm.bak | 104 + tests/poiseuille_2d.prm.bak | 72 + ...iseuille_2d_horizontal_pressure_bc.prm.bak | 102 + tests/poiseuille_2d_pressure_bc.prm.bak | 94 + tests/poiseuille_2d_pressure_bc_gmg.prm.bak | 105 + ...euille_3d_x_horizontal_pressure_bc.prm.bak | 100 + tests/postprocess_initial.prm.bak | 105 + .../postprocess_iterations_Stokes_only.cc.bak | 21 + ...postprocess_iterations_Stokes_only.prm.bak | 88 + ...tprocess_iterations_iterated_Stokes.cc.bak | 21 + ...process_iterations_iterated_Stokes.prm.bak | 96 + ...ions_iterated_advection_and_stokes.prm.bak | 133 + tests/pre_data_out_build_patches.cc.bak | 45 + tests/pre_data_out_build_patches.prm.bak | 72 + tests/prescribed_dilation.cc.bak | 413 + tests/prescribed_dilation.prm.bak | 71 + tests/prescribed_dilation_gmg.cc.bak | 21 + tests/prescribed_dilation_gmg.prm.bak | 19 + tests/prescribed_dilation_newton.cc.bak | 21 + tests/prescribed_dilation_newton.prm.bak | 18 + ...bed_dilation_newton_singleadvection.cc.bak | 21 + ...ed_dilation_newton_singleadvection.prm.bak | 18 + tests/prescribed_field.cc.bak | 92 + tests/prescribed_field.prm.bak | 90 + tests/prescribed_field_temperature.cc.bak | 93 + tests/prescribed_field_temperature.prm.bak | 78 + ...bed_field_temperature_max_isotherm.prm.bak | 21 + tests/prescribed_field_with_diffusion.cc.bak | 95 + tests/prescribed_field_with_diffusion.prm.bak | 107 + tests/prescribed_stokes_solution.prm.bak | 95 + ...cribed_stokes_solution_DG_periodic.prm.bak | 72 + tests/prescribed_stokes_solution_melt.prm.bak | 109 + tests/prescribed_temperature.cc.bak | 95 + tests/prescribed_temperature.prm.bak | 85 + tests/prescribed_temperature_in_field.cc.bak | 182 + tests/prescribed_temperature_in_field.prm.bak | 67 + ...escribed_temperature_with_diffusion.cc.bak | 95 + ...scribed_temperature_with_diffusion.prm.bak | 84 + tests/prescribed_velocity.cc.bak | 21 + tests/prescribed_velocity.prm.bak | 58 + tests/prescribed_velocity_boundary.cc.bak | 446 + tests/prescribed_velocity_boundary.prm.bak | 88 + tests/prescribed_velocity_dgp.cc.bak | 264 + tests/prescribed_velocity_dgp.prm.bak | 62 + ...ribed_viscosity_additional_outputs.prm.bak | 41 + tests/prescribed_viscosity_happy.prm.bak | 72 + tests/pressure_boundary.prm.bak | 92 + tests/pressure_compatibility.prm.bak | 77 + tests/pressure_compatibility_2.prm.bak | 95 + tests/pressure_compatibility_3.prm.bak | 94 + tests/pressure_compatibility_4.prm.bak | 101 + tests/pressure_compatibility_dg.prm.bak | 9 + .../pressure_compatibility_dg_direct.prm.bak | 15 + tests/pressure_compatibility_direct.prm.bak | 11 + tests/pressure_constraint.cc.bak | 60 + tests/pressure_constraint.prm.bak | 70 + tests/pressure_scaling_signal.cc.bak | 44 + tests/pressure_scaling_signal.prm.bak | 88 + tests/principal_deviatoric_stress.cc.bak | 21 + tests/principal_deviatoric_stress.prm.bak | 117 + tests/prm_distance_polygon.cc.bak | 77 + tests/prm_distance_polygon.prm.bak | 1 + tests/prm_polygon_in_out.cc.bak | 82 + tests/prm_polygon_in_out.prm.bak | 1 + tests/prmbackslash.prm | 5 - tests/prmbackslash.prm.bak | 72 + tests/prmbackslash_2.cc.bak | 21 + tests/prmbackslash_2.prm | 164 +- tests/prmbackslash_2.prm.bak | 156 + tests/projected_density_vertical_pipe.cc.bak | 21 + tests/projected_density_vertical_pipe.prm | 2 +- tests/projected_density_vertical_pipe.prm.bak | 31 + tests/pure_shear.cc.bak | 21 + tests/pure_shear.prm.bak | 145 + tests/q1_q1.cc.bak | 474 + tests/q1_q1.prm.bak | 98 + tests/q1_q1_6.cc.bak | 21 + tests/q1_q1_6.prm.bak | 95 + ...iable_coordinate_systems_cartesian.prm.bak | 86 + ..._variable_coordinate_systems_depth.prm.bak | 86 + ...iable_coordinate_systems_spherical.prm.bak | 86 + tests/quick_mpi.cc.bak | 21 + tests/quick_mpi.prm.bak | 82 + tests/radioactive_decay.prm.bak | 87 + tests/radiogenic_heating.prm.bak | 91 + tests/random_perturbation_box.prm.bak | 70 + tests/random_perturbation_chunk.prm.bak | 72 + .../random_perturbation_merged_boxes.prm.bak | 73 + tests/random_perturbation_sphere.prm.bak | 67 + ...andom_perturbation_spherical_shell.prm.bak | 66 + ...active_fluid_transport_no_reaction.prm.bak | 25 + ...ve_fluid_transport_zero_solubility.prm.bak | 138 + tests/refine_vel.prm.bak | 92 + .../refinement_artificial_viscosity_1.prm.bak | 101 + .../refinement_artificial_viscosity_2.prm.bak | 11 + .../refinement_artificial_viscosity_3.prm.bak | 11 + tests/refinement_boundary.prm.bak | 71 + tests/refinement_composition_gradient.prm.bak | 95 + .../refinement_composition_threshold.prm.bak | 18 + ...efinement_nonadiabatic_temperature.prm.bak | 27 + tests/refinement_strainrate.prm.bak | 121 + tests/refinement_switch.prm.bak | 111 + tests/refinement_topography.cc.bak | 21 + tests/refinement_topography.prm.bak | 68 + tests/remove_angular_momentum.prm.bak | 63 + tests/remove_angular_momentum_3d.prm.bak | 66 + tests/remove_net_rotation.prm.bak | 67 + tests/remove_net_rotation_3d.prm.bak | 67 + tests/remove_net_surface_rotation.prm.bak | 15 + ...replace_lithosphere_viscosity_file.prm.bak | 65 + tests/resume_free_surface.cc.bak | 95 + tests/resume_free_surface.prm.bak | 130 + tests/rheology_scaled_profile.cc.bak | 296 + tests/rheology_scaled_profile.prm.bak | 82 + tests/rigid_shear_instantaneous.cc.bak | 21 + tests/rigid_shear_instantaneous.prm.bak | 5 + tests/rigid_shear_steady_state.cc.bak | 21 + tests/rigid_shear_steady_state.prm.bak | 5 + tests/rigid_shear_transient.cc.bak | 21 + tests/rigid_shear_transient.prm.bak | 7 + tests/rising_melt_blob.cc.bak | 103 + tests/rising_melt_blob.prm.bak | 135 + tests/rising_melt_blob_freezing.prm.bak | 123 + tests/rotation_statistics.prm.bak | 76 + tests/rotation_statistics_3d.prm.bak | 76 + .../rotation_statistics_3d_asymmetric.prm.bak | 76 + tests/rotation_statistics_3d_surface.prm.bak | 20 + tests/sea_level_postprocessor.prm.bak | 95 + tests/segregation_heating.cc.bak | 71 + tests/segregation_heating.prm.bak | 142 + tests/shear_bands.cc.bak | 21 + tests/shear_bands.prm.bak | 128 + tests/shear_heating.prm.bak | 85 + tests/shear_heating_compressible.prm.bak | 114 + tests/shear_heating_compressible_melt.prm.bak | 147 + tests/shear_heating_limited.prm.bak | 30 + tests/shear_heating_with_melt.prm.bak | 210 + tests/shear_thinning.cc.bak | 194 + tests/shear_thinning.prm.bak | 88 + tests/shearbox_particle_strain_rate.prm | 2 +- tests/shearbox_particle_strain_rate.prm.bak | 186 + tests/shell_2d_gmg.prm.bak | 81 + tests/shell_3d_gmg.prm.bak | 87 + ...ary_composition_spherical_constant.prm.bak | 89 + tests/shell_quarter_BC.prm.bak | 17 + tests/shell_quarter_gmg.prm.bak | 81 + tests/shell_surface_base_variables.prm | 12 +- tests/shell_surface_base_variables.prm.bak | 96 + ...l_with_variable_coordinate_systems.prm.bak | 92 + tests/signal_fem.cc.bak | 71 + tests/signal_fem.prm.bak | 91 + tests/signals.cc.bak | 60 + tests/signals.prm.bak | 80 + tests/signals_connect.cc.bak | 49 + tests/signals_connect.prm.bak | 78 + tests/signals_post_constraints.cc.bak | 47 + tests/signals_post_constraints.prm.bak | 73 + tests/simple_composite.prm.bak | 96 + ...ple_compressibility_iterated_stokes.cc.bak | 21 + ...le_compressibility_iterated_stokes.prm.bak | 81 + ...compressibility_iterated_stokes_gmg.cc.bak | 21 + ...ompressibility_iterated_stokes_gmg.prm.bak | 19 + tests/simple_compressible.prm.bak | 95 + tests/simple_incompressible.prm.bak | 88 + tests/simple_nonlinear.cc.bak | 253 + tests/simple_nonlinear.prm.bak | 4 + tests/simple_shear.cc.bak | 124 + tests/simple_shear.prm.bak | 134 + tests/simple_shear_output_the_mobility.cc.bak | 124 + .../simple_shear_output_the_mobility.prm.bak | 139 + tests/simpler_box.prm.bak | 63 + tests/simpler_composition.prm.bak | 61 + ..._iterated_defect_correction_Stokes.prm.bak | 127 + tests/sinking_block.cc.bak | 21 + tests/sinking_block.prm.bak | 10 + ...itions_setup_on_initial_refinement.prm.bak | 66 + tests/skip_refinement.prm.bak | 165 + ...skip_solvers_on_initial_refinement.prm.bak | 65 + ...slab2_initial_composition_3d_shell.prm.bak | 78 + tests/slab_tip_depth.prm | 4 +- tests/slab_tip_depth.prm.bak | 157 + tests/slope_refinement.prm.bak | 114 + tests/smoothing.prm.bak | 98 + tests/smoothing_composition_passive.prm.bak | 108 + tests/sol_cx_2.cc.bak | 21 + tests/sol_cx_2.prm.bak | 74 + tests/sol_cx_2_conservative.cc.bak | 21 + tests/sol_cx_2_conservative.prm.bak | 73 + tests/sol_cx_2_equal_order.cc.bak | 21 + tests/sol_cx_2_equal_order.prm.bak | 76 + tests/sol_cx_2_gmg.cc.bak | 21 + tests/sol_cx_2_gmg.prm.bak | 86 + tests/sol_cx_2_normalized_pressure.cc.bak | 21 + tests/sol_cx_2_normalized_pressure.prm.bak | 74 + tests/sol_cx_2_q3.cc.bak | 21 + tests/sol_cx_2_q3.prm.bak | 73 + tests/sol_cx_4.cc.bak | 21 + tests/sol_cx_4.prm.bak | 73 + tests/sol_cx_4_conservative.cc.bak | 21 + tests/sol_cx_4_conservative.prm.bak | 73 + tests/sol_cx_4_equal_order.cc.bak | 21 + tests/sol_cx_4_equal_order.prm.bak | 75 + tests/sol_cx_4_gmg.cc.bak | 21 + tests/sol_cx_4_gmg.prm.bak | 84 + tests/sol_cx_4_normalized_pressure.cc.bak | 21 + tests/sol_cx_4_normalized_pressure.prm.bak | 74 + ...ized_pressure_large_static_pressure.cc.bak | 21 + ...zed_pressure_large_static_pressure.prm.bak | 96 + ...lized_pressure_low_solver_tolerance.cc.bak | 21 + ...ized_pressure_low_solver_tolerance.prm.bak | 90 + tests/sol_cx_mpi_2.cc.bak | 21 + tests/sol_cx_mpi_2.prm.bak | 78 + tests/sol_cx_newton_crash.cc.bak | 21 + tests/sol_cx_newton_crash.prm.bak | 83 + tests/sol_cx_particles.cc.bak | 21 + tests/sol_cx_particles.prm.bak | 9 + tests/sol_kz_2.cc.bak | 21 + tests/sol_kz_2.prm.bak | 73 + ...sol_kz_2_cheaper_first_phase_solver.cc.bak | 21 + ...ol_kz_2_cheaper_first_phase_solver.prm.bak | 79 + tests/sol_kz_2_conservative.cc.bak | 21 + tests/sol_kz_2_conservative.prm.bak | 73 + tests/sol_kz_2_no_first_phase_solver.cc.bak | 21 + tests/sol_kz_2_no_first_phase_solver.prm.bak | 79 + tests/sol_kz_2_project_q1_only_visc.cc.bak | 21 + tests/sol_kz_2_project_q1_only_visc.prm.bak | 14 + tests/sol_kz_2_q3.cc.bak | 21 + tests/sol_kz_2_q3.prm.bak | 73 + tests/sol_kz_4.cc.bak | 21 + tests/sol_kz_4.prm.bak | 73 + tests/sol_kz_4_conservative.cc.bak | 21 + tests/sol_kz_4_conservative.prm.bak | 73 + tests/solidus_initial_conditions.cc.bak | 447 + tests/solidus_initial_conditions.prm.bak | 85 + tests/solitary_wave.cc.bak | 21 + tests/solitary_wave.prm.bak | 159 + tests/solubility.cc.bak | 21 + tests/solubility.prm.bak | 11 + tests/solve_no_advection_no_stokes.prm.bak | 71 + tests/solver_history.cc.bak | 49 + tests/solver_history.prm.bak | 69 + ...r_scheme_no_advection_single_stokes.cc.bak | 21 + ..._scheme_no_advection_single_stokes.prm.bak | 84 + tests/spectral_comparison.prm.bak | 16 + ...erical_constant_boundary_3d_sphere.prm.bak | 74 + tests/spherical_nsinker.cc.bak | 21 + tests/spherical_nsinker.prm.bak | 16 + ...l_initial_topography_ascii_data_3d.prm.bak | 93 + ...ell_initial_topography_function_3d.prm.bak | 88 + tests/spherical_velocity_statistics.prm.bak | 95 + tests/spiegelman_fail_test.cc.bak | 678 ++ tests/spiegelman_fail_test.prm.bak | 129 + tests/spiegelman_material.cc.bak | 303 + tests/spiegelman_material.prm.bak | 4 + tests/splines.cc.bak | 74 + tests/splines.prm.bak | 1 + tests/static_temperature.prm.bak | 98 + tests/statistics_output.prm.bak | 142 + tests/steinberger_averaging.prm.bak | 123 + tests/steinberger_background.prm.bak | 106 + tests/steinberger_compressible.prm.bak | 95 + tests/steinberger_compressible_gmg.prm.bak | 18 + tests/steinberger_conductivity.prm.bak | 80 + tests/steinberger_conductivity_tosi.prm.bak | 87 + .../steinberger_continuous_viscosity.prm.bak | 18 + tests/steinberger_cookbook.prm.bak | 12 + tests/steinberger_latent_heat.prm.bak | 90 + tests/steinberger_latent_heat_2.prm.bak | 125 + tests/steinberger_lateral_fail.prm.bak | 101 + tests/steinberger_phase_fractions.prm.bak | 112 + ...nberger_phase_fractions_background.prm.bak | 129 + tests/steinberger_phases.prm.bak | 110 + tests/steinberger_phases_2_lookups.prm.bak | 108 + tests/steinberger_phases_hefesto.prm.bak | 111 + tests/steinberger_projected_density.prm.bak | 114 + ...nberger_projected_density_dcPicard.prm.bak | 118 + tests/steinberger_seismic_velocities.prm.bak | 98 + tests/steinberger_several_fields.prm.bak | 110 + tests/steinberger_single_field.prm.bak | 110 + tests/steinberger_viscosity.prm.bak | 91 + tests/steinberger_viscosity_adiabatic.prm.bak | 101 + tests/stokes.prm.bak | 124 + tests/stokes_residual.prm.bak | 66 + tests/stokes_residual_cheap.prm.bak | 11 + tests/stokes_solver_fail.prm | 2 +- tests/stokes_solver_fail.prm.bak | 17 + tests/stokes_solver_fail_A.prm.bak | 15 + tests/stokes_solver_fail_S.prm.bak | 15 + tests/stokes_solver_fail_cheap.prm.bak | 17 + tests/stokes_solver_fail_gmg.prm.bak | 21 + tests/stress_vs_surface_stress.cc.bak | 21 + tests/stress_vs_surface_stress.prm.bak | 92 + ...ress_vs_surface_stress_point_values.cc.bak | 21 + ...ess_vs_surface_stress_point_values.prm.bak | 17 + ...on_initiation_compositional_fields.prm.bak | 51 + tests/supg-compositional-passive.prm.bak | 107 + tests/supg.prm.bak | 98 + .../surface_elevation_box_ascii_data.prm.bak | 17 + ...vation_box_ascii_data_moved_origin.prm.bak | 17 + tests/surface_elevation_box_function.prm.bak | 17 + .../surface_elevation_box_prm_polygon.prm.bak | 17 + ...surface_elevation_chunk_ascii_data.prm.bak | 17 + ...face_elevation_chunk_ascii_data_3d.prm.bak | 17 + ...ion_chunk_ascii_data_3d_colatitude.prm.bak | 32 + ...evation_chunk_ascii_data_global_3d.prm.bak | 112 + ...herical_shell_ascii_data_global_3d.prm.bak | 95 + tests/surface_stress_strainrate_3d.cc.bak | 1 + tests/surface_stress_strainrate_3d.prm.bak | 99 + tests/symbolic_boundary_names_box.prm.bak | 66 + ...lic_boundary_names_box_constant_bc.prm.bak | 70 + ...mes_spherical_shell_2d_180_degrees.prm.bak | 64 + ...ames_spherical_shell_2d_90_degrees.prm.bak | 64 + ...dary_names_spherical_shell_2d_full.prm.bak | 60 + ...ames_spherical_shell_3d_90_degrees.prm.bak | 64 + ...dary_names_spherical_shell_3d_full.prm.bak | 60 + tests/tangurnis.cc.bak | 21 + tests/tangurnis_ba.cc.bak | 21 + tests/tangurnis_ba.prm.bak | 248 + tests/tangurnis_ba_custom.cc.bak | 21 + tests/tangurnis_ba_custom.prm.bak | 247 + tests/tangurnis_tala.cc.bak | 21 + tests/tangurnis_tala.prm.bak | 262 + tests/tangurnis_tala_c.cc.bak | 21 + tests/tangurnis_tala_c.prm.bak | 262 + tests/tangurnis_tala_gmg.cc.bak | 21 + tests/tangurnis_tala_gmg.prm.bak | 19 + tests/tangurnis_tala_implicit.cc.bak | 21 + tests/tangurnis_tala_implicit.prm.bak | 265 + ...emperature_dependent_stokes_matrix.prm.bak | 76 + tests/terminate_user_request.cc.bak | 34 + tests/terminate_user_request.prm.bak | 71 + tests/thermal_alpha_s40rts.prm.bak | 66 + tests/tian_MORB.prm.bak | 27 + tests/tian_gabbro.prm.bak | 27 + tests/tian_peridotite.prm.bak | 122 + tests/tian_sediment.prm.bak | 27 + tests/time_dependent_annulus.cc.bak | 21 + tests/time_dependent_annulus.prm.bak | 10 + tests/time_dependent_temperature_bc.cc.bak | 251 + tests/time_dependent_temperature_bc.prm.bak | 100 + tests/time_dependent_temperature_bc_2.cc.bak | 21 + tests/time_dependent_temperature_bc_2.prm.bak | 97 + tests/time_stepping_fail.prm.bak | 65 + tests/time_stepping_function.prm.bak | 63 + tests/time_stepping_min.prm.bak | 66 + tests/time_stepping_repeat.prm.bak | 99 + tests/time_stepping_repeat_particles.prm.bak | 127 + ...epeat_particles_iterated_advection.prm.bak | 30 + ...graphy_based_plate_motions_cookbook.cc.bak | 22 + ...raphy_based_plate_motions_cookbook.prm.bak | 39 + tests/topo_box.prm.bak | 119 + tests/topo_chunk.prm.bak | 86 + tests/topo_shell.prm.bak | 75 + tests/tosi_benchmark.cc.bak | 21 + tests/tosi_benchmark.prm.bak | 8 + ...tosi_benchmark_gmg_dc_picard_solver.cc.bak | 1 + ...osi_benchmark_gmg_dc_picard_solver.prm.bak | 17 + tests/tosi_benchmark_gmg_newton_solver.cc.bak | 21 + .../tosi_benchmark_gmg_newton_solver.prm.bak | 18 + tests/tosi_benchmark_newton_solver.cc.bak | 21 + tests/tosi_benchmark_newton_solver.prm.bak | 8 + ...tosi_benchmark_newton_solver_full_A.cc.bak | 21 + ...osi_benchmark_newton_solver_full_A.prm.bak | 15 + tests/traction_ascii_data.prm.bak | 133 + tests/traction_multiple_model.prm.bak | 135 + tests/transform_fault_behn_2007.prm.bak | 11 + tests/two_merged_boxes_free_surface.prm.bak | 72 + ...an_parameterization_kinematic_slab.prm.bak | 50 + tests/update_script.cc.bak | 65 + tests/update_script_2.cc.bak | 70 + tests/update_script_2/updated2.prm.bak | 135 + tests/upwelling_melting_peridotite.prm.bak | 135 + ...ng_melting_peridotite_compressible.prm.bak | 128 + tests/upwelling_melting_pyroxenite.prm.bak | 161 + tests/use_full_A_block_preconditioner.prm.bak | 88 + tests/van_keken_smooth_particle.prm.bak | 108 + tests/vankeken_subduction.cc.bak | 2 + tests/vankeken_subduction.prm.bak | 13 + tests/var_declaration_expansion.cc.bak | 55 + tests/var_declaration_expansion.prm.bak | 80 + tests/velocity_boundary_statistics.prm.bak | 92 + tests/velocity_divergence.cc.bak | 69 + tests/velocity_divergence.prm.bak | 161 + tests/velocity_in_years.prm.bak | 89 + tests/vep_chemical_compositions.prm.bak | 84 + tests/vis_velocity_in_years.prm.bak | 63 + tests/visco_elastic_top_beam.prm | 2 +- tests/visco_elastic_top_beam.prm.bak | 154 + tests/visco_plastic.prm.bak | 96 + ...plastic_additional_plastic_outputs.prm.bak | 132 + .../visco_plastic_adiabat_temperature.prm.bak | 118 + ..._plastic_adiabatic_heating_density.prm.bak | 115 + ...diabatic_pressure_in_viscous_creep.prm.bak | 149 + tests/visco_plastic_complex.prm.bak | 174 + tests/visco_plastic_composite.prm.bak | 108 + ...astic_constant_viscosity_prefactor.prm.bak | 104 + tests/visco_plastic_derivatives_2d.cc.bak | 274 + tests/visco_plastic_derivatives_2d.prm.bak | 118 + tests/visco_plastic_derivatives_3d.cc.bak | 289 + tests/visco_plastic_derivatives_3d.prm.bak | 118 + tests/visco_plastic_diffusion.prm.bak | 110 + ...ic_diffusion_dislocation_composite.prm.bak | 116 + tests/visco_plastic_dislocation.prm.bak | 109 + tests/visco_plastic_frank_kamenetskii.prm.bak | 107 + ...plastic_frank_kamenetskii_pressure.prm.bak | 108 + tests/visco_plastic_friction_function.prm.bak | 111 + tests/visco_plastic_gerya_2019_vp.prm.bak | 21 + ...astic_newton_nonlinear_channelflow.prm.bak | 124 + .../visco_plastic_peierls_cutoff_test.prm.bak | 100 + ...isco_plastic_peierls_idrissi_exact.prm.bak | 120 + tests/visco_plastic_peierls_mei_exact.prm.bak | 120 + ...astic_peierls_mei_viscosity_approx.prm.bak | 77 + ...plastic_peierls_strict_cutoff_test.prm.bak | 101 + tests/visco_plastic_phases.prm.bak | 106 + .../visco_plastic_phases_compositions.prm.bak | 123 + ...o_plastic_phases_peierls_mei_exact.prm.bak | 80 + tests/visco_plastic_phases_plasticity.prm.bak | 111 + ...ic_phases_temperature_limit_basalt.prm.bak | 117 + ...ases_temperature_limit_harzburgite.prm.bak | 117 + ..._phases_temperature_limit_pyrolite.prm.bak | 117 + ...erature_limit_pyrolite_complicated.prm.bak | 117 + tests/visco_plastic_phases_viscosity.prm.bak | 129 + ...o_plastic_phases_viscosity_max_min.prm.bak | 133 + ..._plastic_reference_density_profile.prm.bak | 103 + ...visco_plastic_thermal_conductivity.prm.bak | 21 + ...rain_healing_temperature_dependent.prm.bak | 166 + ...ic_track_noninitial_plastic_strain.prm.bak | 133 + tests/visco_plastic_vep_bending_beam.prm.bak | 49 + .../visco_plastic_vep_brick_extension.prm.bak | 63 + tests/visco_plastic_vep_plate_flexure.prm.bak | 51 + tests/visco_plastic_vep_simple_shear.prm.bak | 7 + .../visco_plastic_vep_stress_build-up.prm.bak | 58 + ...s_build-up_fixed_elastic_time_step.prm.bak | 57 + ...p_stress_build-up_stress_averaging.prm.bak | 59 + ..._plastic_vep_stress_build-up_yield.prm.bak | 71 + ...ep_stress_build-up_yield_particles.prm.bak | 92 + ...o_plastic_viscous_strain_weakening.prm.bak | 130 + tests/visco_plastic_yield.prm.bak | 99 + tests/visco_plastic_yield_max.prm.bak | 118 + ...oninitial-plastic-strain_particles.prm.bak | 59 + ...visco_plastic_yield_plastic_damper.prm.bak | 26 + ...tic_yield_plastic_strain_weakening.prm.bak | 132 + ...plastic_strain_weakening_particles.prm.bak | 31 + ...eld_plastic_viscous_strain_healing.prm.bak | 148 + ...d_plastic_viscous_strain_weakening.prm.bak | 135 + ...viscous_strain_weakening_particles.prm.bak | 31 + ...sco_plastic_yield_strain_weakening.prm.bak | 132 + ...ield_strain_weakening_compositions.prm.bak | 127 + ...train_weakening_defect_corr_stokes.prm.bak | 4 + ...train_weakening_full_strain_tensor.prm.bak | 134 + ...in_weakening_full_strain_tensor_3d.prm.bak | 130 + ...train_weakening_iterated_advection.prm.bak | 44 + ...rain_weakening_no-advect_no_stokes.prm.bak | 7 + ...c_yield_strain_weakening_particles.prm.bak | 31 + ...activated_viscous_strain_weakening.prm.bak | 46 + ...plastic_yield_total_strain_healing.prm.bak | 147 + ...tic_yield_viscous_strain_weakening.prm.bak | 131 + ...viscous_strain_weakening_particles.prm.bak | 31 + tests/viscoelastic_bending_beam.prm.bak | 51 + ...iscoelastic_bending_beam_averaging.prm.bak | 38 + tests/viscoelastic_bending_beam_gmg.prm.bak | 47 + ...iscoelastic_bending_beam_particles.prm.bak | 53 + ...stic_bending_beam_principal_stress.prm.bak | 34 + ...scoelastic_fixed_elastic_time_step.prm.bak | 54 + ...lastic_numerical_elastic_time_step.prm.bak | 55 + ...erical_elastic_time_step_particles.prm.bak | 75 + tests/viscoelastic_plate_flexure.prm.bak | 32 + tests/viscoelastic_sheared_torsion.prm.bak | 9 + tests/viscoelastic_stress_averaging.prm.bak | 56 + tests/viscoelastic_stress_build-up.prm.bak | 83 + .../viscoelastic_stress_build-up_gmg.prm.bak | 98 + ...d_plastic_viscous_strain_weakening.prm.bak | 77 + tests/viscoplastic_melt_blob_freezing.prm.bak | 64 + tests/viscoplastic_melt_fraction.prm.bak | 118 + tests/viscosity_refinement.prm.bak | 67 + tests/viscous_dissipation_statistics.prm.bak | 124 + tests/viscous_top_beam.prm | 2 +- tests/viscous_top_beam.prm.bak | 163 + ...visualization_averaged_strain_rate.prm.bak | 84 + ...isualization_averaged_strain_rate2.prm.bak | 12 + ...alization_conductivity_diffusivity.prm.bak | 80 + .../visualization_higher_order_output.prm.bak | 17 + tests/visualization_shear_stress.prm.bak | 87 + ...sualization_shear_stress_pointwise.prm.bak | 12 + ...lization_shear_stress_viscoelastic.prm.bak | 49 + tests/visualization_strain_rate.prm.bak | 84 + ...isualization_strain_rate_pointwise.prm.bak | 12 + .../visualization_strain_rate_tensor.prm.bak | 83 + ...ation_strain_rate_tensor_pointwise.prm.bak | 12 + tests/visualization_stress.prm.bak | 90 + tests/visualization_stress_pointwise.prm.bak | 12 + .../visualization_stress_viscoelastic.prm.bak | 49 + .../visualization_temperature_anomaly.prm.bak | 85 + tests/visualization_unique_list.prm.bak | 83 + .../visualization_vertical_heat_flux.prm.bak | 90 + tests/viz_mesh_deform_vector.prm.bak | 124 + tests/viz_plugin_dependency.cc.bak | 89 + tests/viz_plugin_dependency.prm.bak | 80 + .../viz_spherical_velocity_components.prm.bak | 80 + tests/vof_circle_1.cc.bak | 23 + tests/vof_circle_1.prm.bak | 94 + tests/vof_circle_amr.cc.bak | 23 + tests/vof_circle_amr.prm.bak | 97 + tests/vof_circle_mpi.cc.bak | 23 + tests/vof_circle_mpi.prm.bak | 96 + tests/vof_circle_mpi_amr.cc.bak | 23 + tests/vof_circle_mpi_amr.prm.bak | 99 + tests/vof_composition_init.prm.bak | 81 + tests/vof_err_calc.h.bak | 342 + tests/vof_linear.cc.bak | 23 + tests/vof_linear.prm.bak | 93 + tests/vof_linear_2f.cc.bak | 23 + tests/vof_linear_2f.prm.bak | 93 + tests/vof_linear_amr.cc.bak | 23 + tests/vof_linear_amr.prm.bak | 95 + tests/vof_linear_amr_mpi.cc.bak | 23 + tests/vof_linear_amr_mpi.prm.bak | 97 + tests/vof_linear_inflow.prm.bak | 86 + tests/vof_linear_periodic.cc.bak | 23 + tests/vof_linear_periodic.prm.bak | 94 + tests/vof_linear_periodic_amr.cc.bak | 23 + tests/vof_linear_periodic_amr.prm.bak | 96 + tests/vof_mpi_amr_no_dof.prm.bak | 85 + tests/walltime.prm.bak | 64 + tests/weighted_p_norm_average.cc.bak | 46 + .../world_builder_select_composition.prm.bak | 69 + tests/world_builder_select_grains.prm.bak | 95 + tests/world_builder_simple.prm.bak | 70 + ...der_simple_2d_cartesian_sticky_air.prm.bak | 71 + tests/write_plugin_graph.cc.bak | 98 + tests/write_plugin_graph.prm.bak | 76 + tests/zero_RHS.prm.bak | 120 + tests/zero_matrix.prm.bak | 115 + tests/zero_temperature.prm.bak | 94 + unit_tests/additional_outputs.cc.bak | 98 + unit_tests/common.h.bak | 67 + .../crystal_preferred_orientation.cc.bak | 2309 +++++ unit_tests/first.cc.bak | 89 + unit_tests/introspection.cc.bak | 135 + unit_tests/mesh_refinement.cc.bak | 59 + unit_tests/netcdf.cc.bak | 101 + unit_tests/parse_map_to_double_array.cc.bak | 460 + unit_tests/particles.cc.bak | 56 + unit_tests/termination_criteria.cc.bak | 68 + unit_tests/utilities.cc.bak | 628 ++ 2964 files changed, 427292 insertions(+), 237 deletions(-) create mode 100644 benchmarks/advection/drop_ev.prm.bak create mode 100644 benchmarks/advection/drop_supg.prm.bak create mode 100644 benchmarks/advection/rotate_shape_dg_bp.prm.bak create mode 100644 benchmarks/advection/rotate_shape_dg_weno.prm.bak create mode 100644 benchmarks/advection/rotate_shape_ev.prm.bak create mode 100644 benchmarks/advection/rotate_shape_supg.prm.bak create mode 100644 benchmarks/advection_in_annulus/advection_in_annulus.cc.bak create mode 100644 benchmarks/advection_in_annulus/advection_in_annulus.prm.bak create mode 100644 benchmarks/annulus/instantaneous/annulus.prm.bak create mode 100644 benchmarks/annulus/plugin/annulus.cc.bak create mode 100644 benchmarks/annulus/transient/transient_annulus.prm.bak create mode 100644 benchmarks/blankenbach/base_case1a.prm.bak create mode 100644 benchmarks/blankenbach/base_case1b.prm.bak create mode 100644 benchmarks/blankenbach/base_case1c.prm.bak create mode 100644 benchmarks/blankenbach/base_case2a.prm.bak create mode 100644 benchmarks/blankenbach/base_case2b.prm.bak create mode 100644 benchmarks/blankenbach/plugin/code.cc.bak create mode 100644 benchmarks/blankenbach/plugin/heat_flux_statistics_gradient.cc.bak create mode 100644 benchmarks/blankenbach/plugin/heat_flux_statistics_gradient.h.bak create mode 100644 benchmarks/buiter_et_al_2008_jgr/figure_6_1e20.prm.bak create mode 100644 benchmarks/buiter_et_al_2008_jgr/figure_6_1e22.prm.bak create mode 100644 benchmarks/buiter_et_al_2016_jsg/doc/convergence.part.prm.bak create mode 100644 benchmarks/buiter_et_al_2016_jsg/doc/velocity_bc.part.prm.bak create mode 100644 benchmarks/buiter_et_al_2016_jsg/exp_1.prm.bak create mode 100644 benchmarks/buiter_et_al_2016_jsg/exp_2_high_resolution.prm.bak create mode 100644 benchmarks/buiter_et_al_2016_jsg/exp_2_low_resolution.prm.bak create mode 100644 benchmarks/burstedde/burstedde.cc.bak create mode 100644 benchmarks/burstedde/burstedde.prm.bak create mode 100644 benchmarks/burstedde/doc/burstedde.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe/adiabatic.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe/ala.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe/hydrostatic.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe/isentropic.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe/lateral_pipe.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe/projected_density.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe/sub_adiabatic.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_advect/ala.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_advect/hydrostatic.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_advect/isentropic.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_advect/lateral_pipe.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_advect/projected_density.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/ala.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/hydrostatic.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/isentropic.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/lateral_pipe.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/projected_density.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/projected_density_full_pressure.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_transient/ala.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_transient/hydrostatic.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_transient/isentropic.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_transient/lateral_pipe.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_transient/projected_density.prm.bak create mode 100644 benchmarks/compressibility_formulations/lateral_pipe_transient/timestep.prm.bak create mode 100644 benchmarks/compressibility_formulations/plugins/compressibility_formulations.cc.bak create mode 100644 benchmarks/compressibility_formulations/vertical_pipe/adiabatic.prm.bak create mode 100644 benchmarks/compressibility_formulations/vertical_pipe/ala.prm.bak create mode 100644 benchmarks/compressibility_formulations/vertical_pipe/hydrostatic.prm.bak create mode 100644 benchmarks/compressibility_formulations/vertical_pipe/isentropic.prm.bak create mode 100644 benchmarks/compressibility_formulations/vertical_pipe/projected_density.prm.bak create mode 100644 benchmarks/compressibility_formulations/vertical_pipe/sub_adiabatic.prm.bak create mode 100644 benchmarks/compressibility_formulations/vertical_pipe/vertical_pipe.prm.bak create mode 100644 benchmarks/crameri_et_al/case_1/crameri_benchmark_1.cc.bak create mode 100644 benchmarks/crameri_et_al/case_1/crameri_benchmark_1.prm.bak create mode 100644 benchmarks/crameri_et_al/case_1/crameri_benchmark_1_gmg.prm.bak create mode 100644 benchmarks/crameri_et_al/case_2/crameri_benchmark_2.prm.bak create mode 100644 benchmarks/crameri_et_al/doc/crameri_benchmark_1.prm.bak create mode 100644 benchmarks/crameri_et_al/doc/crameri_benchmark_2.prm.bak create mode 100644 benchmarks/davies_et_al/case-1.1.prm.bak create mode 100644 benchmarks/davies_et_al/case-2.1.prm.bak create mode 100644 benchmarks/davies_et_al/case-2.2.prm.bak create mode 100644 benchmarks/davies_et_al/case-2.3-plugin/VoT.cc.bak create mode 100644 benchmarks/davies_et_al/case-2.3.prm.bak create mode 100644 benchmarks/davies_et_al/doc/case-1.1.prm.bak create mode 100644 benchmarks/davies_et_al/doc/case-2.1.prm.bak create mode 100644 benchmarks/davies_et_al/doc/case-2.2.prm.bak create mode 100644 benchmarks/davies_et_al/doc/case-2.3.prm.bak create mode 100644 benchmarks/diffusion_of_hill/1_sine_zero_flux.prm.bak create mode 100644 benchmarks/diffusion_of_hill/2_sine_constant_h.prm.bak create mode 100644 benchmarks/diffusion_of_hill/analytical_topography.cc.bak create mode 100644 benchmarks/diffusion_of_hill/analytical_topography.h.bak create mode 100644 benchmarks/doneahuerta/doneahuerta.cc.bak create mode 100644 benchmarks/doneahuerta/doneahuerta.prm.bak create mode 100644 benchmarks/entropy_adiabat/entropy_adiabat.prm.bak create mode 100644 benchmarks/entropy_adiabat/entropy_combined.prm.bak create mode 100644 benchmarks/entropy_adiabat/entropy_conduction.prm.bak create mode 100644 benchmarks/entropy_adiabat/entropy_half_space.prm.bak create mode 100644 benchmarks/entropy_adiabat/plugins/entropy_advection.cc.bak create mode 100644 benchmarks/entropy_adiabat/plugins/entropy_advection.h.bak create mode 100644 benchmarks/finite_strain/finite_strain.cc.bak create mode 100644 benchmarks/finite_strain/pure_shear.prm.bak create mode 100644 benchmarks/finite_strain/simple_shear.prm.bak create mode 100644 benchmarks/free_surface_tractions/viscoelastic/free_surface_VE_cylinder_2D_loading.prm.bak create mode 100644 benchmarks/free_surface_tractions/viscoelastic/free_surface_VE_cylinder_2D_loading_fixed_elastic_dt.prm.bak create mode 100644 benchmarks/free_surface_tractions/viscoelastic/free_surface_VE_cylinder_2D_loading_unloading.prm.bak create mode 100644 benchmarks/free_surface_tractions/viscoelastic/free_surface_VE_cylinder_3D_loading.prm.bak create mode 100644 benchmarks/free_surface_tractions/viscoelastic/free_surface_VE_cylinder_3D_loading_fixed_elastic_dt.prm.bak create mode 100644 benchmarks/free_surface_tractions/viscous/free_surface_viscous_cylinder_2D_loading.prm.bak create mode 100644 benchmarks/free_surface_tractions/viscous/free_surface_viscous_cylinder_3D_loading.prm.bak create mode 100644 benchmarks/geoid-spectral-comparison/spectral-comparison.prm.bak create mode 100644 benchmarks/grain_size_pinned_state/grain_size_plunge.prm.bak create mode 100644 benchmarks/gravity_mantle/mantle_gravity.prm.bak create mode 100644 benchmarks/gravity_thick_shell/doc/thick_shell.prm.bak create mode 100644 benchmarks/gravity_thick_shell/thick_shell.prm.bak create mode 100644 benchmarks/gravity_thin_shell/doc/thinshell_a.prm.bak create mode 100644 benchmarks/gravity_thin_shell/doc/thinshell_b.prm.bak create mode 100644 benchmarks/gravity_thin_shell/doc/thinshell_c.prm.bak create mode 100644 benchmarks/gravity_thin_shell/gravity_thin_shell.prm.bak create mode 100644 benchmarks/hollow_sphere/hollow_sphere.cc.bak create mode 100644 benchmarks/hollow_sphere/hollow_sphere.prm.bak create mode 100644 benchmarks/inclusion/adaptive.prm.base.bak create mode 100644 benchmarks/inclusion/compositional_fields/inclusion_compositional_fields.cc.bak create mode 100644 benchmarks/inclusion/compositional_fields/inclusion_compositional_fields.h.bak create mode 100644 benchmarks/inclusion/compositional_fields/inclusion_compositional_fields.prm.bak create mode 100644 benchmarks/inclusion/compositional_fields/inclusion_particles.prm.bak create mode 100644 benchmarks/inclusion/doc/inclusion.prm.bak create mode 100644 benchmarks/inclusion/global.prm.base.bak create mode 100644 benchmarks/inclusion/inclusion.cc.bak create mode 100644 benchmarks/inclusion/inclusion.h.bak create mode 100644 benchmarks/infill_density/infill_ascii.prm.bak create mode 100644 benchmarks/infill_density/infill_ascii_data.cc.bak create mode 100644 benchmarks/king2dcompressible/ala.prm.bak create mode 100644 benchmarks/king2dcompressible/plugin/code.cc.bak create mode 100644 benchmarks/layeredflow/layeredflow.cc.bak create mode 100644 benchmarks/layeredflow/layeredflow.prm.bak create mode 100644 benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_t.prm.bak create mode 100644 benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_t_gmg.prm.bak create mode 100644 benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v.prm.bak create mode 100644 benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v_gmg.prm.bak create mode 100644 benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/simple_nonlinear.cc.bak create mode 100644 benchmarks/newton_solver_benchmark_set/spiegelman_et_al_2016/drucker_prager_compositions.cc.bak create mode 100644 benchmarks/newton_solver_benchmark_set/spiegelman_et_al_2016/input.prm.bak create mode 100644 benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input.prm.bak create mode 100644 benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input_gmg.prm.bak create mode 100644 benchmarks/nsinker/nsinker.cc.bak create mode 100644 benchmarks/nsinker/nsinker.prm.bak create mode 100644 benchmarks/nsinker/nsinker_2d.prm.bak create mode 100644 benchmarks/nsinker/nsinker_bfbt.prm.bak create mode 100644 benchmarks/nsinker/nsinker_gmg.prm.bak create mode 100644 benchmarks/nsinker_spherical_shell/amg.prm.bak create mode 100644 benchmarks/nsinker_spherical_shell/gmg.prm.bak create mode 100644 benchmarks/nsinker_spherical_shell/nsinker.cc.bak create mode 100644 benchmarks/onset-of-convection/convection-box-base.prm.bak create mode 100644 benchmarks/operator_splitting/advection_reaction/advection_reaction.base.prm.bak create mode 100644 benchmarks/operator_splitting/advection_reaction/advection_reaction.cc.bak create mode 100644 benchmarks/operator_splitting/doc/exponential_decay.part.1.prm.bak create mode 100644 benchmarks/operator_splitting/doc/exponential_decay.part.2.prm.bak create mode 100644 benchmarks/operator_splitting/exponential_decay/exponential_decay.base.prm.bak create mode 100644 benchmarks/operator_splitting/exponential_decay/exponential_decay.cc.bak create mode 100644 benchmarks/particle_integration_scheme/circle.prm.bak create mode 100644 benchmarks/particle_integration_scheme/euler.part.prm.bak create mode 100644 benchmarks/particle_integration_scheme/rk2.part.prm.bak create mode 100644 benchmarks/particle_integration_scheme/rk4.part.prm.bak create mode 100644 benchmarks/polydiapirs/polydiapirs.prm.bak create mode 100644 benchmarks/rayleigh_taylor_instability/blank.prm.bak create mode 100644 benchmarks/rayleigh_taylor_instability/rayleigh_taylor_instability.cc.bak create mode 100644 benchmarks/rayleigh_taylor_instability/rayleigh_taylor_instability.prm.bak create mode 100644 benchmarks/rayleigh_taylor_instability_free_surface/kaus_rayleigh_taylor_instability.prm.bak create mode 100644 benchmarks/rayleigh_taylor_instability_free_surface/rose_rayleigh_taylor_instability.prm.bak create mode 100644 benchmarks/rigid_shear/instantaneous/rigid_shear.prm.bak create mode 100644 benchmarks/rigid_shear/plugin/rigid_shear.cc.bak create mode 100644 benchmarks/rigid_shear/steady-state/rigid_shear.prm.bak create mode 100644 benchmarks/rigid_shear/transient/rigid_shear.prm.bak create mode 100644 benchmarks/shear_bands/magmatic_shear_bands.prm.bak create mode 100644 benchmarks/shear_bands/shear_bands.cc.bak create mode 100644 benchmarks/shear_bands/shear_bands.prm.bak create mode 100644 benchmarks/sinking_block/blank.prm.bak create mode 100644 benchmarks/sinking_block/sinking_block.cc.bak create mode 100644 benchmarks/sinking_block/sinking_block.prm.bak create mode 100644 benchmarks/slab_detachment/slab_detachment.prm.bak create mode 100644 benchmarks/solcx/compositional_fields/solcx_compositional_fields.cc.bak create mode 100644 benchmarks/solcx/compositional_fields/solcx_compositional_fields.h.bak create mode 100644 benchmarks/solcx/compositional_fields/solcx_compositional_fields.prm.bak create mode 100644 benchmarks/solcx/compositional_fields/solcx_particles.prm.bak create mode 100644 benchmarks/solcx/doc/solcx.prm.bak create mode 100644 benchmarks/solcx/solcx.cc.bak create mode 100644 benchmarks/solcx/solcx.h.bak create mode 100644 benchmarks/solcx/solcx.prm.bak create mode 100644 benchmarks/solitary_wave/doc/solitary_wave.prm.bak create mode 100644 benchmarks/solitary_wave/solitary_wave.cc.bak create mode 100644 benchmarks/solitary_wave/solitary_wave.prm.bak create mode 100644 benchmarks/solkz/compositional_fields/solkz_compositional_fields.cc.bak create mode 100644 benchmarks/solkz/compositional_fields/solkz_compositional_fields.h.bak create mode 100644 benchmarks/solkz/compositional_fields/solkz_compositional_fields.prm.bak create mode 100644 benchmarks/solkz/compositional_fields/solkz_particles.prm.bak create mode 100644 benchmarks/solkz/doc/solkz.prm.bak create mode 100644 benchmarks/solkz/solkz.cc.bak create mode 100644 benchmarks/solkz/solkz.h.bak create mode 100644 benchmarks/solkz/solkz.prm.bak create mode 100644 benchmarks/solubility/plugin/solubility.cc.bak create mode 100644 benchmarks/solubility/solubility.prm.bak create mode 100644 benchmarks/tangurnis/ba/tan.prm.bak create mode 100644 benchmarks/tangurnis/code/tangurnis.cc.bak create mode 100644 benchmarks/tangurnis/tala/tan.prm.bak create mode 100644 benchmarks/tangurnis/tala_c/tan.prm.bak create mode 100644 benchmarks/time_dependent_annulus/plugin/time_dependent_annulus.cc.bak create mode 100644 benchmarks/time_dependent_annulus/plugin/time_dependent_annulus.h.bak create mode 100644 benchmarks/time_dependent_annulus/time_dependent_annulus.prm.bak create mode 100644 benchmarks/tosi_et_al_2015_gcubed/Tosi_Case1.prm.bak create mode 100644 benchmarks/tosi_et_al_2015_gcubed/Tosi_Case2.prm.bak create mode 100644 benchmarks/tosi_et_al_2015_gcubed/Tosi_Case3.prm.bak create mode 100644 benchmarks/tosi_et_al_2015_gcubed/Tosi_Case4.prm.bak create mode 100644 benchmarks/tosi_et_al_2015_gcubed/Tosi_Case5.prm.bak create mode 100644 benchmarks/tosi_et_al_2015_gcubed/Tosi_base.prm.bak create mode 100644 benchmarks/tosi_et_al_2015_gcubed/doc/tosi_benchmark_2.prm.bak create mode 100644 benchmarks/tosi_et_al_2015_gcubed/tosi.cc.bak create mode 100644 benchmarks/viscoelastic_beam_modified/20km_opentopbot.prm.bak create mode 100644 benchmarks/viscoelastic_beam_modified/20km_opentopbot_weno.prm.bak create mode 100644 benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam.prm.bak create mode 100644 benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_particles.prm.bak create mode 100644 benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_weno.prm.bak create mode 100644 benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vep.prm.bak create mode 100644 benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vp.prm.bak create mode 100644 benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vp_damper.prm.bak create mode 100644 benchmarks/viscoelastic_plastic_shear_bands/kaus_2010/kaus_2010_extension.prm.bak create mode 100644 benchmarks/viscoelastic_plastic_simple_shear/viscoelastic_plastic_simple_shear.prm.bak create mode 100644 benchmarks/viscoelastic_plate_flexure/viscoelastic_plate_flexure.prm.bak create mode 100644 benchmarks/viscoelastic_sheared_torsion/viscoelastic_sheared_torsion.prm.bak create mode 100644 benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up.prm.bak create mode 100644 benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_particles.prm.bak create mode 100644 benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_yield.prm.bak create mode 100644 benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_yield_particles.prm.bak create mode 100644 benchmarks/viscosity_grooves/viscosity_grooves.cc.bak create mode 100644 benchmarks/viscosity_grooves/viscosity_grooves.prm.bak create mode 100644 benchmarks/yamauchi_takei_2016_anelasticity/anelasticity_temperature.cc.bak create mode 100644 benchmarks/yamauchi_takei_2016_anelasticity/anelasticity_temperature.h.bak create mode 100644 benchmarks/yamauchi_takei_2016_anelasticity/yamauchi_takei_2016_anelasticity.prm.bak create mode 100644 benchmarks/zhong_et_al_93/zhong_case1.prm.bak create mode 100644 contrib/opendap/prm_files/aspect_test.prm.bak create mode 100644 contrib/opendap/prm_files/aspect_url_test.prm.bak create mode 100644 contrib/perplex/perplex_lookup_composition.prm.bak create mode 100644 contrib/python/notebooks/read_output_files/convection-box.prm.bak create mode 100644 contrib/python/scripts/__pycache__/aspect_input.cpython-312.pyc create mode 100644 contrib/world_builder/include/app/main.h.bak create mode 100644 contrib/world_builder/include/glm/glm.h.bak create mode 100644 contrib/world_builder/include/rapidjson/allocators.h.bak create mode 100644 contrib/world_builder/include/rapidjson/cursorstreamwrapper.h.bak create mode 100644 contrib/world_builder/include/rapidjson/encodedstream.h.bak create mode 100644 contrib/world_builder/include/rapidjson/encodings.h.bak create mode 100644 contrib/world_builder/include/rapidjson/error/en.h.bak create mode 100644 contrib/world_builder/include/rapidjson/error/error.h.bak create mode 100644 contrib/world_builder/include/rapidjson/filereadstream.h.bak create mode 100644 contrib/world_builder/include/rapidjson/filewritestream.h.bak create mode 100644 contrib/world_builder/include/rapidjson/fwd.h.bak create mode 100644 contrib/world_builder/include/rapidjson/internal/biginteger.h.bak create mode 100644 contrib/world_builder/include/rapidjson/internal/diyfp.h.bak create mode 100644 contrib/world_builder/include/rapidjson/internal/dtoa.h.bak create mode 100644 contrib/world_builder/include/rapidjson/internal/ieee754.h.bak create mode 100644 contrib/world_builder/include/rapidjson/internal/itoa.h.bak create mode 100644 contrib/world_builder/include/rapidjson/internal/meta.h.bak create mode 100644 contrib/world_builder/include/rapidjson/internal/pow10.h.bak create mode 100644 contrib/world_builder/include/rapidjson/internal/regex.h.bak create mode 100644 contrib/world_builder/include/rapidjson/internal/stack.h.bak create mode 100644 contrib/world_builder/include/rapidjson/internal/strfunc.h.bak create mode 100644 contrib/world_builder/include/rapidjson/internal/strtod.h.bak create mode 100644 contrib/world_builder/include/rapidjson/internal/swap.h.bak create mode 100644 contrib/world_builder/include/rapidjson/istreamwrapper.h.bak create mode 100644 contrib/world_builder/include/rapidjson/latexwriter.h.bak create mode 100644 contrib/world_builder/include/rapidjson/memorybuffer.h.bak create mode 100644 contrib/world_builder/include/rapidjson/memorystream.h.bak create mode 100644 contrib/world_builder/include/rapidjson/msinttypes/inttypes.h.bak create mode 100644 contrib/world_builder/include/rapidjson/msinttypes/stdint.h.bak create mode 100644 contrib/world_builder/include/rapidjson/mystwriter.h.bak create mode 100644 contrib/world_builder/include/rapidjson/ostreamwrapper.h.bak create mode 100644 contrib/world_builder/include/rapidjson/pointer.h.bak create mode 100644 contrib/world_builder/include/rapidjson/prettywriter.h.bak create mode 100644 contrib/world_builder/include/rapidjson/rapidjson.h.bak create mode 100644 contrib/world_builder/include/rapidjson/reader.h.bak create mode 100644 contrib/world_builder/include/rapidjson/schema.h.bak create mode 100644 contrib/world_builder/include/rapidjson/stream.h.bak create mode 100644 contrib/world_builder/include/rapidjson/stringbuffer.h.bak create mode 100644 contrib/world_builder/include/rapidjson/writer.h.bak create mode 100644 contrib/world_builder/include/visualization/main.h.bak create mode 100644 contrib/world_builder/include/world_builder/assert.h.bak create mode 100644 contrib/world_builder/include/world_builder/bounding_box.h.bak create mode 100644 contrib/world_builder/include/world_builder/consts.h.bak create mode 100644 contrib/world_builder/include/world_builder/coordinate_system.h.bak create mode 100644 contrib/world_builder/include/world_builder/coordinate_systems/cartesian.h.bak create mode 100644 contrib/world_builder/include/world_builder/coordinate_systems/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/coordinate_systems/invalid.h.bak create mode 100644 contrib/world_builder/include/world_builder/coordinate_systems/spherical.h.bak create mode 100644 contrib/world_builder/include/world_builder/deprecate.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/continental_plate.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/continental_plate_models/composition/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/continental_plate_models/composition/random.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/continental_plate_models/composition/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/continental_plate_models/grains/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/continental_plate_models/grains/random_uniform_distribution.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/continental_plate_models/grains/random_uniform_distribution_deflected.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/continental_plate_models/grains/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/adiabatic.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/linear.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/fault.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/fault_models/composition/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/fault_models/composition/smooth.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/fault_models/composition/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/fault_models/grains/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/fault_models/grains/random_uniform_distribution.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/fault_models/grains/random_uniform_distribution_deflected.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/fault_models/grains/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/fault_models/temperature/adiabatic.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/fault_models/temperature/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/fault_models/temperature/linear.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/fault_models/temperature/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/feature_utilities.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/mantle_layer.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/mantle_layer_models/composition/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/mantle_layer_models/composition/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/random_uniform_distribution.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/random_uniform_distribution_deflected.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/adiabatic.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/linear.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/composition/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/composition/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution_deflected.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/adiabatic.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/half_space_model.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/linear.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/plate_model.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/plate_model_constant_age.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/plume.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/plume_models/composition/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/plume_models/composition/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/plume_models/grains/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/plume_models/grains/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/plume_models/temperature/gaussian.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/plume_models/temperature/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/plume_models/temperature/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/composition/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/composition/smooth.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/composition/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/random_uniform_distribution.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/random_uniform_distribution_deflected.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/adiabatic.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/linear.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/mass_conserving.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/plate_model.h.bak create mode 100644 contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/grains.h.bak create mode 100644 contrib/world_builder/include/world_builder/gravity_model/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/gravity_model/uniform.h.bak create mode 100644 contrib/world_builder/include/world_builder/kd_tree.h.bak create mode 100644 contrib/world_builder/include/world_builder/nan.h.bak create mode 100644 contrib/world_builder/include/world_builder/objects/bezier_curve.h.bak create mode 100644 contrib/world_builder/include/world_builder/objects/closest_point_on_curve.h.bak create mode 100644 contrib/world_builder/include/world_builder/objects/distance_from_surface.h.bak create mode 100644 contrib/world_builder/include/world_builder/objects/natural_coordinate.h.bak create mode 100644 contrib/world_builder/include/world_builder/objects/segment.h.bak create mode 100644 contrib/world_builder/include/world_builder/objects/surface.h.bak create mode 100644 contrib/world_builder/include/world_builder/parameters.h.bak create mode 100644 contrib/world_builder/include/world_builder/point.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/array.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/bool.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/double.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/int.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/interface.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/object.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/one_of.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/plugin_system.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/point.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/segment.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/string.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/unsigned_int.h.bak create mode 100644 contrib/world_builder/include/world_builder/types/value_at_points.h.bak create mode 100644 contrib/world_builder/include/world_builder/utilities.h.bak create mode 100644 contrib/world_builder/include/world_builder/world.h.bak create mode 100644 contrib/world_builder/include/world_builder/wrapper_c.h.bak create mode 100644 contrib/world_builder/include/world_builder/wrapper_cpp.h.bak create mode 100644 contrib/world_builder/source/gwb-dat/main.cc.bak create mode 100644 contrib/world_builder/source/gwb-grid/main.cc.bak create mode 100644 contrib/world_builder/source/world_builder/coordinate_systems/cartesian.cc.bak create mode 100644 contrib/world_builder/source/world_builder/coordinate_systems/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/coordinate_systems/invalid.cc.bak create mode 100644 contrib/world_builder/source/world_builder/coordinate_systems/spherical.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/continental_plate.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/continental_plate_models/composition/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/continental_plate_models/composition/random.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/continental_plate_models/composition/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/continental_plate_models/grains/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/continental_plate_models/grains/random_uniform_distribution.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/continental_plate_models/grains/random_uniform_distribution_deflected.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/continental_plate_models/grains/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/adiabatic.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/linear.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/fault.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/fault_models/composition/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/fault_models/composition/smooth.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/fault_models/composition/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/fault_models/grains/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/fault_models/grains/random_uniform_distribution.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/fault_models/grains/random_uniform_distribution_deflected.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/fault_models/grains/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/fault_models/temperature/adiabatic.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/fault_models/temperature/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/fault_models/temperature/linear.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/fault_models/temperature/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/feature_utilities.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/mantle_layer.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/mantle_layer_models/composition/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/mantle_layer_models/composition/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/random_uniform_distribution.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/random_uniform_distribution_deflected.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/adiabatic.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/linear.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/composition/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/composition/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution_deflected.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/adiabatic.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/half_space_model.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/linear.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/plate_model.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/plate_model_constant_age.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/plume.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/plume_models/composition/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/plume_models/composition/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/plume_models/grains/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/plume_models/grains/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/plume_models/temperature/gaussian.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/plume_models/temperature/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/plume_models/temperature/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/composition/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/composition/smooth.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/composition/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/random_uniform_distribution.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/random_uniform_distribution_deflected.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/adiabatic.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/linear.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/mass_conserving.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/plate_model.cc.bak create mode 100644 contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/grains.cc.bak create mode 100644 contrib/world_builder/source/world_builder/gravity_model/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/gravity_model/uniform.cc.bak create mode 100644 contrib/world_builder/source/world_builder/kd_tree.cc.bak create mode 100644 contrib/world_builder/source/world_builder/objects/bezier_curve.cc.bak create mode 100644 contrib/world_builder/source/world_builder/objects/distance_from_surface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/objects/natural_coordinate.cc.bak create mode 100644 contrib/world_builder/source/world_builder/objects/segment.cc.bak create mode 100644 contrib/world_builder/source/world_builder/objects/surface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/parameters.cc.bak create mode 100644 contrib/world_builder/source/world_builder/point.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/array.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/bool.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/double.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/int.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/interface.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/object.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/one_of.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/plugin_system.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/point.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/segment.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/string.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/unsigned_int.cc.bak create mode 100644 contrib/world_builder/source/world_builder/types/value_at_points.cc.bak create mode 100644 contrib/world_builder/source/world_builder/utilities.cc.bak create mode 100644 contrib/world_builder/source/world_builder/world.cc.bak create mode 100644 contrib/world_builder/source/world_builder/wrapper_c.cc.bak create mode 100644 contrib/world_builder/source/world_builder/wrapper_cpp.cc.bak create mode 100644 contrib/world_builder/tests/unit_tests/bounding_box.cc.bak create mode 100644 contrib/world_builder/tests/unit_tests/gwb_gravity.cc.bak create mode 100644 contrib/world_builder/tests/unit_tests/kd_tree.cc.bak create mode 100644 contrib/world_builder/tests/unit_tests/main.cc.bak create mode 100644 contrib/world_builder/tests/unit_tests/unit_test_wb_glm.cc.bak create mode 100644 contrib/world_builder/tests/unit_tests/unit_test_world_builder.cc.bak create mode 100644 cookbooks/2d_annulus_visualization/2d_annulus_example.prm.bak create mode 100644 cookbooks/allken_et_al_2012_rift_interaction/allken.prm.bak create mode 100644 cookbooks/anisotropic_viscosity/AV_Rayleigh_Taylor.prm.bak create mode 100644 cookbooks/anisotropic_viscosity/av_material.cc.bak create mode 100644 cookbooks/bunge_et_al_mantle_convection/bunge_et_al.prm.bak create mode 100644 cookbooks/burnman/burnman.prm.bak create mode 100644 cookbooks/burnman/doc/adiabatic_conditions.part.prm.bak create mode 100644 cookbooks/burnman/doc/formulation.part.prm.bak create mode 100644 cookbooks/burnman/doc/formulation_ica.part.prm.bak create mode 100644 cookbooks/burnman/doc/gravity_model.part.prm.bak create mode 100644 cookbooks/burnman/doc/material_model.part.prm.bak create mode 100644 cookbooks/burnman/doc/tala.part.prm.bak create mode 100644 cookbooks/christensen_yuen_phase_function/christensen_yuen_phase_function.prm.bak create mode 100644 cookbooks/christensen_yuen_phase_function/doc/material.part.prm.bak create mode 100644 cookbooks/composition-reaction/composition-reaction.prm.bak create mode 100644 cookbooks/composition-reaction/doc/initial.part.prm.bak create mode 100644 cookbooks/composition-reaction/doc/material.part.prm.bak create mode 100644 cookbooks/composition_active/composition_active.prm.bak create mode 100644 cookbooks/composition_active/doc/active.part.prm.bak create mode 100644 cookbooks/composition_active/doc/postprocess.part.prm.bak create mode 100644 cookbooks/composition_active_particles/composition_active_particles.prm.bak create mode 100644 cookbooks/composition_active_particles/doc/composition.part.prm.bak create mode 100644 cookbooks/composition_active_particles/doc/particles.part.prm.bak create mode 100644 cookbooks/composition_passive/composition_passive.prm.bak create mode 100644 cookbooks/composition_passive/doc/passive.part.prm.bak create mode 100644 cookbooks/composition_passive/doc/postprocess.part.prm.bak create mode 100644 cookbooks/composition_passive_particles/composition_passive_particles.prm.bak create mode 100644 cookbooks/composition_passive_particles/composition_passive_particles_properties.prm.bak create mode 100644 cookbooks/composition_passive_particles/doc/particle-properties.part.prm.bak create mode 100644 cookbooks/composition_passive_particles/doc/particles.part.prm.bak create mode 100644 cookbooks/continental_extension/continental_extension.prm.bak create mode 100644 cookbooks/continental_extension/doc/continental_extension_boundary_conditions.prm.bak create mode 100644 cookbooks/continental_extension/doc/continental_extension_composition.prm.bak create mode 100644 cookbooks/continental_extension/doc/continental_extension_geometry_mesh.prm.bak create mode 100644 cookbooks/continental_extension/doc/continental_extension_material_model.prm.bak create mode 100644 cookbooks/convection-box-particles/convection-box-particles.prm.bak create mode 100644 cookbooks/convection-box/convection-box.prm.bak create mode 100644 cookbooks/convection-box/doc/disc.part.prm.bak create mode 100644 cookbooks/convection-box/doc/gravity.part.prm.bak create mode 100644 cookbooks/convection-box/doc/refine.part.prm.bak create mode 100644 cookbooks/convection-box/doc/refine2.part.prm.bak create mode 100644 cookbooks/convection-box/tutorial-onset-of-convection/model_input/convection-box.prm.bak create mode 100644 cookbooks/convection-box/tutorial-onset-of-convection/model_input/convection-box2.prm.bak create mode 100644 cookbooks/convection-box/tutorial-onset-of-convection/model_input/tutorial.prm.bak create mode 100644 cookbooks/convection_box_3d/convection_box_3d.prm.bak create mode 100644 cookbooks/convection_box_3d/doc/amr.part.prm.bak create mode 100644 cookbooks/convection_box_3d/doc/checkpoint.part.prm.bak create mode 100644 cookbooks/convection_box_3d/doc/gravity.part.prm.bak create mode 100644 cookbooks/convection_box_3d/doc/initial.part.prm.bak create mode 100644 cookbooks/convection_box_3d/doc/postprocess.part.prm.bak create mode 100644 cookbooks/convection_box_3d/doc/start.part.prm.bak create mode 100644 cookbooks/crustal_deformation/crustal_model_2D.prm.bak create mode 100644 cookbooks/crustal_deformation/crustal_model_3D.prm.bak create mode 100644 cookbooks/crustal_deformation/doc/crustal_model_2D_part1.prm.bak create mode 100644 cookbooks/crustal_deformation/doc/crustal_model_2D_part2.prm.bak create mode 100644 cookbooks/crustal_deformation/doc/crustal_model_2D_part3.prm.bak create mode 100644 cookbooks/crustal_deformation/doc/crustal_model_2D_part4.prm.bak create mode 100644 cookbooks/crustal_deformation/doc/crustal_model_3D_part1.prm.bak create mode 100644 cookbooks/fastscape_eroding_box/fastscape_eroding_box.prm.bak create mode 100644 cookbooks/finite_strain/doc/finite_strain.part.prm.bak create mode 100644 cookbooks/finite_strain/finite_strain.cc.bak create mode 100644 cookbooks/finite_strain/finite_strain.prm.bak create mode 100644 cookbooks/free_surface/doc/free_surface.part.prm.bak create mode 100644 cookbooks/free_surface/free_surface.prm.bak create mode 100644 cookbooks/free_surface_with_crust/doc/free_surface_with_crust.part1.prm.bak create mode 100644 cookbooks/free_surface_with_crust/doc/free_surface_with_crust.part2.prm.bak create mode 100644 cookbooks/free_surface_with_crust/free_surface_with_crust.prm.bak create mode 100644 cookbooks/free_surface_with_crust/plugin/simpler_with_crust.cc.bak create mode 100644 cookbooks/future/mantle_setup_restart.prm.bak create mode 100644 cookbooks/future/mantle_setup_start.prm.bak create mode 100644 cookbooks/future/net_rotation.prm.bak create mode 100644 cookbooks/future/periodic_box.prm.bak create mode 100644 cookbooks/future/radiogenic_heating.prm.bak create mode 100644 cookbooks/future/radiogenic_heating_function.prm.bak create mode 100644 cookbooks/future/sphere.prm.bak create mode 100644 cookbooks/geomio/doc/geomIO.prm.bak create mode 100644 cookbooks/geomio/geomIO.prm.bak create mode 100644 cookbooks/global_melt/doc/global_melt.prm.bak create mode 100644 cookbooks/global_melt/doc/global_no_melt.prm.bak create mode 100644 cookbooks/global_melt/global_melt.prm.bak create mode 100644 cookbooks/global_melt/global_no_melt.prm.bak create mode 100644 cookbooks/gplates/doc/gplates.part.prm.bak create mode 100644 cookbooks/gplates/doc/slice1.part.prm.bak create mode 100644 cookbooks/gplates/doc/slice2.part.prm.bak create mode 100644 cookbooks/gplates/gplates_2d.prm.bak create mode 100644 cookbooks/gplates/gplates_3d.prm.bak create mode 100644 cookbooks/grain_size_ridge/doc/fields.part.prm.bak create mode 100644 cookbooks/grain_size_ridge/doc/material_model.part.prm.bak create mode 100644 cookbooks/grain_size_ridge/doc/particles.part.prm.bak create mode 100644 cookbooks/grain_size_ridge/grain_size_ridge.prm.bak create mode 100644 cookbooks/heat_flow/heat-flow-plume.prm.bak create mode 100644 cookbooks/heat_flow/heat-flow-terms.prm.bak create mode 100644 cookbooks/heat_flow/heat-flow.prm.bak create mode 100644 cookbooks/inclusions/ellipse_pure_shear.prm.bak create mode 100644 cookbooks/inclusions/ellipse_pure_shear_nonlinear.prm.bak create mode 100644 cookbooks/inclusions/ellipse_ref.prm.bak create mode 100644 cookbooks/inclusions/ellipse_simple_shear.prm.bak create mode 100644 cookbooks/inclusions/rectangle_pure_shear.prm.bak create mode 100644 cookbooks/inclusions/rectangle_ref.prm.bak create mode 100644 cookbooks/inclusions/rectangle_simple_shear.prm.bak create mode 100644 cookbooks/initial-condition-S20RTS/S20RTS.prm.bak create mode 100644 cookbooks/initial-condition-S20RTS/doc/S20RTS.part.prm.bak create mode 100644 cookbooks/inner_core_convection/doc/inner_core_traction.part.1.prm.bak create mode 100644 cookbooks/inner_core_convection/doc/inner_core_traction.part.2.prm.bak create mode 100644 cookbooks/inner_core_convection/doc/inner_core_traction.part.3.prm.bak create mode 100644 cookbooks/inner_core_convection/inner_core_assembly.cc.bak create mode 100644 cookbooks/inner_core_convection/inner_core_convection.cc.bak create mode 100644 cookbooks/inner_core_convection/inner_core_traction.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/composition_trms_statistics.cc.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/composition_trms_statistics.h.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/doc/Case1_compositions.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/doc/Case1_materialmodel.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/doc/Case1_meshrefinement.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/doc/Case1_postprocessing.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/doc/Case1_velocity.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/doc/Case2a_materialmodel.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/doc/Case2a_postprocessing.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/doc/Case2a_temperatures.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/doc/Case2b_materialmodel.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/isotherm_depth.cc.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/isotherm_depth.h.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case1.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case2a.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case2b.prm.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/subduction_plate_cooling.cc.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/subduction_plate_cooling.h.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/trench_location.cc.bak create mode 100644 cookbooks/kinematically_driven_subduction_2d/trench_location.h.bak create mode 100644 cookbooks/latent-heat/doc/material.part.prm.bak create mode 100644 cookbooks/latent-heat/latent-heat.prm.bak create mode 100644 cookbooks/lower_crustal_flow/lower_crustal_flow_obstacle.prm.bak create mode 100644 cookbooks/magnetic_stripes/magnetic_stripes.cc.bak create mode 100644 cookbooks/magnetic_stripes/magnetic_stripes.prm.bak create mode 100644 cookbooks/mantle_convection_with_continents_in_annulus/modelR.prm.bak create mode 100644 cookbooks/mid_ocean_ridge/doc/boundary_conditions.part.prm.bak create mode 100644 cookbooks/mid_ocean_ridge/doc/compaction_length.part.prm.bak create mode 100644 cookbooks/mid_ocean_ridge/doc/melting_and_freezing.part.prm.bak create mode 100644 cookbooks/mid_ocean_ridge/doc/mesh_refinement.part.prm.bak create mode 100644 cookbooks/mid_ocean_ridge/mid_ocean_ridge.prm.bak create mode 100644 cookbooks/morency_doin_2004/doc/morency_doin.part.prm.bak create mode 100644 cookbooks/morency_doin_2004/morency_doin.cc.bak create mode 100644 cookbooks/morency_doin_2004/morency_doin.h.bak create mode 100644 cookbooks/morency_doin_2004/morency_doin.prm.bak create mode 100644 cookbooks/multicomponent_steinberger/doc/comp.field.prm.bak create mode 100644 cookbooks/multicomponent_steinberger/doc/comp.setup.prm.bak create mode 100644 cookbooks/multicomponent_steinberger/doc/conductivity.setup.prm.bak create mode 100644 cookbooks/multicomponent_steinberger/doc/lookup.part.prm.bak create mode 100644 cookbooks/multicomponent_steinberger/doc/temperature.setup.prm.bak create mode 100644 cookbooks/multicomponent_steinberger/steinberger_thermochemical_plume.prm.bak create mode 100644 cookbooks/muparser_temperature_example/doc/check-initial-condition.part.prm.bak create mode 100644 cookbooks/muparser_temperature_example/doc/mesh-refinement.part.prm.bak create mode 100644 cookbooks/muparser_temperature_example/doc/repetitions.part.prm.bak create mode 100644 cookbooks/muparser_temperature_example/doc/temperature.part.prm.bak create mode 100644 cookbooks/muparser_temperature_example/muparser-temperature-example.prm.bak create mode 100644 cookbooks/onset_of_convection/onset_of_convection.prm.bak create mode 100644 cookbooks/platelike-boundary/doc/boundary.part.prm.bak create mode 100644 cookbooks/platelike-boundary/doc/platelike.prm.bak create mode 100644 cookbooks/platelike-boundary/platelike-boundary.prm.bak create mode 100644 cookbooks/plume_2D_chunk/opening_angle_45degrees.prm.bak create mode 100644 cookbooks/plume_2D_chunk/opening_angle_90degrees.prm.bak create mode 100644 cookbooks/plume_2D_chunk/plume2D.prm.bak create mode 100644 cookbooks/plume_2D_chunk/strongly_temperature_dependent.prm.bak create mode 100644 cookbooks/plume_2D_chunk/weakly_temperature_dependent.prm.bak create mode 100644 cookbooks/prescribed_velocity/circle.prm.bak create mode 100644 cookbooks/prescribed_velocity/corner_flow.prm.bak create mode 100644 cookbooks/prescribed_velocity/doc/minimal.prm.bak create mode 100644 cookbooks/prescribed_velocity/prescribed_velocity.cc.bak create mode 100644 cookbooks/prescribed_velocity_ascii_data/doc/prescribed_velocity_ascii_data.prm.0.out.bak create mode 100644 cookbooks/prescribed_velocity_ascii_data/doc/prescribed_velocity_ascii_data.prm.1.out.bak create mode 100644 cookbooks/prescribed_velocity_ascii_data/doc/prescribed_velocity_ascii_data.prm.2.out.bak create mode 100644 cookbooks/prescribed_velocity_ascii_data/prescribed_velocity_ascii_data.cc.bak create mode 100644 cookbooks/prescribed_velocity_ascii_data/prescribed_velocity_ascii_data.prm.bak create mode 100644 cookbooks/shell_3d_postprocess/doc/shell_3d_postprocess.part.prm.bak create mode 100644 cookbooks/shell_3d_postprocess/shell_3d_postprocess.prm.bak create mode 100644 cookbooks/shell_simple_2d/doc/shearheat.part.prm.bak create mode 100644 cookbooks/shell_simple_2d/doc/shell.prm.bak create mode 100644 cookbooks/shell_simple_2d/shell_simple_2d.prm.bak create mode 100644 cookbooks/shell_simple_2d_smoothing/doc/shell_simple_2d_smoothing.part.prm.bak create mode 100644 cookbooks/shell_simple_2d_smoothing/shell_simple_2d_smoothing.prm.bak create mode 100644 cookbooks/shell_simple_3d/doc/amr.part.prm.bak create mode 100644 cookbooks/shell_simple_3d/doc/checkpoint.part.prm.bak create mode 100644 cookbooks/shell_simple_3d/doc/part1.part.prm.bak create mode 100644 cookbooks/shell_simple_3d/doc/part2.part.prm.bak create mode 100644 cookbooks/shell_simple_3d/doc/part3.part.prm.bak create mode 100644 cookbooks/shell_simple_3d/doc/part4.part.prm.bak create mode 100644 cookbooks/shell_simple_3d/doc/postprocess.part.prm.bak create mode 100644 cookbooks/shell_simple_3d/shell_simple_3d.prm.bak create mode 100644 cookbooks/sinker-with-averaging/doc/conservative.prm.bak create mode 100644 cookbooks/sinker-with-averaging/doc/full.prm.bak create mode 100644 cookbooks/sinker-with-averaging/doc/harmonic.prm.bak create mode 100644 cookbooks/sinker-with-averaging/sinker-with-averaging.prm.bak create mode 100644 cookbooks/steinberger/doc/geometry.part.prm.bak create mode 100644 cookbooks/steinberger/doc/lookup.part.prm.bak create mode 100644 cookbooks/steinberger/doc/nullspace.part.prm.bak create mode 100644 cookbooks/steinberger/doc/projected_density.part.prm.bak create mode 100644 cookbooks/steinberger/doc/rheology.part.prm.bak create mode 100644 cookbooks/steinberger/doc/rheology2.part.prm.bak create mode 100644 cookbooks/steinberger/steinberger.prm.bak create mode 100644 cookbooks/stokes/doc/stokeslaw.prm.bak create mode 100644 cookbooks/stokes/stokes.prm.bak create mode 100644 cookbooks/subduction_initiation/subduction_initiation.prm.base.bak create mode 100644 cookbooks/subduction_initiation/subduction_initiation_compositional_fields.prm.bak create mode 100644 cookbooks/subduction_initiation/subduction_initiation_particle_in_cell.prm.bak create mode 100644 cookbooks/tian_parameterization_kinematic_slab/coupled-two-phase-tian-parameterization-kinematic-slab.prm.bak create mode 100644 cookbooks/tian_parameterization_kinematic_slab/uncoupled-two-phase-tian-parameterization-kinematic-slab.prm.bak create mode 100644 cookbooks/tomography_based_plate_motions/2D_slice_with_faults_and_cratons.prm.bak create mode 100644 cookbooks/tomography_based_plate_motions/doc/tomography_based_plate_motions.part.prm.bak create mode 100644 cookbooks/tomography_based_plate_motions/plugins/reference_profile.cc.bak create mode 100644 cookbooks/tomography_based_plate_motions/plugins/reference_profile.h.bak create mode 100644 cookbooks/tomography_based_plate_motions/plugins/tomography_based_plate_motions.cc.bak create mode 100644 cookbooks/tomography_based_plate_motions/plugins/tomography_based_plate_motions.h.bak create mode 100644 cookbooks/transform_fault_behn_2007/doc/material.part.prm.bak create mode 100644 cookbooks/transform_fault_behn_2007/doc/temperature.part.prm.bak create mode 100644 cookbooks/transform_fault_behn_2007/temperature_dependent.prm.bak create mode 100644 cookbooks/transform_fault_behn_2007/transform_fault_behn_2007.prm.bak create mode 100644 cookbooks/van-keken-vof/doc/amr.part.prm.bak create mode 100644 cookbooks/van-keken-vof/doc/main.part.prm.bak create mode 100644 cookbooks/van-keken-vof/doc/postprocess.part.prm.bak create mode 100644 cookbooks/van-keken-vof/doc/variation.part.prm.bak create mode 100644 cookbooks/van-keken-vof/van-keken-vof.prm.bak create mode 100644 cookbooks/van-keken/doc/main.part.prm.bak create mode 100644 cookbooks/van-keken/doc/postprocess.part.prm.bak create mode 100644 cookbooks/van-keken/doc/smooth.part.prm.bak create mode 100644 cookbooks/van-keken/van-keken-discontinuous.prm.bak create mode 100644 cookbooks/van-keken/van-keken-smooth.prm.bak create mode 100644 cookbooks/vankeken_subduction/plugin/van_Keken_mesh.cc.bak create mode 100644 cookbooks/vankeken_subduction/vankeken_corner_flow.prm.bak create mode 100644 cookbooks/visualizing_phase_diagram/doc/harzburgite.prm.bak create mode 100644 cookbooks/visualizing_phase_diagram/doc/material_model.prm.bak create mode 100644 cookbooks/visualizing_phase_diagram/doc/steinberg.prm.bak create mode 100644 cookbooks/visualizing_phase_diagram/visualizing_phase_diagram.prm.bak create mode 100644 doc/logo/logo.prm.bak create mode 100644 doc/manual/cookbooks/overview/doc/boundary-conditions.part.prm.bak create mode 100644 doc/manual/cookbooks/overview/doc/dim.part.prm.bak create mode 100644 doc/manual/cookbooks/overview/doc/geometry.part.prm.bak create mode 100644 doc/manual/cookbooks/overview/doc/gmg-average.part.prm.bak create mode 100644 doc/manual/cookbooks/overview/doc/gmg-enable.part.prm.bak create mode 100644 doc/manual/cookbooks/overview/doc/simple.prm.bak create mode 100644 doc/manual/cookbooks/overview/doc/structure.part.prm.bak create mode 100644 doc/manual/empty.prm.bak create mode 100644 include/aspect/adiabatic_conditions/ascii_data.h.bak create mode 100644 include/aspect/adiabatic_conditions/compute_entropy_profile.h.bak create mode 100644 include/aspect/adiabatic_conditions/compute_profile.h.bak create mode 100644 include/aspect/adiabatic_conditions/function.h.bak create mode 100644 include/aspect/adiabatic_conditions/interface.h.bak create mode 100644 include/aspect/boundary_composition/ascii_data.h.bak create mode 100644 include/aspect/boundary_composition/box.h.bak create mode 100644 include/aspect/boundary_composition/function.h.bak create mode 100644 include/aspect/boundary_composition/initial_composition.h.bak create mode 100644 include/aspect/boundary_composition/interface.h.bak create mode 100644 include/aspect/boundary_composition/spherical_constant.h.bak create mode 100644 include/aspect/boundary_composition/two_merged_boxes.h.bak create mode 100644 include/aspect/boundary_fluid_pressure/density.h.bak create mode 100644 include/aspect/boundary_fluid_pressure/interface.h.bak create mode 100644 include/aspect/boundary_heat_flux/function.h.bak create mode 100644 include/aspect/boundary_heat_flux/interface.h.bak create mode 100644 include/aspect/boundary_temperature/ascii_data.h.bak create mode 100644 include/aspect/boundary_temperature/box.h.bak create mode 100644 include/aspect/boundary_temperature/constant.h.bak create mode 100644 include/aspect/boundary_temperature/dynamic_core.h.bak create mode 100644 include/aspect/boundary_temperature/function.h.bak create mode 100644 include/aspect/boundary_temperature/initial_temperature.h.bak create mode 100644 include/aspect/boundary_temperature/interface.h.bak create mode 100644 include/aspect/boundary_temperature/spherical_constant.h.bak create mode 100644 include/aspect/boundary_temperature/two_merged_boxes.h.bak create mode 100644 include/aspect/boundary_traction/ascii_data.h.bak create mode 100644 include/aspect/boundary_traction/function.h.bak create mode 100644 include/aspect/boundary_traction/initial_lithostatic_pressure.h.bak create mode 100644 include/aspect/boundary_traction/interface.h.bak create mode 100644 include/aspect/boundary_traction/zero_traction.h.bak create mode 100644 include/aspect/boundary_velocity/ascii_data.h.bak create mode 100644 include/aspect/boundary_velocity/function.h.bak create mode 100644 include/aspect/boundary_velocity/gplates.h.bak create mode 100644 include/aspect/boundary_velocity/interface.h.bak create mode 100644 include/aspect/boundary_velocity/zero_velocity.h.bak create mode 100644 include/aspect/citation_info.h.bak create mode 100644 include/aspect/compat.h.bak create mode 100644 include/aspect/coordinate_systems.h.bak create mode 100644 include/aspect/fe_variable_collection.h.bak create mode 100644 include/aspect/geometry_model/box.h.bak create mode 100644 include/aspect/geometry_model/chunk.h.bak create mode 100644 include/aspect/geometry_model/ellipsoidal_chunk.h.bak create mode 100644 include/aspect/geometry_model/initial_topography_model/ascii_data.h.bak create mode 100644 include/aspect/geometry_model/initial_topography_model/function.h.bak create mode 100644 include/aspect/geometry_model/initial_topography_model/interface.h.bak create mode 100644 include/aspect/geometry_model/initial_topography_model/prm_polygon.h.bak create mode 100644 include/aspect/geometry_model/initial_topography_model/zero_topography.h.bak create mode 100644 include/aspect/geometry_model/interface.h.bak create mode 100644 include/aspect/geometry_model/sphere.h.bak create mode 100644 include/aspect/geometry_model/spherical_shell.h.bak create mode 100644 include/aspect/geometry_model/two_merged_boxes.h.bak create mode 100644 include/aspect/geometry_model/two_merged_chunks.h.bak create mode 100644 include/aspect/global.h.bak create mode 100644 include/aspect/gravity_model/ascii_data.h.bak create mode 100644 include/aspect/gravity_model/function.h.bak create mode 100644 include/aspect/gravity_model/interface.h.bak create mode 100644 include/aspect/gravity_model/radial.h.bak create mode 100644 include/aspect/gravity_model/vertical.h.bak create mode 100644 include/aspect/heating_model/adiabatic_heating.h.bak create mode 100644 include/aspect/heating_model/adiabatic_heating_of_melt.h.bak create mode 100644 include/aspect/heating_model/compositional_heating.h.bak create mode 100644 include/aspect/heating_model/constant_heating.h.bak create mode 100644 include/aspect/heating_model/function.h.bak create mode 100644 include/aspect/heating_model/interface.h.bak create mode 100644 include/aspect/heating_model/latent_heat.h.bak create mode 100644 include/aspect/heating_model/latent_heat_melt.h.bak create mode 100644 include/aspect/heating_model/radioactive_decay.h.bak create mode 100644 include/aspect/heating_model/shear_heating.h.bak create mode 100644 include/aspect/heating_model/shear_heating_with_melt.h.bak create mode 100644 include/aspect/initial_composition/adiabatic_density.h.bak create mode 100644 include/aspect/initial_composition/ascii_data.h.bak create mode 100644 include/aspect/initial_composition/ascii_data_layered.h.bak create mode 100644 include/aspect/initial_composition/entropy_table_lookup.h.bak create mode 100644 include/aspect/initial_composition/function.h.bak create mode 100644 include/aspect/initial_composition/interface.h.bak create mode 100644 include/aspect/initial_composition/porosity.h.bak create mode 100644 include/aspect/initial_composition/slab_model.h.bak create mode 100644 include/aspect/initial_composition/world_builder.h.bak create mode 100644 include/aspect/initial_temperature/S40RTS_perturbation.h.bak create mode 100644 include/aspect/initial_temperature/SAVANI_perturbation.h.bak create mode 100644 include/aspect/initial_temperature/adiabatic.h.bak create mode 100644 include/aspect/initial_temperature/adiabatic_boundary.h.bak create mode 100644 include/aspect/initial_temperature/ascii_data.h.bak create mode 100644 include/aspect/initial_temperature/ascii_data_layered.h.bak create mode 100644 include/aspect/initial_temperature/ascii_profile.h.bak create mode 100644 include/aspect/initial_temperature/box.h.bak create mode 100644 include/aspect/initial_temperature/continental_geotherm.h.bak create mode 100644 include/aspect/initial_temperature/function.h.bak create mode 100644 include/aspect/initial_temperature/harmonic_perturbation.h.bak create mode 100644 include/aspect/initial_temperature/interface.h.bak create mode 100644 include/aspect/initial_temperature/lithosphere_mask.h.bak create mode 100644 include/aspect/initial_temperature/patch_on_S40RTS.h.bak create mode 100644 include/aspect/initial_temperature/prescribed_temperature.h.bak create mode 100644 include/aspect/initial_temperature/random_gaussian_perturbation.h.bak create mode 100644 include/aspect/initial_temperature/spherical_shell.h.bak create mode 100644 include/aspect/initial_temperature/world_builder.h.bak create mode 100644 include/aspect/introspection.h.bak create mode 100644 include/aspect/lateral_averaging.h.bak create mode 100644 include/aspect/material_model/ascii_reference_profile.h.bak create mode 100644 include/aspect/material_model/averaging.h.bak create mode 100644 include/aspect/material_model/compositing.h.bak create mode 100644 include/aspect/material_model/composition_reaction.h.bak create mode 100644 include/aspect/material_model/depth_dependent.h.bak create mode 100644 include/aspect/material_model/diffusion_dislocation.h.bak create mode 100644 include/aspect/material_model/drucker_prager.h.bak create mode 100644 include/aspect/material_model/entropy_model.h.bak create mode 100644 include/aspect/material_model/equation_of_state/interface.h.bak create mode 100644 include/aspect/material_model/equation_of_state/linearized_incompressible.h.bak create mode 100644 include/aspect/material_model/equation_of_state/multicomponent_compressible.h.bak create mode 100644 include/aspect/material_model/equation_of_state/multicomponent_incompressible.h.bak create mode 100644 include/aspect/material_model/equation_of_state/thermodynamic_table_lookup.h.bak create mode 100644 include/aspect/material_model/grain_size.h.bak create mode 100644 include/aspect/material_model/interface.h.bak create mode 100644 include/aspect/material_model/latent_heat.h.bak create mode 100644 include/aspect/material_model/latent_heat_melt.h.bak create mode 100644 include/aspect/material_model/melt_boukare.h.bak create mode 100644 include/aspect/material_model/melt_global.h.bak create mode 100644 include/aspect/material_model/melt_simple.h.bak create mode 100644 include/aspect/material_model/modified_tait.h.bak create mode 100644 include/aspect/material_model/multicomponent.h.bak create mode 100644 include/aspect/material_model/multicomponent_compressible.h.bak create mode 100644 include/aspect/material_model/nondimensional.h.bak create mode 100644 include/aspect/material_model/perplex_lookup.h.bak create mode 100644 include/aspect/material_model/prescribed_viscosity.h.bak create mode 100644 include/aspect/material_model/reaction_model/katz2003_mantle_melting.h.bak create mode 100644 include/aspect/material_model/reactive_fluid_transport.h.bak create mode 100644 include/aspect/material_model/replace_lithosphere_viscosity.h.bak create mode 100644 include/aspect/material_model/rheology/ascii_depth_profile.h.bak create mode 100644 include/aspect/material_model/rheology/composite_visco_plastic.h.bak create mode 100644 include/aspect/material_model/rheology/compositional_viscosity_prefactors.h.bak create mode 100644 include/aspect/material_model/rheology/constant_viscosity.h.bak create mode 100644 include/aspect/material_model/rheology/constant_viscosity_prefactors.h.bak create mode 100644 include/aspect/material_model/rheology/diffusion_creep.h.bak create mode 100644 include/aspect/material_model/rheology/diffusion_dislocation.h.bak create mode 100644 include/aspect/material_model/rheology/dislocation_creep.h.bak create mode 100644 include/aspect/material_model/rheology/drucker_prager.h.bak create mode 100644 include/aspect/material_model/rheology/elasticity.h.bak create mode 100644 include/aspect/material_model/rheology/frank_kamenetskii.h.bak create mode 100644 include/aspect/material_model/rheology/friction_models.h.bak create mode 100644 include/aspect/material_model/rheology/peierls_creep.h.bak create mode 100644 include/aspect/material_model/rheology/strain_dependent.h.bak create mode 100644 include/aspect/material_model/rheology/visco_plastic.h.bak create mode 100644 include/aspect/material_model/simple.h.bak create mode 100644 include/aspect/material_model/simple_compressible.h.bak create mode 100644 include/aspect/material_model/simpler.h.bak create mode 100644 include/aspect/material_model/steinberger.h.bak create mode 100644 include/aspect/material_model/utilities.h.bak create mode 100644 include/aspect/material_model/visco_plastic.h.bak create mode 100644 include/aspect/material_model/viscoelastic.h.bak create mode 100644 include/aspect/melt.h.bak create mode 100644 include/aspect/mesh_deformation/ascii_data.h.bak create mode 100644 include/aspect/mesh_deformation/diffusion.h.bak create mode 100644 include/aspect/mesh_deformation/fastscape.h.bak create mode 100644 include/aspect/mesh_deformation/free_surface.h.bak create mode 100644 include/aspect/mesh_deformation/function.h.bak create mode 100644 include/aspect/mesh_deformation/interface.h.bak create mode 100644 include/aspect/mesh_refinement/artificial_viscosity.h.bak create mode 100644 include/aspect/mesh_refinement/boundary.h.bak create mode 100644 include/aspect/mesh_refinement/compaction_length.h.bak create mode 100644 include/aspect/mesh_refinement/composition.h.bak create mode 100644 include/aspect/mesh_refinement/composition_approximate_gradient.h.bak create mode 100644 include/aspect/mesh_refinement/composition_gradient.h.bak create mode 100644 include/aspect/mesh_refinement/composition_threshold.h.bak create mode 100644 include/aspect/mesh_refinement/density.h.bak create mode 100644 include/aspect/mesh_refinement/interface.h.bak create mode 100644 include/aspect/mesh_refinement/isosurfaces.h.bak create mode 100644 include/aspect/mesh_refinement/maximum_refinement_function.h.bak create mode 100644 include/aspect/mesh_refinement/minimum_refinement_function.h.bak create mode 100644 include/aspect/mesh_refinement/nonadiabatic_temperature.h.bak create mode 100644 include/aspect/mesh_refinement/nonadiabatic_temperature_threshold.h.bak create mode 100644 include/aspect/mesh_refinement/particle_density.h.bak create mode 100644 include/aspect/mesh_refinement/slope.h.bak create mode 100644 include/aspect/mesh_refinement/strain_rate.h.bak create mode 100644 include/aspect/mesh_refinement/temperature.h.bak create mode 100644 include/aspect/mesh_refinement/thermal_energy_density.h.bak create mode 100644 include/aspect/mesh_refinement/topography.h.bak create mode 100644 include/aspect/mesh_refinement/velocity.h.bak create mode 100644 include/aspect/mesh_refinement/viscosity.h.bak create mode 100644 include/aspect/mesh_refinement/volume_of_fluid_interface.h.bak create mode 100644 include/aspect/newton.h.bak create mode 100644 include/aspect/parameters.h.bak create mode 100644 include/aspect/particle/generator/ascii_file.h.bak create mode 100644 include/aspect/particle/generator/interface.h.bak create mode 100644 include/aspect/particle/generator/probability_density_function.h.bak create mode 100644 include/aspect/particle/generator/quadrature_points.h.bak create mode 100644 include/aspect/particle/generator/random_uniform.h.bak create mode 100644 include/aspect/particle/generator/reference_cell.h.bak create mode 100644 include/aspect/particle/generator/uniform_box.h.bak create mode 100644 include/aspect/particle/generator/uniform_radial.h.bak create mode 100644 include/aspect/particle/integrator/euler.h.bak create mode 100644 include/aspect/particle/integrator/interface.h.bak create mode 100644 include/aspect/particle/integrator/rk_2.h.bak create mode 100644 include/aspect/particle/integrator/rk_4.h.bak create mode 100644 include/aspect/particle/interface.h.bak create mode 100644 include/aspect/particle/interpolator/bilinear_least_squares.h.bak create mode 100644 include/aspect/particle/interpolator/cell_average.h.bak create mode 100644 include/aspect/particle/interpolator/harmonic_average.h.bak create mode 100644 include/aspect/particle/interpolator/interface.h.bak create mode 100644 include/aspect/particle/interpolator/nearest_neighbor.h.bak create mode 100644 include/aspect/particle/interpolator/quadratic_least_squares.h.bak create mode 100644 include/aspect/particle/property/composition.h.bak create mode 100644 include/aspect/particle/property/cpo_bingham_average.h.bak create mode 100644 include/aspect/particle/property/cpo_elastic_tensor.h.bak create mode 100644 include/aspect/particle/property/crystal_preferred_orientation.h.bak create mode 100644 include/aspect/particle/property/elastic_stress.h.bak create mode 100644 include/aspect/particle/property/elastic_tensor_decomposition.h.bak create mode 100644 include/aspect/particle/property/function.h.bak create mode 100644 include/aspect/particle/property/grain_size.h.bak create mode 100644 include/aspect/particle/property/initial_composition.h.bak create mode 100644 include/aspect/particle/property/initial_position.h.bak create mode 100644 include/aspect/particle/property/integrated_strain.h.bak create mode 100644 include/aspect/particle/property/integrated_strain_invariant.h.bak create mode 100644 include/aspect/particle/property/interface.h.bak create mode 100644 include/aspect/particle/property/melt_particle.h.bak create mode 100644 include/aspect/particle/property/pT_path.h.bak create mode 100644 include/aspect/particle/property/position.h.bak create mode 100644 include/aspect/particle/property/reference_position.h.bak create mode 100644 include/aspect/particle/property/strain_rate.h.bak create mode 100644 include/aspect/particle/property/velocity.h.bak create mode 100644 include/aspect/particle/property/viscoplastic_strain_invariants.h.bak create mode 100644 include/aspect/particle/world.h.bak create mode 100644 include/aspect/plugins.h.bak create mode 100644 include/aspect/postprocess/ODE_statistics.h.bak create mode 100644 include/aspect/postprocess/basic_statistics.h.bak create mode 100644 include/aspect/postprocess/boundary_densities.h.bak create mode 100644 include/aspect/postprocess/boundary_pressures.h.bak create mode 100644 include/aspect/postprocess/boundary_strain_rate_residual_statistics.h.bak create mode 100644 include/aspect/postprocess/boundary_velocity_residual_statistics.h.bak create mode 100644 include/aspect/postprocess/command.h.bak create mode 100644 include/aspect/postprocess/composition_statistics.h.bak create mode 100644 include/aspect/postprocess/composition_velocity_statistics.h.bak create mode 100644 include/aspect/postprocess/core_statistics.h.bak create mode 100644 include/aspect/postprocess/crystal_preferred_orientation.h.bak create mode 100644 include/aspect/postprocess/depth_average.h.bak create mode 100644 include/aspect/postprocess/domain_volume_statistics.h.bak create mode 100644 include/aspect/postprocess/dynamic_topography.h.bak create mode 100644 include/aspect/postprocess/entropy_viscosity_statistics.h.bak create mode 100644 include/aspect/postprocess/geoid.h.bak create mode 100644 include/aspect/postprocess/global_statistics.h.bak create mode 100644 include/aspect/postprocess/gravity_point_values.h.bak create mode 100644 include/aspect/postprocess/heat_flux_densities.h.bak create mode 100644 include/aspect/postprocess/heat_flux_map.h.bak create mode 100644 include/aspect/postprocess/heat_flux_statistics.h.bak create mode 100644 include/aspect/postprocess/heating_statistics.h.bak create mode 100644 include/aspect/postprocess/interface.h.bak create mode 100644 include/aspect/postprocess/load_balance_statistics.h.bak create mode 100644 include/aspect/postprocess/mass_flux_statistics.h.bak create mode 100644 include/aspect/postprocess/material_statistics.h.bak create mode 100644 include/aspect/postprocess/matrix_statistics.h.bak create mode 100644 include/aspect/postprocess/max_depth_field.h.bak create mode 100644 include/aspect/postprocess/melt_statistics.h.bak create mode 100644 include/aspect/postprocess/memory_statistics.h.bak create mode 100644 include/aspect/postprocess/mobility_statistics.h.bak create mode 100644 include/aspect/postprocess/particle_count_statistics.h.bak create mode 100644 include/aspect/postprocess/particles.h.bak create mode 100644 include/aspect/postprocess/point_values.h.bak create mode 100644 include/aspect/postprocess/pressure_statistics.h.bak create mode 100644 include/aspect/postprocess/rotation_statistics.h.bak create mode 100644 include/aspect/postprocess/sea_level.h.bak create mode 100644 include/aspect/postprocess/spherical_velocity_statistics.h.bak create mode 100644 include/aspect/postprocess/stokes_residual.h.bak create mode 100644 include/aspect/postprocess/temperature_statistics.h.bak create mode 100644 include/aspect/postprocess/topography.h.bak create mode 100644 include/aspect/postprocess/velocity_boundary_statistics.h.bak create mode 100644 include/aspect/postprocess/velocity_statistics.h.bak create mode 100644 include/aspect/postprocess/viscous_dissipation_statistics.h.bak create mode 100644 include/aspect/postprocess/visualization.h.bak create mode 100644 include/aspect/postprocess/visualization/ISA_rotation_timescale.h.bak create mode 100644 include/aspect/postprocess/visualization/adiabat.h.bak create mode 100644 include/aspect/postprocess/visualization/artificial_viscosity.h.bak create mode 100644 include/aspect/postprocess/visualization/artificial_viscosity_composition.h.bak create mode 100644 include/aspect/postprocess/visualization/boundary_indicator.h.bak create mode 100644 include/aspect/postprocess/visualization/boundary_strain_rate_residual.h.bak create mode 100644 include/aspect/postprocess/visualization/boundary_velocity_residual.h.bak create mode 100644 include/aspect/postprocess/visualization/compositional_vector.h.bak create mode 100644 include/aspect/postprocess/visualization/depth.h.bak create mode 100644 include/aspect/postprocess/visualization/dynamic_topography.h.bak create mode 100644 include/aspect/postprocess/visualization/error_indicator.h.bak create mode 100644 include/aspect/postprocess/visualization/geoid.h.bak create mode 100644 include/aspect/postprocess/visualization/grain_lag_angle.h.bak create mode 100644 include/aspect/postprocess/visualization/gravity.h.bak create mode 100644 include/aspect/postprocess/visualization/heat_flux_map.h.bak create mode 100644 include/aspect/postprocess/visualization/heating.h.bak create mode 100644 include/aspect/postprocess/visualization/kxrcf_indicator.h.bak create mode 100644 include/aspect/postprocess/visualization/material_properties.h.bak create mode 100644 include/aspect/postprocess/visualization/maximum_horizontal_compressive_stress.h.bak create mode 100644 include/aspect/postprocess/visualization/melt.h.bak create mode 100644 include/aspect/postprocess/visualization/melt_fraction.h.bak create mode 100644 include/aspect/postprocess/visualization/named_additional_outputs.h.bak create mode 100644 include/aspect/postprocess/visualization/nonadiabatic_pressure.h.bak create mode 100644 include/aspect/postprocess/visualization/nonadiabatic_temperature.h.bak create mode 100644 include/aspect/postprocess/visualization/particle_count.h.bak create mode 100644 include/aspect/postprocess/visualization/partition.h.bak create mode 100644 include/aspect/postprocess/visualization/principal_stress.h.bak create mode 100644 include/aspect/postprocess/visualization/seismic_anomalies.h.bak create mode 100644 include/aspect/postprocess/visualization/shear_stress.h.bak create mode 100644 include/aspect/postprocess/visualization/spd_factor.h.bak create mode 100644 include/aspect/postprocess/visualization/spherical_velocity_components.h.bak create mode 100644 include/aspect/postprocess/visualization/strain_rate.h.bak create mode 100644 include/aspect/postprocess/visualization/strain_rate_tensor.h.bak create mode 100644 include/aspect/postprocess/visualization/stress.h.bak create mode 100644 include/aspect/postprocess/visualization/stress_second_invariant.h.bak create mode 100644 include/aspect/postprocess/visualization/surface_dynamic_topography.h.bak create mode 100644 include/aspect/postprocess/visualization/surface_elevation.h.bak create mode 100644 include/aspect/postprocess/visualization/surface_strain_rate_tensor.h.bak create mode 100644 include/aspect/postprocess/visualization/surface_stress.h.bak create mode 100644 include/aspect/postprocess/visualization/temperature_anomaly.h.bak create mode 100644 include/aspect/postprocess/visualization/vertical_heat_flux.h.bak create mode 100644 include/aspect/postprocess/visualization/volume_of_fluid_values.h.bak create mode 100644 include/aspect/postprocess/visualization/volumetric_strain_rate.h.bak create mode 100644 include/aspect/postprocess/volume_of_fluid_statistics.h.bak create mode 100644 include/aspect/prescribed_stokes_solution/ascii_data.h.bak create mode 100644 include/aspect/prescribed_stokes_solution/circle.h.bak create mode 100644 include/aspect/prescribed_stokes_solution/function.h.bak create mode 100644 include/aspect/prescribed_stokes_solution/interface.h.bak create mode 100644 include/aspect/simulator.h.bak create mode 100644 include/aspect/simulator/assemblers/advection.h.bak create mode 100644 include/aspect/simulator/assemblers/interface.h.bak create mode 100644 include/aspect/simulator/assemblers/stokes.h.bak create mode 100644 include/aspect/simulator_access.h.bak create mode 100644 include/aspect/simulator_signals.h.bak create mode 100644 include/aspect/stokes_matrix_free.h.bak create mode 100644 include/aspect/structured_data.h.bak create mode 100644 include/aspect/termination_criteria/end_step.h.bak create mode 100644 include/aspect/termination_criteria/end_time.h.bak create mode 100644 include/aspect/termination_criteria/end_walltime.h.bak create mode 100644 include/aspect/termination_criteria/interface.h.bak create mode 100644 include/aspect/termination_criteria/steady_heat_flux.h.bak create mode 100644 include/aspect/termination_criteria/steady_rms_velocity.h.bak create mode 100644 include/aspect/termination_criteria/steady_temperature.h.bak create mode 100644 include/aspect/termination_criteria/user_request.h.bak create mode 100644 include/aspect/time_stepping/conduction_time_step.h.bak create mode 100644 include/aspect/time_stepping/convection_time_step.h.bak create mode 100644 include/aspect/time_stepping/function.h.bak create mode 100644 include/aspect/time_stepping/interface.h.bak create mode 100644 include/aspect/time_stepping/repeat_on_cutback.h.bak create mode 100644 include/aspect/utilities.h.bak create mode 100644 include/aspect/volume_of_fluid/assembly.h.bak create mode 100644 include/aspect/volume_of_fluid/field.h.bak create mode 100644 include/aspect/volume_of_fluid/handler.h.bak create mode 100644 include/aspect/volume_of_fluid/utilities.h.bak create mode 100644 source/adiabatic_conditions/ascii_data.cc.bak create mode 100644 source/adiabatic_conditions/compute_entropy_profile.cc.bak create mode 100644 source/adiabatic_conditions/compute_profile.cc.bak create mode 100644 source/adiabatic_conditions/function.cc.bak create mode 100644 source/adiabatic_conditions/interface.cc.bak create mode 100644 source/boundary_composition/ascii_data.cc.bak create mode 100644 source/boundary_composition/box.cc.bak create mode 100644 source/boundary_composition/function.cc.bak create mode 100644 source/boundary_composition/initial_composition.cc.bak create mode 100644 source/boundary_composition/interface.cc.bak create mode 100644 source/boundary_composition/spherical_constant.cc.bak create mode 100644 source/boundary_composition/two_merged_boxes.cc.bak create mode 100644 source/boundary_fluid_pressure/density.cc.bak create mode 100644 source/boundary_fluid_pressure/interface.cc.bak create mode 100644 source/boundary_heat_flux/function.cc.bak create mode 100644 source/boundary_heat_flux/interface.cc.bak create mode 100644 source/boundary_temperature/ascii_data.cc.bak create mode 100644 source/boundary_temperature/box.cc.bak create mode 100644 source/boundary_temperature/constant.cc.bak create mode 100644 source/boundary_temperature/dynamic_core.cc.bak create mode 100644 source/boundary_temperature/function.cc.bak create mode 100644 source/boundary_temperature/initial_temperature.cc.bak create mode 100644 source/boundary_temperature/interface.cc.bak create mode 100644 source/boundary_temperature/spherical_constant.cc.bak create mode 100644 source/boundary_temperature/two_merged_boxes.cc.bak create mode 100644 source/boundary_traction/ascii_data.cc.bak create mode 100644 source/boundary_traction/function.cc.bak create mode 100644 source/boundary_traction/initial_lithostatic_pressure.cc.bak create mode 100644 source/boundary_traction/interface.cc.bak create mode 100644 source/boundary_traction/zero_traction.cc.bak create mode 100644 source/boundary_velocity/ascii_data.cc.bak create mode 100644 source/boundary_velocity/function.cc.bak create mode 100644 source/boundary_velocity/gplates.cc.bak create mode 100644 source/boundary_velocity/interface.cc.bak create mode 100644 source/boundary_velocity/zero_velocity.cc.bak create mode 100644 source/citation_info.cc.bak create mode 100644 source/compat.cc.bak create mode 100644 source/fe_variable_collection.cc.bak create mode 100644 source/geometry_model/box.cc.bak create mode 100644 source/geometry_model/chunk.cc.bak create mode 100644 source/geometry_model/ellipsoidal_chunk.cc.bak create mode 100644 source/geometry_model/initial_topography_model/ascii_data.cc.bak create mode 100644 source/geometry_model/initial_topography_model/function.cc.bak create mode 100644 source/geometry_model/initial_topography_model/interface.cc.bak create mode 100644 source/geometry_model/initial_topography_model/prm_polygon.cc.bak create mode 100644 source/geometry_model/initial_topography_model/zero_topography.cc.bak create mode 100644 source/geometry_model/interface.cc.bak create mode 100644 source/geometry_model/sphere.cc.bak create mode 100644 source/geometry_model/spherical_shell.cc.bak create mode 100644 source/geometry_model/two_merged_boxes.cc.bak create mode 100644 source/geometry_model/two_merged_chunks.cc.bak create mode 100644 source/global.cc.bak create mode 100644 source/gravity_model/ascii_data.cc.bak create mode 100644 source/gravity_model/function.cc.bak create mode 100644 source/gravity_model/interface.cc.bak create mode 100644 source/gravity_model/radial.cc.bak create mode 100644 source/gravity_model/vertical.cc.bak create mode 100644 source/heating_model/adiabatic_heating.cc.bak create mode 100644 source/heating_model/adiabatic_heating_of_melt.cc.bak create mode 100644 source/heating_model/compositional_heating.cc.bak create mode 100644 source/heating_model/constant_heating.cc.bak create mode 100644 source/heating_model/function.cc.bak create mode 100644 source/heating_model/interface.cc.bak create mode 100644 source/heating_model/latent_heat.cc.bak create mode 100644 source/heating_model/latent_heat_melt.cc.bak create mode 100644 source/heating_model/radioactive_decay.cc.bak create mode 100644 source/heating_model/shear_heating.cc.bak create mode 100644 source/heating_model/shear_heating_with_melt.cc.bak create mode 100644 source/initial_composition/adiabatic_density.cc.bak create mode 100644 source/initial_composition/ascii_data.cc.bak create mode 100644 source/initial_composition/ascii_data_layered.cc.bak create mode 100644 source/initial_composition/entropy_table_lookup.cc.bak create mode 100644 source/initial_composition/function.cc.bak create mode 100644 source/initial_composition/interface.cc.bak create mode 100644 source/initial_composition/porosity.cc.bak create mode 100644 source/initial_composition/slab_model.cc.bak create mode 100644 source/initial_composition/world_builder.cc.bak create mode 100644 source/initial_temperature/S40RTS_perturbation.cc.bak create mode 100644 source/initial_temperature/SAVANI_perturbation.cc.bak create mode 100644 source/initial_temperature/adiabatic.cc.bak create mode 100644 source/initial_temperature/adiabatic_boundary.cc.bak create mode 100644 source/initial_temperature/ascii_data.cc.bak create mode 100644 source/initial_temperature/ascii_data_layered.cc.bak create mode 100644 source/initial_temperature/ascii_profile.cc.bak create mode 100644 source/initial_temperature/box.cc.bak create mode 100644 source/initial_temperature/continental_geotherm.cc.bak create mode 100644 source/initial_temperature/function.cc.bak create mode 100644 source/initial_temperature/harmonic_perturbation.cc.bak create mode 100644 source/initial_temperature/interface.cc.bak create mode 100644 source/initial_temperature/lithosphere_mask.cc.bak create mode 100644 source/initial_temperature/patch_on_S40RTS.cc.bak create mode 100644 source/initial_temperature/prescribed_temperature.cc.bak create mode 100644 source/initial_temperature/random_gaussian_perturbation.cc.bak create mode 100644 source/initial_temperature/spherical_shell.cc.bak create mode 100644 source/initial_temperature/world_builder.cc.bak create mode 100644 source/main.cc.bak create mode 100644 source/material_model/ascii_reference_profile.cc.bak create mode 100644 source/material_model/averaging.cc.bak create mode 100644 source/material_model/compositing.cc.bak create mode 100644 source/material_model/composition_reaction.cc.bak create mode 100644 source/material_model/depth_dependent.cc.bak create mode 100644 source/material_model/diffusion_dislocation.cc.bak create mode 100644 source/material_model/drucker_prager.cc.bak create mode 100644 source/material_model/entropy_model.cc.bak create mode 100644 source/material_model/equation_of_state/interface.cc.bak create mode 100644 source/material_model/equation_of_state/linearized_incompressible.cc.bak create mode 100644 source/material_model/equation_of_state/multicomponent_compressible.cc.bak create mode 100644 source/material_model/equation_of_state/multicomponent_incompressible.cc.bak create mode 100644 source/material_model/equation_of_state/thermodynamic_table_lookup.cc.bak create mode 100644 source/material_model/grain_size.cc.bak create mode 100644 source/material_model/interface.cc.bak create mode 100644 source/material_model/latent_heat.cc.bak create mode 100644 source/material_model/latent_heat_melt.cc.bak create mode 100644 source/material_model/melt_boukare.cc.bak create mode 100644 source/material_model/melt_global.cc.bak create mode 100644 source/material_model/melt_simple.cc.bak create mode 100644 source/material_model/modified_tait.cc.bak create mode 100644 source/material_model/multicomponent.cc.bak create mode 100644 source/material_model/multicomponent_compressible.cc.bak create mode 100644 source/material_model/nondimensional.cc.bak create mode 100644 source/material_model/perplex_lookup.cc.bak create mode 100644 source/material_model/prescribed_viscosity.cc.bak create mode 100644 source/material_model/reaction_model/katz2003_mantle_melting.cc.bak create mode 100644 source/material_model/reactive_fluid_transport.cc.bak create mode 100644 source/material_model/replace_lithosphere_viscosity.cc.bak create mode 100644 source/material_model/rheology/ascii_depth_profile.cc.bak create mode 100644 source/material_model/rheology/composite_visco_plastic.cc.bak create mode 100644 source/material_model/rheology/compositional_viscosity_prefactors.cc.bak create mode 100644 source/material_model/rheology/constant_viscosity.cc.bak create mode 100644 source/material_model/rheology/constant_viscosity_prefactors.cc.bak create mode 100644 source/material_model/rheology/diffusion_creep.cc.bak create mode 100644 source/material_model/rheology/diffusion_dislocation.cc.bak create mode 100644 source/material_model/rheology/dislocation_creep.cc.bak create mode 100644 source/material_model/rheology/drucker_prager.cc.bak create mode 100644 source/material_model/rheology/elasticity.cc.bak create mode 100644 source/material_model/rheology/frank_kamenetskii.cc.bak create mode 100644 source/material_model/rheology/friction_models.cc.bak create mode 100644 source/material_model/rheology/peierls_creep.cc.bak create mode 100644 source/material_model/rheology/strain_dependent.cc.bak create mode 100644 source/material_model/rheology/visco_plastic.cc.bak create mode 100644 source/material_model/simple.cc.bak create mode 100644 source/material_model/simple_compressible.cc.bak create mode 100644 source/material_model/simpler.cc.bak create mode 100644 source/material_model/steinberger.cc.bak create mode 100644 source/material_model/utilities.cc.bak create mode 100644 source/material_model/visco_plastic.cc.bak create mode 100644 source/material_model/viscoelastic.cc.bak create mode 100644 source/mesh_deformation/ascii_data.cc.bak create mode 100644 source/mesh_deformation/diffusion.cc.bak create mode 100644 source/mesh_deformation/fastscape.cc.bak create mode 100644 source/mesh_deformation/free_surface.cc.bak create mode 100644 source/mesh_deformation/function.cc.bak create mode 100644 source/mesh_deformation/interface.cc.bak create mode 100644 source/mesh_refinement/artificial_viscosity.cc.bak create mode 100644 source/mesh_refinement/boundary.cc.bak create mode 100644 source/mesh_refinement/compaction_length.cc.bak create mode 100644 source/mesh_refinement/composition.cc.bak create mode 100644 source/mesh_refinement/composition_approximate_gradient.cc.bak create mode 100644 source/mesh_refinement/composition_gradient.cc.bak create mode 100644 source/mesh_refinement/composition_threshold.cc.bak create mode 100644 source/mesh_refinement/density.cc.bak create mode 100644 source/mesh_refinement/interface.cc.bak create mode 100644 source/mesh_refinement/isosurfaces.cc.bak create mode 100644 source/mesh_refinement/maximum_refinement_function.cc.bak create mode 100644 source/mesh_refinement/minimum_refinement_function.cc.bak create mode 100644 source/mesh_refinement/nonadiabatic_temperature.cc.bak create mode 100644 source/mesh_refinement/nonadiabatic_temperature_threshold.cc.bak create mode 100644 source/mesh_refinement/particle_density.cc.bak create mode 100644 source/mesh_refinement/slope.cc.bak create mode 100644 source/mesh_refinement/strain_rate.cc.bak create mode 100644 source/mesh_refinement/temperature.cc.bak create mode 100644 source/mesh_refinement/thermal_energy_density.cc.bak create mode 100644 source/mesh_refinement/topography.cc.bak create mode 100644 source/mesh_refinement/velocity.cc.bak create mode 100644 source/mesh_refinement/viscosity.cc.bak create mode 100644 source/mesh_refinement/volume_of_fluid_interface.cc.bak create mode 100644 source/particle/generator/ascii_file.cc.bak create mode 100644 source/particle/generator/interface.cc.bak create mode 100644 source/particle/generator/probability_density_function.cc.bak create mode 100644 source/particle/generator/quadrature_points.cc.bak create mode 100644 source/particle/generator/random_uniform.cc.bak create mode 100644 source/particle/generator/reference_cell.cc.bak create mode 100644 source/particle/generator/uniform_box.cc.bak create mode 100644 source/particle/generator/uniform_radial.cc.bak create mode 100644 source/particle/integrator/euler.cc.bak create mode 100644 source/particle/integrator/interface.cc.bak create mode 100644 source/particle/integrator/rk_2.cc.bak create mode 100644 source/particle/integrator/rk_4.cc.bak create mode 100644 source/particle/interface.cc.bak create mode 100644 source/particle/interpolator/bilinear_least_squares.cc.bak create mode 100644 source/particle/interpolator/cell_average.cc.bak create mode 100644 source/particle/interpolator/harmonic_average.cc.bak create mode 100644 source/particle/interpolator/interface.cc.bak create mode 100644 source/particle/interpolator/nearest_neighbor.cc.bak create mode 100644 source/particle/interpolator/quadratic_least_squares.cc.bak create mode 100644 source/particle/property/composition.cc.bak create mode 100644 source/particle/property/cpo_bingham_average.cc.bak create mode 100644 source/particle/property/cpo_elastic_tensor.cc.bak create mode 100644 source/particle/property/crystal_preferred_orientation.cc.bak create mode 100644 source/particle/property/elastic_stress.cc.bak create mode 100644 source/particle/property/elastic_tensor_decomposition.cc.bak create mode 100644 source/particle/property/function.cc.bak create mode 100644 source/particle/property/grain_size.cc.bak create mode 100644 source/particle/property/initial_composition.cc.bak create mode 100644 source/particle/property/initial_position.cc.bak create mode 100644 source/particle/property/integrated_strain.cc.bak create mode 100644 source/particle/property/integrated_strain_invariant.cc.bak create mode 100644 source/particle/property/interface.cc.bak create mode 100644 source/particle/property/melt_particle.cc.bak create mode 100644 source/particle/property/pT_path.cc.bak create mode 100644 source/particle/property/position.cc.bak create mode 100644 source/particle/property/reference_position.cc.bak create mode 100644 source/particle/property/strain_rate.cc.bak create mode 100644 source/particle/property/velocity.cc.bak create mode 100644 source/particle/property/viscoplastic_strain_invariants.cc.bak create mode 100644 source/particle/world.cc.bak create mode 100644 source/plugins.cc.bak create mode 100644 source/postprocess/ODE_statistics.cc.bak create mode 100644 source/postprocess/basic_statistics.cc.bak create mode 100644 source/postprocess/boundary_densities.cc.bak create mode 100644 source/postprocess/boundary_pressures.cc.bak create mode 100644 source/postprocess/boundary_strain_rate_residual_statistics.cc.bak create mode 100644 source/postprocess/boundary_velocity_residual_statistics.cc.bak create mode 100644 source/postprocess/command.cc.bak create mode 100644 source/postprocess/composition_statistics.cc.bak create mode 100644 source/postprocess/composition_velocity_statistics.cc.bak create mode 100644 source/postprocess/core_statistics.cc.bak create mode 100644 source/postprocess/crystal_preferred_orientation.cc.bak create mode 100644 source/postprocess/depth_average.cc.bak create mode 100644 source/postprocess/domain_volume_statistics.cc.bak create mode 100644 source/postprocess/dynamic_topography.cc.bak create mode 100644 source/postprocess/entropy_viscosity_statistics.cc.bak create mode 100644 source/postprocess/geoid.cc.bak create mode 100644 source/postprocess/global_statistics.cc.bak create mode 100644 source/postprocess/gravity_point_values.cc.bak create mode 100644 source/postprocess/heat_flux_densities.cc.bak create mode 100644 source/postprocess/heat_flux_map.cc.bak create mode 100644 source/postprocess/heat_flux_statistics.cc.bak create mode 100644 source/postprocess/heating_statistics.cc.bak create mode 100644 source/postprocess/interface.cc.bak create mode 100644 source/postprocess/load_balance_statistics.cc.bak create mode 100644 source/postprocess/mass_flux_statistics.cc.bak create mode 100644 source/postprocess/material_statistics.cc.bak create mode 100644 source/postprocess/matrix_statistics.cc.bak create mode 100644 source/postprocess/max_depth_field.cc.bak create mode 100644 source/postprocess/melt_statistics.cc.bak create mode 100644 source/postprocess/memory_statistics.cc.bak create mode 100644 source/postprocess/mobility_statistics.cc.bak create mode 100644 source/postprocess/particle_count_statistics.cc.bak create mode 100644 source/postprocess/particles.cc.bak create mode 100644 source/postprocess/point_values.cc.bak create mode 100644 source/postprocess/pressure_statistics.cc.bak create mode 100644 source/postprocess/rotation_statistics.cc.bak create mode 100644 source/postprocess/sea_level.cc.bak create mode 100644 source/postprocess/spherical_velocity_statistics.cc.bak create mode 100644 source/postprocess/stokes_residual.cc.bak create mode 100644 source/postprocess/temperature_statistics.cc.bak create mode 100644 source/postprocess/topography.cc.bak create mode 100644 source/postprocess/velocity_boundary_statistics.cc.bak create mode 100644 source/postprocess/velocity_statistics.cc.bak create mode 100644 source/postprocess/viscous_dissipation_statistics.cc.bak create mode 100644 source/postprocess/visualization.cc.bak create mode 100644 source/postprocess/visualization/ISA_rotation_timescale.cc.bak create mode 100644 source/postprocess/visualization/adiabat.cc.bak create mode 100644 source/postprocess/visualization/artificial_viscosity.cc.bak create mode 100644 source/postprocess/visualization/artificial_viscosity_composition.cc.bak create mode 100644 source/postprocess/visualization/boundary_indicator.cc.bak create mode 100644 source/postprocess/visualization/boundary_strain_rate_residual.cc.bak create mode 100644 source/postprocess/visualization/boundary_velocity_residual.cc.bak create mode 100644 source/postprocess/visualization/compositional_vector.cc.bak create mode 100644 source/postprocess/visualization/depth.cc.bak create mode 100644 source/postprocess/visualization/dynamic_topography.cc.bak create mode 100644 source/postprocess/visualization/error_indicator.cc.bak create mode 100644 source/postprocess/visualization/geoid.cc.bak create mode 100644 source/postprocess/visualization/grain_lag_angle.cc.bak create mode 100644 source/postprocess/visualization/gravity.cc.bak create mode 100644 source/postprocess/visualization/heat_flux_map.cc.bak create mode 100644 source/postprocess/visualization/heating.cc.bak create mode 100644 source/postprocess/visualization/kxrcf_indicator.cc.bak create mode 100644 source/postprocess/visualization/material_properties.cc.bak create mode 100644 source/postprocess/visualization/maximum_horizontal_compressive_stress.cc.bak create mode 100644 source/postprocess/visualization/melt.cc.bak create mode 100644 source/postprocess/visualization/melt_fraction.cc.bak create mode 100644 source/postprocess/visualization/named_additional_outputs.cc.bak create mode 100644 source/postprocess/visualization/nonadiabatic_pressure.cc.bak create mode 100644 source/postprocess/visualization/nonadiabatic_temperature.cc.bak create mode 100644 source/postprocess/visualization/particle_count.cc.bak create mode 100644 source/postprocess/visualization/partition.cc.bak create mode 100644 source/postprocess/visualization/principal_stress.cc.bak create mode 100644 source/postprocess/visualization/seismic_anomalies.cc.bak create mode 100644 source/postprocess/visualization/shear_stress.cc.bak create mode 100644 source/postprocess/visualization/spd_factor.cc.bak create mode 100644 source/postprocess/visualization/spherical_velocity_components.cc.bak create mode 100644 source/postprocess/visualization/strain_rate.cc.bak create mode 100644 source/postprocess/visualization/strain_rate_tensor.cc.bak create mode 100644 source/postprocess/visualization/stress.cc.bak create mode 100644 source/postprocess/visualization/stress_second_invariant.cc.bak create mode 100644 source/postprocess/visualization/surface_dynamic_topography.cc.bak create mode 100644 source/postprocess/visualization/surface_elevation.cc.bak create mode 100644 source/postprocess/visualization/surface_strain_rate_tensor.cc.bak create mode 100644 source/postprocess/visualization/surface_stress.cc.bak create mode 100644 source/postprocess/visualization/temperature_anomaly.cc.bak create mode 100644 source/postprocess/visualization/vertical_heat_flux.cc.bak create mode 100644 source/postprocess/visualization/volume_of_fluid_values.cc.bak create mode 100644 source/postprocess/visualization/volumetric_strain_rate.cc.bak create mode 100644 source/postprocess/volume_of_fluid_statistics.cc.bak create mode 100644 source/prescribed_stokes_solution/ascii_data.cc.bak create mode 100644 source/prescribed_stokes_solution/circle.cc.bak create mode 100644 source/prescribed_stokes_solution/function.cc.bak create mode 100644 source/prescribed_stokes_solution/interface.cc.bak create mode 100644 source/simulator/assemblers/advection.cc.bak create mode 100644 source/simulator/assemblers/interface.cc.bak create mode 100644 source/simulator/assemblers/newton_stokes.cc.bak create mode 100644 source/simulator/assemblers/stokes.cc.bak create mode 100644 source/simulator/assembly.cc.bak create mode 100644 source/simulator/checkpoint_restart.cc.bak create mode 100644 source/simulator/core.cc.bak create mode 100644 source/simulator/entropy_viscosity.cc.bak create mode 100644 source/simulator/helper_functions.cc.bak create mode 100644 source/simulator/initial_conditions.cc.bak create mode 100644 source/simulator/introspection.cc.bak create mode 100644 source/simulator/lateral_averaging.cc.bak create mode 100644 source/simulator/limiters.cc.bak create mode 100644 source/simulator/melt.cc.bak create mode 100644 source/simulator/newton.cc.bak create mode 100644 source/simulator/nullspace.cc.bak create mode 100644 source/simulator/parameters.cc.bak create mode 100644 source/simulator/simulator_access.cc.bak create mode 100644 source/simulator/simulator_signals.cc.bak create mode 100644 source/simulator/solver.cc.bak create mode 100644 source/simulator/solver_schemes.cc.bak create mode 100644 source/simulator/stokes_matrix_free.cc.bak create mode 100644 source/structured_data.cc.bak create mode 100644 source/termination_criteria/end_step.cc.bak create mode 100644 source/termination_criteria/end_time.cc.bak create mode 100644 source/termination_criteria/end_walltime.cc.bak create mode 100644 source/termination_criteria/interface.cc.bak create mode 100644 source/termination_criteria/steady_heat_flux.cc.bak create mode 100644 source/termination_criteria/steady_rms_velocity.cc.bak create mode 100644 source/termination_criteria/steady_temperature.cc.bak create mode 100644 source/termination_criteria/user_request.cc.bak create mode 100644 source/time_stepping/conduction_time_step.cc.bak create mode 100644 source/time_stepping/convection_time_step.cc.bak create mode 100644 source/time_stepping/function.cc.bak create mode 100644 source/time_stepping/interface.cc.bak create mode 100644 source/time_stepping/repeat_on_cutback.cc.bak create mode 100644 source/utilities.cc.bak create mode 100644 source/volume_of_fluid/assembler.cc.bak create mode 100644 source/volume_of_fluid/handler.cc.bak create mode 100644 source/volume_of_fluid/reconstruct.cc.bak create mode 100644 source/volume_of_fluid/setup_initial_conditions.cc.bak create mode 100644 source/volume_of_fluid/solver.cc.bak create mode 100644 source/volume_of_fluid/utilities.cc.bak create mode 100644 tests/2d_annulus_pyvista_cookbook.prm.bak create mode 100644 tests/ISA_rotation_timescale.prm.bak create mode 100644 tests/Picard_compressible.prm.bak create mode 100644 tests/additional_outputs_02.cc.bak create mode 100644 tests/additional_outputs_02.prm.bak create mode 100644 tests/additional_outputs_03.cc.bak create mode 100644 tests/additional_outputs_03.prm.bak create mode 100644 tests/adiabatic_boundary.prm.bak create mode 100644 tests/adiabatic_conditions.prm.bak create mode 100644 tests/adiabatic_conditions_composition_function.prm.bak create mode 100644 tests/adiabatic_conditions_function.prm.bak create mode 100644 tests/adiabatic_conditions_time_change.prm.bak create mode 100644 tests/adiabatic_heating.prm.bak create mode 100644 tests/adiabatic_heating_simplified.prm.bak create mode 100644 tests/adiabatic_heating_with_melt.prm.bak create mode 100644 tests/adiabatic_initial_conditions.prm.bak create mode 100644 tests/adiabatic_initial_conditions_chunk.prm.bak create mode 100644 tests/adiabatic_initial_conditions_chunk_3d.prm.bak create mode 100644 tests/adiabatic_initial_conditions_compressible.prm.bak create mode 100644 tests/adiabatic_initial_conditions_constant.prm.bak create mode 100644 tests/adiabatic_initial_conditions_points.prm.bak create mode 100644 tests/adiabatic_initial_conditions_subadiabaticity.prm.bak create mode 100644 tests/adiabatic_initial_conditions_without_boundary.prm.bak create mode 100644 tests/adiabatic_plate_cooling.prm.bak create mode 100644 tests/adiabatic_plate_function.prm.bak create mode 100644 tests/advect_field_with_melt_velocity.cc.bak create mode 100644 tests/advect_field_with_melt_velocity.prm.bak create mode 100644 tests/advect_mesh_vertically.prm.bak create mode 100644 tests/advection_reaction.cc.bak create mode 100644 tests/advection_reaction.prm.bak create mode 100644 tests/advection_solver_fail.prm.bak create mode 100644 tests/airy_isostasy.prm.bak create mode 100644 tests/airy_isostasy_initial_topo.cc.bak create mode 100644 tests/airy_isostasy_initial_topo.prm.bak create mode 100644 tests/airy_isostasy_initial_topo_lithostatic_pressure.prm.bak create mode 100644 tests/always_refine.prm.bak create mode 100644 tests/analytic_artificial_viscosity_0.prm.bak create mode 100644 tests/anisotropic_viscosity.cc.bak create mode 100644 tests/anisotropic_viscosity.prm.bak create mode 100644 tests/annulus.cc.bak create mode 100644 tests/annulus.prm.bak create mode 100644 tests/annulus_transient.cc.bak create mode 100644 tests/annulus_transient.prm.bak create mode 100644 tests/artificial_postprocess.cc.bak create mode 100644 tests/artificial_postprocess.prm.bak create mode 100644 tests/artificial_viscosity.prm.bak create mode 100644 tests/artificial_viscosity_dirichlet_boundaries.prm.bak create mode 100644 tests/artificial_viscosity_list.prm.bak create mode 100644 tests/ascii_boundary_member.cc.bak create mode 100644 tests/ascii_boundary_member.prm.bak create mode 100644 tests/ascii_data_adiabatic_conditions.prm.bak create mode 100644 tests/ascii_data_boundary_composition_2d_box_time.prm.bak create mode 100644 tests/ascii_data_boundary_composition_3d_box.prm.bak create mode 100644 tests/ascii_data_boundary_temperature_2d_box_time.prm.bak create mode 100644 tests/ascii_data_boundary_temperature_3d_box.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_2d_box.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_2d_box_list.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_2d_box_time.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_2d_box_time_backward.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_2d_box_time_non_equidistant.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_2d_chunk.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_2d_shell.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_2d_shell_spherical.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_3d_box.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_3d_chunk.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_3d_shell.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_3d_shell_spherical.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_3d_sphere.prm.bak create mode 100644 tests/ascii_data_boundary_velocity_residual_shell.prm.bak create mode 100644 tests/ascii_data_fail_1.prm.bak create mode 100644 tests/ascii_data_fail_2.prm.bak create mode 100644 tests/ascii_data_fail_3.prm.bak create mode 100644 tests/ascii_data_fail_4.prm.bak create mode 100644 tests/ascii_data_gravity.prm.bak create mode 100644 tests/ascii_data_initial_composition_2d_box.prm.bak create mode 100644 tests/ascii_data_initial_composition_2d_box_gz.prm.bak create mode 100644 tests/ascii_data_initial_composition_3d_chunk.prm.bak create mode 100644 tests/ascii_data_initial_composition_3d_shell.prm.bak create mode 100644 tests/ascii_data_initial_temperature_2d_box.prm.bak create mode 100644 tests/ascii_data_initial_temperature_3d_chunk.prm.bak create mode 100644 tests/ascii_data_initial_temperature_3d_ellipsoidal_chunk.prm.bak create mode 100644 tests/ascii_data_initial_temperature_3d_shell.prm.bak create mode 100644 tests/ascii_data_initial_temperature_3d_two_chunks.prm.bak create mode 100644 tests/ascii_data_layered_initial_composition_2d_box.prm.bak create mode 100644 tests/ascii_data_layered_initial_temperature_2d_box.prm.bak create mode 100644 tests/ascii_data_layered_initial_temperature_2d_chunk.prm.bak create mode 100644 tests/ascii_data_layered_initial_temperature_3d_box.prm.bak create mode 100644 tests/ascii_data_layered_initial_temperature_3d_chunk.prm.bak create mode 100644 tests/ascii_data_layered_initial_temperature_piecewise_constant_3d_box.prm.bak create mode 100644 tests/ascii_data_nonuniform_initial_composition_2d_box.prm.bak create mode 100644 tests/ascii_data_prescribed_stokes_2d_box.prm.bak create mode 100644 tests/ascii_data_slice.prm.bak create mode 100644 tests/ascii_data_slice_temperature.prm.bak create mode 100644 tests/average_arithmetic.prm.bak create mode 100644 tests/average_density_boundary_fluid_pressure.prm.bak create mode 100644 tests/average_geometric.prm.bak create mode 100644 tests/average_harmonic.prm.bak create mode 100644 tests/average_log.prm.bak create mode 100644 tests/average_none.prm.bak create mode 100644 tests/average_nwd_arithmetic.prm.bak create mode 100644 tests/average_nwd_geometric.prm.bak create mode 100644 tests/average_nwd_harmonic.prm.bak create mode 100644 tests/average_pick_largest.prm.bak create mode 100644 tests/average_project_to_q1.prm.bak create mode 100644 tests/background_output_writer.prm.bak create mode 100644 tests/backward_advection.prm.bak create mode 100644 tests/benchmark_layeredflow.cc.bak create mode 100644 tests/benchmark_layeredflow.prm.bak create mode 100644 tests/benchmark_particle_integration_scheme.prm.bak create mode 100644 tests/blankenbach.prm.bak create mode 100644 tests/blankenbach_approximation.prm.bak create mode 100644 tests/blankenbach_case1a.cc.bak create mode 100644 tests/blankenbach_case1a.prm.bak create mode 100644 tests/blankenbach_case1b.cc.bak create mode 100644 tests/blankenbach_case1b.prm.bak create mode 100644 tests/blankenbach_case1c.cc.bak create mode 100644 tests/blankenbach_case1c.prm.bak create mode 100644 tests/blankenbach_case2a.cc.bak create mode 100644 tests/blankenbach_case2a.prm.bak create mode 100644 tests/blankenbach_case2b.cc.bak create mode 100644 tests/blankenbach_case2b.prm.bak create mode 100644 tests/boukare_bulk_composition.prm.bak create mode 100644 tests/boukare_conserve_mass.prm.bak create mode 100644 tests/boukare_latent_heat.prm.bak create mode 100644 tests/boukare_melting_diagram.prm.bak create mode 100644 tests/boundary_composition_list.prm.bak create mode 100644 tests/boundary_composition_passive_cartesian.prm.bak create mode 100644 tests/boundary_composition_passive_depth.prm.bak create mode 100644 tests/boundary_composition_passive_sphere.prm.bak create mode 100644 tests/boundary_heatflux.prm.bak create mode 100644 tests/boundary_heatflux_update.cc.bak create mode 100644 tests/boundary_heatflux_update.prm.bak create mode 100644 tests/boundary_temperature_function.prm.bak create mode 100644 tests/boundary_temperature_list.prm.bak create mode 100644 tests/boundary_traction_function_cartesian_free_surface.prm.bak create mode 100644 tests/boundary_traction_function_spherical_free_surface.prm.bak create mode 100644 tests/boundary_velocity_function_spherical.prm.bak create mode 100644 tests/box_end_time_1e7_terminate.prm.bak create mode 100644 tests/box_first_time_step.prm.bak create mode 100644 tests/box_first_time_step_alternate_bc.prm.bak create mode 100644 tests/box_initial_mesh_deformation.cc.bak create mode 100644 tests/box_initial_mesh_deformation.prm.bak create mode 100644 tests/box_initial_mesh_deformation_ascii_data.prm.bak create mode 100644 tests/box_initial_mesh_deformation_periodic.cc.bak create mode 100644 tests/box_initial_mesh_deformation_periodic.prm.bak create mode 100644 tests/box_initial_topography_ascii_data.prm.bak create mode 100644 tests/box_initial_topography_ascii_data_moved_origin.prm.bak create mode 100644 tests/box_initial_topography_function.prm.bak create mode 100644 tests/box_initial_topography_prm_polygon.prm.bak create mode 100644 tests/box_lithostatic_pressure_2d.prm.bak create mode 100644 tests/box_lithostatic_pressure_3d.prm.bak create mode 100644 tests/box_origin.prm.bak create mode 100644 tests/box_repetitions.prm.bak create mode 100644 tests/box_simple_log_viscosity_depth_average.prm.bak create mode 100644 tests/box_simple_surface_strain_rate_residual.prm.bak create mode 100644 tests/box_steady_state_terminate.prm.bak create mode 100644 tests/box_steady_temperature_terminate.prm.bak create mode 100644 tests/box_surface_base_variables.prm.bak create mode 100644 tests/bunge_cookbook.prm.bak create mode 100644 tests/burnman_seismic_test.prm.bak create mode 100644 tests/burnman_test.prm.bak create mode 100644 tests/burstedde.cc.bak create mode 100644 tests/burstedde.prm.bak create mode 100644 tests/burstedde_stokes_rhs.cc.bak create mode 100644 tests/burstedde_stokes_rhs.prm.bak create mode 100644 tests/cell_reference.cc.bak create mode 100644 tests/cell_reference.prm.bak create mode 100644 tests/cells_in_circumference.prm.bak create mode 100644 tests/check_compositional_field_functions.cc.bak create mode 100644 tests/check_compositional_field_functions.prm.bak create mode 100644 tests/check_compositional_field_names.cc.bak create mode 100644 tests/check_compositional_field_names.prm.bak create mode 100644 tests/checkpoint_01.cc.bak create mode 100644 tests/checkpoint_01.prm.bak create mode 100644 tests/checkpoint_01_check_parameters.cc.bak create mode 100644 tests/checkpoint_01_check_parameters.prm.bak create mode 100644 tests/checkpoint_02.cc.bak create mode 100644 tests/checkpoint_02.prm.bak create mode 100644 tests/checkpoint_02_direct.cc.bak create mode 100644 tests/checkpoint_02_direct.prm.bak create mode 100644 tests/checkpoint_03_particles.cc.bak create mode 100644 tests/checkpoint_03_particles.prm.bak create mode 100644 tests/checkpoint_04_particles_no_output.cc.bak create mode 100644 tests/checkpoint_04_particles_no_output.prm.bak create mode 100644 tests/checkpoint_05_mpi_create.prm.bak create mode 100644 tests/checkpoint_05_mpi_resume.cc.bak create mode 100644 tests/checkpoint_05_mpi_resume.prm.bak create mode 100644 tests/checkpoint_06_spherical_shell.cc.bak create mode 100644 tests/checkpoint_06_spherical_shell.prm.bak create mode 100644 tests/checkpoint_07_enable_free_surface_create.prm.bak create mode 100644 tests/checkpoint_07_enable_free_surface_resume.cc.bak create mode 100644 tests/checkpoint_07_enable_free_surface_resume.prm.bak create mode 100644 tests/chunk_ascii_initial_temperature.prm.bak create mode 100644 tests/chunk_conditions.prm.bak create mode 100644 tests/chunk_cross_hemisphere.prm.bak create mode 100644 tests/chunk_first_time_step_2d.prm.bak create mode 100644 tests/chunk_first_time_step_3d.prm.bak create mode 100644 tests/chunk_initial_topography_ascii_data.prm.bak create mode 100644 tests/chunk_initial_topography_ascii_data_3d.prm.bak create mode 100644 tests/chunk_initial_topography_ascii_data_3d_colatitude.prm.bak create mode 100644 tests/chunk_lithostatic_pressure_2d.prm.bak create mode 100644 tests/chunk_lithostatic_pressure_2d_initial_topography.prm.bak create mode 100644 tests/chunk_tangential_velocity.prm.bak create mode 100644 tests/chunk_topography_postprocessor.prm.bak create mode 100644 tests/command_postprocessor.prm.bak create mode 100644 tests/compaction_length_refinement.prm.bak create mode 100644 tests/compaction_length_visualization.prm.bak create mode 100644 tests/composite_viscous_outputs.cc.bak create mode 100644 tests/composite_viscous_outputs.prm.bak create mode 100644 tests/compositing_02.prm.bak create mode 100644 tests/compositing_named_outputs.prm.bak create mode 100644 tests/composition_active.prm.bak create mode 100644 tests/composition_active_nans.prm.bak create mode 100644 tests/composition_active_with_melt.cc.bak create mode 100644 tests/composition_active_with_melt.prm.bak create mode 100644 tests/composition_active_without_melt.cc.bak create mode 100644 tests/composition_active_without_melt.prm.bak create mode 100644 tests/composition_cg_dg_fem.prm.bak create mode 100644 tests/composition_names.prm.bak create mode 100644 tests/composition_names_duplicates.prm.bak create mode 100644 tests/composition_passive_discontinuous_constant.prm.bak create mode 100644 tests/composition_passive_particles.prm.bak create mode 100644 tests/composition_passive_quarter_shell_cartesian.prm.bak create mode 100644 tests/composition_passive_quarter_shell_depth.prm.bak create mode 100644 tests/composition_passive_quarter_shell_spherical.prm.bak create mode 100644 tests/composition_passive_static.prm.bak create mode 100644 tests/composition_reaction.prm.bak create mode 100644 tests/composition_reaction_iterated_IMPES.cc.bak create mode 100644 tests/composition_reaction_iterated_IMPES.prm.bak create mode 100644 tests/composition_stabilization.prm.bak create mode 100644 tests/compositional_boundary_values.prm.bak create mode 100644 tests/compositional_boundary_values_02.prm.bak create mode 100644 tests/compositional_boundary_values_03.prm.bak create mode 100644 tests/compositional_heating.prm.bak create mode 100644 tests/compositional_heating_exclude_background.prm.bak create mode 100644 tests/compositional_vectors.prm.bak create mode 100644 tests/compositional_vectors_3d.prm.bak create mode 100644 tests/compressibility.cc.bak create mode 100644 tests/compressibility.prm.bak create mode 100644 tests/compressibility_iterated_stokes.cc.bak create mode 100644 tests/compressibility_iterated_stokes.prm.bak create mode 100644 tests/compressibility_iterated_stokes_direct_solver.cc.bak create mode 100644 tests/compressibility_iterated_stokes_direct_solver.prm.bak create mode 100644 tests/compressibility_lateral_pipe.cc.bak create mode 100644 tests/compressibility_lateral_pipe.prm.bak create mode 100644 tests/compressibility_lateral_pipe_advect.cc.bak create mode 100644 tests/compressibility_lateral_pipe_advect.prm.bak create mode 100644 tests/compressibility_lateral_pipe_advect_projected_density.cc.bak create mode 100644 tests/compressibility_lateral_pipe_advect_projected_density.prm.bak create mode 100644 tests/compressibility_lateral_pipe_increase_pressure.cc.bak create mode 100644 tests/compressibility_lateral_pipe_increase_pressure.prm.bak create mode 100644 tests/compressibility_lateral_pipe_increase_pressure_projected_density.cc.bak create mode 100644 tests/compressibility_lateral_pipe_increase_pressure_projected_density.prm.bak create mode 100644 tests/compressibility_lateral_pipe_projected_density.cc.bak create mode 100644 tests/compressibility_lateral_pipe_projected_density.prm.bak create mode 100644 tests/compressibility_lateral_pipe_transient.cc.bak create mode 100644 tests/compressibility_lateral_pipe_transient.prm.bak create mode 100644 tests/compressibility_lateral_pipe_transient_projected_density.cc.bak create mode 100644 tests/compressibility_lateral_pipe_transient_projected_density.prm.bak create mode 100644 tests/compressibility_vertical_pipe.cc.bak create mode 100644 tests/compressibility_vertical_pipe.prm.bak create mode 100644 tests/compressibility_vertical_pipe_projected_density.cc.bak create mode 100644 tests/compressibility_vertical_pipe_projected_density.prm.bak create mode 100644 tests/compressibility_volumetric_strain_rate.cc.bak create mode 100644 tests/compressibility_volumetric_strain_rate.prm.bak create mode 100644 tests/compressible_forsterite_box.prm.bak create mode 100644 tests/compression_heating.cc.bak create mode 100644 tests/compression_heating.prm.bak create mode 100644 tests/compute-no-normal-flux-constraints.prm.bak create mode 100644 tests/conservative_with_mpi.cc.bak create mode 100644 tests/conservative_with_mpi.prm.bak create mode 100644 tests/consistent_boundary_flux_adjacent_dirichlet.prm.bak create mode 100644 tests/consistent_boundary_flux_neumann.prm.bak create mode 100644 tests/consistent_boundary_flux_open_boundary.prm.bak create mode 100644 tests/constant_composition_convergence.prm.bak create mode 100644 tests/constant_temperature_boundary_conditions.prm.bak create mode 100644 tests/continental_extension.prm.bak create mode 100644 tests/convection_box_particles.prm.bak create mode 100644 tests/convection_box_phase_function.prm.bak create mode 100644 tests/cookbook_mantle_convection_annulus.prm.bak create mode 100644 tests/cookbook_simpler_with_crust.cc.bak create mode 100644 tests/coordinate_transformation.cc.bak create mode 100644 tests/coordinate_transformation.prm.bak create mode 100644 tests/coupled_two_phase_tian_parameterization_kinematic_slab.prm.bak create mode 100644 tests/cpo_simple_shearbox.prm.bak create mode 100644 tests/crameri_benchmark_1_gmg.cc.bak create mode 100644 tests/crameri_benchmark_1_gmg.prm.bak create mode 100644 tests/crustal_model_3D.prm.bak create mode 100644 tests/custom_spherical_shell_2d_list.prm.bak create mode 100644 tests/custom_spherical_shell_2d_slices.prm.bak create mode 100644 tests/custom_spherical_shell_3d_list.prm.bak create mode 100644 tests/custom_spherical_shell_3d_slices.prm.bak create mode 100644 tests/damped_viscoelastic_bending_beam.prm.bak create mode 100644 tests/darcy_velocity.cc.bak create mode 100644 tests/darcy_velocity.prm.bak create mode 100644 tests/darcy_velocity_vertical.cc.bak create mode 100644 tests/darcy_velocity_vertical.prm.bak create mode 100644 tests/dash_dash.cc.bak create mode 100644 tests/dash_dash.prm.bak create mode 100644 tests/dc_Picard_compressible.prm.bak create mode 100644 tests/density_boundary.prm.bak create mode 100644 tests/depth_average_01.prm.bak create mode 100644 tests/depth_average_02.prm.bak create mode 100644 tests/depth_average_03.prm.bak create mode 100644 tests/depth_average_04.prm.bak create mode 100644 tests/depth_average_05.prm.bak create mode 100644 tests/depth_average_06.prm.bak create mode 100644 tests/depth_average_rounding_bug.prm.bak create mode 100644 tests/depth_average_txt_output.prm.bak create mode 100644 tests/depth_average_underres.prm.bak create mode 100644 tests/depth_dependent_3d_shell_list_simple.prm.bak create mode 100644 tests/depth_dependent_additional_outputs.prm.bak create mode 100644 tests/depth_dependent_box_file_simple.prm.bak create mode 100644 tests/depth_dependent_box_function_simple.prm.bak create mode 100644 tests/depth_dependent_box_function_time_dependent.prm.bak create mode 100644 tests/depth_dependent_box_none_simple.prm.bak create mode 100644 tests/depth_dependent_initialize_base_model.prm.bak create mode 100644 tests/depth_postprocessor_box.prm.bak create mode 100644 tests/depth_postprocessor_chunk.prm.bak create mode 100644 tests/depth_postprocessor_ellipsoidal_chunk.prm.bak create mode 100644 tests/depth_postprocessor_sphere.prm.bak create mode 100644 tests/depth_postprocessor_spherical_shell.prm.bak create mode 100644 tests/depth_postprocessor_two_merged_boxes.prm.bak create mode 100644 tests/derivative_of_weighted_p_norm_average.cc.bak create mode 100644 tests/derivative_of_weighted_p_norm_average.prm.bak create mode 100644 tests/diffusion.prm.bak create mode 100644 tests/diffusion_dislocation.prm.bak create mode 100644 tests/diffusion_dislocation_fixed_strain_rate.prm.bak create mode 100644 tests/diffusion_dislocation_fixed_strain_rate2.prm.bak create mode 100644 tests/diffusion_dislocation_reference_density_profile.prm.bak create mode 100644 tests/diffusion_velocity.prm.bak create mode 100644 tests/direct_solver_1.prm.bak create mode 100644 tests/direct_solver_2.prm.bak create mode 100644 tests/discontinuous_composition_1.prm.bak create mode 100644 tests/discontinuous_composition_bound_preserving_limiter.prm.bak create mode 100644 tests/discontinuous_composition_bound_preserving_limiter_3d.prm.bak create mode 100644 tests/discontinuous_composition_bound_preserving_limiter_selected_fields.prm.bak create mode 100644 tests/discontinuous_composition_serial_periodic_amr.prm.bak create mode 100644 tests/discontinuous_temperature.prm.bak create mode 100644 tests/discontinuous_temperature_blankenbach.cc.bak create mode 100644 tests/discontinuous_temperature_blankenbach.prm.bak create mode 100644 tests/discontinuous_temperature_spherical_shell_3d.prm.bak create mode 100644 tests/doneahuerta_3.cc.bak create mode 100644 tests/doneahuerta_3.prm.bak create mode 100644 tests/drucker_prager_compression.prm.bak create mode 100644 tests/drucker_prager_derivatives_2d.cc.bak create mode 100644 tests/drucker_prager_derivatives_2d.prm.bak create mode 100644 tests/drucker_prager_derivatives_3d.cc.bak create mode 100644 tests/drucker_prager_derivatives_3d.prm.bak create mode 100644 tests/drucker_prager_extension.prm.bak create mode 100644 tests/dynamic_core.prm.bak create mode 100644 tests/dynamic_friction.prm.bak create mode 100644 tests/dynamic_topography.prm.bak create mode 100644 tests/dynamic_topography2.prm.bak create mode 100644 tests/dynamic_topography3.prm.bak create mode 100644 tests/dynamic_topography_back.prm.bak create mode 100644 tests/dynamic_topography_vs_surface_dynamic_topography.prm.bak create mode 100644 tests/edit_parameters.cc.bak create mode 100644 tests/edit_parameters.prm.bak create mode 100644 tests/elastic_stabilization_time_scale_factor.prm.bak create mode 100644 tests/ellipsoidal_chunk_coordinate_parallel.prm.bak create mode 100644 tests/ellipsoidal_chunk_geometry.cc.bak create mode 100644 tests/ellipsoidal_chunk_geometry.prm.bak create mode 100644 tests/ellipsoidal_chunk_noncoordinate_parallel.prm.bak create mode 100644 tests/ellipsoidal_chunk_topography.prm.bak create mode 100644 tests/entropy_adiabat.cc.bak create mode 100644 tests/entropy_adiabat.prm.bak create mode 100644 tests/entropy_conduction.cc.bak create mode 100644 tests/entropy_conduction.prm.bak create mode 100644 tests/entropy_half_space.cc.bak create mode 100644 tests/entropy_half_space.prm.bak create mode 100644 tests/entropy_initial_lookup.cc.bak create mode 100644 tests/entropy_initial_lookup.prm.bak create mode 100644 tests/entropy_initial_lookup_wb.cc.bak create mode 100644 tests/entropy_initial_lookup_wb.prm.bak create mode 100644 tests/entropy_plasticity.cc.bak create mode 100644 tests/entropy_plasticity.prm.bak create mode 100644 tests/entropy_read_multi_table.cc.bak create mode 100644 tests/entropy_read_multi_table.prm.bak create mode 100644 tests/entropy_viscosity_statistics.prm.bak create mode 100644 tests/exponential_decay.cc.bak create mode 100644 tests/exponential_decay.prm.bak create mode 100644 tests/fail.prm.bak create mode 100644 tests/find_boundary_composition_model.cc.bak create mode 100644 tests/find_boundary_composition_model.prm.bak create mode 100644 tests/find_boundary_composition_model_fail_1.cc.bak create mode 100644 tests/find_boundary_composition_model_fail_1.prm.bak create mode 100644 tests/find_mesh_refinement.cc.bak create mode 100644 tests/find_mesh_refinement.prm.bak create mode 100644 tests/find_mesh_refinement_fail_1.cc.bak create mode 100644 tests/find_mesh_refinement_fail_1.prm.bak create mode 100644 tests/find_postprocess.cc.bak create mode 100644 tests/find_postprocess.prm.bak create mode 100644 tests/find_postprocess_fail_1.cc.bak create mode 100644 tests/find_postprocess_fail_1.prm.bak create mode 100644 tests/free_surface_VE_cylinder_2D_loading_fixed_elastic_dt_gmg.prm.bak create mode 100644 tests/free_surface_adaptive_blob.prm.bak create mode 100644 tests/free_surface_blob.prm.bak create mode 100644 tests/free_surface_blob_gmg.prm.bak create mode 100644 tests/free_surface_blob_melt.cc.bak create mode 100644 tests/free_surface_blob_melt.prm.bak create mode 100644 tests/free_surface_blob_nonzero_melt.cc.bak create mode 100644 tests/free_surface_blob_nonzero_melt.prm.bak create mode 100644 tests/free_surface_iterated_IMPES.prm.bak create mode 100644 tests/free_surface_iterated_stokes.prm.bak create mode 100644 tests/free_surface_iterated_stokes_gmg.prm.bak create mode 100644 tests/free_surface_relaxation.cc.bak create mode 100644 tests/free_surface_relaxation.prm.bak create mode 100644 tests/free_surface_tangential_mesh_velocity.prm.bak create mode 100644 tests/free_surface_tangential_mesh_velocity_2.prm.bak create mode 100644 tests/free_surface_timestep_repeat.prm.bak create mode 100644 tests/function_mesh_deformation_tangential_mesh_velocity.prm.bak create mode 100644 tests/gaussian_initial_temperature.prm.bak create mode 100644 tests/geoid.prm.bak create mode 100644 tests/geoid_freesurface.prm.bak create mode 100644 tests/geoid_no_topo.prm.bak create mode 100644 tests/geoid_visualization.prm.bak create mode 100644 tests/geometric_average_crash.prm.bak create mode 100644 tests/geometric_average_only_viscosity.prm.bak create mode 100644 tests/global_latent_heat.prm.bak create mode 100644 tests/global_melt.prm.bak create mode 100644 tests/global_melt_parallel.prm.bak create mode 100644 tests/global_refine_amr.cc.bak create mode 100644 tests/global_refine_amr.prm.bak create mode 100644 tests/global_refine_bug.prm.bak create mode 100644 tests/gmg_mesh_deform.prm.bak create mode 100644 tests/gmg_mesh_deform_adaptive.prm.bak create mode 100644 tests/gmg_mesh_deform_adaptive_bug.prm.bak create mode 100644 tests/gmg_mesh_deform_adaptive_bug2.prm.bak create mode 100644 tests/gmg_mesh_deform_function.prm.bak create mode 100644 tests/gmg_mesh_deform_ghost_entries.prm.bak create mode 100644 tests/gmg_mesh_deform_prescribed.cc.bak create mode 100644 tests/gmg_mesh_deform_prescribed.prm.bak create mode 100644 tests/gmg_mesh_deform_topo.prm.bak create mode 100644 tests/gmg_no_normal_flux_only.prm.bak create mode 100644 tests/gmg_test_project_q1.prm.bak create mode 100644 tests/gmg_velocity_boundary_2d_box_no_flux.prm.bak create mode 100644 tests/gmg_velocity_boundary_2d_box_no_normal_flux.prm.bak create mode 100644 tests/gmg_velocity_boundary_2d_chunk_no_flux.prm.bak create mode 100644 tests/gmg_velocity_boundary_2d_chunk_no_normal_flux.prm.bak create mode 100644 tests/gmg_velocity_boundary_3d_box_no_flux.prm.bak create mode 100644 tests/gmg_velocity_boundary_3d_box_no_normal_flux.prm.bak create mode 100644 tests/gmg_velocity_boundary_3d_chunk_no_flux.prm.bak create mode 100644 tests/gmg_velocity_boundary_3d_chunk_no_normal_flux.prm.bak create mode 100644 tests/gmg_velocity_boundary_component.prm.bak create mode 100644 tests/gplates_1_3.prm.bak create mode 100644 tests/gplates_1_4.prm.bak create mode 100644 tests/gplates_3d.prm.bak create mode 100644 tests/gplates_rotation.prm.bak create mode 100644 tests/gplates_scale_factor.prm.bak create mode 100644 tests/grain_lag_angle.prm.bak create mode 100644 tests/grain_size_additional_outputs.prm.bak create mode 100644 tests/grain_size_averaging.prm.bak create mode 100644 tests/grain_size_crossed_transition.prm.bak create mode 100644 tests/grain_size_friction_heating.prm.bak create mode 100644 tests/grain_size_growth.prm.bak create mode 100644 tests/grain_size_growth_one_cell.prm.bak create mode 100644 tests/grain_size_growth_one_cell_particles.prm.bak create mode 100644 tests/grain_size_growth_particles.prm.bak create mode 100644 tests/grain_size_growth_pinned.prm.bak create mode 100644 tests/grain_size_latent_heat.cc.bak create mode 100644 tests/grain_size_latent_heat.prm.bak create mode 100644 tests/grain_size_phase_function.prm.bak create mode 100644 tests/grain_size_plunge.prm.bak create mode 100644 tests/grain_size_ridge.prm.bak create mode 100644 tests/grain_size_ridge_traction.prm.bak create mode 100644 tests/grain_size_strain.prm.bak create mode 100644 tests/grain_size_strain_pinned.prm.bak create mode 100644 tests/grain_size_strain_pinned_state.prm.bak create mode 100644 tests/grain_size_yield.prm.bak create mode 100644 tests/graphical_output.cc.bak create mode 100644 tests/graphical_output.prm.bak create mode 100644 tests/graphical_output_02.prm.bak create mode 100644 tests/graphical_output_hdf5.cc.bak create mode 100644 tests/graphical_output_hdf5.prm.bak create mode 100644 tests/gravity_function.prm.bak create mode 100644 tests/gravity_function_time.prm.bak create mode 100644 tests/gravity_model_cartesian.prm.bak create mode 100644 tests/gravity_model_depth.prm.bak create mode 100644 tests/gravity_model_spherical.prm.bak create mode 100644 tests/gravity_point_values_list.prm.bak create mode 100644 tests/gravity_point_values_map.prm.bak create mode 100644 tests/gravity_point_values_spiral.prm.bak create mode 100644 tests/gravity_point_values_spiral_parallel.prm.bak create mode 100644 tests/gravity_prem.prm.bak create mode 100644 tests/gravity_quadrature_degree_increase.prm.bak create mode 100644 tests/gs_drucker_prager.prm.bak create mode 100644 tests/gs_drucker_prager_extension.prm.bak create mode 100644 tests/gs_drucker_prager_extension_adiabatic.prm.bak create mode 100644 tests/heat_advection_by_melt.cc.bak create mode 100644 tests/heat_advection_by_melt.prm.bak create mode 100644 tests/heat_advection_by_melt_operator_splitting.cc.bak create mode 100644 tests/heat_advection_by_melt_operator_splitting.prm.bak create mode 100644 tests/heat_flow.prm.bak create mode 100644 tests/heat_flow_plume.prm.bak create mode 100644 tests/heat_flux_densities.prm.bak create mode 100644 tests/heat_flux_map.prm.bak create mode 100644 tests/heat_flux_map_vis.prm.bak create mode 100644 tests/heat_flux_map_vis_point_wise.prm.bak create mode 100644 tests/heating_function.prm.bak create mode 100644 tests/heating_function_depth.prm.bak create mode 100644 tests/heating_function_spherical.prm.bak create mode 100644 tests/hexagonal_initial_temperature.prm.bak create mode 100644 tests/hill_diffusion.prm.bak create mode 100644 tests/hill_diffusion_3D.prm.bak create mode 100644 tests/hk04_olivine_composite_hydration_prefactor.prm.bak create mode 100644 tests/hk04_olivine_composite_hydration_prefactor_cutoff.prm.bak create mode 100644 tests/hk04_olivine_diffusion_hydration_prefactor.prm.bak create mode 100644 tests/hk04_olivine_dislocation_hydration_prefactor.prm.bak create mode 100644 tests/hollow_sphere.cc.bak create mode 100644 tests/hollow_sphere.prm.bak create mode 100644 tests/hollow_sphere_gmg.cc.bak create mode 100644 tests/hollow_sphere_gmg.prm.bak create mode 100644 tests/hollow_sphere_gmg_project_q1.cc.bak create mode 100644 tests/hollow_sphere_gmg_project_q1.prm.bak create mode 100644 tests/hollow_sphere_gmg_q3.cc.bak create mode 100644 tests/hollow_sphere_gmg_q3.prm.bak create mode 100644 tests/hydrostatic_compression.cc.bak create mode 100644 tests/hydrostatic_compression.prm.bak create mode 100644 tests/inclusion_2.cc.bak create mode 100644 tests/inclusion_2.prm.bak create mode 100644 tests/inclusion_4.cc.bak create mode 100644 tests/inclusion_4.prm.bak create mode 100644 tests/inclusion_adaptive.cc.bak create mode 100644 tests/inclusion_adaptive.prm.bak create mode 100644 tests/infill_density_flexure.cc.bak create mode 100644 tests/infill_density_flexure.prm.bak create mode 100644 tests/initial_composition_list.prm.bak create mode 100644 tests/initial_composition_list_using_maximum.prm.bak create mode 100644 tests/initial_composition_list_using_minimum.prm.bak create mode 100644 tests/initial_composition_list_using_subtract.prm.bak create mode 100644 tests/initial_condition_S20RTS.prm.bak create mode 100644 tests/initial_condition_S20RTS_2D.prm.bak create mode 100644 tests/initial_condition_S20RTS_dgp.prm.bak create mode 100644 tests/initial_condition_S40RTS.prm.bak create mode 100644 tests/initial_condition_SAVANI.prm.bak create mode 100644 tests/initial_condition_lithosphere_mask.prm.bak create mode 100644 tests/initial_condition_patch_on_S40RTS.prm.bak create mode 100644 tests/initial_condition_vs_to_density.prm.bak create mode 100644 tests/initial_condition_vs_to_density_SAVANI.prm.bak create mode 100644 tests/initial_global_refinement.prm.bak create mode 100644 tests/initial_porosity.prm.bak create mode 100644 tests/initial_temperature_list.prm.bak create mode 100644 tests/initial_temperature_list_using_maximum.prm.bak create mode 100644 tests/initial_temperature_list_using_minimum.prm.bak create mode 100644 tests/initial_temperature_list_using_subtract.prm.bak create mode 100644 tests/initial_temperature_profile.prm.bak create mode 100644 tests/inner_core.cc.bak create mode 100644 tests/inner_core.prm.bak create mode 100644 tests/internal_heating_statistics.prm.bak create mode 100644 tests/interpolor_particles_harmonic_average.prm.bak create mode 100644 tests/interpolor_particles_nearest_neighbor.prm.bak create mode 100644 tests/interpolor_particles_quadratic_least_squares.prm.bak create mode 100644 tests/isosurfaces_simple_box_2D.prm.bak create mode 100644 tests/isosurfaces_simple_box_2D_custom_fieldnames.prm.bak create mode 100644 tests/isosurfaces_simple_box_2D_custom_fieldnames_fail.prm.bak create mode 100644 tests/isosurfaces_simple_box_2D_min_max_1.prm.bak create mode 100644 tests/isosurfaces_simple_box_2D_min_max_2.prm.bak create mode 100644 tests/isosurfaces_simple_box_3D.prm.bak create mode 100644 tests/isosurfaces_slab_2D.prm.bak create mode 100644 tests/isosurfaces_slab_3D.prm.bak create mode 100644 tests/iterated_advection_and_defect_correction_Stokes.prm.bak create mode 100644 tests/iterated_advection_and_stokes.prm.bak create mode 100644 tests/iterated_advection_and_stokes_DG.prm.bak create mode 100644 tests/iterated_advection_and_stokes_DG_limiter.prm.bak create mode 100644 tests/iterated_advection_and_stokes_direct_solver.prm.bak create mode 100644 tests/iterated_advection_and_stokes_residual.prm.bak create mode 100644 tests/kaus_rayleigh_taylor_instability.prm.bak create mode 100644 tests/kinematically_driven_subduction_2d_case1.prm.bak create mode 100644 tests/kinematically_driven_subduction_2d_case2a.cc.bak create mode 100644 tests/kinematically_driven_subduction_2d_case2a.prm.bak create mode 100644 tests/kinematically_driven_subduction_2d_case2b.cc.bak create mode 100644 tests/kinematically_driven_subduction_2d_case2b.prm.bak create mode 100644 tests/king_ala.cc.bak create mode 100644 tests/king_ala.prm.bak create mode 100644 tests/king_ala_nondim.prm.bak create mode 100644 tests/latent_heat.prm.bak create mode 100644 tests/latent_heat_composition.prm.bak create mode 100644 tests/latent_heat_enthalpy.cc.bak create mode 100644 tests/latent_heat_enthalpy.prm.bak create mode 100644 tests/latent_heat_melt.prm.bak create mode 100644 tests/latent_heat_melt_operator_split.prm.bak create mode 100644 tests/latent_heat_melt_statistics.prm.bak create mode 100644 tests/latent_heat_melt_transport.prm.bak create mode 100644 tests/latent_heat_pressure.prm.bak create mode 100644 tests/latent_heat_viscosity.prm.bak create mode 100644 tests/latent_heat_viscosity_adiabatic.prm.bak create mode 100644 tests/lithosphere_boundary_indicator.prm.bak create mode 100644 tests/lithosphere_boundary_indicator_3d.prm.bak create mode 100644 tests/lithosphere_boundary_indicator_3d_one_grid.prm.bak create mode 100644 tests/lithosphere_boundary_indicator_3d_periodic.prm.bak create mode 100644 tests/lithosphere_boundary_indicator_one_grid.prm.bak create mode 100644 tests/lithosphere_boundary_indicator_origin.prm.bak create mode 100644 tests/logo.prm.bak create mode 100644 tests/magnetic_stripes.cc.bak create mode 100644 tests/magnetic_stripes.prm.bak create mode 100644 tests/mass_flux_statistics.prm.bak create mode 100644 tests/mass_reaction_term.prm.bak create mode 100644 tests/material_model_dependencies.cc.bak create mode 100644 tests/material_model_dependencies_burstedde.cc.bak create mode 100644 tests/material_model_dependencies_burstedde.prm.bak create mode 100644 tests/material_model_dependencies_composition_reaction.cc.bak create mode 100644 tests/material_model_dependencies_composition_reaction.prm.bak create mode 100644 tests/material_model_dependencies_cookbooks_freesurface_with_crust.cc.bak create mode 100644 tests/material_model_dependencies_cookbooks_freesurface_with_crust.prm.bak create mode 100644 tests/material_model_dependencies_diffusion_dislocation.cc.bak create mode 100644 tests/material_model_dependencies_diffusion_dislocation.prm.bak create mode 100644 tests/material_model_dependencies_inclusion_2.cc.bak create mode 100644 tests/material_model_dependencies_inclusion_2.prm.bak create mode 100644 tests/material_model_dependencies_latent_heat.cc.bak create mode 100644 tests/material_model_dependencies_latent_heat.prm.bak create mode 100644 tests/material_model_dependencies_latent_heat_melt.cc.bak create mode 100644 tests/material_model_dependencies_latent_heat_melt.prm.bak create mode 100644 tests/material_model_dependencies_morency_doin.cc.bak create mode 100644 tests/material_model_dependencies_morency_doin.prm.bak create mode 100644 tests/material_model_dependencies_multicomponent.cc.bak create mode 100644 tests/material_model_dependencies_multicomponent.prm.bak create mode 100644 tests/material_model_dependencies_shear_thinning.cc.bak create mode 100644 tests/material_model_dependencies_shear_thinning.prm.bak create mode 100644 tests/material_model_dependencies_simple.cc.bak create mode 100644 tests/material_model_dependencies_simple.prm.bak create mode 100644 tests/material_model_dependencies_simple_compressible.cc.bak create mode 100644 tests/material_model_dependencies_simple_compressible.prm.bak create mode 100644 tests/material_model_dependencies_simpler.cc.bak create mode 100644 tests/material_model_dependencies_simpler.prm.bak create mode 100644 tests/material_model_dependencies_solcx.cc.bak create mode 100644 tests/material_model_dependencies_solcx.prm.bak create mode 100644 tests/material_model_dependencies_solkz.cc.bak create mode 100644 tests/material_model_dependencies_solkz.prm.bak create mode 100644 tests/material_model_dependencies_steinberger.cc.bak create mode 100644 tests/material_model_dependencies_steinberger.prm.bak create mode 100644 tests/material_model_dependencies_tangurnis.cc.bak create mode 100644 tests/material_model_dependencies_tangurnis.prm.bak create mode 100644 tests/material_statistics.prm.bak create mode 100644 tests/matrix_nonzeros_1.prm.bak create mode 100644 tests/matrix_nonzeros_2.prm.bak create mode 100644 tests/matrix_nonzeros_3.prm.bak create mode 100644 tests/matrix_nonzeros_4.prm.bak create mode 100644 tests/matrix_nonzeros_5.prm.bak create mode 100644 tests/matrix_nonzeros_6.prm.bak create mode 100644 tests/matrix_nonzeros_7.prm.bak create mode 100644 tests/max_timesteps_btwn_output.prm.bak create mode 100644 tests/maximum_horizontal_compressive_stress_case_one.prm.bak create mode 100644 tests/maximum_horizontal_compressive_stress_case_two.prm.bak create mode 100644 tests/maximum_refinement_function.prm.bak create mode 100644 tests/maximum_refinement_function_cartesian.prm.bak create mode 100644 tests/maximum_refinement_function_spherical.prm.bak create mode 100644 tests/maxtimestep.prm.bak create mode 100644 tests/melt_and_traction.prm.bak create mode 100644 tests/melt_boukare_EOS.prm.bak create mode 100644 tests/melt_boukare_averaging.prm.bak create mode 100644 tests/melt_boundary_heat_flux.cc.bak create mode 100644 tests/melt_boundary_heat_flux.prm.bak create mode 100644 tests/melt_compressible_advection.cc.bak create mode 100644 tests/melt_compressible_advection.prm.bak create mode 100644 tests/melt_force_vector.cc.bak create mode 100644 tests/melt_force_vector.prm.bak create mode 100644 tests/melt_fraction_postprocessor.prm.bak create mode 100644 tests/melt_introspection.cc.bak create mode 100644 tests/melt_introspection.prm.bak create mode 100644 tests/melt_material_1.cc.bak create mode 100644 tests/melt_material_1.prm.bak create mode 100644 tests/melt_material_2.cc.bak create mode 100644 tests/melt_material_2.prm.bak create mode 100644 tests/melt_material_3.cc.bak create mode 100644 tests/melt_material_3.prm.bak create mode 100644 tests/melt_material_4.cc.bak create mode 100644 tests/melt_material_4.prm.bak create mode 100644 tests/melt_postprocessor_peridotite.prm.bak create mode 100644 tests/melt_postprocessor_pyroxenite.prm.bak create mode 100644 tests/melt_property_visualization.cc.bak create mode 100644 tests/melt_property_visualization.prm.bak create mode 100644 tests/melt_restart.cc.bak create mode 100644 tests/melt_restart.prm.bak create mode 100644 tests/melt_statistics.prm.bak create mode 100644 tests/melt_track.cc.bak create mode 100644 tests/melt_track.prm.bak create mode 100644 tests/melt_transport.prm.bak create mode 100644 tests/melt_transport_adaptive.cc.bak create mode 100644 tests/melt_transport_adaptive.prm.bak create mode 100644 tests/melt_transport_compressible.cc.bak create mode 100644 tests/melt_transport_compressible.prm.bak create mode 100644 tests/melt_transport_compressible_iterative.cc.bak create mode 100644 tests/melt_transport_compressible_iterative.prm.bak create mode 100644 tests/melt_transport_convergence_simple.cc.bak create mode 100644 tests/melt_transport_convergence_simple.prm.bak create mode 100644 tests/melt_transport_convergence_test.cc.bak create mode 100644 tests/melt_transport_convergence_test.prm.bak create mode 100644 tests/melt_velocity_boundary_conditions.cc.bak create mode 100644 tests/melt_velocity_boundary_conditions.prm.bak create mode 100644 tests/melt_visco_plastic.cc.bak create mode 100644 tests/melt_visco_plastic_mohr_circle_compaction.cc.bak create mode 100644 tests/melt_visco_plastic_mohr_circle_compaction.prm.bak create mode 100644 tests/melt_visco_plastic_mohr_circle_shear.cc.bak create mode 100644 tests/melt_visco_plastic_mohr_circle_shear.prm.bak create mode 100644 tests/melting_rate.cc.bak create mode 100644 tests/melting_rate.prm.bak create mode 100644 tests/melting_rate_operator_splitting.prm.bak create mode 100644 tests/melting_rate_operator_splitting2.prm.bak create mode 100644 tests/melting_rate_test.prm.bak create mode 100644 tests/memory_statistics_1.prm.bak create mode 100644 tests/merged_chunks_2D.prm.bak create mode 100644 tests/merged_chunks_2D_one_grid.prm.bak create mode 100644 tests/merged_chunks_3D.prm.bak create mode 100644 tests/merged_chunks_3D_one_grid.prm.bak create mode 100644 tests/mesh_deformation_gmg_2d_spherical_shell.prm.bak create mode 100644 tests/mesh_deformation_particles.cc.bak create mode 100644 tests/mesh_deformation_particles.prm.bak create mode 100644 tests/mesh_velocity_output.prm.bak create mode 100644 tests/mid_ocean_ridge.prm.bak create mode 100644 tests/minimum_refinement_function.prm.bak create mode 100644 tests/minimum_refinement_function_cartesian.prm.bak create mode 100644 tests/minimum_refinement_function_spherical.prm.bak create mode 100644 tests/minimum_refinement_function_time_dependent.prm.bak create mode 100644 tests/modified_tait_forsterite_box.prm.bak create mode 100644 tests/morency_doin.cc.bak create mode 100644 tests/morency_doin.prm.bak create mode 100644 tests/multicomponent_arithmetic.prm.bak create mode 100644 tests/multicomponent_compressible_averaging.prm.bak create mode 100644 tests/multicomponent_geometric.prm.bak create mode 100644 tests/multicomponent_harmonic.prm.bak create mode 100644 tests/multicomponent_max_composition.prm.bak create mode 100644 tests/multicomponent_steinberger.prm.bak create mode 100644 tests/multiple_named_additional_outputs.cc.bak create mode 100644 tests/multiple_named_additional_outputs.prm.bak create mode 100644 tests/muparser-temperature-example.prm.bak create mode 100644 tests/n_expensive_stokes_solver_steps.prm.bak create mode 100644 tests/natural_coordinates_conversion.cc.bak create mode 100644 tests/natural_coordinates_conversion.prm.bak create mode 100644 tests/netcdf_boundary_velocity_2d_box.prm.bak create mode 100644 tests/newton_postprocess_nonlinear.prm.bak create mode 100644 tests/no_Advection_iterated_defect_correction_Stokes.prm.bak create mode 100644 tests/no_adiabatic_heating.cc.bak create mode 100644 tests/no_adiabatic_heating.prm.bak create mode 100644 tests/no_adiabatic_heating_02.cc.bak create mode 100644 tests/no_adiabatic_heating_02.prm.bak create mode 100644 tests/no_adiabatic_heating_03.cc.bak create mode 100644 tests/no_adiabatic_heating_03.prm.bak create mode 100644 tests/no_cheap_gmg.cc.bak create mode 100644 tests/no_cheap_gmg.prm.bak create mode 100644 tests/no_conduction_timestep.prm.bak create mode 100644 tests/no_dirichlet_on_outflow.prm.bak create mode 100644 tests/no_dirichlet_on_outflow_C.prm.bak create mode 100644 tests/no_dirichlet_on_outflow_adaptive.prm.bak create mode 100644 tests/no_dirichlet_on_outflow_melt.cc.bak create mode 100644 tests/no_dirichlet_on_outflow_melt.prm.bak create mode 100644 tests/no_dirichlet_on_outflow_only_new_constraints.prm.bak create mode 100644 tests/no_dirichlet_on_outflow_refine.prm.bak create mode 100644 tests/no_flow.prm.bak create mode 100644 tests/non_conservative_with_mpi.cc.bak create mode 100644 tests/non_conservative_with_mpi.prm.bak create mode 100644 tests/nonlinear_channel_flow_tractions_Newton_Stokes.cc.bak create mode 100644 tests/nonlinear_channel_flow_tractions_Newton_Stokes.prm.bak create mode 100644 tests/nonlinear_channel_flow_tractions_Newton_Stokes_GMG.cc.bak create mode 100644 tests/nonlinear_channel_flow_tractions_Newton_Stokes_GMG.prm.bak create mode 100644 tests/nonlinear_channel_flow_tractions_Newton_Stokes_no_deviator.cc.bak create mode 100644 tests/nonlinear_channel_flow_tractions_Newton_Stokes_no_deviator.prm.bak create mode 100644 tests/nonlinear_channel_flow_tractions_Newton_Stokes_no_line_search.cc.bak create mode 100644 tests/nonlinear_channel_flow_tractions_Newton_Stokes_no_line_search.prm.bak create mode 100644 tests/nonlinear_channel_flow_tractions_Newton_Stokes_particles.cc.bak create mode 100644 tests/nonlinear_channel_flow_tractions_Newton_Stokes_particles.prm.bak create mode 100644 tests/nonlinear_channel_flow_tractions_dc_picard_Stokes_GMG.cc.bak create mode 100644 tests/nonlinear_channel_flow_tractions_dc_picard_Stokes_GMG.prm.bak create mode 100644 tests/nonlinear_channel_flow_tractions_iterated_IMPES.cc.bak create mode 100644 tests/nonlinear_channel_flow_tractions_iterated_IMPES.prm.bak create mode 100644 tests/nonlinear_channel_flow_velocities_Newton_Stokes.cc.bak create mode 100644 tests/nonlinear_channel_flow_velocities_Newton_Stokes.prm.bak create mode 100644 tests/nonlinear_channel_flow_velocities_Newton_Stokes_GMG.cc.bak create mode 100644 tests/nonlinear_channel_flow_velocities_Newton_Stokes_GMG.prm.bak create mode 100644 tests/nonlinear_channel_flow_velocities_Newton_Stokes_no_derivative.cc.bak create mode 100644 tests/nonlinear_channel_flow_velocities_Newton_Stokes_no_derivative.prm.bak create mode 100644 tests/nonlinear_channel_flow_velocities_Newton_Stokes_no_derivative_EW.cc.bak create mode 100644 tests/nonlinear_channel_flow_velocities_Newton_Stokes_no_derivative_EW.prm.bak create mode 100644 tests/nonlinear_channel_flow_velocities_Newton_Stokes_no_deviator.cc.bak create mode 100644 tests/nonlinear_channel_flow_velocities_Newton_Stokes_no_deviator.prm.bak create mode 100644 tests/nonlinear_channel_flow_velocities_Newton_Stokes_no_line_search.cc.bak create mode 100644 tests/nonlinear_channel_flow_velocities_Newton_Stokes_no_line_search.prm.bak create mode 100644 tests/nonlinear_channel_flow_velocities_iterated_IMPES.cc.bak create mode 100644 tests/nonlinear_channel_flow_velocities_iterated_IMPES.prm.bak create mode 100644 tests/nonlinear_channel_flow_velocities_single_advection_Newton_Stokes.cc.bak create mode 100644 tests/nonlinear_channel_flow_velocities_single_advection_Newton_Stokes.prm.bak create mode 100644 tests/nonlinear_convergence_for_small_composition.cc.bak create mode 100644 tests/nonlinear_convergence_for_small_composition.prm.bak create mode 100644 tests/nonlinear_solver_history.cc.bak create mode 100644 tests/nonlinear_solver_history.prm.bak create mode 100644 tests/normalize_initial_composition.prm.bak create mode 100644 tests/normalize_pressure_volume.prm.bak create mode 100644 tests/nsinker.cc.bak create mode 100644 tests/nsinker.prm.bak create mode 100644 tests/nsinker_2d.cc.bak create mode 100644 tests/nsinker_2d.prm.bak create mode 100644 tests/nsinker_bfbt.cc.bak create mode 100644 tests/nsinker_bfbt.prm.bak create mode 100644 tests/nsinker_gmg_idr.cc.bak create mode 100644 tests/nsinker_gmg_idr.prm.bak create mode 100644 tests/octagonal_initial_temperature.prm.bak create mode 100644 tests/octagonal_initial_temperature_ellipsoidal_chunk.prm.bak create mode 100644 tests/octagonal_initial_temperature_rotated.prm.bak create mode 100644 tests/onset_of_convection.prm.bak create mode 100644 tests/original_prm.prm.bak create mode 100644 tests/original_prm/original.prm.bak create mode 100644 tests/output_averaging_arithmetic.cc.bak create mode 100644 tests/output_averaging_arithmetic.prm.bak create mode 100644 tests/output_averaging_harmonic.cc.bak create mode 100644 tests/output_averaging_harmonic.prm.bak create mode 100644 tests/own_gravity.cc.bak create mode 100644 tests/own_gravity.prm.bak create mode 100644 tests/parallel_output_group_0.prm.bak create mode 100644 tests/parallel_output_group_1.prm.bak create mode 100644 tests/parallel_output_group_2.prm.bak create mode 100644 tests/parallel_refine_crash.prm.bak create mode 100644 tests/particle_count_statistics.cc.bak create mode 100644 tests/particle_count_statistics.prm.bak create mode 100644 tests/particle_exclude_all_properties.prm.bak create mode 100644 tests/particle_exclude_one_property.prm.bak create mode 100644 tests/particle_exclude_one_property_vtu.prm.bak create mode 100644 tests/particle_exclude_three_properties_vtu.prm.bak create mode 100644 tests/particle_exclude_two_properties_vtu.prm.bak create mode 100644 tests/particle_fast_evaluate_many_compositions.prm.bak create mode 100644 tests/particle_fast_evaluate_multiple_compositions.prm.bak create mode 100644 tests/particle_free_surface.prm.bak create mode 100644 tests/particle_generator_ascii.prm.bak create mode 100644 tests/particle_generator_box.prm.bak create mode 100644 tests/particle_generator_box_3d.prm.bak create mode 100644 tests/particle_generator_quadrature_points.prm.bak create mode 100644 tests/particle_generator_radial.prm.bak create mode 100644 tests/particle_generator_random_uniform.prm.bak create mode 100644 tests/particle_generator_random_uniform_3mpi_1particle.prm.bak create mode 100644 tests/particle_generator_random_uniform_3mpi_2particle.prm.bak create mode 100644 tests/particle_generator_random_uniform_3mpi_3particle.prm.bak create mode 100644 tests/particle_generator_random_uniform_3mpi_4particle.prm.bak create mode 100644 tests/particle_generator_random_uniform_deterministic_cell.prm.bak create mode 100644 tests/particle_generator_random_uniform_empty_rank.prm.bak create mode 100644 tests/particle_generator_reference_cell.prm.bak create mode 100644 tests/particle_handler_copy.cc.bak create mode 100644 tests/particle_handler_copy.prm.bak create mode 100644 tests/particle_initial_adaptive_output.prm.bak create mode 100644 tests/particle_initial_adaptive_refinement.prm.bak create mode 100644 tests/particle_integrator_euler.prm.bak create mode 100644 tests/particle_integrator_rk2_first_order_time.prm.bak create mode 100644 tests/particle_integrator_rk4.prm.bak create mode 100644 tests/particle_interpolator_bilinear_3d.prm.bak create mode 100644 tests/particle_interpolator_bilinear_3d_add_particles.prm.bak create mode 100644 tests/particle_interpolator_bilinear_add_particles.cc.bak create mode 100644 tests/particle_interpolator_bilinear_add_particles.prm.bak create mode 100644 tests/particle_interpolator_bilinear_least_squares_solkz.cc.bak create mode 100644 tests/particle_interpolator_bilinear_least_squares_solkz.prm.bak create mode 100644 tests/particle_interpolator_bilinear_limiter.prm.bak create mode 100644 tests/particle_interpolator_cell_average.prm.bak create mode 100644 tests/particle_interpolator_cell_average_2.prm.bak create mode 100644 tests/particle_interpolator_empty_cells.prm.bak create mode 100644 tests/particle_interpolator_from_ghost_cells.prm.bak create mode 100644 tests/particle_interpolator_harmonic_average_solkz.cc.bak create mode 100644 tests/particle_interpolator_harmonic_average_solkz.prm.bak create mode 100644 tests/particle_interpolator_nearest_neighbor.prm.bak create mode 100644 tests/particle_interpolator_quadratic_least_squares_2d_add_particles.cc.bak create mode 100644 tests/particle_interpolator_quadratic_least_squares_2d_add_particles.prm.bak create mode 100644 tests/particle_interpolator_quadratic_least_squares_2d_limiter.cc.bak create mode 100644 tests/particle_interpolator_quadratic_least_squares_2d_limiter.prm.bak create mode 100644 tests/particle_interpolator_quadratic_least_squares_2d_periodic.prm.bak create mode 100644 tests/particle_interpolator_quadratic_least_squares_3d.prm.bak create mode 100644 tests/particle_interpolator_time_dependence.prm.bak create mode 100644 tests/particle_linear_accelerated_flow_rk2.prm.bak create mode 100644 tests/particle_load_balancing_none.prm.bak create mode 100644 tests/particle_load_balancing_refinement.prm.bak create mode 100644 tests/particle_load_balancing_refinement_02.prm.bak create mode 100644 tests/particle_load_balancing_removal.prm.bak create mode 100644 tests/particle_load_balancing_removal_addition.prm.bak create mode 100644 tests/particle_load_balancing_removal_addition_properties.prm.bak create mode 100644 tests/particle_load_balancing_repartition.prm.bak create mode 100644 tests/particle_load_balancing_repartition_1000.prm.bak create mode 100644 tests/particle_melt_advection.cc.bak create mode 100644 tests/particle_melt_advection.prm.bak create mode 100644 tests/particle_output_gnuplot.prm.bak create mode 100644 tests/particle_output_hdf5.prm.bak create mode 100644 tests/particle_output_multiple_formats.prm.bak create mode 100644 tests/particle_output_none.prm.bak create mode 100644 tests/particle_output_vtu.prm.bak create mode 100644 tests/particle_output_vtu_group.prm.bak create mode 100644 tests/particle_output_vtu_temp.prm.bak create mode 100644 tests/particle_periodic_boundaries.prm.bak create mode 100644 tests/particle_periodic_boundaries_dc.prm.bak create mode 100644 tests/particle_periodic_boundaries_rk4.prm.bak create mode 100644 tests/particle_periodic_quarter_shell.prm.bak create mode 100644 tests/particle_periodic_quarter_shell_2.prm.bak create mode 100644 tests/particle_property_composition.cc.bak create mode 100644 tests/particle_property_composition.prm.bak create mode 100644 tests/particle_property_function.prm.bak create mode 100644 tests/particle_property_initial_composition.prm.bak create mode 100644 tests/particle_property_initial_composition_boundary.prm.bak create mode 100644 tests/particle_property_integrated_strain_invariant.prm.bak create mode 100644 tests/particle_property_integrated_strain_pure_shear.prm.bak create mode 100644 tests/particle_property_integrated_strain_simple_shear.prm.bak create mode 100644 tests/particle_property_multiple_functions.prm.bak create mode 100644 tests/particle_property_multiple_functions_with_interpolation.prm.bak create mode 100644 tests/particle_property_post_initialize_function.cc.bak create mode 100644 tests/particle_property_post_initialize_function.prm.bak create mode 100644 tests/particle_timing_information.prm.bak create mode 100644 tests/particle_visualization_particle_count.prm.bak create mode 100644 tests/particles_with_AMR_on.prm.bak create mode 100644 tests/passive_comp.prm.bak create mode 100644 tests/periodic_box.prm.bak create mode 100644 tests/periodic_box2.prm.bak create mode 100644 tests/periodic_box_freesurface.prm.bak create mode 100644 tests/periodic_box_gmg.prm.bak create mode 100644 tests/periodic_box_mpi4.prm.bak create mode 100644 tests/periodic_compressible.prm.bak create mode 100644 tests/periodic_linear_momentum.prm.bak create mode 100644 tests/periodic_quarter_shell.prm.bak create mode 100644 tests/plugin.cc.bak create mode 100644 tests/plugin.prm.bak create mode 100644 tests/plugin_dependency.cc.bak create mode 100644 tests/plugin_dependency.prm.bak create mode 100644 tests/plugin_dependency_redundant.cc.bak create mode 100644 tests/plugin_dependency_redundant.prm.bak create mode 100644 tests/plugin_dependency_redundant_02.cc.bak create mode 100644 tests/plugin_dependency_redundant_02.prm.bak create mode 100644 tests/point_value_01.prm.bak create mode 100644 tests/point_value_02.prm.bak create mode 100644 tests/point_value_02_mpi.prm.bak create mode 100644 tests/point_value_03.prm.bak create mode 100644 tests/point_value_natural_coordinates.prm.bak create mode 100644 tests/point_value_natural_coordinates_shell.prm.bak create mode 100644 tests/point_value_specific_output_times.prm.bak create mode 100644 tests/poiseuille_2d.prm.bak create mode 100644 tests/poiseuille_2d_horizontal_pressure_bc.prm.bak create mode 100644 tests/poiseuille_2d_pressure_bc.prm.bak create mode 100644 tests/poiseuille_2d_pressure_bc_gmg.prm.bak create mode 100644 tests/poiseuille_3d_x_horizontal_pressure_bc.prm.bak create mode 100644 tests/postprocess_initial.prm.bak create mode 100644 tests/postprocess_iterations_Stokes_only.cc.bak create mode 100644 tests/postprocess_iterations_Stokes_only.prm.bak create mode 100644 tests/postprocess_iterations_iterated_Stokes.cc.bak create mode 100644 tests/postprocess_iterations_iterated_Stokes.prm.bak create mode 100644 tests/postprocess_iterations_iterated_advection_and_stokes.prm.bak create mode 100644 tests/pre_data_out_build_patches.cc.bak create mode 100644 tests/pre_data_out_build_patches.prm.bak create mode 100644 tests/prescribed_dilation.cc.bak create mode 100644 tests/prescribed_dilation.prm.bak create mode 100644 tests/prescribed_dilation_gmg.cc.bak create mode 100644 tests/prescribed_dilation_gmg.prm.bak create mode 100644 tests/prescribed_dilation_newton.cc.bak create mode 100644 tests/prescribed_dilation_newton.prm.bak create mode 100644 tests/prescribed_dilation_newton_singleadvection.cc.bak create mode 100644 tests/prescribed_dilation_newton_singleadvection.prm.bak create mode 100644 tests/prescribed_field.cc.bak create mode 100644 tests/prescribed_field.prm.bak create mode 100644 tests/prescribed_field_temperature.cc.bak create mode 100644 tests/prescribed_field_temperature.prm.bak create mode 100644 tests/prescribed_field_temperature_max_isotherm.prm.bak create mode 100644 tests/prescribed_field_with_diffusion.cc.bak create mode 100644 tests/prescribed_field_with_diffusion.prm.bak create mode 100644 tests/prescribed_stokes_solution.prm.bak create mode 100644 tests/prescribed_stokes_solution_DG_periodic.prm.bak create mode 100644 tests/prescribed_stokes_solution_melt.prm.bak create mode 100644 tests/prescribed_temperature.cc.bak create mode 100644 tests/prescribed_temperature.prm.bak create mode 100644 tests/prescribed_temperature_in_field.cc.bak create mode 100644 tests/prescribed_temperature_in_field.prm.bak create mode 100644 tests/prescribed_temperature_with_diffusion.cc.bak create mode 100644 tests/prescribed_temperature_with_diffusion.prm.bak create mode 100644 tests/prescribed_velocity.cc.bak create mode 100644 tests/prescribed_velocity.prm.bak create mode 100644 tests/prescribed_velocity_boundary.cc.bak create mode 100644 tests/prescribed_velocity_boundary.prm.bak create mode 100644 tests/prescribed_velocity_dgp.cc.bak create mode 100644 tests/prescribed_velocity_dgp.prm.bak create mode 100644 tests/prescribed_viscosity_additional_outputs.prm.bak create mode 100644 tests/prescribed_viscosity_happy.prm.bak create mode 100644 tests/pressure_boundary.prm.bak create mode 100644 tests/pressure_compatibility.prm.bak create mode 100644 tests/pressure_compatibility_2.prm.bak create mode 100644 tests/pressure_compatibility_3.prm.bak create mode 100644 tests/pressure_compatibility_4.prm.bak create mode 100644 tests/pressure_compatibility_dg.prm.bak create mode 100644 tests/pressure_compatibility_dg_direct.prm.bak create mode 100644 tests/pressure_compatibility_direct.prm.bak create mode 100644 tests/pressure_constraint.cc.bak create mode 100644 tests/pressure_constraint.prm.bak create mode 100644 tests/pressure_scaling_signal.cc.bak create mode 100644 tests/pressure_scaling_signal.prm.bak create mode 100644 tests/principal_deviatoric_stress.cc.bak create mode 100644 tests/principal_deviatoric_stress.prm.bak create mode 100644 tests/prm_distance_polygon.cc.bak create mode 100644 tests/prm_distance_polygon.prm.bak create mode 100644 tests/prm_polygon_in_out.cc.bak create mode 100644 tests/prm_polygon_in_out.prm.bak create mode 100644 tests/prmbackslash.prm.bak create mode 100644 tests/prmbackslash_2.cc.bak create mode 100644 tests/prmbackslash_2.prm.bak create mode 100644 tests/projected_density_vertical_pipe.cc.bak create mode 100644 tests/projected_density_vertical_pipe.prm.bak create mode 100644 tests/pure_shear.cc.bak create mode 100644 tests/pure_shear.prm.bak create mode 100644 tests/q1_q1.cc.bak create mode 100644 tests/q1_q1.prm.bak create mode 100644 tests/q1_q1_6.cc.bak create mode 100644 tests/q1_q1_6.prm.bak create mode 100644 tests/quarter_shell_variable_coordinate_systems_cartesian.prm.bak create mode 100644 tests/quarter_shell_variable_coordinate_systems_depth.prm.bak create mode 100644 tests/quarter_shell_variable_coordinate_systems_spherical.prm.bak create mode 100644 tests/quick_mpi.cc.bak create mode 100644 tests/quick_mpi.prm.bak create mode 100644 tests/radioactive_decay.prm.bak create mode 100644 tests/radiogenic_heating.prm.bak create mode 100644 tests/random_perturbation_box.prm.bak create mode 100644 tests/random_perturbation_chunk.prm.bak create mode 100644 tests/random_perturbation_merged_boxes.prm.bak create mode 100644 tests/random_perturbation_sphere.prm.bak create mode 100644 tests/random_perturbation_spherical_shell.prm.bak create mode 100644 tests/reactive_fluid_transport_no_reaction.prm.bak create mode 100644 tests/reactive_fluid_transport_zero_solubility.prm.bak create mode 100644 tests/refine_vel.prm.bak create mode 100644 tests/refinement_artificial_viscosity_1.prm.bak create mode 100644 tests/refinement_artificial_viscosity_2.prm.bak create mode 100644 tests/refinement_artificial_viscosity_3.prm.bak create mode 100644 tests/refinement_boundary.prm.bak create mode 100644 tests/refinement_composition_gradient.prm.bak create mode 100644 tests/refinement_composition_threshold.prm.bak create mode 100644 tests/refinement_nonadiabatic_temperature.prm.bak create mode 100644 tests/refinement_strainrate.prm.bak create mode 100644 tests/refinement_switch.prm.bak create mode 100644 tests/refinement_topography.cc.bak create mode 100644 tests/refinement_topography.prm.bak create mode 100644 tests/remove_angular_momentum.prm.bak create mode 100644 tests/remove_angular_momentum_3d.prm.bak create mode 100644 tests/remove_net_rotation.prm.bak create mode 100644 tests/remove_net_rotation_3d.prm.bak create mode 100644 tests/remove_net_surface_rotation.prm.bak create mode 100644 tests/replace_lithosphere_viscosity_file.prm.bak create mode 100644 tests/resume_free_surface.cc.bak create mode 100644 tests/resume_free_surface.prm.bak create mode 100644 tests/rheology_scaled_profile.cc.bak create mode 100644 tests/rheology_scaled_profile.prm.bak create mode 100644 tests/rigid_shear_instantaneous.cc.bak create mode 100644 tests/rigid_shear_instantaneous.prm.bak create mode 100644 tests/rigid_shear_steady_state.cc.bak create mode 100644 tests/rigid_shear_steady_state.prm.bak create mode 100644 tests/rigid_shear_transient.cc.bak create mode 100644 tests/rigid_shear_transient.prm.bak create mode 100644 tests/rising_melt_blob.cc.bak create mode 100644 tests/rising_melt_blob.prm.bak create mode 100644 tests/rising_melt_blob_freezing.prm.bak create mode 100644 tests/rotation_statistics.prm.bak create mode 100644 tests/rotation_statistics_3d.prm.bak create mode 100644 tests/rotation_statistics_3d_asymmetric.prm.bak create mode 100644 tests/rotation_statistics_3d_surface.prm.bak create mode 100644 tests/sea_level_postprocessor.prm.bak create mode 100644 tests/segregation_heating.cc.bak create mode 100644 tests/segregation_heating.prm.bak create mode 100644 tests/shear_bands.cc.bak create mode 100644 tests/shear_bands.prm.bak create mode 100644 tests/shear_heating.prm.bak create mode 100644 tests/shear_heating_compressible.prm.bak create mode 100644 tests/shear_heating_compressible_melt.prm.bak create mode 100644 tests/shear_heating_limited.prm.bak create mode 100644 tests/shear_heating_with_melt.prm.bak create mode 100644 tests/shear_thinning.cc.bak create mode 100644 tests/shear_thinning.prm.bak create mode 100644 tests/shearbox_particle_strain_rate.prm.bak create mode 100644 tests/shell_2d_gmg.prm.bak create mode 100644 tests/shell_3d_gmg.prm.bak create mode 100644 tests/shell_boundary_composition_spherical_constant.prm.bak create mode 100644 tests/shell_quarter_BC.prm.bak create mode 100644 tests/shell_quarter_gmg.prm.bak create mode 100644 tests/shell_surface_base_variables.prm.bak create mode 100644 tests/shell_with_variable_coordinate_systems.prm.bak create mode 100644 tests/signal_fem.cc.bak create mode 100644 tests/signal_fem.prm.bak create mode 100644 tests/signals.cc.bak create mode 100644 tests/signals.prm.bak create mode 100644 tests/signals_connect.cc.bak create mode 100644 tests/signals_connect.prm.bak create mode 100644 tests/signals_post_constraints.cc.bak create mode 100644 tests/signals_post_constraints.prm.bak create mode 100644 tests/simple_composite.prm.bak create mode 100644 tests/simple_compressibility_iterated_stokes.cc.bak create mode 100644 tests/simple_compressibility_iterated_stokes.prm.bak create mode 100644 tests/simple_compressibility_iterated_stokes_gmg.cc.bak create mode 100644 tests/simple_compressibility_iterated_stokes_gmg.prm.bak create mode 100644 tests/simple_compressible.prm.bak create mode 100644 tests/simple_incompressible.prm.bak create mode 100644 tests/simple_nonlinear.cc.bak create mode 100644 tests/simple_nonlinear.prm.bak create mode 100644 tests/simple_shear.cc.bak create mode 100644 tests/simple_shear.prm.bak create mode 100644 tests/simple_shear_output_the_mobility.cc.bak create mode 100644 tests/simple_shear_output_the_mobility.prm.bak create mode 100644 tests/simpler_box.prm.bak create mode 100644 tests/simpler_composition.prm.bak create mode 100644 tests/single_Advection_iterated_defect_correction_Stokes.prm.bak create mode 100644 tests/sinking_block.cc.bak create mode 100644 tests/sinking_block.prm.bak create mode 100644 tests/skip_initial_conditions_setup_on_initial_refinement.prm.bak create mode 100644 tests/skip_refinement.prm.bak create mode 100644 tests/skip_solvers_on_initial_refinement.prm.bak create mode 100644 tests/slab2_initial_composition_3d_shell.prm.bak create mode 100644 tests/slab_tip_depth.prm.bak create mode 100644 tests/slope_refinement.prm.bak create mode 100644 tests/smoothing.prm.bak create mode 100644 tests/smoothing_composition_passive.prm.bak create mode 100644 tests/sol_cx_2.cc.bak create mode 100644 tests/sol_cx_2.prm.bak create mode 100644 tests/sol_cx_2_conservative.cc.bak create mode 100644 tests/sol_cx_2_conservative.prm.bak create mode 100644 tests/sol_cx_2_equal_order.cc.bak create mode 100644 tests/sol_cx_2_equal_order.prm.bak create mode 100644 tests/sol_cx_2_gmg.cc.bak create mode 100644 tests/sol_cx_2_gmg.prm.bak create mode 100644 tests/sol_cx_2_normalized_pressure.cc.bak create mode 100644 tests/sol_cx_2_normalized_pressure.prm.bak create mode 100644 tests/sol_cx_2_q3.cc.bak create mode 100644 tests/sol_cx_2_q3.prm.bak create mode 100644 tests/sol_cx_4.cc.bak create mode 100644 tests/sol_cx_4.prm.bak create mode 100644 tests/sol_cx_4_conservative.cc.bak create mode 100644 tests/sol_cx_4_conservative.prm.bak create mode 100644 tests/sol_cx_4_equal_order.cc.bak create mode 100644 tests/sol_cx_4_equal_order.prm.bak create mode 100644 tests/sol_cx_4_gmg.cc.bak create mode 100644 tests/sol_cx_4_gmg.prm.bak create mode 100644 tests/sol_cx_4_normalized_pressure.cc.bak create mode 100644 tests/sol_cx_4_normalized_pressure.prm.bak create mode 100644 tests/sol_cx_4_normalized_pressure_large_static_pressure.cc.bak create mode 100644 tests/sol_cx_4_normalized_pressure_large_static_pressure.prm.bak create mode 100644 tests/sol_cx_4_normalized_pressure_low_solver_tolerance.cc.bak create mode 100644 tests/sol_cx_4_normalized_pressure_low_solver_tolerance.prm.bak create mode 100644 tests/sol_cx_mpi_2.cc.bak create mode 100644 tests/sol_cx_mpi_2.prm.bak create mode 100644 tests/sol_cx_newton_crash.cc.bak create mode 100644 tests/sol_cx_newton_crash.prm.bak create mode 100644 tests/sol_cx_particles.cc.bak create mode 100644 tests/sol_cx_particles.prm.bak create mode 100644 tests/sol_kz_2.cc.bak create mode 100644 tests/sol_kz_2.prm.bak create mode 100644 tests/sol_kz_2_cheaper_first_phase_solver.cc.bak create mode 100644 tests/sol_kz_2_cheaper_first_phase_solver.prm.bak create mode 100644 tests/sol_kz_2_conservative.cc.bak create mode 100644 tests/sol_kz_2_conservative.prm.bak create mode 100644 tests/sol_kz_2_no_first_phase_solver.cc.bak create mode 100644 tests/sol_kz_2_no_first_phase_solver.prm.bak create mode 100644 tests/sol_kz_2_project_q1_only_visc.cc.bak create mode 100644 tests/sol_kz_2_project_q1_only_visc.prm.bak create mode 100644 tests/sol_kz_2_q3.cc.bak create mode 100644 tests/sol_kz_2_q3.prm.bak create mode 100644 tests/sol_kz_4.cc.bak create mode 100644 tests/sol_kz_4.prm.bak create mode 100644 tests/sol_kz_4_conservative.cc.bak create mode 100644 tests/sol_kz_4_conservative.prm.bak create mode 100644 tests/solidus_initial_conditions.cc.bak create mode 100644 tests/solidus_initial_conditions.prm.bak create mode 100644 tests/solitary_wave.cc.bak create mode 100644 tests/solitary_wave.prm.bak create mode 100644 tests/solubility.cc.bak create mode 100644 tests/solubility.prm.bak create mode 100644 tests/solve_no_advection_no_stokes.prm.bak create mode 100644 tests/solver_history.cc.bak create mode 100644 tests/solver_history.prm.bak create mode 100644 tests/solver_scheme_no_advection_single_stokes.cc.bak create mode 100644 tests/solver_scheme_no_advection_single_stokes.prm.bak create mode 100644 tests/spectral_comparison.prm.bak create mode 100644 tests/spherical_constant_boundary_3d_sphere.prm.bak create mode 100644 tests/spherical_nsinker.cc.bak create mode 100644 tests/spherical_nsinker.prm.bak create mode 100644 tests/spherical_shell_initial_topography_ascii_data_3d.prm.bak create mode 100644 tests/spherical_shell_initial_topography_function_3d.prm.bak create mode 100644 tests/spherical_velocity_statistics.prm.bak create mode 100644 tests/spiegelman_fail_test.cc.bak create mode 100644 tests/spiegelman_fail_test.prm.bak create mode 100644 tests/spiegelman_material.cc.bak create mode 100644 tests/spiegelman_material.prm.bak create mode 100644 tests/splines.cc.bak create mode 100644 tests/splines.prm.bak create mode 100644 tests/static_temperature.prm.bak create mode 100644 tests/statistics_output.prm.bak create mode 100644 tests/steinberger_averaging.prm.bak create mode 100644 tests/steinberger_background.prm.bak create mode 100644 tests/steinberger_compressible.prm.bak create mode 100644 tests/steinberger_compressible_gmg.prm.bak create mode 100644 tests/steinberger_conductivity.prm.bak create mode 100644 tests/steinberger_conductivity_tosi.prm.bak create mode 100644 tests/steinberger_continuous_viscosity.prm.bak create mode 100644 tests/steinberger_cookbook.prm.bak create mode 100644 tests/steinberger_latent_heat.prm.bak create mode 100644 tests/steinberger_latent_heat_2.prm.bak create mode 100644 tests/steinberger_lateral_fail.prm.bak create mode 100644 tests/steinberger_phase_fractions.prm.bak create mode 100644 tests/steinberger_phase_fractions_background.prm.bak create mode 100644 tests/steinberger_phases.prm.bak create mode 100644 tests/steinberger_phases_2_lookups.prm.bak create mode 100644 tests/steinberger_phases_hefesto.prm.bak create mode 100644 tests/steinberger_projected_density.prm.bak create mode 100644 tests/steinberger_projected_density_dcPicard.prm.bak create mode 100644 tests/steinberger_seismic_velocities.prm.bak create mode 100644 tests/steinberger_several_fields.prm.bak create mode 100644 tests/steinberger_single_field.prm.bak create mode 100644 tests/steinberger_viscosity.prm.bak create mode 100644 tests/steinberger_viscosity_adiabatic.prm.bak create mode 100644 tests/stokes.prm.bak create mode 100644 tests/stokes_residual.prm.bak create mode 100644 tests/stokes_residual_cheap.prm.bak create mode 100644 tests/stokes_solver_fail.prm.bak create mode 100644 tests/stokes_solver_fail_A.prm.bak create mode 100644 tests/stokes_solver_fail_S.prm.bak create mode 100644 tests/stokes_solver_fail_cheap.prm.bak create mode 100644 tests/stokes_solver_fail_gmg.prm.bak create mode 100644 tests/stress_vs_surface_stress.cc.bak create mode 100644 tests/stress_vs_surface_stress.prm.bak create mode 100644 tests/stress_vs_surface_stress_point_values.cc.bak create mode 100644 tests/stress_vs_surface_stress_point_values.prm.bak create mode 100644 tests/subduction_initiation_compositional_fields.prm.bak create mode 100644 tests/supg-compositional-passive.prm.bak create mode 100644 tests/supg.prm.bak create mode 100644 tests/surface_elevation_box_ascii_data.prm.bak create mode 100644 tests/surface_elevation_box_ascii_data_moved_origin.prm.bak create mode 100644 tests/surface_elevation_box_function.prm.bak create mode 100644 tests/surface_elevation_box_prm_polygon.prm.bak create mode 100644 tests/surface_elevation_chunk_ascii_data.prm.bak create mode 100644 tests/surface_elevation_chunk_ascii_data_3d.prm.bak create mode 100644 tests/surface_elevation_chunk_ascii_data_3d_colatitude.prm.bak create mode 100644 tests/surface_elevation_chunk_ascii_data_global_3d.prm.bak create mode 100644 tests/surface_elevation_spherical_shell_ascii_data_global_3d.prm.bak create mode 100644 tests/surface_stress_strainrate_3d.cc.bak create mode 100644 tests/surface_stress_strainrate_3d.prm.bak create mode 100644 tests/symbolic_boundary_names_box.prm.bak create mode 100644 tests/symbolic_boundary_names_box_constant_bc.prm.bak create mode 100644 tests/symbolic_boundary_names_spherical_shell_2d_180_degrees.prm.bak create mode 100644 tests/symbolic_boundary_names_spherical_shell_2d_90_degrees.prm.bak create mode 100644 tests/symbolic_boundary_names_spherical_shell_2d_full.prm.bak create mode 100644 tests/symbolic_boundary_names_spherical_shell_3d_90_degrees.prm.bak create mode 100644 tests/symbolic_boundary_names_spherical_shell_3d_full.prm.bak create mode 100644 tests/tangurnis.cc.bak create mode 100644 tests/tangurnis_ba.cc.bak create mode 100644 tests/tangurnis_ba.prm.bak create mode 100644 tests/tangurnis_ba_custom.cc.bak create mode 100644 tests/tangurnis_ba_custom.prm.bak create mode 100644 tests/tangurnis_tala.cc.bak create mode 100644 tests/tangurnis_tala.prm.bak create mode 100644 tests/tangurnis_tala_c.cc.bak create mode 100644 tests/tangurnis_tala_c.prm.bak create mode 100644 tests/tangurnis_tala_gmg.cc.bak create mode 100644 tests/tangurnis_tala_gmg.prm.bak create mode 100644 tests/tangurnis_tala_implicit.cc.bak create mode 100644 tests/tangurnis_tala_implicit.prm.bak create mode 100644 tests/temperature_dependent_stokes_matrix.prm.bak create mode 100644 tests/terminate_user_request.cc.bak create mode 100644 tests/terminate_user_request.prm.bak create mode 100644 tests/thermal_alpha_s40rts.prm.bak create mode 100644 tests/tian_MORB.prm.bak create mode 100644 tests/tian_gabbro.prm.bak create mode 100644 tests/tian_peridotite.prm.bak create mode 100644 tests/tian_sediment.prm.bak create mode 100644 tests/time_dependent_annulus.cc.bak create mode 100644 tests/time_dependent_annulus.prm.bak create mode 100644 tests/time_dependent_temperature_bc.cc.bak create mode 100644 tests/time_dependent_temperature_bc.prm.bak create mode 100644 tests/time_dependent_temperature_bc_2.cc.bak create mode 100644 tests/time_dependent_temperature_bc_2.prm.bak create mode 100644 tests/time_stepping_fail.prm.bak create mode 100644 tests/time_stepping_function.prm.bak create mode 100644 tests/time_stepping_min.prm.bak create mode 100644 tests/time_stepping_repeat.prm.bak create mode 100644 tests/time_stepping_repeat_particles.prm.bak create mode 100644 tests/time_stepping_repeat_particles_iterated_advection.prm.bak create mode 100644 tests/tomography_based_plate_motions_cookbook.cc.bak create mode 100644 tests/tomography_based_plate_motions_cookbook.prm.bak create mode 100644 tests/topo_box.prm.bak create mode 100644 tests/topo_chunk.prm.bak create mode 100644 tests/topo_shell.prm.bak create mode 100644 tests/tosi_benchmark.cc.bak create mode 100644 tests/tosi_benchmark.prm.bak create mode 100644 tests/tosi_benchmark_gmg_dc_picard_solver.cc.bak create mode 100644 tests/tosi_benchmark_gmg_dc_picard_solver.prm.bak create mode 100644 tests/tosi_benchmark_gmg_newton_solver.cc.bak create mode 100644 tests/tosi_benchmark_gmg_newton_solver.prm.bak create mode 100644 tests/tosi_benchmark_newton_solver.cc.bak create mode 100644 tests/tosi_benchmark_newton_solver.prm.bak create mode 100644 tests/tosi_benchmark_newton_solver_full_A.cc.bak create mode 100644 tests/tosi_benchmark_newton_solver_full_A.prm.bak create mode 100644 tests/traction_ascii_data.prm.bak create mode 100644 tests/traction_multiple_model.prm.bak create mode 100644 tests/transform_fault_behn_2007.prm.bak create mode 100644 tests/two_merged_boxes_free_surface.prm.bak create mode 100644 tests/uncoupled_two_phase_tian_parameterization_kinematic_slab.prm.bak create mode 100644 tests/update_script.cc.bak create mode 100644 tests/update_script_2.cc.bak create mode 100644 tests/update_script_2/updated2.prm.bak create mode 100644 tests/upwelling_melting_peridotite.prm.bak create mode 100644 tests/upwelling_melting_peridotite_compressible.prm.bak create mode 100644 tests/upwelling_melting_pyroxenite.prm.bak create mode 100644 tests/use_full_A_block_preconditioner.prm.bak create mode 100644 tests/van_keken_smooth_particle.prm.bak create mode 100644 tests/vankeken_subduction.cc.bak create mode 100644 tests/vankeken_subduction.prm.bak create mode 100644 tests/var_declaration_expansion.cc.bak create mode 100644 tests/var_declaration_expansion.prm.bak create mode 100644 tests/velocity_boundary_statistics.prm.bak create mode 100644 tests/velocity_divergence.cc.bak create mode 100644 tests/velocity_divergence.prm.bak create mode 100644 tests/velocity_in_years.prm.bak create mode 100644 tests/vep_chemical_compositions.prm.bak create mode 100644 tests/vis_velocity_in_years.prm.bak create mode 100644 tests/visco_elastic_top_beam.prm.bak create mode 100644 tests/visco_plastic.prm.bak create mode 100644 tests/visco_plastic_additional_plastic_outputs.prm.bak create mode 100644 tests/visco_plastic_adiabat_temperature.prm.bak create mode 100644 tests/visco_plastic_adiabatic_heating_density.prm.bak create mode 100644 tests/visco_plastic_adiabatic_pressure_in_viscous_creep.prm.bak create mode 100644 tests/visco_plastic_complex.prm.bak create mode 100644 tests/visco_plastic_composite.prm.bak create mode 100644 tests/visco_plastic_constant_viscosity_prefactor.prm.bak create mode 100644 tests/visco_plastic_derivatives_2d.cc.bak create mode 100644 tests/visco_plastic_derivatives_2d.prm.bak create mode 100644 tests/visco_plastic_derivatives_3d.cc.bak create mode 100644 tests/visco_plastic_derivatives_3d.prm.bak create mode 100644 tests/visco_plastic_diffusion.prm.bak create mode 100644 tests/visco_plastic_diffusion_dislocation_composite.prm.bak create mode 100644 tests/visco_plastic_dislocation.prm.bak create mode 100644 tests/visco_plastic_frank_kamenetskii.prm.bak create mode 100644 tests/visco_plastic_frank_kamenetskii_pressure.prm.bak create mode 100644 tests/visco_plastic_friction_function.prm.bak create mode 100644 tests/visco_plastic_gerya_2019_vp.prm.bak create mode 100644 tests/visco_plastic_newton_nonlinear_channelflow.prm.bak create mode 100644 tests/visco_plastic_peierls_cutoff_test.prm.bak create mode 100644 tests/visco_plastic_peierls_idrissi_exact.prm.bak create mode 100644 tests/visco_plastic_peierls_mei_exact.prm.bak create mode 100644 tests/visco_plastic_peierls_mei_viscosity_approx.prm.bak create mode 100644 tests/visco_plastic_peierls_strict_cutoff_test.prm.bak create mode 100644 tests/visco_plastic_phases.prm.bak create mode 100644 tests/visco_plastic_phases_compositions.prm.bak create mode 100644 tests/visco_plastic_phases_peierls_mei_exact.prm.bak create mode 100644 tests/visco_plastic_phases_plasticity.prm.bak create mode 100644 tests/visco_plastic_phases_temperature_limit_basalt.prm.bak create mode 100644 tests/visco_plastic_phases_temperature_limit_harzburgite.prm.bak create mode 100644 tests/visco_plastic_phases_temperature_limit_pyrolite.prm.bak create mode 100644 tests/visco_plastic_phases_temperature_limit_pyrolite_complicated.prm.bak create mode 100644 tests/visco_plastic_phases_viscosity.prm.bak create mode 100644 tests/visco_plastic_phases_viscosity_max_min.prm.bak create mode 100644 tests/visco_plastic_reference_density_profile.prm.bak create mode 100644 tests/visco_plastic_thermal_conductivity.prm.bak create mode 100644 tests/visco_plastic_total_strain_healing_temperature_dependent.prm.bak create mode 100644 tests/visco_plastic_track_noninitial_plastic_strain.prm.bak create mode 100644 tests/visco_plastic_vep_bending_beam.prm.bak create mode 100644 tests/visco_plastic_vep_brick_extension.prm.bak create mode 100644 tests/visco_plastic_vep_plate_flexure.prm.bak create mode 100644 tests/visco_plastic_vep_simple_shear.prm.bak create mode 100644 tests/visco_plastic_vep_stress_build-up.prm.bak create mode 100644 tests/visco_plastic_vep_stress_build-up_fixed_elastic_time_step.prm.bak create mode 100644 tests/visco_plastic_vep_stress_build-up_stress_averaging.prm.bak create mode 100644 tests/visco_plastic_vep_stress_build-up_yield.prm.bak create mode 100644 tests/visco_plastic_vep_stress_build-up_yield_particles.prm.bak create mode 100644 tests/visco_plastic_viscous_strain_weakening.prm.bak create mode 100644 tests/visco_plastic_yield.prm.bak create mode 100644 tests/visco_plastic_yield_max.prm.bak create mode 100644 tests/visco_plastic_yield_noninitial-plastic-strain_particles.prm.bak create mode 100644 tests/visco_plastic_yield_plastic_damper.prm.bak create mode 100644 tests/visco_plastic_yield_plastic_strain_weakening.prm.bak create mode 100644 tests/visco_plastic_yield_plastic_strain_weakening_particles.prm.bak create mode 100644 tests/visco_plastic_yield_plastic_viscous_strain_healing.prm.bak create mode 100644 tests/visco_plastic_yield_plastic_viscous_strain_weakening.prm.bak create mode 100644 tests/visco_plastic_yield_plastic_viscous_strain_weakening_particles.prm.bak create mode 100644 tests/visco_plastic_yield_strain_weakening.prm.bak create mode 100644 tests/visco_plastic_yield_strain_weakening_compositions.prm.bak create mode 100644 tests/visco_plastic_yield_strain_weakening_defect_corr_stokes.prm.bak create mode 100644 tests/visco_plastic_yield_strain_weakening_full_strain_tensor.prm.bak create mode 100644 tests/visco_plastic_yield_strain_weakening_full_strain_tensor_3d.prm.bak create mode 100644 tests/visco_plastic_yield_strain_weakening_iterated_advection.prm.bak create mode 100644 tests/visco_plastic_yield_strain_weakening_no-advect_no_stokes.prm.bak create mode 100644 tests/visco_plastic_yield_strain_weakening_particles.prm.bak create mode 100644 tests/visco_plastic_yield_temperature_activated_viscous_strain_weakening.prm.bak create mode 100644 tests/visco_plastic_yield_total_strain_healing.prm.bak create mode 100644 tests/visco_plastic_yield_viscous_strain_weakening.prm.bak create mode 100644 tests/visco_plastic_yield_viscous_strain_weakening_particles.prm.bak create mode 100644 tests/viscoelastic_bending_beam.prm.bak create mode 100644 tests/viscoelastic_bending_beam_averaging.prm.bak create mode 100644 tests/viscoelastic_bending_beam_gmg.prm.bak create mode 100644 tests/viscoelastic_bending_beam_particles.prm.bak create mode 100644 tests/viscoelastic_bending_beam_principal_stress.prm.bak create mode 100644 tests/viscoelastic_fixed_elastic_time_step.prm.bak create mode 100644 tests/viscoelastic_numerical_elastic_time_step.prm.bak create mode 100644 tests/viscoelastic_numerical_elastic_time_step_particles.prm.bak create mode 100644 tests/viscoelastic_plate_flexure.prm.bak create mode 100644 tests/viscoelastic_sheared_torsion.prm.bak create mode 100644 tests/viscoelastic_stress_averaging.prm.bak create mode 100644 tests/viscoelastic_stress_build-up.prm.bak create mode 100644 tests/viscoelastic_stress_build-up_gmg.prm.bak create mode 100644 tests/viscoelastoplastic_yield_plastic_viscous_strain_weakening.prm.bak create mode 100644 tests/viscoplastic_melt_blob_freezing.prm.bak create mode 100644 tests/viscoplastic_melt_fraction.prm.bak create mode 100644 tests/viscosity_refinement.prm.bak create mode 100644 tests/viscous_dissipation_statistics.prm.bak create mode 100644 tests/viscous_top_beam.prm.bak create mode 100644 tests/visualization_averaged_strain_rate.prm.bak create mode 100644 tests/visualization_averaged_strain_rate2.prm.bak create mode 100644 tests/visualization_conductivity_diffusivity.prm.bak create mode 100644 tests/visualization_higher_order_output.prm.bak create mode 100644 tests/visualization_shear_stress.prm.bak create mode 100644 tests/visualization_shear_stress_pointwise.prm.bak create mode 100644 tests/visualization_shear_stress_viscoelastic.prm.bak create mode 100644 tests/visualization_strain_rate.prm.bak create mode 100644 tests/visualization_strain_rate_pointwise.prm.bak create mode 100644 tests/visualization_strain_rate_tensor.prm.bak create mode 100644 tests/visualization_strain_rate_tensor_pointwise.prm.bak create mode 100644 tests/visualization_stress.prm.bak create mode 100644 tests/visualization_stress_pointwise.prm.bak create mode 100644 tests/visualization_stress_viscoelastic.prm.bak create mode 100644 tests/visualization_temperature_anomaly.prm.bak create mode 100644 tests/visualization_unique_list.prm.bak create mode 100644 tests/visualization_vertical_heat_flux.prm.bak create mode 100644 tests/viz_mesh_deform_vector.prm.bak create mode 100644 tests/viz_plugin_dependency.cc.bak create mode 100644 tests/viz_plugin_dependency.prm.bak create mode 100644 tests/viz_spherical_velocity_components.prm.bak create mode 100644 tests/vof_circle_1.cc.bak create mode 100644 tests/vof_circle_1.prm.bak create mode 100644 tests/vof_circle_amr.cc.bak create mode 100644 tests/vof_circle_amr.prm.bak create mode 100644 tests/vof_circle_mpi.cc.bak create mode 100644 tests/vof_circle_mpi.prm.bak create mode 100644 tests/vof_circle_mpi_amr.cc.bak create mode 100644 tests/vof_circle_mpi_amr.prm.bak create mode 100644 tests/vof_composition_init.prm.bak create mode 100644 tests/vof_err_calc.h.bak create mode 100644 tests/vof_linear.cc.bak create mode 100644 tests/vof_linear.prm.bak create mode 100644 tests/vof_linear_2f.cc.bak create mode 100644 tests/vof_linear_2f.prm.bak create mode 100644 tests/vof_linear_amr.cc.bak create mode 100644 tests/vof_linear_amr.prm.bak create mode 100644 tests/vof_linear_amr_mpi.cc.bak create mode 100644 tests/vof_linear_amr_mpi.prm.bak create mode 100644 tests/vof_linear_inflow.prm.bak create mode 100644 tests/vof_linear_periodic.cc.bak create mode 100644 tests/vof_linear_periodic.prm.bak create mode 100644 tests/vof_linear_periodic_amr.cc.bak create mode 100644 tests/vof_linear_periodic_amr.prm.bak create mode 100644 tests/vof_mpi_amr_no_dof.prm.bak create mode 100644 tests/walltime.prm.bak create mode 100644 tests/weighted_p_norm_average.cc.bak create mode 100644 tests/world_builder_select_composition.prm.bak create mode 100644 tests/world_builder_select_grains.prm.bak create mode 100644 tests/world_builder_simple.prm.bak create mode 100644 tests/world_builder_simple_2d_cartesian_sticky_air.prm.bak create mode 100644 tests/write_plugin_graph.cc.bak create mode 100644 tests/write_plugin_graph.prm.bak create mode 100644 tests/zero_RHS.prm.bak create mode 100644 tests/zero_matrix.prm.bak create mode 100644 tests/zero_temperature.prm.bak create mode 100644 unit_tests/additional_outputs.cc.bak create mode 100644 unit_tests/common.h.bak create mode 100644 unit_tests/crystal_preferred_orientation.cc.bak create mode 100644 unit_tests/first.cc.bak create mode 100644 unit_tests/introspection.cc.bak create mode 100644 unit_tests/mesh_refinement.cc.bak create mode 100644 unit_tests/netcdf.cc.bak create mode 100644 unit_tests/parse_map_to_double_array.cc.bak create mode 100644 unit_tests/particles.cc.bak create mode 100644 unit_tests/termination_criteria.cc.bak create mode 100644 unit_tests/utilities.cc.bak diff --git a/benchmarks/advection/drop_ev.prm.bak b/benchmarks/advection/drop_ev.prm.bak new file mode 100644 index 00000000000..d0f3400f9d1 --- /dev/null +++ b/benchmarks/advection/drop_ev.prm.bak @@ -0,0 +1,13 @@ +# like drop_supg.prm but with entropy viscosity + +set Dimension = 2 + +include drop_supg.prm + +set Output directory = output-drop-ev + +subsection Discretization + subsection Stabilization parameters + set Stabilization method = entropy viscosity + end +end diff --git a/benchmarks/advection/drop_supg.prm.bak b/benchmarks/advection/drop_supg.prm.bak new file mode 100644 index 00000000000..73c1421d522 --- /dev/null +++ b/benchmarks/advection/drop_supg.prm.bak @@ -0,0 +1,123 @@ +# Dropping box benchmark on the right half of the domain + +set Dimension = 2 +set Use years in output instead of seconds = false +set End time = 5.0 +set Output directory = output-drop-supg +set Nonlinear solver scheme = single Advection, no Stokes + +subsection Prescribed Stokes solution + set Model name = function + + subsection Velocity function + set Function expression = 0; if (x>0,-0.2,0) + end +end + +subsection Discretization + set Temperature polynomial degree = 2 + + subsection Stabilization parameters + set Stabilization method = SUPG + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 2 + set Box origin X coordinate = -1 + set Box origin Y coordinate = -1 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = + set Function expression = if ((abs(x)<0.2)&(abs(y-0.5)<0.2),1,0) + end +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = + set Function expression = if ((abs(x)<0.2)&(abs(y-0.5)<0.2),1,0) + end +end + +subsection Boundary temperature model + set List of model names = box + set Fixed temperature boundary indicators = top, bottom, left, right + + subsection Box + set Bottom temperature = 0 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +subsection Boundary composition model + set List of model names = box + set Fixed composition boundary indicators = top, bottom, left, right + + subsection Box + set Bottom composition = 0 + set Left composition = 0 + set Right composition = 0 + set Top composition = 0 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0.0 + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 1 + set Reference specific heat = 1 + set Reference temperature = 0 + set Thermal conductivity = 1e-5 + set Thermal expansion coefficient = 0 + set Viscosity = 0 + end +end + +subsection Compositional fields + set Number of fields = 1 + set Compositional field methods = field +end + +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, visualization + + subsection Visualization + set Time between graphical output = .1 + set List of output variables = artificial viscosity + end +end + +subsection Solver parameters + set Temperature solver tolerance = 1e-10 +end diff --git a/benchmarks/advection/rotate_shape_dg_bp.prm b/benchmarks/advection/rotate_shape_dg_bp.prm index bf877a98975..b1c2b7309a1 100644 --- a/benchmarks/advection/rotate_shape_dg_bp.prm +++ b/benchmarks/advection/rotate_shape_dg_bp.prm @@ -10,6 +10,7 @@ set Output directory = output-rotate-shape-dg-bp subsection Discretization set Use discontinuous temperature discretization = true set Use discontinuous composition discretization = true + subsection Stabilization parameters set Limiter for discontinuous temperature solution = bound preserving set Limiter for discontinuous composition solution = bound preserving diff --git a/benchmarks/advection/rotate_shape_dg_bp.prm.bak b/benchmarks/advection/rotate_shape_dg_bp.prm.bak new file mode 100644 index 00000000000..bf877a98975 --- /dev/null +++ b/benchmarks/advection/rotate_shape_dg_bp.prm.bak @@ -0,0 +1,21 @@ +# Like rotate_shape_supg but with discontinuous Galerkin method +# and bound-preserving limiter + +set Dimension = 2 + +include rotate_shape_supg.prm + +set Output directory = output-rotate-shape-dg-bp + +subsection Discretization + set Use discontinuous temperature discretization = true + set Use discontinuous composition discretization = true + subsection Stabilization parameters + set Limiter for discontinuous temperature solution = bound preserving + set Limiter for discontinuous composition solution = bound preserving + set Global temperature maximum = 1 + set Global temperature minimum = 0 + set Global composition maximum = 1 + set Global composition minimum = 0 + end +end diff --git a/benchmarks/advection/rotate_shape_dg_weno.prm b/benchmarks/advection/rotate_shape_dg_weno.prm index 895cf0ccdb3..aae23e8b1e7 100644 --- a/benchmarks/advection/rotate_shape_dg_weno.prm +++ b/benchmarks/advection/rotate_shape_dg_weno.prm @@ -10,6 +10,7 @@ set Output directory = output-rotate-shape-dg-weno subsection Discretization set Use discontinuous temperature discretization = true set Use discontinuous composition discretization = true + subsection Stabilization parameters set Limiter for discontinuous temperature solution = WENO set Limiter for discontinuous composition solution = WENO @@ -19,6 +20,7 @@ end subsection Postprocess subsection Visualization set List of output variables = kxrcf indicator + subsection KXRCF indicator set Name of advection field = C_1 end diff --git a/benchmarks/advection/rotate_shape_dg_weno.prm.bak b/benchmarks/advection/rotate_shape_dg_weno.prm.bak new file mode 100644 index 00000000000..895cf0ccdb3 --- /dev/null +++ b/benchmarks/advection/rotate_shape_dg_weno.prm.bak @@ -0,0 +1,26 @@ +# Like rotate_shape_supg but with discontinuous Galerkin method +# and WENO limiter + +set Dimension = 2 + +include rotate_shape_supg.prm + +set Output directory = output-rotate-shape-dg-weno + +subsection Discretization + set Use discontinuous temperature discretization = true + set Use discontinuous composition discretization = true + subsection Stabilization parameters + set Limiter for discontinuous temperature solution = WENO + set Limiter for discontinuous composition solution = WENO + end +end + +subsection Postprocess + subsection Visualization + set List of output variables = kxrcf indicator + subsection KXRCF indicator + set Name of advection field = C_1 + end + end +end diff --git a/benchmarks/advection/rotate_shape_ev.prm.bak b/benchmarks/advection/rotate_shape_ev.prm.bak new file mode 100644 index 00000000000..72d335d9bb4 --- /dev/null +++ b/benchmarks/advection/rotate_shape_ev.prm.bak @@ -0,0 +1,13 @@ +# Like rotate_shape_supg but with entropy viscosity + +set Dimension = 2 + +include rotate_shape_supg.prm + +set Output directory = output-rotate-shape-ev + +subsection Discretization + subsection Stabilization parameters + set Stabilization method = entropy viscosity + end +end diff --git a/benchmarks/advection/rotate_shape_supg.prm.bak b/benchmarks/advection/rotate_shape_supg.prm.bak new file mode 100644 index 00000000000..2ec59286181 --- /dev/null +++ b/benchmarks/advection/rotate_shape_supg.prm.bak @@ -0,0 +1,119 @@ +# Rotating shapes + +set Dimension = 2 +set Use years in output instead of seconds = false +set End time = 6.2831 +set Output directory = output-rotate-shape-supg +set Nonlinear solver scheme = single Advection, no Stokes + +subsection Prescribed Stokes solution + set Model name = circle +end + +subsection Discretization + set Temperature polynomial degree = 2 + + subsection Stabilization parameters + set Stabilization method = SUPG + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 2 + set Box origin X coordinate = -1 + set Box origin Y coordinate = -1 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = + set Function expression = if((sqrt((x-0)^2+(y-0.5)^2)<0.3)&(abs(x)>=0.05|y>=0.7),1,if(sqrt((x-0)^2+(y+0.5)^2)<0.3,1-sqrt((x-0)^2+(y+0.5)^2)/0.3,if(sqrt((x+0.5)^2+(y+0)^2)<0.3,1.0/4.0*(1+cos(pi*min(sqrt((x+0.5)^2+(y+0)^2)/0.3,1))),0))) + end +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = + set Function expression = if((sqrt((x-0)^2+(y-0.5)^2)<0.3)&(abs(x)>=0.05|y>=0.7),1,if(sqrt((x-0)^2+(y+0.5)^2)<0.3,1-sqrt((x-0)^2+(y+0.5)^2)/0.3,if(sqrt((x+0.5)^2+(y+0)^2)<0.3,1.0/4.0*(1+cos(pi*min(sqrt((x+0.5)^2+(y+0)^2)/0.3,1))),0))) + end +end + +subsection Boundary temperature model + set List of model names = box + set Fixed temperature boundary indicators = top, bottom, left, right + + subsection Box + set Bottom temperature = 0 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +subsection Boundary composition model + set List of model names = box + set Fixed composition boundary indicators = top, bottom, left, right + + subsection Box + set Bottom composition = 0 + set Left composition = 0 + set Right composition = 0 + set Top composition = 0 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0.0 # = Ra / Thermal expansion coefficient + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 1 + set Reference specific heat = 1 + set Reference temperature = 0 + set Thermal conductivity = 1e-5 + set Thermal expansion coefficient = 0 + set Viscosity = 0 + end +end + +subsection Compositional fields + set Number of fields = 1 + set Compositional field methods = field +end + +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, visualization + + subsection Visualization + set Time between graphical output = .12566 # = 2pi/50 + set List of output variables = artificial viscosity + end +end + +subsection Solver parameters + set Temperature solver tolerance = 1e-10 +end diff --git a/benchmarks/advection_in_annulus/advection_in_annulus.cc.bak b/benchmarks/advection_in_annulus/advection_in_annulus.cc.bak new file mode 100644 index 00000000000..b0eeeb741e5 --- /dev/null +++ b/benchmarks/advection_in_annulus/advection_in_annulus.cc.bak @@ -0,0 +1,162 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + /** + * This is a variation of the "annulus" benchmark in benchmark/annulus + * that tests the influence of the stabilization method on the temperature + * equation. + * + */ + namespace AdvectionInAnnulus + { + using namespace dealii; + + namespace AnalyticSolutions + { + const double A=2.0, B=-3.0/std::log(2.0), C=-1; + const double outer_radius = 2.; + const double rho_0 = 1000.; + const double gravity = 1.; + + Tensor<1,2> + Annulus_velocity (const Point<2> &pos, + const double k) + { + const double x = pos[0]; + const double y = pos[1]; + const double r = std::sqrt(x*x+y*y); + const double theta = std::atan2(y,x); + const double f_r = A*r + B/r; + const double g_r = A*r/2 + B*std::log(r)/r + C/r; + const double v_r = g_r*k*sin(k*theta); + const double v_theta = f_r*cos(k*theta); + const double v_x = cos(theta)*v_r - sin(theta)*v_theta; + const double v_y = sin(theta)*v_r + cos(theta)*v_theta; + return Point<2> (v_x,v_y); + } + + double + Annulus_pressure (const Point<2> &pos, + const double k) + { + const double x = pos[0]; + const double y = pos[1]; + const double r=std::sqrt(x*x+y*y); + const double theta = std::atan2(y,x); + const double f_r = 2*r + B/r; + const double g_r = A*r/2 + B*std::log(r)/r + C/r; + const double h_r=(2*g_r-f_r)/r; + return k*h_r*sin(k*theta)+rho_0*gravity*(outer_radius-r); + } + + template + double + Annulus_normal_traction (const Point &pos, + const double k) + { + Assert (dim == 2, ExcNotImplemented()); + const double x = pos[0]; + const double y = pos[1]; + const double r=std::sqrt(x*x+y*y); + const double theta = std::atan2(y,x); + const double f_r = 2*r + B/r; + const double g_r = A*r/2 + B*std::log(r)/r + C/r; + return k * 3.*f_r/r * std::sin(k*theta) - rho_0 * g_r * (outer_radius - r); + } + + } + } +} + + +namespace aspect +{ + namespace PrescribedStokesSolution + { + using namespace dealii; + + /** + * A class that implements the flow field of the annulus benchmark. + * + * @ingroup PrescribedStokesSolution + */ + template + class AdvectionInAnnulus : public Interface, public SimulatorAccess + { + public: + void stokes_solution (const Point &p, Vector &value) const override; + }; + } +} + +namespace aspect +{ + namespace PrescribedStokesSolution + { + template + void AdvectionInAnnulus::stokes_solution (const Point &, Vector &) const + { + return; + } + + + template <> + void AdvectionInAnnulus<2>::stokes_solution (const Point<2> &p, Vector &value) const + { + Tensor<1,2> velocity = aspect::AdvectionInAnnulus::AnalyticSolutions::Annulus_velocity (p, 4); + value(0) = velocity[0]; + value(1) = velocity[1]; + + double pressure = aspect::AdvectionInAnnulus::AnalyticSolutions::Annulus_pressure (p, 4); + value(2) = pressure; // pressure + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace PrescribedStokesSolution + { + ASPECT_REGISTER_PRESCRIBED_STOKES_SOLUTION(AdvectionInAnnulus, + "advection in annulus", + "This plugin prescribes the Stokes solution of " + "the annulus benchmark.") + } +} diff --git a/benchmarks/advection_in_annulus/advection_in_annulus.prm.bak b/benchmarks/advection_in_annulus/advection_in_annulus.prm.bak new file mode 100644 index 00000000000..ba93d9017d5 --- /dev/null +++ b/benchmarks/advection_in_annulus/advection_in_annulus.prm.bak @@ -0,0 +1,120 @@ +# The advection benchmark creates a simple, 2d annulus +# with prescribed Stokes flow creating 4 convection cells. +# Various parameters can be changed to test their effect +# on the overall cooling of the model. +# +# See run_all_models.sh for running multiple iterations +# of various parameters in a row. +# +# Also see creates_formatted_tables for grabbing specific +# data points from the log file. + +############### Global parameters +# We use a 2d setup. We are only interested in +# advection, so we prescribe a Stokes flow and +# solve only for advection. + +set Additional shared libraries = ./libadvection_in_annulus.so +set Dimension = 2 +set Start time = 0 +set End time = 1 +set Use years in output instead of seconds = false +set Nonlinear solver scheme = single Advection, no Stokes +set Output directory = output_advection_in_annulus +set Pressure normalization = surface +set Timing output frequency = 100 + +subsection Prescribed Stokes solution + set Model name = advection in annulus +end + +############### Parameters describing the model +# We are interested in the flow of heat out of the top +# boundary and how the advection is stabilized. Interesting +# values to look at are in subsection Discretization, which +# control the stabilization directly, as well as thermal +# conductivity which effectively controls the Rayleigh number. +# The thermal conductivity and Rayleigh number are inversely +# proportional. + +subsection Geometry model + set Model name = spherical shell + + # NOTE: the analytical solutions are hard-coded + # to these geometry values: do not change them. + subsection Spherical shell + set Inner radius = 1 + set Outer radius = 2 + set Opening angle = 360 + end +end + +subsection Discretization + set Temperature polynomial degree = 2 + + subsection Stabilization parameters + set beta = 0.052 + set cR = 0.11 + end +end + +subsection Material model + set Model name = simpler + + subsection Simpler model + set Reference density = 1.0 + set Reference temperature = 1.0 + set Viscosity = 1.0 + set Thermal conductivity = 1e-3 + set Reference specific heat = 1.0 + set Thermal expansion coefficient = 0 + end +end + +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 1 + end +end + +############### Parameters describing the temperature field +# Since we are interested in the flow of heat through +# the top of the model, we set the temperature to 1 +# everywhere within the model except for the top +# boundary, which is set to 0. + +subsection Boundary temperature model + set List of model names = function + set Fixed temperature boundary indicators = top + + subsection Function + set Function expression = 0 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 2 + set Time steps between mesh refinement = 0 + set Refinement fraction = 0.2 + set Strategy = velocity +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics, entropy viscosity statistics, depth average + + subsection Visualization + set List of output variables = heat flux map, artificial viscosity + set Time between graphical output = 0.1 + end +end diff --git a/benchmarks/annulus/instantaneous/annulus.prm.bak b/benchmarks/annulus/instantaneous/annulus.prm.bak new file mode 100644 index 00000000000..1417770fa71 --- /dev/null +++ b/benchmarks/annulus/instantaneous/annulus.prm.bak @@ -0,0 +1,90 @@ +# The 2D Stokes in an annulus benchmark, for which an +# analytical solution is available. +# +# See the manual for more information. + +# We use a 2d setup. Since we are only interested +# in an instantaneous solution, we set the end time +# equal to the start time to force a single time +# step before the program terminates. + +set Additional shared libraries = ../plugin/libannulus.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = false +set Nonlinear solver scheme = no Advection, single Stokes +set Output directory = output +set Pressure normalization = surface + +# Because the temperature plays no role in this model we need not +# bother to describe temperature boundary conditions or +# the material parameters that pertain to the temperature. + +subsection Geometry model + set Model name = spherical shell + + # NOTE: the analytical solutions are hard-coded + # to these geometry values: do not change them. + subsection Spherical shell + set Inner radius = 1 + set Outer radius = 2 + set Opening angle = 360 + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = bottom : AnnulusBoundary, \ + top : AnnulusBoundary +end + +subsection Material model + set Model name = AnnulusMaterial +end + +subsection Gravity model + set Model name = annulus gravity +end + +# k controls the number of convection cells. +subsection Annulus benchmark + set k = 4 +end + +# Temperature does not influence this benchmark +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +# Disable adaptive mesh refinement +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, AnnulusPostprocessor + + subsection Dynamic topography + set Density above = 0 + set Density below = 0 + end + + subsection Visualization + set List of output variables = density, viscosity, strain rate, dynamic topography, AnnulusVisualizationPostprocessor + set Time between graphical output = 0 + end +end + +# Increase Stokes solver accuracy to ensure convergence to +# very low error values +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + end +end diff --git a/benchmarks/annulus/plugin/annulus.cc.bak b/benchmarks/annulus/plugin/annulus.cc.bak new file mode 100644 index 00000000000..72f77ca337f --- /dev/null +++ b/benchmarks/annulus/plugin/annulus.cc.bak @@ -0,0 +1,837 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + /** + * This is the "annulus" benchmark defined in the following paper: + * @code + * @Article{thph17, + * author = {Rene Gassm\"{o}ller, Juliane Dannberg, Wolfgang Bangerth, Elbridge Gerry Puckett, Cedric Thieulot}, + * title = {Benchmarking the accuracy of higher order particle methods in geodynamic models of transient flow}, + * journal = {xxx}, + * year = 2023, + * volume = xxx, + * number = {x}, + * publisher = {xxx}, + * pages = {xxx--xxx}} + * @endcode + * + */ + namespace AnnulusBenchmark + { + using namespace dealii; + using namespace aspect::Utilities::Coordinates; + + /** + * The exact solution for the Annulus benchmark. + */ + namespace AnalyticSolutions + { + // Inner and outer radius are hard-coded to guarantee + // tangential flow at the boundaries + const double R1 = 1.0; + const double R2 = 2.0; + const double A = 2.0; + const double B = -3.0/std::log(2.0); + const double C=-1; + const double rho_0 = 1000.; + const double gravity = 1.; + + double + phase(const double t) + { + return std::exp(t)-1; + } + + + + double + f(const double r) + { + return A*r + B/r; + } + + + + double + g(const double r) + { + return A*r/2 + B*std::log(r)/r + C/r; + } + + + + double + h(const double r) + { + return (2*g(r)-f(r))/r; + } + + + + double + m(const double r, const double k) + { + const double f_prime = A - B/(r*r); + const double g_prime = A/2 - B*std::log(r)/(r*r) + B/(r*r) - C/(r*r); + const double g_prime_prime = -B/(r*r*r)*(3-2*std::log(r)) - 2./(r*r*r); + return g_prime_prime - g_prime/r - (g(r)*(k*k - 1))/(r*r) + f(r)/(r*r) + f_prime/r; + } + + + + template + Tensor<1,dim> + Annulus_velocity (const Point &pos, + const double k, + const double t, + const bool transient) + { + Assert (dim == 2, ExcNotImplemented()); + + const std::array spherical_position = cartesian_to_spherical_coordinates(pos); + const double r = spherical_position[0]; + const double theta = spherical_position[1]; + + Tensor<1,dim> spherical_velocity; + spherical_velocity[0] = g(r) * k * std::sin(k*(theta-phase(t))); + spherical_velocity[1] = f(r) * std::cos(k*(theta-phase(t))); + + if (transient == true) + spherical_velocity[1] += r * std::exp(t); + + return spherical_to_cartesian_vector(spherical_velocity, pos); + } + + + + template + double + Annulus_pressure (const Point &pos, + const double k, + const double t) + { + Assert (dim == 2, ExcNotImplemented()); + const std::array spherical_position = cartesian_to_spherical_coordinates(pos); + const double r = spherical_position[0]; + const double theta = spherical_position[1]; + + return k * h(r) * std::sin(k*(theta-phase(t))) + + rho_0 * gravity * (R2-r); + } + + + + template + double + Annulus_normal_traction (const Point &pos, + const double k, + const double t) + { + Assert (dim == 2, ExcNotImplemented()); + const std::array spherical_position = cartesian_to_spherical_coordinates(pos); + const double r = spherical_position[0]; + const double theta = spherical_position[1]; + + return k * 3.*f(r)/r * std::sin(k*(theta-phase(t))) - rho_0 * g(r) * (R2 - r); + } + + + + template + double + Annulus_density (const Point &pos, + const double k, + const double t, + const bool transient) + { + Assert (dim == 2, ExcNotImplemented()); + const std::array spherical_position = cartesian_to_spherical_coordinates(pos); + const double r = spherical_position[0]; + const double theta = spherical_position[1]; + + double density = 0.0; + if (transient == true) + { + const double stream_function = -((A/2)*r*r + B * std::log(r) + C) * std::cos(k*(theta-phase(t))); + density = stream_function + rho_0; + } + else + { + density = m(r,k) * k * std::sin(k*theta) + rho_0; + } + + return density; + } + + + + template + Tensor<1,dim> + Annulus_gravity (const Point &pos, + const double k, + const double t, + const bool transient) + { + Assert (dim == 2, ExcNotImplemented()); + + double gravity_magnitude = 1.0; + + // see benchmark description for a justification. we want to change + // the density, but keep the forcing term of the Stokes equation constant + if (transient == true) + { + const std::array spherical_position = cartesian_to_spherical_coordinates(pos); + const double r = spherical_position[0]; + const double theta = spherical_position[1]; + + const double forcing_term = m(r,k)*k*sin(k*(theta-phase(t))) + rho_0; + gravity_magnitude = forcing_term / Annulus_density(pos,k,t, transient); + } + + const Tensor<1,dim> gravity_direction = -pos / pos.norm(); + return gravity_magnitude * gravity_direction; + } + + + + template + class FunctionAnnulus : public Function + { + public: + FunctionAnnulus (const double k, + const unsigned int n_comp, + const bool transient) + : + Function(n_comp), + k_(k), + n_components(n_comp), + transient_(transient) + { + Assert(n_components >= 4, ExcInternalError()); + } + + void + vector_value (const Point &pos, + Vector &values) const override + { + Assert (dim == 2, ExcNotImplemented()); + Assert (values.size() >= n_components, ExcInternalError()); + + const double t = this->get_time(); + + const Tensor<1,dim> v = AnalyticSolutions::Annulus_velocity (pos, k_, t, transient_); + values[0] = v[0]; + values[1] = v[1]; + values[2] = AnalyticSolutions::Annulus_pressure (pos, k_, t); + values[3] = 0.0; + + if (n_components >= 5) + values[4] = AnalyticSolutions::Annulus_density (pos, k_, t, transient_); + } + + private: + const double k_; + const unsigned int n_components; + const bool transient_; + }; + } + + + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @ingroup MaterialModels + */ + template + class AnnulusMaterial : public MaterialModel::Interface, public aspect::SimulatorAccess + { + public: + void + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + double t = 0.0; + if (this->simulator_is_past_initialization() == true) + t = this->get_time(); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + out.viscosities[i] = 1; + if (use_analytical_density == true) + { + out.densities[i] = AnalyticSolutions::Annulus_density(in.position[i], k, t, use_transient_flow_solution); + } + else + { + out.densities[i] = in.composition[i][density_index]; + } + + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + + for (unsigned int c=0; c to use as density."); + + prm.declare_entry("Use transient solution", "false", + Patterns::Bool(), + "Whether to use the transient flow solution, or to use the " + "default instantaneous solution."); + } + prm.leave_subsection(); + } + + + + void + parse_parameters (ParameterHandler &prm) override + { + prm.enter_subsection("Annulus benchmark"); + { + k = prm.get_double ("k"); + use_analytical_density = prm.get_bool ("Use analytical density"); + use_transient_flow_solution = prm.get_bool ("Use transient solution"); + } + prm.leave_subsection(); + + density_index = numbers::invalid_unsigned_int; + if (use_analytical_density == false) + { + Assert(this->introspection().compositional_name_exists("density_field"), + ExcInternalError()); + density_index = this->introspection().compositional_index_for_name("density_field"); + } + + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + + + double get_k() const + { + return k; + } + + + + bool use_transient_solution() const + { + return use_transient_flow_solution; + } + + + + bool analytical_density() const + { + return use_analytical_density; + } + + private: + /** + * Whether to use the analytical density. + */ + bool use_analytical_density; + + /** + * If not using the analytical density, store the + * field index of the density field. + */ + unsigned int density_index; + + /** + * Number of positive and negative density anomalies, + * resulting in 2*k convection cells. + */ + double k; + + /** + * Whether to use the transient flow solution. + */ + bool use_transient_flow_solution; + }; + + + + /** + * Velocity boundary condition for the Annulus benchmark + */ + template + class AnnulusBoundary : public BoundaryVelocity::Interface, public aspect::SimulatorAccess + { + public: + Tensor<1,dim> + boundary_velocity (const types::boundary_id , + const Point &position) const override + { + Assert (dim==2, ExcNotImplemented()); + + const AnnulusMaterial & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + return AnalyticSolutions::Annulus_velocity (position, + material_model.get_k(), + this->get_time(), + material_model.use_transient_solution()); + } + }; + + + + /** + * Gravity model for the Annulus benchmark + */ + template + class AnnulusGravity : public aspect::GravityModel::Interface, public aspect::SimulatorAccess + { + public: + Tensor<1,dim> + gravity_vector (const Point &pos) const override + { + const AnnulusMaterial &material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + double t = 0.0; + if (this->simulator_is_past_initialization() == true) + t = this->get_time(); + + return AnalyticSolutions::Annulus_gravity(pos, + material_model.get_k(), + t, + material_model.use_transient_solution()); + } + }; + + + /** + * A postprocessor that evaluates the accuracy of the solution. + */ + template + class AnnulusPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + void initialize() override + { + const AnnulusMaterial &material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + const unsigned int n_components = this->introspection().n_components; + + compute_density_error = (material_model.analytical_density() == false); + reference_solution = std::make_unique>(material_model.get_k(), + n_components, + material_model.use_transient_solution()); + } + + + + std::pair + execute (TableHandler &statistics) override + { + const unsigned int n_components = this->introspection().n_components; + reference_solution->set_time(this->get_time()); + + const QGauss quadrature_formula (this->introspection().polynomial_degree.velocities+2); + + Vector cellwise_errors_ul2 (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_pl2 (this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_u(std::pair(0,dim), + n_components); + ComponentSelectFunction comp_p(dim, n_components); + + VectorTools::integrate_difference (this->get_mapping(), + this->get_dof_handler(), + this->get_solution(), + *reference_solution, + cellwise_errors_ul2, + quadrature_formula, + VectorTools::L2_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(), + this->get_dof_handler(), + this->get_solution(), + *reference_solution, + cellwise_errors_pl2, + quadrature_formula, + VectorTools::L2_norm, + &comp_p); + + + const double u_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_ul2, VectorTools::L2_norm); + const double p_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_pl2, VectorTools::L2_norm); + + // we output the density error either way, but set it to 0 if we do not compute it. + // this simplifies postprocessing the output. + double rho_l2 = 0.0; + if (compute_density_error == true) + { + Vector cellwise_errors_rhol2 (this->get_triangulation().n_active_cells()); + ComponentSelectFunction comp_rho(dim+2, n_components); + VectorTools::integrate_difference (this->get_mapping(), + this->get_dof_handler(), + this->get_solution(), + *reference_solution, + cellwise_errors_rhol2, + quadrature_formula, + VectorTools::L2_norm, + &comp_rho); + rho_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_rhol2, VectorTools::L2_norm); + } + + const double topo_l2 = compute_dynamic_topography_error(); + + statistics.add_value ("u_L2", + u_l2); + statistics.set_precision ("u_L2", 14); + statistics.set_scientific ("u_L2", true); + + statistics.add_value ("p_L2", + p_l2); + statistics.set_precision ("p_L2", 14); + statistics.set_scientific ("p_L2", true); + + statistics.add_value ("rho_L2", + rho_l2); + statistics.set_precision ("rho_L2", 14); + statistics.set_scientific ("rho_L2", true); + + statistics.add_value ("topo_L2", + topo_l2); + statistics.set_precision ("topo_L2", 14); + statistics.set_scientific ("topo_L2", true); + + std::ostringstream os; + + os << std::scientific << u_l2 + << ", " << p_l2 + << ", " << rho_l2 + << ", " << topo_l2; + + return std::make_pair("Errors u_L2, p_L2, rho_L2, topo_L2:", os.str()); + } + + + + std::list + required_other_postprocessors() const override + { + return std::list (1, "dynamic topography"); + } + + private: + /** + * Function that defines the reference solution to compare against. + */ + std::unique_ptr> reference_solution; + + /** + * Whether to compute the density error. This only makes sense + * if the material model does not use the analytical density solution, + * otherwise the error is always 0. + */ + bool compute_density_error; + + /** + * Calculate the L2 dynamic topography error. + */ + double + compute_dynamic_topography_error() const + { + const Postprocess::DynamicTopography &dynamic_topography = + this->get_postprocess_manager().template get_matching_postprocessor>(); + + const AnnulusMaterial &material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + const double k = material_model.get_k(); + + const QGauss quadrature_formula (this->introspection().polynomial_degree.velocities+2); + FEFaceValues fe_face_values(this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | update_gradients | + update_quadrature_points | update_JxW_values); + LinearAlgebra::BlockVector topo_vector = dynamic_topography.topography_vector(); + std::vector topo_values(quadrature_formula.size()); + + double l2_error = 0.; + + typename DoFHandler::active_cell_iterator + cell = this->get_dof_handler().begin_active(), + endc = this->get_dof_handler().end(); + + for (; cell!=endc; ++cell) + if (cell->is_locally_owned()) + if (cell->at_boundary()) + for (unsigned int f=0; f::faces_per_cell; ++f) + if (cell->face(f)->at_boundary()) + { + fe_face_values.reinit(cell, f); + MaterialModel::MaterialModelInputs in_face(fe_face_values, cell, this->introspection(), this->get_solution()); + MaterialModel::MaterialModelOutputs out_face(fe_face_values.n_quadrature_points, this->n_compositional_fields()); + fe_face_values[this->introspection().extractors.temperature].get_function_values(topo_vector, topo_values); + in_face.requested_properties = MaterialModel::MaterialProperties::density; + material_model.evaluate(in_face, out_face); + + for (unsigned int q=0; q < quadrature_formula.size(); ++q) + { + const Point p = fe_face_values.quadrature_point(q); + const double analytic_normal_stress = AnalyticSolutions::Annulus_normal_traction(p, k, this->get_time()); + const double gravity = this->get_gravity_model().gravity_vector(p).norm(); + const double density = out_face.densities[q]; + const double diff = - analytic_normal_stress / gravity/ density - topo_values[q]; + l2_error += (diff*diff) * fe_face_values.JxW(q); + } + } + const double total_l2_error = Utilities::MPI::sum(l2_error,this->get_mpi_communicator()); + return std::sqrt(total_l2_error); + } + }; + + /** + * A postprocessor that visualizes the analytical solution. + */ + template + class AnnulusVisualizationPostprocessor : public DataPostprocessor, + public Postprocess::VisualizationPostprocessors::Interface, + public ::aspect::SimulatorAccess + { + public: + AnnulusVisualizationPostprocessor () + : + DataPostprocessor () + {}; + + std::vector + get_names () const override + { + std::vector solution_names; + + solution_names.push_back ("analytic_pressure"); + solution_names.push_back ("analytic_density"); + return solution_names; + }; + + std::vector + get_data_component_interpretation () const override + { + std::vector interpretation; + interpretation.push_back (DataComponentInterpretation::component_is_scalar); + interpretation.push_back (DataComponentInterpretation::component_is_scalar); + + return interpretation; + }; + + UpdateFlags + get_needed_update_flags () const override + { + return update_quadrature_points; + }; + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override + { + const unsigned int n_quadrature_points = input_data.solution_values.size(); + Assert (computed_quantities.size() == n_quadrature_points, ExcInternalError()); + Assert (input_data.solution_values[0].size() == this->introspection().n_components, ExcInternalError()); + + + const AnnulusMaterial &material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + for (unsigned int q=0; qget_time()); + computed_quantities[q][1] = AnalyticSolutions::Annulus_density(input_data.evaluation_points[q], + material_model.get_k(), + this->get_time(), + material_model.use_transient_solution()); + } + }; + }; + + + + /** + * A particle property that represents the density on particles. + */ + template + class ParticleDensity : public aspect::Particle::Property::Interface, public ::aspect::SimulatorAccess + { + public: + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override + { + const AnnulusMaterial &material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + const double density = AnalyticSolutions::Annulus_density(position, + material_model.get_k(), + /*time*/ 0.0, + material_model.use_transient_solution()); + + particle_properties.push_back(density); + } + + + + std::vector> + get_property_information() const override + { + return {{"particle_density",1}}; + } + }; + + + + /** + * A initial condition for compositional fields that represents the initial density. + */ + template + class AnnulusInitialDensity : public aspect::InitialComposition::Interface, public ::aspect::SimulatorAccess + { + public: + double initial_composition (const Point &position, + const unsigned int n_comp) const override + { + const double density_index = this->introspection().compositional_index_for_name("density_field"); + + if (n_comp == density_index) + { + const AnnulusMaterial &material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + return AnalyticSolutions::Annulus_density(position, + material_model.get_k(), + /*time*/ 0.0, + material_model.use_transient_solution()); + } + + return 0.0; + } + }; + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace AnnulusBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(AnnulusMaterial, + "AnnulusMaterial", + "A material model that corresponds to the `Annulus' benchmark. " + "See the manual for more information.") + + ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(AnnulusBoundary, + "AnnulusBoundary", + "Implementation of the velocity boundary conditions for the " + "`Annulus' benchmark. See the manual for more information about this " + "benchmark.") + + ASPECT_REGISTER_POSTPROCESSOR(AnnulusPostprocessor, + "AnnulusPostprocessor", + "A postprocessor that compares the solution of the `Annulus' benchmark " + "with the one computed by ASPECT " + "and reports the error. See the manual for more information.") + + ASPECT_REGISTER_VISUALIZATION_POSTPROCESSOR(AnnulusVisualizationPostprocessor, + "AnnulusVisualizationPostprocessor", + "A visualization output object that visualizes " + "the analytical solution of the Annulus benchmark.") + + ASPECT_REGISTER_PARTICLE_PROPERTY(ParticleDensity, + "particle density", + "A particle property that represents the density.") + + ASPECT_REGISTER_GRAVITY_MODEL(AnnulusGravity, + "annulus gravity", + "A gravity model for the `Annulus' benchmark.") + + ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(AnnulusInitialDensity, + "initial density", + "An initial condition for composition following the initial density.") + } +} diff --git a/benchmarks/annulus/transient/transient_annulus.prm.bak b/benchmarks/annulus/transient/transient_annulus.prm.bak new file mode 100644 index 00000000000..46833d000a9 --- /dev/null +++ b/benchmarks/annulus/transient/transient_annulus.prm.bak @@ -0,0 +1,89 @@ +# The 2D Stokes in an annulus benchmark, for which an +# analytical solution is available. This is the rotating +# version of the benchmark described in Gassmoeller et al. 2023. +# +# See the doc/ directory or manual for more information. + +# Most parameters are identical to the instantaneous version +# of the benchmark. Refer to that parameter file for most settings. +include $ASPECT_SOURCE_DIR/benchmarks/annulus/instantaneous/annulus.prm + + +# Only list parameters that are specific for the transient benchmark +set Additional shared libraries = ../plugin/libannulus.so +set Dimension = 2 + +# for benchmark: t = log(1 + 4 pi) +set End time = 2.6075939815049280917817614240391581472837221358084918109292273672 +set Nonlinear solver scheme = single Advection, single Stokes + +subsection Discretization + set Use discontinuous composition discretization = true +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = density_field +end + +subsection Initial composition model + set List of model names = initial density +end + +subsection Material model + set Material averaging = harmonic average only viscosity +end + +subsection Annulus benchmark + set Use analytical density = false + set Use transient solution = true + set k = 4 +end + +subsection Mesh refinement + set Initial global refinement = 2 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, AnnulusPostprocessor, rotation statistics + + subsection Dynamic topography + set Density above = 0 + set Density below = 0 + end + + subsection Visualization + set List of output variables = density, gravity, AnnulusVisualizationPostprocessor + set Time between graphical output = 0.1 + end + + subsection Particles + set Time between data output = 2.6 + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + set Number of cheap Stokes solver steps = 200 + set Stokes solver type = block GMG + set Krylov method for cheap solver steps = IDR(s) + set IDR(s) parameter = 4 + end +end + +subsection Particles + set Integration scheme = rk2 + set Interpolation scheme = bilinear least squares + set List of particle properties = particle density + set Update ghost particles = true + set Particle generator name = random uniform + set Load balancing strategy = add particles + set Minimum particles per cell = 12 + + subsection Generator + subsection Probability density function + set Number of particles = 49152 + end + end +end diff --git a/benchmarks/blankenbach/base_case1a.prm.bak b/benchmarks/blankenbach/base_case1a.prm.bak new file mode 100644 index 00000000000..67dfd748504 --- /dev/null +++ b/benchmarks/blankenbach/base_case1a.prm.bak @@ -0,0 +1,111 @@ +# This is case 1a from the Blankenbach Benchmark (Blankenbach 1989). + +set Additional shared libraries = ./plugin/libblankenbach.so +set End time = 1.0 +set Use years in output instead of seconds = false +set CFL number = 5.0 + +subsection Adiabatic conditions model + set Model name = function + + subsection Function + set Function constants = + set Function expression = 0; 0; 1 + set Variable names = depth + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +subsection Initial temperature model + set Model name = ascii data + + subsection Function + set Function constants = z1=0.102367, z2=0.897633, pi=3.14159265359 + set Function expression = if(zz2,0.5*(1-z)/(1-z2),0.5)) + 0.1 * cos(x*pi) * sin(z*pi) + set Variable names = x,z + end + + subsection Ascii data model + set Data directory = + set Data file name = initial_temperature_case1a.txt + end +end + +subsection Material model + set Model name = nondimensional + + subsection Nondimensional model + set Di = 0.0 + set Ra = 1e4 + set Reference density = 1 + set Reference specific heat = 1 + set Use TALA = false + set Viscosity temperature prefactor = 0.0 + set Viscosity depth prefactor = 0.0 + set gamma = 1.0 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 4 + set Time steps between mesh refinement = 0 + set Coarsening fraction = 0.0 + set Refinement fraction = 1.0 +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Formulation + set Formulation = custom # with this selection equivalent to BA + set Mass conservation = incompressible + set Temperature equation = reference density profile +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics, heat flux statistics gradient, heating statistics, heat flux densities, temperature ascii out + + subsection Visualization + set Time between graphical output = 0.05 + set List of output variables = material properties, adiabat, thermal conductivity, heating, artificial viscosity + end +end + +subsection Termination criteria + set Termination criteria = steady state velocity + + subsection Steady state velocity + set Maximum relative deviation = 1e-5 + set Time in steady state = 0.1 + end +end diff --git a/benchmarks/blankenbach/base_case1b.prm.bak b/benchmarks/blankenbach/base_case1b.prm.bak new file mode 100644 index 00000000000..80953a9d798 --- /dev/null +++ b/benchmarks/blankenbach/base_case1b.prm.bak @@ -0,0 +1,18 @@ +include base_case1a.prm + +set Additional shared libraries = ./plugin/libblankenbach.so + +subsection Initial temperature model + set Model name = ascii data + + subsection Ascii data model + set Data directory = + set Data file name = initial_temperature_case1b.txt + end +end + +subsection Material model + subsection Nondimensional model + set Ra = 1e5 + end +end diff --git a/benchmarks/blankenbach/base_case1c.prm.bak b/benchmarks/blankenbach/base_case1c.prm.bak new file mode 100644 index 00000000000..4f3c92497d9 --- /dev/null +++ b/benchmarks/blankenbach/base_case1c.prm.bak @@ -0,0 +1,18 @@ +include base_case1a.prm + +set Additional shared libraries = ./plugin/libblankenbach.so + +subsection Initial temperature model + set Model name = ascii data + + subsection Ascii data model + set Data directory = + set Data file name = initial_temperature_case1c.txt + end +end + +subsection Material model + subsection Nondimensional model + set Ra = 1e6 + end +end diff --git a/benchmarks/blankenbach/base_case2a.prm.bak b/benchmarks/blankenbach/base_case2a.prm.bak new file mode 100644 index 00000000000..34442d9d319 --- /dev/null +++ b/benchmarks/blankenbach/base_case2a.prm.bak @@ -0,0 +1,111 @@ +# This is case 2a from the Blankenbach Benchmark (Blankenbach 1989). + +set Additional shared libraries = ./plugin/libblankenbach.so +set End time = 1.0 +set Use years in output instead of seconds = false +set CFL number = 5.0 + +subsection Adiabatic conditions model + set Model name = function + + subsection Function + set Function constants = + set Function expression = 0; 0; 1 + set Variable names = depth + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +subsection Initial temperature model + set Model name = ascii data + + subsection Function + set Function constants = z1=0.102367, z2=0.897633, pi=3.14159265359 + set Function expression = if(zz2,0.5*(1-z)/(1-z2),0.5)) + 0.1 * cos(x*pi) * sin(z*pi) + set Variable names = x,z + end + + subsection Ascii data model + set Data directory = + set Data file name = initial_temperature_case2a.txt + end +end + +subsection Material model + set Model name = nondimensional + + subsection Nondimensional model + set Di = 0.0 + set Ra = 1e4 + set Reference density = 1 + set Reference specific heat = 1 + set Use TALA = false + set Viscosity temperature prefactor = 6.907755279 + set Viscosity depth prefactor = 0.0 + set gamma = 1.0 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 4 + set Time steps between mesh refinement = 0 + set Coarsening fraction = 0.0 + set Refinement fraction = 1.0 +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Formulation + set Formulation = custom # with this selection equivalent to BA + set Mass conservation = incompressible + set Temperature equation = reference density profile +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics, heat flux statistics gradient, heating statistics, heat flux densities, temperature ascii out + + subsection Visualization + set Time between graphical output = 0.05 + set List of output variables = material properties, adiabat, thermal conductivity, heating, artificial viscosity + end +end + +subsection Termination criteria + set Termination criteria = steady state velocity + + subsection Steady state velocity + set Maximum relative deviation = 1e-5 + set Time in steady state = 0.1 + end +end diff --git a/benchmarks/blankenbach/base_case2b.prm.bak b/benchmarks/blankenbach/base_case2b.prm.bak new file mode 100644 index 00000000000..0851fcf0cf5 --- /dev/null +++ b/benchmarks/blankenbach/base_case2b.prm.bak @@ -0,0 +1,118 @@ +# This is case 2b from the Blankenbach Benchmark (Blankenbach 1989). + +set Additional shared libraries = ./plugin/libblankenbach.so +set End time = 1.0 +set Use years in output instead of seconds = false +set CFL number = 5.0 + +subsection Adiabatic conditions model + set Model name = function + + subsection Function + set Function constants = + set Function expression = 0; 0; 1 + set Variable names = depth + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2.5 + set Y extent = 1 + set X repetitions = 5 + set Y repetitions = 2 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +subsection Initial temperature model + set Model name = ascii data + + subsection Function + set Variable names = x,z + set Function constants = p=0.01, L=1, pi=3.1415926536, k=1, ratio=2.5 + set Function expression = 1* ((1.0-z/L) + p*cos(k*pi*x/L/ratio)*sin(pi*z/L)) + end + + subsection Ascii data model + set Data directory = + set Data file name = initial_temperature_case2b.txt + end +end + +subsection Material model + set Model name = nondimensional + + subsection Nondimensional model + set Di = 0.0 + set Ra = 1e4 + set Reference density = 1 + set Reference specific heat = 1 + set Use TALA = false + set Viscosity temperature prefactor = 9.70406052783923433184 + set Viscosity depth prefactor = 4.1588830833596718565 + set gamma = 1.0 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 3 + set Time steps between mesh refinement = 0 + set Coarsening fraction = 0.0 + set Refinement fraction = 1.0 +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Formulation + set Formulation = custom # with this selection equivalent to BA + set Mass conservation = incompressible + set Temperature equation = reference density profile +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics, heat flux statistics gradient, heating statistics, heat flux densities, temperature ascii out + + subsection Visualization + set Time between graphical output = 0.002 + set List of output variables = material properties, adiabat, thermal conductivity, heating, artificial viscosity + end +end + +subsection Termination criteria + set Termination criteria = steady state velocity + set Checkpoint on termination = true + + subsection Steady state velocity + set Maximum relative deviation = 1e-5 + set Time in steady state = 0.1 + end +end + +subsection Checkpointing + set Time between checkpoint = 600 +end diff --git a/benchmarks/blankenbach/plugin/code.cc.bak b/benchmarks/blankenbach/plugin/code.cc.bak new file mode 100644 index 00000000000..49920460923 --- /dev/null +++ b/benchmarks/blankenbach/plugin/code.cc.bak @@ -0,0 +1,167 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that generates ascii data output of the temperature + * field to be used as initial condition. + */ + template + class TemperatureAsciiOut : public Interface, public ::aspect::SimulatorAccess + { + public: + std::pair + execute (TableHandler &statistics) override; + }; + + template + std::pair + TemperatureAsciiOut::execute (TableHandler &) + { + std::string filename = (this->get_output_directory() + "temperature_ascii_data.txt"); + + struct entry + { + Point p; + double t; + }; + std::vector entries; + + const QMidpoint quadrature_formula; + + const unsigned int n_q_points = quadrature_formula.size(); + FEValues fe_values (this->get_mapping(), this->get_fe(), quadrature_formula, + update_JxW_values | update_values | update_quadrature_points); + + std::vector temperature_values(n_q_points); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + fe_values[this->introspection().extractors.temperature].get_function_values (this->get_solution(), temperature_values); + + for (unsigned int q=0; q x_values, y_values; + for (unsigned int idx = 0; idx< entries.size(); ++idx) + { + x_values.push_back(entries[idx].p(0)); + y_values.push_back(entries[idx].p(1)); + } + std::sort(x_values.begin(), x_values.end(), sort_double_instance); + x_values.erase( std::unique( x_values.begin(), x_values.end(), compare_double_instance ), x_values.end() ); + std::sort(y_values.begin(), y_values.end(), sort_double_instance); + y_values.erase( std::unique( y_values.begin(), y_values.end(), compare_double_instance ), y_values.end() ); + + n_x = x_values.size(); + n_y = y_values.size(); + } + + + std::stringstream f; + + f << std::scientific << std::setprecision(15); + + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + // Note: POINTS is only useful if our mesh is a structured grid + f << "# POINTS: " << n_x << ' ' << n_y << "\n"; + f << "# x y T\n"; + } + + for (unsigned int idx = 0; idx< entries.size(); ++idx) + f << entries[idx].p << ' ' << entries[idx].t << '\n'; + + aspect::Utilities::collect_and_write_file_content(filename, + f.str(), + this->get_mpi_communicator()); + + return std::make_pair (std::string ("Writing TemperatureAsciiOut:"), + filename); + } + + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(TemperatureAsciiOut, + "temperature ascii out", + "A postprocessor that generates ascii data " + "output of the temperature field that can " + "be read in in a subsequent computation.") + } +} diff --git a/benchmarks/blankenbach/plugin/heat_flux_statistics_gradient.cc.bak b/benchmarks/blankenbach/plugin/heat_flux_statistics_gradient.cc.bak new file mode 100644 index 00000000000..33dd11fe2fa --- /dev/null +++ b/benchmarks/blankenbach/plugin/heat_flux_statistics_gradient.cc.bak @@ -0,0 +1,198 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include "heat_flux_statistics_gradient.h" +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + template + std::pair + HeatFluxStatisticsGradient::execute (TableHandler &statistics) + { + // create a quadrature formula based on the temperature element alone. + const QGauss quadrature_formula (this->get_fe().base_element(this->introspection().base_elements.temperature).degree+1); + + FEFaceValues fe_face_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_gradients | update_values | + update_normal_vectors | + update_quadrature_points | update_JxW_values); + + std::vector> temperature_gradients (quadrature_formula.size()); + std::vector> composition_values (this->n_compositional_fields(),std::vector (quadrature_formula.size())); + + std::map local_boundary_fluxes; + + MaterialModel::MaterialModelInputs in(fe_face_values.n_quadrature_points, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(fe_face_values.n_quadrature_points, this->n_compositional_fields()); + + // for every surface face on which it makes sense to compute a + // heat flux and that is owned by this processor, + // integrate the normal heat flux given by the formula + // j = - k * n . grad T + // + // for the spherical shell geometry, note that for the inner boundary, + // the normal vector points *into* the core, i.e. we compute the flux + // *out* of the mantle, not into it. we fix this when we add the local + // contribution to the global flux + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + for (unsigned int f=0; f::faces_per_cell; ++f) + if (cell->at_boundary(f)) + { + fe_face_values.reinit (cell, f); + in.reinit(fe_face_values, cell, this->introspection(), this->get_solution()); + + this->get_material_model().evaluate(in, out); + + // Get the temperature gradients from the solution. + fe_face_values[this->introspection().extractors.temperature].get_function_gradients (this->get_solution(), temperature_gradients); + + double local_normal_flux = 0; + for (unsigned int q=0; qface(f)->boundary_id(); + local_boundary_fluxes[boundary_indicator] += local_normal_flux; + } + + // now communicate to get the global values + std::map global_boundary_fluxes; + { + // first collect local values in the same order in which they are listed + // in the set of boundary indicators + const std::set + boundary_indicators + = this->get_geometry_model().get_used_boundary_indicators (); + std::vector local_values; + for (std::set::const_iterator + p = boundary_indicators.begin(); + p != boundary_indicators.end(); ++p) + local_values.push_back (local_boundary_fluxes[*p]); + + // then collect contributions from all processors + std::vector global_values (local_values.size()); + Utilities::MPI::sum (local_values, this->get_mpi_communicator(), global_values); + + // and now take them apart into the global map again + unsigned int index = 0; + for (std::set::const_iterator + p = boundary_indicators.begin(); + p != boundary_indicators.end(); ++p, ++index) + global_boundary_fluxes[*p] = global_values[index]; + } + + // now add all of the computed heat fluxes to the statistics object + // and create a single string that can be output to the screen + std::ostringstream screen_text; + unsigned int index = 0; + for (std::map::const_iterator + p = global_boundary_fluxes.begin(); + p != global_boundary_fluxes.end(); ++p, ++index) + { + const std::string name = "Outward heat flux (gradient) through boundary with indicator " + + Utilities::int_to_string(p->first) + + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() + .translate_id_to_symbol_name (p->first)) + + " (W)"; + statistics.add_value (name, p->second); + + // also make sure that the other columns filled by the this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name, 8); + statistics.set_scientific (name, true); + + // finally have something for the screen + screen_text.precision(4); + screen_text << p->second << " W" + << (index == global_boundary_fluxes.size()-1 ? "" : ", "); + } + + return std::pair ("Heat fluxes (gradient) through boundary parts:", + screen_text.str()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(HeatFluxStatisticsGradient, + "heat flux statistics gradient", + "A postprocessor that computes some statistics about " + "the (conductive) heat flux across boundaries. For each boundary " + "indicator (see your geometry description for which boundary " + "indicators are used), the heat flux is computed in outward " + "direction, i.e., from the domain to the outside, using the " + "formula $\\int_{\\Gamma_i} -k \\nabla T \\cdot \\mathbf n$ " + "where $\\Gamma_i$ is the part of the boundary with indicator $i$, " + "$k$ is the thermal conductivity as reported by the material model, " + "$T$ is the temperature, and $\\mathbf n$ is the outward normal. " + "Note that the quantity so computed does not include any energy " + "transported across the boundary by material transport in cases " + "where $\\mathbf u \\cdot \\mathbf n \\neq 0$. The point-wise " + "heat flux can be obtained from the heat flux map postprocessor, " + "which outputs the heat flux to a file, or the heat flux map " + "visualization postprocessor, which outputs the heat flux for " + "visualization. " + "\n\n" + "As stated, this postprocessor computes the \\textit{outbound} heat " + "flux. If you " + "are interested in the opposite direction, for example from " + "the core into the mantle when the domain describes the " + "mantle, then you need to multiply the result by -1." + "\n\n" + "\\note{In geodynamics, the term ``heat flux'' is often understood " + "to be the quantity $- k \\nabla T$, which is really a heat " + "flux \\textit{density}, i.e., a vector-valued field. In contrast " + "to this, the current postprocessor only computes the integrated " + "flux over each part of the boundary. Consequently, the units of " + "the quantity computed here are $W=\\frac{J}{s}$.}" + "\n\n" + "The ``heat flux densities'' postprocessor computes the same " + "quantity as the one here, but divided by the area of " + "the surface.") + } +} diff --git a/benchmarks/blankenbach/plugin/heat_flux_statistics_gradient.h.bak b/benchmarks/blankenbach/plugin/heat_flux_statistics_gradient.h.bak new file mode 100644 index 00000000000..be9b019128c --- /dev/null +++ b/benchmarks/blankenbach/plugin/heat_flux_statistics_gradient.h.bak @@ -0,0 +1,53 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_heat_flux_statistics_gradient_h +#define _aspect_postprocess_heat_flux_statistics_gradient_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + /** + * A postprocessor that computes some statistics about the heat_flux based + * on the gradient of the temperature. + * + * @ingroup Postprocessing + */ + template + class HeatFluxStatisticsGradient : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/benchmarks/buiter_et_al_2008_jgr/figure_6_1e20.prm b/benchmarks/buiter_et_al_2008_jgr/figure_6_1e20.prm index d3006d93625..e72349df709 100644 --- a/benchmarks/buiter_et_al_2008_jgr/figure_6_1e20.prm +++ b/benchmarks/buiter_et_al_2008_jgr/figure_6_1e20.prm @@ -100,7 +100,6 @@ subsection Discretization set Use discontinuous composition discretization = true subsection Stabilization parameters - set Use limiter for discontinuous composition solution = true # apply the limiter to the DG solutions set Global composition maximum = 100.0, 1.0, 1.0, 1.0 set Global composition minimum = 0.0, 0.0, 0.0, 1.0 end diff --git a/benchmarks/buiter_et_al_2008_jgr/figure_6_1e20.prm.bak b/benchmarks/buiter_et_al_2008_jgr/figure_6_1e20.prm.bak new file mode 100644 index 00000000000..d3006d93625 --- /dev/null +++ b/benchmarks/buiter_et_al_2008_jgr/figure_6_1e20.prm.bak @@ -0,0 +1,179 @@ +# Global parameters +set Dimension = 2 +set Start time = 0 +set End time = 1e6 +set Use years in output instead of seconds = true +set Nonlinear solver scheme = single Advection, iterated Stokes +set Nonlinear solver tolerance = 1e-3 +set Max nonlinear iterations = 100 +set CFL number = 0.5 +set Output directory = output_figure_6_1e20 +set Timing output frequency = 1 +set Pressure normalization = no + +# Model geometry (400x35 km) +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 400 + set Y repetitions = 100 + set X extent = 400e3 + set Y extent = 35e3 + end +end + +# No mesh refinement, but the coarse mesh is 400x100 +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +# The nonlinear solver typically converges more quickly +# when no cheap Stokes solver steps are used for +# problems with Drucker-Prager plasticity. +subsection Solver parameters + subsection Stokes solver parameters + set Number of cheap Stokes solver steps = 0 + end +end + +# Free surface boundary classifications. +# Advecting the free surface vertically rather than +# in the surface normal direction can result in a +# more stable mesh when the deformation is large +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + + subsection Free surface + set Surface velocity projection = vertical + end +end + +# Velocity on boundaries characterized by functions +# Total extension rate is 1 cm/yr (0.5 cm/yr on each side) +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left x: function, right x:function + set Tangential velocity boundary indicators = bottom + + subsection Function + set Variable names = x,y + set Function constants = m=0.005, year=1 + set Function expression = if (x<200e3 , -1*m/year, 1*m/year); 0. + end +end + +# Number and name of compositional fields +# The field plastic_strain is used for tracking the plastic finite strain invariant +# upper: brittle upper crust; seed: 'weaker' brittle region +# lower: viscous lower crust +subsection Compositional fields + set Number of fields = 4 + set Names of fields = plastic_strain, upper, seed, lower +end + +# Spatial domain of different compositional fields +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = 0; \ + if((y>=17.5e3 && x<=198.0e3) || (y>=17.5e3 && x>=202.0e3) || \ + (y>=18.9e3 && x>=198.0e3 && x<=202.0e3), 1, 0); \ + if(y>=17.5e3 && y<18.9e3 && x>198.0e3 && x<202.0e3, 1, 0); \ + if(y<17.5e3, 1, 0); + end +end + +# Composition boundary conditions +subsection Boundary composition model + set List of model names = initial composition +end + +# Use discontinuous composition bound preserving limiter +subsection Discretization + set Composition polynomial degree = 2 + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 2 + set Use discontinuous composition discretization = true + + subsection Stabilization parameters + set Use limiter for discontinuous composition solution = true # apply the limiter to the DG solutions + set Global composition maximum = 100.0, 1.0, 1.0, 1.0 + set Global composition minimum = 0.0, 0.0, 0.0, 1.0 + end +end + +# Temperature boundary conditions +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 273 + set Left temperature = 273 + set Right temperature = 273 + set Top temperature = 273 + end +end + +# Temperature initial conditions (isothermal) +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 273 + end +end + +# Material model +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + set Reference temperature = 273 + set Minimum strain rate = 1.e-20 + set Reference strain rate = 1.e-16 + set Minimum viscosity = 1e18 + set Maximum viscosity = 1e26 + set Thermal diffusivities = 1.e-6 + set Heat capacities = 750. + set Densities = 2800 + set Thermal expansivities = 0. + set Viscosity averaging scheme = harmonic + set Viscous flow law = dislocation + set Prefactors for dislocation creep = 5.e-25, 5.e-25, 5.e-25, 5.e-25, 5.e-21 + set Stress exponents for dislocation creep = 1.0 + set Activation energies for dislocation creep = 0. + set Activation volumes for dislocation creep = 0. + set Angles of internal friction = 30., 30., 30., 4., 30. + set Cohesions = 20.e6, 20.e6, 20.e6, 2.e6, 1.e11 + set Strain weakening mechanism = plastic weakening with plastic strain only + set Start plasticity strain weakening intervals = 0.5, 0.5, 0.5, 0.5, 0.5 + set End plasticity strain weakening intervals = 1.5, 1.5, 1.5, 1.5, 1.5 + set Cohesion strain weakening factors = 0.1, 0.1, 0.1, 1.0, 1.0 + set Friction strain weakening factors = 0.13333, 0.1333, 0.1333, 1.0, 1.0 + end +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +# Post processing +subsection Postprocess + set List of postprocessors = velocity statistics, basic statistics, temperature statistics, visualization + + subsection Visualization + set List of output variables = density, viscosity, strain rate, error indicator, partition + set Time between graphical output = 1e5 + set Interpolate output = false + end +end diff --git a/benchmarks/buiter_et_al_2008_jgr/figure_6_1e22.prm.bak b/benchmarks/buiter_et_al_2008_jgr/figure_6_1e22.prm.bak new file mode 100644 index 00000000000..1a5a5380b6d --- /dev/null +++ b/benchmarks/buiter_et_al_2008_jgr/figure_6_1e22.prm.bak @@ -0,0 +1,12 @@ +include figure_6_1e20.prm + +set Dimension = 2 +set Output directory = output_figure_6_1e22 + +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + set Prefactors for dislocation creep = 5.e-25, 5.e-25, 5.e-25, 5.e-25, 5.e-23 + end +end diff --git a/benchmarks/buiter_et_al_2016_jsg/doc/convergence.part.prm b/benchmarks/buiter_et_al_2016_jsg/doc/convergence.part.prm index 544ad88b0ac..6e2907fd476 100644 --- a/benchmarks/buiter_et_al_2016_jsg/doc/convergence.part.prm +++ b/benchmarks/buiter_et_al_2016_jsg/doc/convergence.part.prm @@ -21,9 +21,9 @@ subsection Discretization set Use discontinuous composition discretization = true subsection Stabilization parameters - set Use limiter for discontinuous composition solution = true set Global composition maximum = 1, 1, 1, 1, 1, 100 set Global composition minimum = 0, 0, 0, 0, 0, 0 + set Limiter for discontinuous composition solution = bound preserving end end diff --git a/benchmarks/buiter_et_al_2016_jsg/doc/convergence.part.prm.bak b/benchmarks/buiter_et_al_2016_jsg/doc/convergence.part.prm.bak new file mode 100644 index 00000000000..544ad88b0ac --- /dev/null +++ b/benchmarks/buiter_et_al_2016_jsg/doc/convergence.part.prm.bak @@ -0,0 +1,44 @@ +# Note that the Linear/Nonlinear solver tolerance should be sufficiently strict +# to avoid numerical instabilities. +set Nonlinear solver scheme = single Advection, iterated Stokes +set Nonlinear solver tolerance = 1e-7 +set Max nonlinear iterations = 100 + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-8 + set Number of cheap Stokes solver steps = 0 + + # A higher restart length makes the solver more robust for large viscosity + # contrasts. + set GMRES solver restart length = 200 + end +end + +# The discontinuous composition bound preserving limiter produces sharp +# interfaces between compositional layers. +subsection Discretization + set Use discontinuous composition discretization = true + + subsection Stabilization parameters + set Use limiter for discontinuous composition solution = true + set Global composition maximum = 1, 1, 1, 1, 1, 100 + set Global composition minimum = 0, 0, 0, 0, 0, 0 + end +end + +# Material properties +# Using harmonic material averaging is required to achieve reasonable +# convergence behavior, particulally when the viscosity contrast is large. +subsection Material model + set Material averaging = harmonic average + set Model name = visco plastic + + subsection Visco Plastic + # The viscosity contrast is 10^7 here and any value higher than this causes + # divergence of the solver. + set Minimum viscosity = 1e5 + set Maximum viscosity = 1e12 + set Viscosity averaging scheme = harmonic + end +end diff --git a/benchmarks/buiter_et_al_2016_jsg/doc/velocity_bc.part.prm.bak b/benchmarks/buiter_et_al_2016_jsg/doc/velocity_bc.part.prm.bak new file mode 100644 index 00000000000..3a997ed04db --- /dev/null +++ b/benchmarks/buiter_et_al_2016_jsg/doc/velocity_bc.part.prm.bak @@ -0,0 +1,37 @@ +# Spatial domain of different compositional fields: +# Quartz sand (qsand) has two layers with 1 cm thickness each. +# Corundum sand (csand) is in the middle of the 2-layer quatz sand and is +# 1 cm thick. +# The boundary 2-mm-thin layers (bound) sit on both the bottom of the domain and +# between the sand and rigid indenter block. The right boundary has a constant +# inflow velocity, which pushes a rigid block that approximates a mobile wall. +# Movement of the rigid block drives deformation in the sand layers. +# The boundary between the rigid block and boundary layers produces a sharp +# velocity discontinuity that localizes brittle deformation. +# The sticky air layer is set on top of the sand layer and approximates a +# free surface. + +# Velocity boundary conditions +subsection Boundary velocity model + set Zero velocity boundary indicators = bottom #no slip + set Tangential velocity boundary indicators = left #free slip + + # right - material inflow with a velocity of 2.5 cm/hour at the height of + # the pushing block. The velocity linearly decreases from the base of the + # rigid block to 0 cm/hour at the base of the model. + set Prescribed velocity boundary indicators = right:function + + subsection Function + set Variable names = x,y + set Function constants = cm=0.01, h=3600, th=0.002 + set Function expression = if(y>th, -2.5*cm/h, -(y/th)*2.5*cm/h); 0 + end +end + +# The top boundary is open (zero traction), which allows the sticky air to +# flow freely through it as topography develops along the wedge. Additional +# testing revealed that using a true free surface leads to significant mesh +# distortion and associated numerical instabilities. +subsection Boundary traction model + set Prescribed traction boundary indicators = top: zero traction +end diff --git a/benchmarks/buiter_et_al_2016_jsg/exp_1.prm b/benchmarks/buiter_et_al_2016_jsg/exp_1.prm index 51b2116626e..976b4f505b3 100644 --- a/benchmarks/buiter_et_al_2016_jsg/exp_1.prm +++ b/benchmarks/buiter_et_al_2016_jsg/exp_1.prm @@ -106,11 +106,10 @@ subsection Discretization set Use discontinuous composition discretization = true subsection Stabilization parameters - set Use limiter for discontinuous composition solution = true - # [sand, bound, block, sticky_air, total_strain] set Global composition maximum = 1., 1., 1., 1., 1e5 set Global composition minimum = 0., 0., 0., 0., 0. + set Limiter for discontinuous composition solution = bound preserving end end diff --git a/benchmarks/buiter_et_al_2016_jsg/exp_1.prm.bak b/benchmarks/buiter_et_al_2016_jsg/exp_1.prm.bak new file mode 100644 index 00000000000..51b2116626e --- /dev/null +++ b/benchmarks/buiter_et_al_2016_jsg/exp_1.prm.bak @@ -0,0 +1,191 @@ +# This is an input file for the setup for the benchmark described in Buiter et al, 2016 +# which simulates a stable wedge undergoing translation. +# Experiment 2 can be found in $ASPECT_INSTALL/aspect/benchmarks/buiter_et_al_2016_jsg +# Please refer to the README file for further details on the experimental setup and results. +##### Global parameters +set Dimension = 2 +set Start time = 0 +set End time = 14400 # Equivalent to 10 cm of horizontal translation +set Use years in output instead of seconds = false +set Nonlinear solver scheme = single Advection, iterated Stokes + +# Note that the Linear/Nonlinear solver tolerance should be sufficiently +# strict to avoid numerical instabilities. + +set Nonlinear solver tolerance = 1e-7 +set Max nonlinear iterations = 100 +set CFL number = 0.5 +set Output directory = output-stable_wedge +set Timing output frequency = 1 +set Pressure normalization = no +set Resume computation = auto + +#### Parameters describing the model + +# Model geometry +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 300 + set Y repetitions = 70 + set X extent = 0.15 + set Y extent = 0.035 + end +end + +# Mesh refinement specifications +# AMR is not used since model X,Y repetitions are defined. +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +# Boundary classifications +# Temperature boundary conditions +# Temperature does not affect model +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = initial temperature +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left + set Prescribed velocity boundary indicators = right:function + set Zero velocity boundary indicators = bottom + + subsection Function + set Variable names = x,y + set Function constants = cm=0.01, h=3600., th=0.002 # h = hr = 3600 s; th = thickness of bounding box + set Function expression = if (y>th, -2.5*cm/h, -(y/th)*2.5*cm/h) ; 0. # velocity BC is defined such that the wedge is pushed at 2.5 cm/h to the left above the bound -ing box and tapers to zero from the top to the bottom of the bounding box. + end +end + +# The zero traction surface allows sticky air to leave the system in response to compression. +subsection Boundary traction model + set Prescribed traction boundary indicators = top: zero traction +end + +# Initial temperature field +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 100 + end +end + +# Number and name of compositional fields +subsection Compositional fields + set Number of fields = 5 + set Names of fields = sand, bound, block, sticky_air, total_strain +end + +# Spatial domain of different compositional fields: +# Sand wedge with taper angle of 20 degrees, +# Box bounding simulated sandbox experiment, +# Rigid indentor used to translate wedge, and +# Sticky air layer above modelled materials +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = th=0.002 + set Function expression = if((x<0.1324 && x>=0.05) && (y<=0.36408*x-0.0182039 && y>=th), 1, 0); \ + if((x>=0.1324 && x<0.1329) || (x>0 && y<=th),1,0); \ + if(x>=0.1329 && y>th,1,0); \ + if((x<=0.1324 && y>0.36408*x-0.0182039 && y>th) || (x<0.05 && y>th),1,0); \ + 0; + end +end + +# Use disccontinous composition bound preserving limiter +subsection Discretization + set Use discontinuous composition discretization = true + + subsection Stabilization parameters + set Use limiter for discontinuous composition solution = true + + # [sand, bound, block, sticky_air, total_strain] + set Global composition maximum = 1., 1., 1., 1., 1e5 + set Global composition minimum = 0., 0., 0., 0., 0. + end +end + +# Material model +subsection Material model + set Material averaging = harmonic average + set Model name = visco plastic + + subsection Visco Plastic + # [bkd, sand, bound, block, sticky_air, total_strain] + set Densities = 1560, 1560., 3100, 1560 , 0, 1560 + set Reference temperature = 293 + set Heat capacities = 750. + set Thermal diffusivities = 1e-6 + set Thermal expansivities = 0. + set Minimum viscosity = 1e4 + set Maximum viscosity = 1e12 + set Viscosity averaging scheme = maximum composition + set Viscous flow law = dislocation + set Prefactors for dislocation creep = 5e-11,5e-50, 5e-50, 5e-11, 5e-5, 1e5 + set Stress exponents for dislocation creep = 1.0 + set Activation energies for dislocation creep = 0. + set Activation volumes for dislocation creep = 0. + + # [bkd, sand, bound, block, sticky_air, total_strain] + set Reference strain rate = 1.e-5 + set Minimum strain rate = 1.e-10 + set Strain weakening mechanism = total strain + set Start plasticity strain weakening intervals = 0, 0.50, 0.5, 0, 0, 1e5 + set End plasticity strain weakening intervals = 0.1, 1.00, 1, 0.1, 0.1, 1e4 + set Angles of internal friction = 36., 36., 1.6, 0., 0., 1e5 + set Friction strain weakening factors = 1, 0.861, 1, 1, 1, 1e5 + set Cohesions = 30., 30., 3., 1.e18, 1.e18, 1e5 + set Cohesion strain weakening factors = 1, 1.00, 1, 1, 1, 1e5 + end +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +# Checkpointing for restart files +subsection Checkpointing + set Steps between checkpoint = 10 +end + +# Post processing +subsection Postprocess + set List of postprocessors = velocity statistics, basic statistics, visualization + + subsection Visualization + set List of output variables = density, viscosity, strain rate, named additional outputs + set Output format = vtu + set Time between graphical output = 144 + set Interpolate output = false + end +end + +# Termination Criteria +subsection Termination criteria + set Termination criteria = end step + set End step = 10000 +end + +# Note that the Linear/Nonlinear solver tolerance should be sufficiently +# strict to avoid numerical instabilities. + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-8 + set Number of cheap Stokes solver steps = 0 + end +end diff --git a/benchmarks/buiter_et_al_2016_jsg/exp_2_high_resolution.prm b/benchmarks/buiter_et_al_2016_jsg/exp_2_high_resolution.prm index b2496ed311c..dba24612726 100644 --- a/benchmarks/buiter_et_al_2016_jsg/exp_2_high_resolution.prm +++ b/benchmarks/buiter_et_al_2016_jsg/exp_2_high_resolution.prm @@ -48,9 +48,9 @@ subsection Discretization set Use discontinuous composition discretization = true subsection Stabilization parameters - set Use limiter for discontinuous composition solution = true set Global composition maximum = 1, 1, 1, 1, 1, 100 set Global composition minimum = 0, 0, 0, 0, 0, 0 + set Limiter for discontinuous composition solution = bound preserving end end diff --git a/benchmarks/buiter_et_al_2016_jsg/exp_2_high_resolution.prm.bak b/benchmarks/buiter_et_al_2016_jsg/exp_2_high_resolution.prm.bak new file mode 100644 index 00000000000..b2496ed311c --- /dev/null +++ b/benchmarks/buiter_et_al_2016_jsg/exp_2_high_resolution.prm.bak @@ -0,0 +1,224 @@ +# This parameter file reproduces the unstable wedge experiment 2 from +# Buiter et al., 2016, JSG. +# Experiment 2 tests how an unstable subcritical wedge deforms to reach the +# critical taper solution. Horizontal layers of sand have 10 cm shortening +# by inward movement of a mobile wall with a velocity of 2.5 cm/hour. Both +# the base and the surface are horizontal and the “wedge” is thus in the +# unstable field. This experiment builds a thrust wedge through a combination +# of mainly in-sequence forward and backward thrusting. Deformation starts by +# forming a pop-up structure near the high viscosity rigid indenter. + +# Global parameters +set Dimension = 2 +set Start time = 0 +set End time = 14400 #Equivalent to ~10 cm of shortening +set Use years in output instead of seconds = false +set CFL number = 0.5 +set Output directory = output-Brittle_thrust_wedge_exp2 +set Pressure normalization = no +set Timing output frequency = 20 + +# Note that the Linear/Nonlinear solver tolerance should be sufficiently +# strict to avoid numerical instabilities. +set Nonlinear solver scheme = single Advection, iterated Stokes +set Nonlinear solver tolerance = 1e-7 +set Max nonlinear iterations = 100 + +# For restarting the model +set Resume computation = auto + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-8 + set Number of cheap Stokes solver steps = 0 + + # A higher restart length makes the solver more robust for large viscosity + # contrasts. + set GMRES solver restart length = 200 + end +end + +# The discontinuous composition bound preserving limiter produces sharp +# interfaces between compositional layers. +subsection Discretization + set Composition polynomial degree = 2 + set Temperature polynomial degree = 2 + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = false + set Use discontinuous composition discretization = true + + subsection Stabilization parameters + set Use limiter for discontinuous composition solution = true + set Global composition maximum = 1, 1, 1, 1, 1, 100 + set Global composition minimum = 0, 0, 0, 0, 0, 0 + end +end + +subsection Checkpointing + set Steps between checkpoint = 20 +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +### Parameters describing the model + +# Model geometry (36 x 8 cm) +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 180 + set Y repetitions = 40 + set X extent = 0.36 + set Y extent = 0.08 + end +end + +# Mesh refinement specifications +subsection Mesh refinement + set Initial adaptive refinement = 0 + + #The resolution is 0.5 mm/cell + set Initial global refinement = 2 + set Time steps between mesh refinement = 0 +end + +# Boundary conditions & initial conditions + +# Composition boundary conditions +subsection Boundary composition model + set Fixed composition boundary indicators = bottom, left, right + set List of model names = initial composition +end + +# Number and names of compositional fields +subsection Compositional fields + set Number of fields = 6 + set Names of fields = qsand,csand,bound,block, \ + sticky_air,total_strain +end + +# Spatial domain of different compositional fields: +# Quartz sand (qsand) has two layers with 1 cm thickness each. +# Corundum sand (csand) is in the middle of the 2-layer quatz sand and is +# 1 cm thick. +# The boundary 2-mm-thin layers (bound) sit on both the bottom of the domain and +# between the sand and rigid indenter block. The right boundary has a constant +# inflow velocity, which pushes a rigid block that approximates a mobile wall. +# Movement of the rigid block drives deformation in the sand layers. +# The boundary between the rigid block and boundary layers produces a sharp +# velocity discontinuity that localizes brittle deformation. +# The sticky air layer is set on top of the sand layer and approximates a +# free surface. + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = w1=0.35, w2=0.352, \ + h1=0.002, h2=0.012, \ + h3=0.022, h4=0.032 + set Function expression = if((x<=w1 & y<=h2 & y>h1) || (x<= w1 & y>h3 & y<=h4), 1,0); \ + if((x<=w1 & y>h2 & y<=h3), 1,0); \ + if((x>w1 & x<=w2 & y>h1) ||(y<=h1), 1, 0); \ + if(x>w2 & y>h1,1,0); \ + if(x<=w1 & y>h4,1,0); 0 + end +end + +# Temperature boundary conditions +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = initial temperature +end + +# Initial temperature field +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 293 + end +end + +# Velocity boundary conditions +subsection Boundary velocity model + set Zero velocity boundary indicators = bottom #no slip + set Tangential velocity boundary indicators = left #free slip + + # right - material inflow with a velocity of 2.5 cm/hour at the height of + # the pushing block. The velocity linearly decreases from the base of the + # rigid block to 0 cm/hour at the base of the model. + set Prescribed velocity boundary indicators = right:function + + subsection Function + set Variable names = x,y + set Function constants = cm=0.01, h=3600, th=0.002 + set Function expression = if(y>th, -2.5*cm/h, -(y/th)*2.5*cm/h); 0 + end +end + +# The top boundary is open (zero traction), which allows the sticky air to +# flow freely through it as topography develops along the wedge. Additional +# testing revealed that using a true free surface leads to significant mesh +# distortion and associated numerical instabilities. +subsection Boundary traction model + set Prescribed traction boundary indicators = top: zero traction +end + +# Material properties +# Using harmonic material averaging is required to achieve reasonable +# convergence behavior, particulally when the viscosity contrast is large. +subsection Material model + set Material averaging = harmonic average + set Model name = visco plastic + + subsection Visco Plastic + set Reference temperature = 293 + set Minimum strain rate = 1e-20 + set Reference strain rate = 2e-5 + + # The viscosity contrast is 10^7 here and any value higher than this causes + # divergence of the solver. + set Minimum viscosity = 1e5 + set Maximum viscosity = 1e12 + set Thermal diffusivities = 1e-6 + set Heat capacities = 750 + set Densities = 1560, 1560, 1890, 1560, 3000, 0, 1e5 + set Thermal expansivities = 0 + set Viscosity averaging scheme = harmonic + set Viscous flow law = dislocation + set Prefactors for dislocation creep = 5e-15, 5e-15, 5e-15, 5e-15, 5e-18, 5e-5, 5e-18 + set Stress exponents for dislocation creep = 1 + set Activation energies for dislocation creep = 0 + set Activation volumes for dislocation creep = 0 + set Angles of internal friction = 36, 36, 36, 16, 0, 0, 1e18 + set Cohesions = 30, 30, 30, 30, 1e18, 1e18, 1e18 + set Strain weakening mechanism = total strain + set Start plasticity strain weakening intervals = 0.5 + set End plasticity strain weakening intervals = 1 + set Cohesion strain weakening factors = 1 + set Friction strain weakening factors = 1, 0.861, 0.861, 0.875, 1, 1, 1 + end +end + +# Post processing +subsection Postprocess + set List of postprocessors = velocity statistics, basic statistics, temperature statistics, visualization + + subsection Visualization + set List of output variables = density, viscosity, strain rate, error indicator + set Output format = vtu + set Time between graphical output = 144 # Equivalent to ~0.5 cm of shortening + set Interpolate output = true + set Number of grouped files = 1 + end +end diff --git a/benchmarks/buiter_et_al_2016_jsg/exp_2_low_resolution.prm.bak b/benchmarks/buiter_et_al_2016_jsg/exp_2_low_resolution.prm.bak new file mode 100644 index 00000000000..977ff6d9841 --- /dev/null +++ b/benchmarks/buiter_et_al_2016_jsg/exp_2_low_resolution.prm.bak @@ -0,0 +1,32 @@ +# This is the unstable wedge experiment 2 +# This prm file is the same as the exp_2_high_resolution.prm file except +# changes below. + + + +include $ASPECT_SOURCE_DIR/benchmarks/buiter_et_al_2016_jsg/exp_2_high_resolution.prm + + +# Mesh refinement specifications +subsection Mesh refinement + set Initial adaptive refinement = 0 + + # The resolution is 2 mm/cell. + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +# Material properties + +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + # Further testing revealed that decreasing the model resolution allows + # using a higher contrast between the minimum and maximum viscosity. + # The viscosity contrast is 10^8 here and any value higher than this + # causes divergence of the solver. + set Minimum viscosity = 1e4 + set Maximum viscosity = 1e12 + end +end diff --git a/benchmarks/burstedde/burstedde.cc.bak b/benchmarks/burstedde/burstedde.cc.bak new file mode 100644 index 00000000000..08a0b68dbb1 --- /dev/null +++ b/benchmarks/burstedde/burstedde.cc.bak @@ -0,0 +1,517 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + /** + * This is the "Burstedde" benchmark defined in the following paper: + * @code + * @Article{busa13, + * author = {Burstedde, Carsten and Stadler, Georg and Alisic, Laura and Wilcox, Lucas C and Tan, Eh and Gurnis, Michael and Ghattas, Omar}, + * title = {Large-scale adaptive mantle convection simulation}, + * journal = {Geophysical Journal International}, + * year = 2013, + * volume = 192, + * number = {3}, + * publisher = {Oxford University Press}, + * pages = {889--906}} + * @endcode + * + */ + namespace BursteddeBenchmark + { + using namespace dealii; + + namespace AnalyticSolutions + { + Tensor<1,3> + burstedde_velocity (const Point<3> &pos, + const double /*eta*/) + { + const double x = pos[0]; + const double y = pos[1]; + const double z = pos[2]; + + // create a Point<3> (because it has a constructor that takes + // three doubles) and return it (it automatically converts to + // the necessary Tensor<1,3>). + return Point<3> (x+x*x+x*y+x*x*x*y, + y+x*y+y*y+x*x*y*y, + -2.*z-3.*x*z-3.*y*z-5.*x*x*y*z); + } + + double + burstedde_pressure (const Point<3> &pos, + const double /*eta*/) + { + const double x = pos[0]; + const double y = pos[1]; + const double z = pos[2]; + + return x*y*z+x*x*x*y*y*y*z-5./32.; + } + + + /** + * The exact solution for the Burstedde benchmark. + */ + template + class FunctionBurstedde : public Function + { + public: + FunctionBurstedde (const double beta) + : + Function(dim+2), + beta_(beta) + {} + + void vector_value (const Point &pos, + Vector &values) const override + { + Assert (dim == 3, ExcNotImplemented()); + Assert (values.size() >= 4, ExcInternalError()); + + const Point<3> p (pos[0], pos[1], pos[2]); + + const Tensor<1,3> v = AnalyticSolutions::burstedde_velocity (p, beta_); + values[0] = v[0]; + values[1] = v[1]; + values[2] = v[2]; + + values[3] = AnalyticSolutions::burstedde_pressure (p, beta_); + } + + private: + const double beta_; + }; + } + + + + template + class BursteddeBoundary : public BoundaryVelocity::Interface + { + public: + /** + * Constructor. + */ + BursteddeBoundary(); + + /** + * Return the boundary velocity as a function of position. + */ + Tensor<1,dim> + boundary_velocity (const types::boundary_id boundary_indicator, + const Point &position) const override; + + private: + const double beta; + }; + + template + BursteddeBoundary::BursteddeBoundary () + : + beta (0) + {} + + + + template <> + Tensor<1,2> + BursteddeBoundary<2>:: + boundary_velocity (const types::boundary_id , + const Point<2> &/*p*/) const + { + Assert (false, ExcNotImplemented()); + return Tensor<1,2>(); + } + + + + template <> + Tensor<1,3> + BursteddeBoundary<3>:: + boundary_velocity (const types::boundary_id , + const Point<3> &p) const + { + return AnalyticSolutions::burstedde_velocity (p, beta); + } + + + + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @ingroup MaterialModels + */ + template + class BursteddeMaterial : public MaterialModel::Interface + { + public: + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const Point &p = in.position[i]; + + const double x=p[0]; + const double y=p[1]; + const double z=p[2]; + const double mu=exp(1. - beta * (x*(1.-x)+y*(1.-y) + z*(1.-z))); + + out.viscosities[i] = mu; + out.thermal_conductivities[i] = 0.0; + out.densities[i] = 1.0; + + out.thermal_expansion_coefficients[i] = 0.0; + out.compressibilities[i] = 0.0; + + out.specific_heat[i] = 0.0; + + // Pressure derivative of entropy at the given positions. + out.entropy_derivative_pressure[i] = 0.0; + // Temperature derivative of entropy at the given positions. + out.entropy_derivative_temperature[i] = 0.0; + // Change in composition due to chemical reactions at the + // given positions. The term reaction_terms[i][c] is the + // change in compositional field c at point i. + for (unsigned int c=0; c + bool + BursteddeMaterial:: + is_compressible () const + { + return false; + } + + template + void + BursteddeMaterial::declare_parameters (ParameterHandler &prm) + { + //create a global section in the parameter file for parameters + //that describe this benchmark. note that we declare them here + //in the material model, but other kinds of plugins (e.g., the gravity + //model below) may also read these parameters even though they do not + //declare them + prm.enter_subsection("Burstedde benchmark"); + { + prm.declare_entry("Viscosity parameter", "20", + Patterns::Double (0), + "Viscosity in the Burstedde benchmark."); + } + prm.leave_subsection(); + } + + + template + void + BursteddeMaterial::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Burstedde benchmark"); + { + beta = prm.get_double ("Viscosity parameter"); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + + template + double + BursteddeMaterial::get_beta() const + { + return beta; + } + + /** + * Gravity model for the Burstedde benchmark + */ + + template + class BursteddeGravity : public aspect::GravityModel::Interface + { + public: + Tensor<1,dim> gravity_vector (const Point &pos) const override; + + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + double beta; + }; + + template + Tensor<1,dim> + BursteddeGravity:: + gravity_vector(const Point &pos) const + { + + const double x=pos[0]; + const double y=pos[1]; + const double z=pos[2]; + const double mu=exp(1. - beta * (x*(1.-x)+y*(1.-y) + z*(1.-z))); + + const double dmudx=-beta*(1.-2.*x)*mu; + const double dmudy=-beta*(1.-2.*y)*mu; + const double dmudz=-beta*(1.-2.*z)*mu; + + Tensor<1,dim> g; + + g[0]=((y*z+3.*std::pow(x,2)*std::pow(y,3)*z)- mu*(2.+6.*x*y)) + -dmudx*(2.+4.*x+2.*y+6.*std::pow(x,2)*y) + -dmudy*(x+std::pow(x,3)+y+2.*x*std::pow(y,2)) + -dmudz*(-3.*z-10.*x*y*z); + + g[1]=((x*z+3.*std::pow(x,3)*std::pow(y,2)*z)- mu*(2.+2.*std::pow(x,2)+2.*std::pow(y,2))) + -dmudx*(x+std::pow(x,3)+y+2.*x*std::pow(y,2)) + -dmudy*(2.+2.*x+4.*y+4.*std::pow(x,2)*y) + -dmudz*(-3.*z-5.*std::pow(x,2)*z); + + g[2]=((x*y+std::pow(x,3)*std::pow(y,3)) - mu*(-10.*y*z)) + -dmudx*(-3.*z-10.*x*y*z) + -dmudy*(-3.*z-5.*std::pow(x,2)*z) + -dmudz*(-4.-6.*x-6.*y-10.*std::pow(x,2)*y); + + return g; + } + + template + void + BursteddeGravity::declare_parameters (ParameterHandler &) + { + //nothing to declare here. This plugin will however, read parameters + //declared by the material model in the "Burstedde benchmark" section + } + + template + void + BursteddeGravity::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Burstedde benchmark"); + { + beta = prm.get_double ("Viscosity parameter"); + } + prm.leave_subsection(); + } + + + /** + * A postprocessor that evaluates the accuracy of the solution. + * + * The implementation of error evaluators that correspond to the + * benchmarks defined in the paper Duretz et al. reference above. + */ + template + class BursteddePostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &statistics) override; + }; + + template + std::pair + BursteddePostprocessor::execute (TableHandler &) + { + std::unique_ptr> ref_func; + { + const BursteddeMaterial & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + ref_func = std::make_unique>(material_model.get_beta()); + } + + const QGauss quadrature_formula (this->introspection().polynomial_degree.velocities+2); + + Vector cellwise_errors_u (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_p (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_ul2 (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_pl2 (this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_u(std::pair(0,dim), + dim+2); + ComponentSelectFunction comp_p(dim, dim+2); + + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_u, + quadrature_formula, + VectorTools::L1_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_p, + quadrature_formula, + VectorTools::L1_norm, + &comp_p); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_ul2, + quadrature_formula, + VectorTools::L2_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_pl2, + quadrature_formula, + VectorTools::L2_norm, + &comp_p); + + const double u_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_u, VectorTools::L1_norm); + const double p_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_p, VectorTools::L1_norm); + const double u_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_ul2, VectorTools::L2_norm); + const double p_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_pl2, VectorTools::L2_norm); + + std::ostringstream os; + + os << std::scientific << u_l1 + << ", " << p_l1 + << ", " << u_l2 + << ", " << p_l2; + + return std::make_pair("Errors u_L1, p_L1, u_L2, p_L2:", os.str()); + } + + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace BursteddeBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(BursteddeMaterial, + "BursteddeMaterial", + "A material model that corresponds to the `Burstedde' benchmark. " + "See the manual for more information.") + + ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(BursteddeBoundary, + "BursteddeBoundary", + "Implementation of the velocity boundary conditions for the " + "`Burstedde' benchmark. See the manual for more information about this " + "benchmark.") + + ASPECT_REGISTER_POSTPROCESSOR(BursteddePostprocessor, + "BursteddePostprocessor", + "A postprocessor that compares the solution of the `Burstedde' benchmark " + "with the one computed by ASPECT " + "and reports the error. See the manual for more information.") + ASPECT_REGISTER_GRAVITY_MODEL(BursteddeGravity, + "BursteddeGravity", + "A gravity model in corresponding to the `Burstedde' benchmark. " + "See the manual for more information.") + } +} diff --git a/benchmarks/burstedde/burstedde.prm.bak b/benchmarks/burstedde/burstedde.prm.bak new file mode 100644 index 00000000000..fc5bcb93414 --- /dev/null +++ b/benchmarks/burstedde/burstedde.prm.bak @@ -0,0 +1,104 @@ +# The 3D polynomial Stokes (burstedde) benchmark, for which an +# analytical solution is available. +# +# See the manual for more information. + +############### Global parameters +# We use a 3d setup. Since we are only interested +# in a steady state solution, we set the end time +# equal to the start time to force a single time +# step before the program terminates. +set Additional shared libraries = ./libburstedde.so +set Dimension = 3 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = false +set Nonlinear solver scheme = no Advection, iterated Stokes +set Output directory = output +set Pressure normalization = volume + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + set Number of cheap Stokes solver steps = 0 + end +end + +############### Parameters describing the model +# The setup is a 3d unit cube. +# Because the temperature plays no role in this model we need not +# bother to describe temperature boundary conditions or +# the material parameters that pertain to the temperature. + + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + set Z extent = 1 + end +end + +#Boundary conditions + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left : BursteddeBoundary, \ + right : BursteddeBoundary, \ + front : BursteddeBoundary, \ + back : BursteddeBoundary, \ + bottom: BursteddeBoundary, \ + top : BursteddeBoundary +end + +subsection Material model + set Model name = BursteddeMaterial +end + +subsection Gravity model + set Model name = BursteddeGravity +end + +subsection Burstedde benchmark + #Viscosity parameter is beta + set Viscosity parameter = 20 +end + +############### Parameters describing the temperature field +# As above, there is no need to set anything for the +# temperature boundary conditions. + + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the discretization +# The following parameters describe how often we want to refine +# the mesh globally and adaptively, what fraction of cells should +# be refined in each adaptive refinement step, and what refinement +# indicator to use when refining the mesh adaptively. + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 3 + set Refinement fraction = 0.2 + set Strategy = velocity +end + +############### Parameters describing what to do with the solution +# The final section allows us to choose which postprocessors to +# run at the end of each time step. + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, BursteddePostprocessor + + subsection Visualization + set List of output variables = density, viscosity, strain rate + end +end diff --git a/benchmarks/burstedde/doc/burstedde.prm.bak b/benchmarks/burstedde/doc/burstedde.prm.bak new file mode 100644 index 00000000000..830ec42fd67 --- /dev/null +++ b/benchmarks/burstedde/doc/burstedde.prm.bak @@ -0,0 +1,32 @@ +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + end +end + +# Boundary conditions +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left : BursteddeBoundary, \ + right : BursteddeBoundary, \ + front : BursteddeBoundary, \ + back : BursteddeBoundary, \ + bottom: BursteddeBoundary, \ + top : BursteddeBoundary +end + +subsection Material model + set Model name = BursteddeMaterial +end + +subsection Gravity model + set Model name = BursteddeGravity +end + +subsection Burstedde benchmark + # Viscosity parameter is beta + set Viscosity parameter = 20 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, BursteddePostprocessor +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe/adiabatic.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe/adiabatic.prm.bak new file mode 100644 index 00000000000..24921c5158f --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe/adiabatic.prm.bak @@ -0,0 +1,8 @@ +subsection Boundary temperature model + set Fixed temperature boundary indicators = left + set List of model names = box + + subsection Box + set Left temperature = 1600 + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe/ala.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe/ala.prm.bak new file mode 100644 index 00000000000..ea154381bf0 --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe/ala.prm.bak @@ -0,0 +1,14 @@ +subsection Formulation + set Mass conservation = reference density profile + set Temperature equation = reference density profile +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + # A gravity is currently necessary to compute the reference profile. + # Set is so low that it does not affect the solution + set Magnitude = 0.000000001 + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe/hydrostatic.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe/hydrostatic.prm.bak new file mode 100644 index 00000000000..503708897df --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe/hydrostatic.prm.bak @@ -0,0 +1,4 @@ +subsection Formulation + set Mass conservation = hydrostatic compression + set Temperature equation = real density +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe/isentropic.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe/isentropic.prm.bak new file mode 100644 index 00000000000..74b3defb28c --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe/isentropic.prm.bak @@ -0,0 +1,4 @@ +subsection Formulation + set Mass conservation = isentropic compression + set Temperature equation = real density +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe/lateral_pipe.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe/lateral_pipe.prm.bak new file mode 100644 index 00000000000..afca18ae037 --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe/lateral_pipe.prm.bak @@ -0,0 +1,125 @@ +# This is a benchmark to illustrate the effect of different formulations +# of compressibility. It starts from a simple lateral pipe flow model, +# in which material enters a lateral pipe with a prescribed velocity. +# Due to internal heating the material expands and the velocity +# changes to conserve mass. + +set Additional shared libraries = ../plugins/libcompressibility_formulations.so +set Dimension = 2 +set End time = 5e8 +set Use years in output instead of seconds = true +set Adiabatic surface temperature = 1600 +set Nonlinear solver scheme = iterated Advection and Stokes +set Nonlinear solver tolerance = 1e-12 +set Max nonlinear iterations = 25 +set Output directory = output-lateral_pipe + +subsection Adiabatic conditions model + subsection Compute profile + set Number of points = 100000 + set Composition reference profile = function + end +end + +subsection Discretization + set Use locally conservative discretization = true + set Use discontinuous composition discretization = true + set Use discontinuous temperature discretization = true +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + end +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = density_field + set Compositional field methods = prescribed field + set Types of fields = density +end + +subsection Initial composition model + set Model name = adiabatic density +end + +subsection Geometry model + set Model name = box + + subsection Box + set Y extent = 100000 + set X extent = 1000000 + set X repetitions = 8 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0.0 + end +end + +subsection Heating model + set List of model names = adiabatic heating, shear heating, function + + subsection Function + set Function expression = 1e-10 * exp(x/1000000) + end +end + +############### Boundary conditions +# We only fix the temperature at the upper boundary, the other boundaries +# are isolating. +subsection Boundary temperature model + set Fixed temperature boundary indicators = left + set List of model names = initial temperature +end + +# To guarantuee a steady downward flow, we fix the velocity +# at the top and bottom, and set it to free slip on the sides. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left:function + set Tangential velocity boundary indicators = bottom,top + + subsection Function + set Function expression = 1e-2;0.0 + set Variable names = x,y + end +end + +subsection Initial temperature model + set Model name = adiabatic +end + +subsection Material model + set Model name = compressibility formulations + + subsection Simple compressible model + set Thermal conductivity = 0.0 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, mass flux statistics, material statistics + + subsection Visualization + set Number of grouped files = 1 + set Output format = vtu + + # We are only interested in the last timestep (when the system hast reached + # a steady state). For following the development of the system or checking + # if the solution already reached steady state, this parameter can be set + # to a smaller value. + set Time between graphical output = 1e7 + set List of output variables = nonadiabatic temperature, nonadiabatic pressure, heating, material properties, strain rate + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe/projected_density.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe/projected_density.prm.bak new file mode 100644 index 00000000000..71b048352cb --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe/projected_density.prm.bak @@ -0,0 +1,10 @@ +subsection Formulation + set Mass conservation = projected density field + set Temperature equation = real density +end + +subsection Material model + subsection Projected density model + set Use adiabatic pressure for density = true + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe/sub_adiabatic.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe/sub_adiabatic.prm.bak new file mode 100644 index 00000000000..b1991f6d47d --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe/sub_adiabatic.prm.bak @@ -0,0 +1,8 @@ +subsection Boundary temperature model + set Fixed temperature boundary indicators = left + set List of model names = box + + subsection Box + set Left temperature = 1400 + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_advect/ala.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_advect/ala.prm.bak new file mode 100644 index 00000000000..ae46431d4a2 --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_advect/ala.prm.bak @@ -0,0 +1,12 @@ +subsection Formulation + set Mass conservation = reference density profile + set Temperature equation = reference density profile +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0.000000001 + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_advect/hydrostatic.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_advect/hydrostatic.prm.bak new file mode 100644 index 00000000000..503708897df --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_advect/hydrostatic.prm.bak @@ -0,0 +1,4 @@ +subsection Formulation + set Mass conservation = hydrostatic compression + set Temperature equation = real density +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_advect/isentropic.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_advect/isentropic.prm.bak new file mode 100644 index 00000000000..74b3defb28c --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_advect/isentropic.prm.bak @@ -0,0 +1,4 @@ +subsection Formulation + set Mass conservation = isentropic compression + set Temperature equation = real density +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_advect/lateral_pipe.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_advect/lateral_pipe.prm.bak new file mode 100644 index 00000000000..c627e9cd948 --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_advect/lateral_pipe.prm.bak @@ -0,0 +1,135 @@ +# This is a benchmark to illustrate the effect of different formulations +# of compressibility. It starts from a simple lateral pipe flow model, +# in which material enters a vertical pipe with a prescribed velocity. +# Due to increasing temperature at the boundary a density gradient is +# advected into the model. + +set Additional shared libraries = ../plugins/libcompressibility_formulations.so +set Dimension = 2 +set End time = 6201145.069582775 +set Use years in output instead of seconds = true +set Adiabatic surface temperature = 1600 +set Nonlinear solver scheme = iterated Advection and Stokes +set Nonlinear solver tolerance = 1e-14 +set Max nonlinear iterations = 25 +set Output directory = output-lateral_pipe + +subsection Adiabatic conditions model + subsection Compute profile + set Number of points = 100000 + set Composition reference profile = function + end +end + +subsection Heating model + set List of model names = +end + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 2 + set Composition polynomial degree = 2 + set Use locally conservative discretization = true + set Use discontinuous composition discretization = true + set Use discontinuous temperature discretization = true +end + +subsection Solver parameters + set Temperature solver tolerance = 1e-14 + set Composition solver tolerance = 1e-14 + + subsection Stokes solver parameters + set Linear solver tolerance = 1e-14 + end +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = density_field + set Compositional field methods = prescribed field + set Types of fields = density +end + +subsection Initial composition model + set Model name = adiabatic density +end + +subsection Geometry model + set Model name = box + + subsection Box + set Y extent = 100000 + set X extent = 1000000 + set X repetitions = 8 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0.0 + end +end + +############### Boundary conditions +# We only fix the temperature at the upper boundary, the other boundaries +# are isolating. +subsection Boundary temperature model + set Fixed temperature boundary indicators = left + set List of model names = function + + subsection Function + set Function expression = 1600 + 200 * t / 1e7 + end +end + +# To guarantuee a steady downward flow, we fix the velocity +# at the top and bottom, and set it to free slip on the sides. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left:function + set Tangential velocity boundary indicators = bottom,top + + subsection Function + set Function expression = 2*1000000/(1e7*(exp(1)-1)) * exp(t/1e7); 0.0 + set Variable names = x,y,t + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1600 + 200 * ln(1-x*(exp(1)-1)/(2*1000000)) + end +end + +subsection Material model + set Model name = compressibility formulations + + subsection Simple compressible model + set Thermal conductivity = 0.0 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, material statistics, mass flux statistics + + subsection Visualization + set Number of grouped files = 1 + set Output format = vtu + + # We are only interested in the last timestep (when the system hast reached + # a steady state). For following the development of the system or checking + # if the solution already reached steady state, this parameter can be set + # to a smaller value. + set Time between graphical output = 6201145.069582775 #1e7 + set List of output variables = nonadiabatic temperature, nonadiabatic pressure, heating, material properties, strain rate + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_advect/projected_density.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_advect/projected_density.prm.bak new file mode 100644 index 00000000000..71b048352cb --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_advect/projected_density.prm.bak @@ -0,0 +1,10 @@ +subsection Formulation + set Mass conservation = projected density field + set Temperature equation = real density +end + +subsection Material model + subsection Projected density model + set Use adiabatic pressure for density = true + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/ala.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/ala.prm.bak new file mode 100644 index 00000000000..ae46431d4a2 --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/ala.prm.bak @@ -0,0 +1,12 @@ +subsection Formulation + set Mass conservation = reference density profile + set Temperature equation = reference density profile +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0.000000001 + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/hydrostatic.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/hydrostatic.prm.bak new file mode 100644 index 00000000000..503708897df --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/hydrostatic.prm.bak @@ -0,0 +1,4 @@ +subsection Formulation + set Mass conservation = hydrostatic compression + set Temperature equation = real density +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/isentropic.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/isentropic.prm.bak new file mode 100644 index 00000000000..74b3defb28c --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/isentropic.prm.bak @@ -0,0 +1,4 @@ +subsection Formulation + set Mass conservation = isentropic compression + set Temperature equation = real density +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/lateral_pipe.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/lateral_pipe.prm.bak new file mode 100644 index 00000000000..ec3f7efd58c --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/lateral_pipe.prm.bak @@ -0,0 +1,147 @@ +# This is a benchmark to illustrate the effect of different formulations +# of compressibility. It starts from a simple lateral pipe flow model. +# There is no prescribed velocity and one end of the pipe is left open. +# Then the pressure at the open end is contiuously increased over time, +# which should lead to a compression of the material in the pipe. +# This effect can not be captured by all common compressibility +# approximations except the projected density approximation if it +# used the full (instead of the adiabatic) pressure. + +set Additional shared libraries = ../plugins/libcompressibility_formulations.so +set Dimension = 2 + +# 1e7 years +set End time = 31557600e7 +set Use years in output instead of seconds = false +set Adiabatic surface temperature = 1600 +set Nonlinear solver scheme = iterated Advection and Stokes +set Nonlinear solver tolerance = 1e-12 +set Maximum time step = 31557600e5 +set Pressure normalization = no +set Output directory = output-lateral-pipe +set Max nonlinear iterations = 10 + +subsection Adiabatic conditions model + subsection Compute profile + set Number of points = 100000 + set Composition reference profile = function + end +end + +subsection Discretization + set Use locally conservative discretization = true + set Use discontinuous composition discretization = true + set Use discontinuous temperature discretization = true +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + end +end + +subsection Formulation + set Mass conservation = projected density field + set Temperature equation = real density +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = density_field + set Compositional field methods = prescribed field + set Types of fields = density +end + +subsection Initial composition model + set Model name = adiabatic density +end + +subsection Geometry model + set Model name = box + + subsection Box + set Y extent = 100000 + set X extent = 1000000 + set X repetitions = 32 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0.0 + end +end + +subsection Heating model + set List of model names = +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = +end + +subsection Boundary traction model + set Prescribed traction boundary indicators = right:function + + subsection Function + # This generates a pressure of e * 100 MPa at 10 Myr + #set Function expression = -10 * t / (3600*24*365.25); 0.0 + set Function expression = -1e8 * exp (t / (1e7*3600*24*365.25)); 0.0 + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left:function + set Tangential velocity boundary indicators = bottom,top + + subsection Function + set Function expression = 0.0;0.0 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1600 + end +end + +subsection Material model + set Model name = compressibility formulations + + subsection Simple compressible model + set Thermal conductivity = 0.0 + + # We need to change the reference viscosity here + # slightly, to improve the accuracy, because + # of a more appropriate pressure scaling. + # This model is somewhat unusual in that all + # velocities are driven by dynamic pressure. + set Viscosity = 1e20 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, mass flux statistics, material statistics, pressure statistics + + subsection Visualization + set Number of grouped files = 1 + set Output format = vtu + + # We are only interested in the last timestep (when the system hast reached + # a steady state). For following the development of the system or checking + # if the solution already reached steady state, this parameter can be set + # to a smaller value. + set Time between graphical output = 1e7 + set List of output variables = adiabat, nonadiabatic temperature, nonadiabatic pressure, heating, material properties, strain rate + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/projected_density.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/projected_density.prm.bak new file mode 100644 index 00000000000..71b048352cb --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/projected_density.prm.bak @@ -0,0 +1,10 @@ +subsection Formulation + set Mass conservation = projected density field + set Temperature equation = real density +end + +subsection Material model + subsection Projected density model + set Use adiabatic pressure for density = true + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/projected_density_full_pressure.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/projected_density_full_pressure.prm.bak new file mode 100644 index 00000000000..500450965b7 --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_increase_pressure/projected_density_full_pressure.prm.bak @@ -0,0 +1,10 @@ +subsection Formulation + set Mass conservation = projected density field + set Temperature equation = real density +end + +subsection Material model + subsection Projected density model + set Use adiabatic pressure for density = false + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_transient/ala.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_transient/ala.prm.bak new file mode 100644 index 00000000000..ae46431d4a2 --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_transient/ala.prm.bak @@ -0,0 +1,12 @@ +subsection Formulation + set Mass conservation = reference density profile + set Temperature equation = reference density profile +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0.000000001 + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_transient/hydrostatic.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_transient/hydrostatic.prm.bak new file mode 100644 index 00000000000..503708897df --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_transient/hydrostatic.prm.bak @@ -0,0 +1,4 @@ +subsection Formulation + set Mass conservation = hydrostatic compression + set Temperature equation = real density +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_transient/isentropic.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_transient/isentropic.prm.bak new file mode 100644 index 00000000000..74b3defb28c --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_transient/isentropic.prm.bak @@ -0,0 +1,4 @@ +subsection Formulation + set Mass conservation = isentropic compression + set Temperature equation = real density +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_transient/lateral_pipe.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_transient/lateral_pipe.prm.bak new file mode 100644 index 00000000000..ffb9245c2b6 --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_transient/lateral_pipe.prm.bak @@ -0,0 +1,138 @@ +# This is a benchmark to illustrate the effect of different formulations +# of compressibility. It starts from a simple lateral pipe flow model. +# There is no prescribed velocity, and one end of the pipe is open. +# Due to internal heating the material in the pipe heats up, expands, +# and creates a flow out of the open end of the pipe. The parameters +# for this benchmark were chosen so that an analytical solution for +# the mass flow out of the pipe exists. + +set Additional shared libraries = ../plugins/libcompressibility_formulations.so +set Dimension = 2 + +# 1e7 years +set End time = 31557600e7 +set Use years in output instead of seconds = false +set Adiabatic surface temperature = 1600 +set Nonlinear solver scheme = iterated Advection and Stokes +set Nonlinear solver tolerance = 1e-12 +set Maximum time step = 31557600e5 +set Output directory = output-lateral_pipe + +subsection Adiabatic conditions model + subsection Compute profile + set Number of points = 100000 + set Composition reference profile = function + end +end + +subsection Discretization + set Use locally conservative discretization = true + set Use discontinuous composition discretization = true + set Use discontinuous temperature discretization = true +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + end +end + +subsection Formulation + set Mass conservation = projected density field + set Temperature equation = real density +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = density_field + set Compositional field methods = prescribed field + set Types of fields = density +end + +subsection Initial composition model + set Model name = adiabatic density +end + +subsection Geometry model + set Model name = box + + subsection Box + set Y extent = 100000 + set X extent = 1000000 + set X repetitions = 32 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0.0 + end +end + +subsection Heating model + set List of model names = function + + subsection Function + # dT_dt[K/yr] / yr_in_secs * c_P + set Function expression = 1e-4 / 31557600 * 1000 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left:function + set Tangential velocity boundary indicators = bottom,top + + subsection Function + set Function expression = 0.0;0.0 + set Variable names = x,y + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1600 + end +end + +subsection Material model + set Model name = compressibility formulations + + subsection Simple compressible model + set Thermal conductivity = 0.0 + set Reference specific heat = 1000 + set Reference compressibility = 0.0 + set Reference density = 3300 + set Thermal expansion coefficient = 2e-5 + set Viscosity = 1e21 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, mass flux statistics, material statistics + + subsection Visualization + set Number of grouped files = 1 + set Output format = vtu + + # We are only interested in the last timestep (when the system hast reached + # a steady state). For following the development of the system or checking + # if the solution already reached steady state, this parameter can be set + # to a smaller value. + set Time between graphical output = 1e7 + set List of output variables = adiabat, nonadiabatic temperature, nonadiabatic pressure, heating, material properties, strain rate + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_transient/projected_density.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_transient/projected_density.prm.bak new file mode 100644 index 00000000000..71b048352cb --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_transient/projected_density.prm.bak @@ -0,0 +1,10 @@ +subsection Formulation + set Mass conservation = projected density field + set Temperature equation = real density +end + +subsection Material model + subsection Projected density model + set Use adiabatic pressure for density = true + end +end diff --git a/benchmarks/compressibility_formulations/lateral_pipe_transient/timestep.prm.bak b/benchmarks/compressibility_formulations/lateral_pipe_transient/timestep.prm.bak new file mode 100644 index 00000000000..f18ce58326e --- /dev/null +++ b/benchmarks/compressibility_formulations/lateral_pipe_transient/timestep.prm.bak @@ -0,0 +1 @@ +set Maximum time step = 24654375e5 diff --git a/benchmarks/compressibility_formulations/plugins/compressibility_formulations.cc.bak b/benchmarks/compressibility_formulations/plugins/compressibility_formulations.cc.bak new file mode 100644 index 00000000000..29fce8b2b58 --- /dev/null +++ b/benchmarks/compressibility_formulations/plugins/compressibility_formulations.cc.bak @@ -0,0 +1,265 @@ +/* + Copyright (C) 2017 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + /** + * A material model that is identical to the simple compressible model, + * except that the density is tracked in a compositional field of type + * 'density' using the prescribed field advection method. It also + * allows some modification to the density and thermal expansivity + * calculation for the compressibility benchmarks. + * + * @ingroup MaterialModels + */ + template + class CompressibilityFormulations : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + void initialize() override; + + void update() override; + + bool is_compressible () const override; + + void + evaluate (const MaterialModelInputs &in, + MaterialModelOutputs &out) const override; + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + static void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Pointer to the material model used as the base model + */ + std::shared_ptr> base_model; + + /** + * The reference density + */ + double reference_rho; + + /** + * The constant thermal expansivity + */ + double thermal_alpha; + bool use_exponential_alpha; + + /** + * The constant compressibility. + */ + double reference_compressibility; + + /** + * Use the adiabatic instead of the full pressure for the + * density calculation. + */ + bool use_adiabatic_pressure_for_density; + }; + + + + template + void + CompressibilityFormulations::initialize() + { + base_model->initialize(); + } + + + + template + void + CompressibilityFormulations::update() + { + base_model->update(); + } + + + + template + bool + CompressibilityFormulations:: + is_compressible () const + { + return this->get_parameters().formulation_mass_conservation != Parameters::Formulation::MassConservation::incompressible; + } + + + + template + void + CompressibilityFormulations::evaluate(const MaterialModelInputs &in, + MaterialModelOutputs &out) const + { + base_model->evaluate(in,out); + + const unsigned int density_field_index = this->introspection().find_composition_type(Parameters::CompositionalFieldDescription::density); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + double pressure_for_density = in.pressure[i]; + + // If using the PDA avoid using the real pressure for the density calculation to prevent + // pressure waves from forming + if (use_adiabatic_pressure_for_density) + pressure_for_density = this->get_adiabatic_conditions().pressure(in.position[i]); + + double thermal_expansivity = thermal_alpha; + if (use_exponential_alpha) + { + thermal_expansivity *= std::exp(-1.117979323e-11*pressure_for_density); + out.thermal_expansion_coefficients[i] = thermal_expansivity; + } + + // Use a thermodynamically consistent thermal expansivity + // (if alpha is constant, rho needs to depend exponentially on it, not linearly) + out.densities[i] = reference_rho * std::exp(reference_compressibility * (pressure_for_density - this->get_surface_pressure()) - + thermal_expansivity * (in.temperature[i] - this->get_adiabatic_surface_temperature())); + + // For the ICA, we have to provide the isentropic rather than isothermal compressibility + // for the mass conservation equation. + if (this->get_parameters().formulation_mass_conservation == + Parameters::Formulation::MassConservation::isentropic_compression) + { + out.compressibilities[i] = reference_compressibility - std::pow(thermal_expansivity, 2) * in.temperature[i] + / (out.densities[i] * out.specific_heat[i]); + } + } + + // prescribe the density field to the current value of the density. The actual projection + // only happens inside Simulator::interpolate_material_output_into_compositional_field, + // this just sets the correct term the field will be set to. + if (PrescribedFieldOutputs *prescribed_field_out = out.template get_additional_output>()) + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + prescribed_field_out->prescribed_field_outputs[i][density_field_index] = out.densities[i]; + } + + + + template + void + CompressibilityFormulations::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::unique_ptr> + (new MaterialModel::PrescribedFieldOutputs (n_points, this->n_compositional_fields()))); + } + } + + + + template + void + CompressibilityFormulations::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Projected density model"); + { + prm.declare_entry ("Use adiabatic pressure for density", "false", + Patterns::Bool(), + ""); + prm.declare_entry ("Use exponential thermal expansivity", "false", + Patterns::Bool(), + ""); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + SimpleCompressible::declare_parameters (prm); + } + + + + template + void + CompressibilityFormulations::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Projected density model"); + { + use_adiabatic_pressure_for_density = prm.get_bool("Use adiabatic pressure for density"); + use_exponential_alpha = prm.get_bool("Use exponential thermal expansivity"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Simple compressible model"); + { + reference_rho = prm.get_double ("Reference density"); + thermal_alpha = prm.get_double ("Thermal expansion coefficient"); + reference_compressibility = prm.get_double ("Reference compressibility"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // create the base model and initialize its SimulatorAccess base + // class; it will get a chance to read its parameters below after we + // leave the current section + base_model = create_material_model("simple compressible"); + if (SimulatorAccess *sim = dynamic_cast*>(base_model.get())) + sim->initialize_simulator (this->get_simulator()); + base_model->parse_parameters(prm); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(CompressibilityFormulations, + "compressibility formulations", + "A material model that is identical to the simple compressible model, " + "except that the density is tracked in a compositional field of type " + "'density' using the prescribed field advection method. It also " + "allows some modification to the density and thermal expansivity " + "calculation for the compressibility benchmarks.") + } +} diff --git a/benchmarks/compressibility_formulations/vertical_pipe/adiabatic.prm.bak b/benchmarks/compressibility_formulations/vertical_pipe/adiabatic.prm.bak new file mode 100644 index 00000000000..e7004ab4649 --- /dev/null +++ b/benchmarks/compressibility_formulations/vertical_pipe/adiabatic.prm.bak @@ -0,0 +1,8 @@ +subsection Boundary temperature model + set Fixed temperature boundary indicators = top + set List of model names = box + + subsection Box + set Top temperature = 1600 + end +end diff --git a/benchmarks/compressibility_formulations/vertical_pipe/ala.prm.bak b/benchmarks/compressibility_formulations/vertical_pipe/ala.prm.bak new file mode 100644 index 00000000000..2c233e84e40 --- /dev/null +++ b/benchmarks/compressibility_formulations/vertical_pipe/ala.prm.bak @@ -0,0 +1,4 @@ +subsection Formulation + set Mass conservation = reference density profile + set Temperature equation = reference density profile +end diff --git a/benchmarks/compressibility_formulations/vertical_pipe/hydrostatic.prm.bak b/benchmarks/compressibility_formulations/vertical_pipe/hydrostatic.prm.bak new file mode 100644 index 00000000000..503708897df --- /dev/null +++ b/benchmarks/compressibility_formulations/vertical_pipe/hydrostatic.prm.bak @@ -0,0 +1,4 @@ +subsection Formulation + set Mass conservation = hydrostatic compression + set Temperature equation = real density +end diff --git a/benchmarks/compressibility_formulations/vertical_pipe/isentropic.prm.bak b/benchmarks/compressibility_formulations/vertical_pipe/isentropic.prm.bak new file mode 100644 index 00000000000..74b3defb28c --- /dev/null +++ b/benchmarks/compressibility_formulations/vertical_pipe/isentropic.prm.bak @@ -0,0 +1,4 @@ +subsection Formulation + set Mass conservation = isentropic compression + set Temperature equation = real density +end diff --git a/benchmarks/compressibility_formulations/vertical_pipe/projected_density.prm.bak b/benchmarks/compressibility_formulations/vertical_pipe/projected_density.prm.bak new file mode 100644 index 00000000000..71b048352cb --- /dev/null +++ b/benchmarks/compressibility_formulations/vertical_pipe/projected_density.prm.bak @@ -0,0 +1,10 @@ +subsection Formulation + set Mass conservation = projected density field + set Temperature equation = real density +end + +subsection Material model + subsection Projected density model + set Use adiabatic pressure for density = true + end +end diff --git a/benchmarks/compressibility_formulations/vertical_pipe/sub_adiabatic.prm.bak b/benchmarks/compressibility_formulations/vertical_pipe/sub_adiabatic.prm.bak new file mode 100644 index 00000000000..7665fa17edc --- /dev/null +++ b/benchmarks/compressibility_formulations/vertical_pipe/sub_adiabatic.prm.bak @@ -0,0 +1,8 @@ +subsection Boundary temperature model + set Fixed temperature boundary indicators = top + set List of model names = box + + subsection Box + set Top temperature = 1400 + end +end diff --git a/benchmarks/compressibility_formulations/vertical_pipe/vertical_pipe.prm.bak b/benchmarks/compressibility_formulations/vertical_pipe/vertical_pipe.prm.bak new file mode 100644 index 00000000000..04866b04635 --- /dev/null +++ b/benchmarks/compressibility_formulations/vertical_pipe/vertical_pipe.prm.bak @@ -0,0 +1,133 @@ +# This is a benchmark to illustrate the effect of different formulations +# of compressibility. It starts from a simple downward pipe flow model, +# in which material enters a vertical pipe with a prescribed velocity. +# Due to gravity and pressure the material compresses and the velocity +# changes to conserve mass. + +set Additional shared libraries = ../plugins/libcompressibility_formulations.so +set Dimension = 2 +set End time = 2e8 +set Use years in output instead of seconds = true +set Adiabatic surface temperature = 1600 +set Nonlinear solver scheme = iterated Advection and Stokes +set Nonlinear solver tolerance = 1e-12 +set Max nonlinear iterations = 25 +set Output directory = output-vertical_pipe + +subsection Adiabatic conditions model + subsection Compute profile + set Number of points = 1000000 + set Composition reference profile = function + end +end + +subsection Discretization + set Use locally conservative discretization = true + set Use discontinuous composition discretization = true + set Use discontinuous temperature discretization = true +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + end +end + +subsection Formulation + set Mass conservation = projected density field + set Temperature equation = real density +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = density_field + set Compositional field methods = prescribed field + set Types of fields = density +end + +subsection Initial composition model + set Model name = adiabatic density +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 10000 + set Y extent = 1000000 + set Y repetitions = 8 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +subsection Heating model + set List of model names = adiabatic heating, shear heating +end + +############### Boundary conditions +# We only fix the temperature at the upper boundary, the other boundaries +# are insulating. +subsection Boundary temperature model + set Fixed temperature boundary indicators = top + set List of model names = box + + subsection Box + set Top temperature = 1600 + end +end + +# To guarantuee a steady downward flow, we fix the velocity +# at the bottom, leave the top open, and set it to free slip on the sides. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = bottom:function + set Tangential velocity boundary indicators = left, right + + subsection Function + set Function expression = 0;-1e-2 + set Variable names = x,y + end +end + +subsection Initial temperature model + set Model name = adiabatic +end + +subsection Material model + set Model name = compressibility formulations + + subsection Simple compressible model + set Thermal conductivity = 0.0 + end +end + +# We use a global refinement of 0 to have a single cell in width. More cells +# allow for instabilities at the open boundary that would influence the +# accuracy with increasing resolution. +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, mass flux statistics, material statistics + + subsection Visualization + set Number of grouped files = 1 + set Output format = vtu + + # We are only interested in the last timestep (when the system hast reached + # a steady state). For following the development of the system or checking + # if the solution already reached steady state, this parameter can be set + # to a smaller value. + set Time between graphical output = 1e7 + set List of output variables = nonadiabatic temperature, nonadiabatic pressure, heating, material properties, strain rate + end +end diff --git a/benchmarks/crameri_et_al/case_1/crameri_benchmark_1.cc.bak b/benchmarks/crameri_et_al/case_1/crameri_benchmark_1.cc.bak new file mode 100644 index 00000000000..51ee940146a --- /dev/null +++ b/benchmarks/crameri_et_al/case_1/crameri_benchmark_1.cc.bak @@ -0,0 +1,179 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace GeometryModel + { + /** + * A class deriving from Box, which changes the upper boundary + with a sinusoidal perturbation of a given order and amplitude. + The top surface is initialized with smooth sinusoidal topography. + Subsequent refinements at the surface would do linear interpolations + between the mesh points, potentially affecting the quality of the + sinusoidal perturbation. As such, if this class is used for topographic + relaxation benchmarks, it makes most sense to do it without mesh + refinement. + */ + template + class ReboundBox : public Box + { + public: + /** + * Generate a coarse mesh for the geometry described by this class. + * Makes perturbs the top boundary of the box with a function + * of the form z' = amplitude * cos(order * x ) + */ + void create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter + * file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Give the depth of a point. + */ + double depth( const Point &position) const override; + + /** + * Give the maximal depth of a point. + */ + double maximal_depth() const override; + + private: + + double order; //Order of the perturbation + double amplitude; //amplitude of the perturbation + + }; + + template + void + ReboundBox:: + create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const + { + + //Call the normal Box mesh generator + Box::create_coarse_mesh( coarse_grid ); + + //move the vertices + std::vector vertex_touched (coarse_grid.n_vertices(), false); + + typename parallel::distributed::Triangulation::active_cell_iterator cell; + for (cell = coarse_grid.begin_active(); cell != coarse_grid.end(); ++cell) + for (unsigned int v = 0; v < GeometryInfo::vertices_per_cell; ++v) + if (vertex_touched[cell->vertex_index(v)] == false) + { + Point &vertex = cell->vertex(v); + vertex[dim-1] = vertex[dim-1] + std::cos(order*2.0*M_PI*vertex[0]/(this->get_extents()[0]))* + amplitude*vertex[dim-1]/(this->get_extents()[dim-1]); + vertex_touched[cell->vertex_index(v)] = true; + } + + } + + template + double + ReboundBox::maximal_depth() const + { + return Box::maximal_depth()+amplitude; + } + + template + double + ReboundBox::depth(const Point &position) const + { + return maximal_depth()-position(dim-1); + } + + template + void + ReboundBox:: + declare_parameters (ParameterHandler &prm) + { + Box::declare_parameters(prm); + + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Rebound Box"); + { + prm.declare_entry ("Order", "1", + Patterns::Double (0), + "Order of the perturbation"); + prm.declare_entry ("Amplitude", "0.1", + Patterns::Double (0), + "Scaled amplitude of the perturbation"); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + ReboundBox::parse_parameters (ParameterHandler &prm) + { + Box::parse_parameters(prm); + + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Rebound Box"); + { + order = prm.get_double ("Order"); + amplitude = prm.get_double ("Amplitude"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace GeometryModel + { + ASPECT_REGISTER_GEOMETRY_MODEL(ReboundBox, + "rebound box", + "Geometry model for benchmarking relaxation of topography.") + } +} diff --git a/benchmarks/crameri_et_al/case_1/crameri_benchmark_1.prm.bak b/benchmarks/crameri_et_al/case_1/crameri_benchmark_1.prm.bak new file mode 100644 index 00000000000..86783abb78a --- /dev/null +++ b/benchmarks/crameri_et_al/case_1/crameri_benchmark_1.prm.bak @@ -0,0 +1,139 @@ +# Can check this benchmark in gnuplot by opening it and running: +# plot "statistics" using 2:(-$14), "statistics" using 2:(7000.*exp(-$2/14825)) +# This compares relaxation of the topography to an analytical solution + + +set Dimension = 2 +set CFL number = 0.01 +set End time = 1e5 +set Output directory = output +set Resume computation = false +set Start time = 0 +set Adiabatic surface temperature = 0 +set Surface pressure = 0 +set Pressure normalization = no +set Timing output frequency = 5 +set Use years in output instead of seconds = true +set Additional shared libraries = ./libcrameri_benchmark_1.so + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = constant + + subsection Constant + set Boundary indicator to temperature mappings = bottom:0, top:0 + end +end + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 2 + set Use locally conservative discretization = false + + subsection Stabilization parameters + set alpha = 2 + set beta = 0.078 + set cR = 0.5 + end +end + +subsection Geometry model + set Model name = rebound box + + subsection Rebound Box + set Order = 1 + set Amplitude = 7.e3 + end + + subsection Box + set X extent = 28.e5 + set Y extent = 7.e5 + set X repetitions = 300 + set Y repetitions = 75 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = 0.0 + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3300 + set Reference specific heat = 1250 + set Reference temperature = 0.0 + set Thermal conductivity = 4.7 + set Thermal expansion coefficient = 4e-5 + set Viscosity = 1.e21 + set Density differential for compositional field 1 = 0.0 + set Composition viscosity prefactor = 100. + end +end + +subsection Mesh refinement + set Additional refinement times = + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Refinement fraction = 0.0 + set Coarsening fraction = 0.00 + set Strategy = composition + set Time steps between mesh refinement = 0 +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right + set Zero velocity boundary indicators = bottom +end + +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + + subsection Free surface + set Free surface stabilization theta = 0.5 + end +end + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if(y>600.e3, 1, 0); + end +end + +subsection Postprocess + set List of postprocessors = visualization,topography + + subsection Visualization + set List of output variables = viscosity + set Number of grouped files = 1 + set Output format = vtu + set Time between graphical output = 1.e4 + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Number of cheap Stokes solver steps = 0 + end +end diff --git a/benchmarks/crameri_et_al/case_1/crameri_benchmark_1_gmg.prm.bak b/benchmarks/crameri_et_al/case_1/crameri_benchmark_1_gmg.prm.bak new file mode 100644 index 00000000000..4ef00bc5874 --- /dev/null +++ b/benchmarks/crameri_et_al/case_1/crameri_benchmark_1_gmg.prm.bak @@ -0,0 +1,27 @@ +# Same as crameri_benchmark_1.prm, but using GMG. + +include $ASPECT_SOURCE_DIR/benchmarks/crameri_et_al/case_1/crameri_benchmark_1.prm + +set Additional shared libraries = $ASPECT_SOURCE_DIR/benchmarks/crameri_et_al/case_1/libcrameri_benchmark_1.so +set Dimension = 2 +set Output directory = output-crameri-gmg + +subsection Solver parameters + subsection Stokes solver parameters + set Stokes solver type = block GMG + end +end + +subsection Material model + set Material averaging = harmonic average +end + +subsection Postprocess + subsection Visualization + set Output mesh velocity = true + end +end + +subsection Nullspace removal + set Remove nullspace = net rotation +end diff --git a/benchmarks/crameri_et_al/case_2/crameri_benchmark_2.prm.bak b/benchmarks/crameri_et_al/case_2/crameri_benchmark_2.prm.bak new file mode 100644 index 00000000000..1111ebef04b --- /dev/null +++ b/benchmarks/crameri_et_al/case_2/crameri_benchmark_2.prm.bak @@ -0,0 +1,134 @@ +set Dimension = 2 +set CFL number = 0.1 +set End time = 2e7 +set Output directory = output +set Resume computation = false +set Start time = 0 +set Adiabatic surface temperature = 0 +set Surface pressure = 0 +set Pressure normalization = no +set Use years in output instead of seconds = true +set Nonlinear solver scheme = single Advection, single Stokes + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Top temperature = 0.0 + set Bottom temperature = 0.0 + end +end + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 2 + set Use locally conservative discretization = false + + subsection Stabilization parameters + set alpha = 2 + set beta = 0.078 + set cR = 0.5 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 28.e5 + set Y extent = 7.e5 + set X repetitions = 4 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = 0.0 + end +end + +subsection Material model + set Model name = multicomponent + + subsection Multicomponent + set Reference temperature = 0.0 + set Densities = 3300, 3200, 3300 + set Specific heats = 1250 + set Thermal conductivities = 4.7 + set Thermal expansivities = 4e-5 + set Viscosities = 1.e21, 1.e20, 1.e23 + set Viscosity averaging scheme = harmonic + end +end + +subsection Mesh refinement + set Additional refinement times = + set Initial adaptive refinement = 4 + set Initial global refinement = 6 + set Refinement fraction = 0.3 + set Coarsening fraction = 0.0 + set Strategy = density,composition,boundary + set Refinement criteria scaling factors = + set Refinement criteria merge operation = plus + set Time steps between mesh refinement = 5 + + subsection Boundary + set Boundary refinement indicators = top + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right + set Zero velocity boundary indicators = bottom +end + +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + + subsection Free surface + # Theta from Kaus et al 2010 + set Free surface stabilization theta = 0.5 + end +end + +subsection Compositional fields + set Number of fields = 2 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if( sqrt( (x-14.e5 )^2 + (y-3.e5)^2) < 5.e4 , 1,0); if( y > 6.e5, 1, 0) + end +end + +subsection Postprocess + set List of postprocessors = visualization,topography + + subsection Visualization + set List of output variables = viscosity,density + set Number of grouped files = 1 + set Output format = vtu + set Time between graphical output = 1e6 + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Number of cheap Stokes solver steps = 30 + end +end diff --git a/benchmarks/crameri_et_al/doc/crameri_benchmark_1.prm.bak b/benchmarks/crameri_et_al/doc/crameri_benchmark_1.prm.bak new file mode 100644 index 00000000000..ad0fa09035b --- /dev/null +++ b/benchmarks/crameri_et_al/doc/crameri_benchmark_1.prm.bak @@ -0,0 +1,18 @@ +set CFL number = 0.01 +set Additional shared libraries = ./libcrameri_benchmark_1.so + +subsection Geometry model + set Model name = rebound box + + subsection Rebound Box + set Order = 1 + set Amplitude = 7.e3 + end + + subsection Box + set X extent = 28.e5 + set Y extent = 7.e5 + set X repetitions = 300 + set Y repetitions = 75 + end +end diff --git a/benchmarks/crameri_et_al/doc/crameri_benchmark_2.prm.bak b/benchmarks/crameri_et_al/doc/crameri_benchmark_2.prm.bak new file mode 100644 index 00000000000..728009ee14c --- /dev/null +++ b/benchmarks/crameri_et_al/doc/crameri_benchmark_2.prm.bak @@ -0,0 +1,22 @@ +set CFL number = 0.1 + +subsection Material model + set Model name = multicomponent + + subsection Multicomponent + set Densities = 3300, 3200, 3300 + set Viscosities = 1.e21, 1.e20, 1.e23 + set Viscosity averaging scheme = harmonic + end +end + +subsection Mesh refinement + set Additional refinement times = + set Initial adaptive refinement = 4 + set Initial global refinement = 5 + set Refinement fraction = 0.3 + set Coarsening fraction = 0.0 + set Strategy = density,composition + set Refinement criteria merge operation = plus + set Time steps between mesh refinement = 5 +end diff --git a/benchmarks/davies_et_al/case-1.1.prm.bak b/benchmarks/davies_et_al/case-1.1.prm.bak new file mode 100644 index 00000000000..7426df13493 --- /dev/null +++ b/benchmarks/davies_et_al/case-1.1.prm.bak @@ -0,0 +1,109 @@ +############### Global parameters + +set CFL number = 10 +set End time = 2 +set Output directory = output +set Start time = 0 +set Use years in output instead of seconds = false + +############### Parameters describing the model + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 1.22 + set Opening angle = 360 + set Outer radius = 2.22 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = top, bottom +end + +# Ra is determined by g*alpha +# Ra = 10^4 +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 1e10 + end +end + +subsection Material model + set Model name = simpler + + subsection Simpler model + set Reference density = 1 + set Reference specific heat = 1. + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1e-6 + set Viscosity = 1 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 1 + set Outer temperature = 0 + end +end + +############### Parameters describing the temperature field +# Angular mode is set to 4 in order to match the number of +# convective cells reported by Davies et al. + +subsection Initial temperature model + set Model name = spherical hexagonal perturbation + + subsection Spherical hexagonal perturbation + set Angular mode = 4 + set Rotation offset = 0 + end +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 2 + set Use locally conservative discretization = false + + subsection Stabilization parameters + set alpha = 2 + set beta = 0.078 + set cR = 0.11 + end +end + +subsection Mesh refinement + set Additional refinement times = + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Refinement fraction = 1 + set Coarsening fraction = 0 + set Strategy = temperature + set Time steps between mesh refinement = 0 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics,temperature statistics,heat flux statistics, depth average, velocity boundary statistics, spherical velocity statistics + + subsection Visualization + set Number of grouped files = 0 + set Output format = vtu + set Time between graphical output = 0.025 + end + + subsection Depth average + set Time between graphical output = 1e6 + end +end diff --git a/benchmarks/davies_et_al/case-2.1.prm.bak b/benchmarks/davies_et_al/case-2.1.prm.bak new file mode 100644 index 00000000000..7bd853a1769 --- /dev/null +++ b/benchmarks/davies_et_al/case-2.1.prm.bak @@ -0,0 +1,120 @@ +############### Global parameters + +set CFL number = 10 +set End time = 2 +set Output directory = output +set Resume computation = false +set Start time = 0 +set Use years in output instead of seconds = false + +subsection Checkpointing + set Steps between checkpoint = 15 +end + +subsection Termination criteria + set Checkpoint on termination = true +end + +############### Parameters describing the model + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 1.22 + set Opening angle = 360 + set Outer radius = 2.22 + end +end + +subsection Nullspace removal + set Remove nullspace = net rotation +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = 0,1 +end + +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 1e10 + end +end + +subsection Material model + set Model name = simpler + + subsection Simpler model + set Reference density = 1 + set Reference specific heat = 1. + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1e-6 + set Viscosity = 1 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = 0,1 + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 1 + set Outer temperature = 0 + end +end + +############### Parameters describing the temperature field +# Angular mode is set to 4 in order to match the number of +# convective cells reported by Davies et al. + +subsection Initial temperature model + set Model name = spherical hexagonal perturbation + + subsection Spherical hexagonal perturbation + set Angular mode = 4 + set Rotation offset = 0 + end +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 2 + set Use locally conservative discretization = false + + subsection Stabilization parameters + set alpha = 2 + set beta = 0.078 + set cR = 0.11 + end +end + +subsection Mesh refinement + set Additional refinement times = + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Refinement fraction = 1 + set Coarsening fraction = 0 + set Strategy = temperature + set Time steps between mesh refinement = 0 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics,temperature statistics,heat flux statistics, depth average, velocity boundary statistics, spherical velocity statistics + + subsection Visualization + set Number of grouped files = 0 + set Output format = vtu + set Time between graphical output = 0.025 + end + + subsection Depth average + set Time between graphical output = 1e6 + end +end diff --git a/benchmarks/davies_et_al/case-2.2.prm.bak b/benchmarks/davies_et_al/case-2.2.prm.bak new file mode 100644 index 00000000000..38edd8d3d18 --- /dev/null +++ b/benchmarks/davies_et_al/case-2.2.prm.bak @@ -0,0 +1,119 @@ +############### Global parameters +# Case 2.2 begins with the final steady state solution of Case 2.1 +# Resume computation must be set to true, and Output directory must +# point to the folder that contains the results of Case 2.1. + +set CFL number = 10 +set End time = 3 +set Output directory = output +set Resume computation = true +set Start time = 0 +set Use years in output instead of seconds = false + +subsection Checkpointing + set Steps between checkpoint = 15 +end + +############### Parameters describing the model + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 1.22 + set Opening angle = 360 + set Outer radius = 2.22 + end +end + +subsection Nullspace removal + set Remove nullspace = net rotation +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = 0,1 +end + +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 1e11 + end +end + +subsection Material model + set Model name = simpler + + subsection Simpler model + set Reference density = 1 + set Reference specific heat = 1. + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1e-6 + set Viscosity = 1 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = 0,1 + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 1 + set Outer temperature = 0 + end +end + +############### Parameters describing the temperature field +# Angular mode is set to 4 in order to match the number of +# convective cells reported by Davies et al. + +subsection Initial temperature model + set Model name = spherical hexagonal perturbation + + subsection Spherical hexagonal perturbation + set Angular mode = 4 + set Rotation offset = 0 + end +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 2 + set Use locally conservative discretization = false + + subsection Stabilization parameters + set alpha = 2 + set beta = 0.078 + set cR = 0.11 + end +end + +subsection Mesh refinement + set Additional refinement times = + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Refinement fraction = 1 + set Coarsening fraction = 0 + set Strategy = temperature + set Time steps between mesh refinement = 0 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics,temperature statistics,heat flux statistics, depth average, velocity boundary statistics, spherical velocity statistics + + subsection Visualization + set Number of grouped files = 0 + set Output format = vtu + set Time between graphical output = 0.025 + end + + subsection Depth average + set Time between graphical output = 1e6 + end +end diff --git a/benchmarks/davies_et_al/case-2.3-plugin/VoT.cc.bak b/benchmarks/davies_et_al/case-2.3-plugin/VoT.cc.bak new file mode 100644 index 00000000000..e3f82ec394e --- /dev/null +++ b/benchmarks/davies_et_al/case-2.3-plugin/VoT.cc.bak @@ -0,0 +1,202 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include + +#include + + +using namespace dealii; + + +namespace aspect +{ + namespace MaterialModel + { + /** + * A material model similar to the "Simpler" model, but with a temperature + * dependent viscosity (a "viscosity as a function of temperature", or VoT). + * + * @ingroup MaterialModels + */ + template + class VoT : public Interface + { + public: + + bool is_compressible () const override; + + void evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + private: + double reference_rho; + double reference_T; + double eta; + double thermal_alpha; + double reference_specific_heat; + double k_value; + }; + + + template + bool + VoT:: + is_compressible () const + { + return false; + } + + + template + void + VoT:: + evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const + { + for (unsigned int i=0; i + void + VoT::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("VoT model"); + { + prm.declare_entry ("Reference density", "3300.", + Patterns::Double (0.), + "Reference density $\\rho_0$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. The reference temperature is used " + "in the density formula. Units: \\si{\\kelvin}."); + prm.declare_entry ("Viscosity", "5e24", + Patterns::Double (0.), + "The value of the viscosity $\\eta$. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Reference specific heat", "1250.", + Patterns::Double (0.), + "The value of the specific heat $cp$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Thermal expansion coefficient", "2e-5", + Patterns::Double (0.), + "The value of the thermal expansion coefficient $\\beta$. " + "Units: \\si{\\per\\kelvin}."); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + VoT::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("VoT model"); + { + reference_rho = prm.get_double ("Reference density"); + reference_T = prm.get_double ("Reference temperature"); + eta = prm.get_double ("Viscosity"); + k_value = prm.get_double ("Thermal conductivity"); + reference_specific_heat = prm.get_double ("Reference specific heat"); + thermal_alpha = prm.get_double ("Thermal expansion coefficient"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::temperature; + this->model_dependence.density = NonlinearDependence::temperature; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(VoT, + "VoT", + "A material model that has constant values " + "except for density, which depends linearly on temperature: " + "\\begin{align}" + " \\rho(p,T) &= \\left(1-\\alpha (T-T_0)\\right)\\rho_0." + "\\end{align}" + "\n\n" + "\\note{This material model fills the role the ``simple'' material " + "model was originally intended to fill, before the latter acquired " + "all sorts of complicated temperature and compositional dependencies.}") + } +} diff --git a/benchmarks/davies_et_al/case-2.3.prm.bak b/benchmarks/davies_et_al/case-2.3.prm.bak new file mode 100644 index 00000000000..3af059bae65 --- /dev/null +++ b/benchmarks/davies_et_al/case-2.3.prm.bak @@ -0,0 +1,121 @@ +set Additional shared libraries = ./case-2.3-plugin/libVoT.so + +############### Global parameters +# Case 2.3 begins with the final steady state solution of Case 2.1 +# Resume computation must be set to true, and Output directory must +# point to the folder that contains the results of Case 2.1. + +set CFL number = 10 +set End time = 3 +set Output directory = output +set Resume computation = true +set Start time = 0 +set Use years in output instead of seconds = false + +subsection Checkpointing + set Steps between checkpoint = 15 +end + +############### Parameters describing the model + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 1.22 + set Opening angle = 360 + set Outer radius = 2.22 + end +end + +subsection Nullspace removal + set Remove nullspace = net rotation +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = 0,1 +end + +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 1e8 + end +end + +subsection Material model + set Model name = VoT + + subsection VoT model + set Reference density = 1 + set Reference specific heat = 1. + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1e-5 + set Viscosity = 1 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = 0,1 + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 1 + set Outer temperature = 0 + end +end + +############### Parameters describing the temperature field +# Angular mode is set to 4 in order to match the number of +# convective cells reported by Davies et al. + +subsection Initial temperature model + set Model name = spherical hexagonal perturbation + + subsection Spherical hexagonal perturbation + set Angular mode = 4 + set Rotation offset = 0 + end +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 2 + set Use locally conservative discretization = false + + subsection Stabilization parameters + set alpha = 2 + set beta = 0.078 + set cR = 0.11 + end +end + +subsection Mesh refinement + set Additional refinement times = + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Refinement fraction = 1 + set Coarsening fraction = 0 + set Strategy = temperature + set Time steps between mesh refinement = 0 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics,temperature statistics,heat flux statistics, depth average, velocity boundary statistics, spherical velocity statistics + + subsection Visualization + set Number of grouped files = 0 + set Output format = vtu + set Time between graphical output = 0.25 + end + + subsection Depth average + set Time between graphical output = 1e6 + end +end diff --git a/benchmarks/davies_et_al/doc/case-1.1.prm.bak b/benchmarks/davies_et_al/doc/case-1.1.prm.bak new file mode 100644 index 00000000000..c714e462cce --- /dev/null +++ b/benchmarks/davies_et_al/doc/case-1.1.prm.bak @@ -0,0 +1,51 @@ +############### Parameters describing the model + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 1.22 + set Opening angle = 360 + set Outer radius = 2.22 + end +end + +# [...] + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 1 + set Reference specific heat = 1. + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1e-6 + set Viscosity = 1 + end +end + +############### Parameters describing the temperature field +# Angular mode is set to 4 in order to match the number of +# convective cells reported by Davies et al. + +subsection Initial temperature model + set Model name = spherical hexagonal perturbation + + subsection Spherical hexagonal perturbation + set Angular mode = 4 + set Rotation offset = 0 + end +end + +############### Prescribe the Rayleigh number as g*alpha +# Here, Ra = 10^4 and alpha was chosen as 10^-6 above. +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 1e10 + end +end + +# [...] diff --git a/benchmarks/davies_et_al/doc/case-2.1.prm.bak b/benchmarks/davies_et_al/doc/case-2.1.prm.bak new file mode 100644 index 00000000000..9e6273a2e01 --- /dev/null +++ b/benchmarks/davies_et_al/doc/case-2.1.prm.bak @@ -0,0 +1,11 @@ +subsection Nullspace removal + set Remove nullspace = net rotation +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = 0,1 +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = 0,1 +end diff --git a/benchmarks/davies_et_al/doc/case-2.2.prm.bak b/benchmarks/davies_et_al/doc/case-2.2.prm.bak new file mode 100644 index 00000000000..98a936fd85e --- /dev/null +++ b/benchmarks/davies_et_al/doc/case-2.2.prm.bak @@ -0,0 +1,9 @@ +############### Global parameters +# Case 2.2 begins with the final steady state solution of Case 2.1 +# "Resume computation" must be set to true, and "Output directory" must +# point to the folder that contains the results of Case 2.1. + +set CFL number = 10 +set End time = 3 +set Output directory = output +set Resume computation = true diff --git a/benchmarks/davies_et_al/doc/case-2.3.prm.bak b/benchmarks/davies_et_al/doc/case-2.3.prm.bak new file mode 100644 index 00000000000..e50b233ad69 --- /dev/null +++ b/benchmarks/davies_et_al/doc/case-2.3.prm.bak @@ -0,0 +1,14 @@ +set Additional shared libraries = ./case-2.3-plugin/libVoT.so + +subsection Material model + set Model name = VoT + + subsection VoT model + set Reference density = 1 + set Reference specific heat = 1. + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1e-5 + set Viscosity = 1 + end +end diff --git a/benchmarks/diffusion_of_hill/1_sine_zero_flux.prm.bak b/benchmarks/diffusion_of_hill/1_sine_zero_flux.prm.bak new file mode 100644 index 00000000000..e674c494033 --- /dev/null +++ b/benchmarks/diffusion_of_hill/1_sine_zero_flux.prm.bak @@ -0,0 +1,125 @@ +set Additional shared libraries = libanalytical_topography.so +set Dimension = 2 +set Use years in output instead of seconds = false +set End time = 0.1 +set Maximum time step = 0.0005 +set Output directory = output-1_sine_zero_flux/ +set Nonlinear solver scheme = no Advection, no Stokes +set Pressure normalization = surface +set Surface pressure = 0 + +# 1x1 box with an initial hill topography +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end + + subsection Initial topography model + set Model name = function + + subsection Function + set Function constants = A=0.075, L=1. + set Function expression = \ + A * sin(x*pi) + end + end +end + +# Temperature effects are ignored +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = initial temperature +end + +# Free slip on all boundaries +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +# The mesh will be deformed according to the displacement +# of the surface nodes due to diffusion of the topography. +# The mesh is allowed to move vertical along the left and +# right boundary. +subsection Mesh deformation + set Mesh deformation boundary indicators = top: diffusion + set Additional tangential mesh velocity boundary indicators = left, right + + subsection Diffusion + # The diffusivity + set Hillslope transport coefficient = 0.25 + end +end + +# Vertical gravity +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +# One material with unity properties +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 1 + set Reference specific heat = 1 + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1 + set Viscosity = 1 + end +end + +# We also have to specify that we want to use the Boussinesq +# approximation (assuming the density in the temperature +# equation to be constant, and incompressibility). +subsection Formulation + set Formulation = Boussinesq approximation +end + +# We here use a globally refined mesh without +# adaptive mesh refinement. +subsection Mesh refinement + set Initial global refinement = 6 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +# We output the computed topography and the analytical topography +# value to file. +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, visualization, analytical topography + + subsection Topography + set Output to file = true + set Analytical solution of example = 1 + set Diffusivity = 0.25 + set Initial sinusoidal topography amplitude = 0.075 + end + + subsection Visualization + set Time between graphical output = 0.025 + set Output mesh velocity = true + set Interpolate output = false + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-7 + end +end diff --git a/benchmarks/diffusion_of_hill/2_sine_constant_h.prm.bak b/benchmarks/diffusion_of_hill/2_sine_constant_h.prm.bak new file mode 100644 index 00000000000..537cefb97df --- /dev/null +++ b/benchmarks/diffusion_of_hill/2_sine_constant_h.prm.bak @@ -0,0 +1,124 @@ +set Additional shared libraries = libanalytical_topography.so +set Dimension = 2 +set Use years in output instead of seconds = false + +# You will want to run the model for longer to see +# significant changes in model height +set End time = 3.15576e9 # 100 yr +set Maximum time step = 3.15576e7 # 1 yr +set Output directory = output-2_sine_constant_h +set Nonlinear solver scheme = no Advection, no Stokes +set Pressure normalization = surface +set Surface pressure = 0 + +# 1x1 box with or without an initial hill topography +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 10000 + set Y extent = 10000 + end + + subsection Initial topography model + set Model name = function + + subsection Function + set Function constants = A=100, L=10000. + set Function expression = \ + A * sin(x*pi/L) + end + end +end + +# Temperature effects are ignored +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = initial temperature +end + +# Free slip on the top and bottom boundaries, +# no slip on the left and right boundaries. +subsection Boundary velocity model + set Tangential velocity boundary indicators = bottom, top + set Zero velocity boundary indicators = left, right +end + +subsection Mesh deformation + set Mesh deformation boundary indicators = top : diffusion + + subsection Diffusion + # The diffusivity + set Hillslope transport coefficient = 0.0001 + end +end + +# Vertical gravity +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +# One material +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3300 + set Reference specific heat = 1250 + set Reference temperature = 0 + set Thermal conductivity = 2.5 + set Thermal expansion coefficient = 2e-5 + set Viscosity = 1e20 + end +end + +# We also have to specify that we want to use the Boussinesq +# approximation (assuming the density in the temperature +# equation to be constant, and incompressibility). +subsection Formulation + set Formulation = Boussinesq approximation +end + +# We here use a globally refined mesh without +# adaptive mesh refinement. +subsection Mesh refinement + set Initial global refinement = 6 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +# We output the computed topography and the analytical topography +# value to file. +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, visualization, analytical topography + + subsection Topography + set Output to file = true + set Analytical solution of example = 2 + set Diffusivity = 0.0001 + set Initial sinusoidal topography amplitude = 100 + end + + subsection Visualization + set Time between graphical output = 3.15576e8 + set Output mesh velocity = true + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-7 + end +end diff --git a/benchmarks/diffusion_of_hill/analytical_topography.cc.bak b/benchmarks/diffusion_of_hill/analytical_topography.cc.bak new file mode 100644 index 00000000000..aa4b00cdde1 --- /dev/null +++ b/benchmarks/diffusion_of_hill/analytical_topography.cc.bak @@ -0,0 +1,369 @@ +/* + Copyright (C) 2020 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include "analytical_topography.h" +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + AnalyticalTopography::execute (TableHandler &statistics) + { + // Only allow use of the plugin with the box geometry model + AssertThrow(Plugins::plugin_type_matches>(this->get_geometry_model()) || + Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage("Topography postprocessor is only implemented for the box geometry model. ") ); + + const types::boundary_id relevant_boundary = this->get_geometry_model().translate_symbolic_boundary_name_to_id ("top"); + + // Get a quadrature rule that exists only on the corners + const QTrapezoid face_corners; + + FEFaceValues face_vals (this->get_mapping(), this->get_fe(), face_corners, update_quadrature_points); + + // have a stream into which we write the data. the text stream is then + // later sent to processor 0 + std::ostringstream output_stats; + std::ostringstream output_file; + + // on processor 0, write the file header + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + output_file << "# " + << ((dim==2)? "x y" : "x y z") + << " topography" << ((analytical_solution_example != 0)? " analytical topography" : "") << std::endl; + } + + // Choose stupidly large values for initialization + double local_max_height = -std::numeric_limits::max(); + double local_min_height = std::numeric_limits::max(); + + // Set up some variables for the analytical solution of the + // topography + const unsigned int n_max = 5000; + const double time = this->get_time(); + + // loop over all of the surface cells and save the elevation to stored_value + for (const auto &cell : this->get_triangulation().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + for (const unsigned int face_no : cell->face_indices()) + if (cell->face(face_no)->at_boundary()) + { + if ( cell->face(face_no)->boundary_id() != relevant_boundary) + continue; + + face_vals.reinit(cell, face_no); + + for (unsigned int corner = 0; corner < face_corners.size(); ++corner) + { + const Point vertex = face_vals.quadrature_point(corner); + const double elevation = this->get_geometry_model().height_above_reference_surface(vertex); + + if (write_to_file) + { + switch (analytical_solution_example) + { + // If there is no analytical solution corresponding to the + // model setup, just output the topography + case 0: + { + output_file << vertex << ' '<< elevation << std::endl; + break; + } + // If the setup corresponds to anaytical solution 1, + // output the topography and the first solution + case 1: + { + double topo = 0; + + // initial topography + if (time <= 0.) + topo = amplitude * std::sin(numbers::PI*vertex[0]/domain_width); + else + { + // compute analytical solution + double sum = 0.; + for (unsigned int n=1; n<=n_max; ++n) + { + sum += std::cos(2.*n*numbers::PI*vertex[0]/domain_width) + * std::exp(-kappa*4.*n*n*numbers::PI*numbers::PI*time/(domain_width*domain_width)) + / ((4.*n*n)-1.) + * (-4.*amplitude/numbers::PI); + } + // a0=4A/pi --> a0/2=2A/pi + topo = 2.*amplitude/numbers::PI + sum; + } + // write out predicted and analytical topography + output_file << vertex << ' ' << elevation << ' ' << topo << std::endl; + break; + } + // If the setup corresponds to anaytical solution 2, + // output the topography and the second solution + case 2: + { + const double topo = amplitude * std::sin(vertex[0]*numbers::PI/domain_width) + * std::exp(-kappa*numbers::PI*numbers::PI*time/(domain_width*domain_width)); + // write out predicted and analytical topography + output_file << vertex << ' ' << elevation << ' ' << topo << std::endl; + break; + } + default: + Assert(false, ExcInternalError()); + } + + if (elevation > local_max_height) + local_max_height = elevation; + if (elevation < local_min_height) + local_min_height = elevation; + } + } + } + + // Calculate min/max topography across all processes + const double max_topography = Utilities::MPI::max(local_max_height, this->get_mpi_communicator()); + const double min_topography = Utilities::MPI::min(local_min_height, this->get_mpi_communicator()); + + // Calculate min/max analytical topography + double max_analytical_topography = 0., min_analytical_topography = 0.; + switch (analytical_solution_example) + { + case 0: + { + // In this case, there is no analytical solution, + // so set the min/max values to something clearly + // nonsensical. + min_analytical_topography = std::numeric_limits::quiet_NaN(); + max_analytical_topography = std::numeric_limits::quiet_NaN(); + break; + } + case 1: + { + if (time<=0) + max_analytical_topography = amplitude * std::sin(0.5*numbers::PI); + else + { + double sum_min = 0., sum_max = 0.; + for (unsigned int n=1; n<=n_max; ++n) + { + sum_min += std::exp(-kappa*4.*n*n*numbers::PI*numbers::PI*time/(domain_width*domain_width)) + / ((4.*n*n)-1.) * -4.*amplitude/numbers::PI; + sum_max += std::cos(n*numbers::PI) + * std::exp(-kappa*4.*n*n*numbers::PI*numbers::PI*time/(domain_width*domain_width)) + / ((4.*n*n)-1.) * -4.*amplitude/numbers::PI; + } + // a0=4A/pi --> a0/2=2A/pi + min_analytical_topography = 2.*amplitude/numbers::PI + sum_min; + max_analytical_topography = 2.*amplitude/numbers::PI + sum_max; + } + break; + } + case 2: + { + max_analytical_topography = amplitude * std::sin(0.5*numbers::PI) + * std::exp(-kappa*numbers::PI*numbers::PI*time/(domain_width*domain_width)); + min_analytical_topography = 0.; + break; + } + default: + Assert(false, ExcInternalError()); + } + + // Write results to statistics file + statistics.add_value ("Minimum topography (m)", + min_topography); + statistics.add_value ("Maximum topography (m)", + max_topography); + statistics.add_value ("Minimum analytical topography (m)", + min_analytical_topography); + statistics.add_value ("Maximum analytical topography (m)", + max_analytical_topography); + const char *columns[] = { "Minimum topography (m)", + "Maximum topography (m)", + "Minimum analytical topography (m)", + "Maximum analytical topography (m)" + }; + for (unsigned int i=0; iget_time() - output_interval; + } + + // Just return stats if text output is not required at all or not needed at this time + if (!write_to_file || ((this->get_time() < last_output_time + output_interval) + && (this->get_timestep_number() != 0))) + return std::pair ("Predicted and analytical topography min/max:", + output_stats.str()); + + std::string filename = this->get_output_directory() + + "topography." + + Utilities::int_to_string(this->get_timestep_number(), 5); + if (this->get_parameters().run_postprocessors_on_nonlinear_iterations) + filename.append("." + Utilities::int_to_string (this->get_nonlinear_iteration(), 4)); + + Utilities::collect_and_write_file_content(filename, output_file.str(), this->get_mpi_communicator()); + + // if output_interval is positive, then update the last supposed output + // time + if (output_interval > 0) + { + // We need to find the last time output was supposed to be written. + // this is the last_output_time plus the largest positive multiple + // of output_intervals that passed since then. We need to handle the + // edge case where last_output_time+output_interval==current_time, + // we did an output and std::floor sadly rounds to zero. This is done + // by forcing std::floor to round 1.0-eps to 1.0. + const double magic = 1.0+2.0*std::numeric_limits::epsilon(); + last_output_time = last_output_time + std::floor((this->get_time()-last_output_time)/output_interval*magic) * output_interval/magic; + } + + return std::pair ("Predicted and analytical topography min/max:", + output_stats.str()); + } + + + + template + void + AnalyticalTopography::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Topography"); + { + prm.declare_entry ("Output to file", "false", + Patterns::Bool(), + "Whether or not to write topography to a text file named named " + "'topography.NNNNN' in the output directory."); + prm.declare_entry ("Time between text output", "0.", + Patterns::Double (0), + "The time interval between each generation of " + "text output files. A value of zero indicates " + "that output should be generated in each time step. " + "Units: years if the " + "'Use years in output instead of seconds' parameter is set; " + "seconds otherwise."); + prm.declare_entry ("Analytical solution of example", "1", + Patterns::Integer (0), + "The number of the diffusion example for " + "which we output the analytical solution. " + "For a value of 0, we do not write the " + "analytical solution."); + prm.declare_entry ("Diffusivity", "0.5", + Patterns::Double (0), + "The diffusivity in the diffusion equation. " + "Units: \\si{m^2/s}."); + prm.declare_entry ("Initial sinusoidal topography amplitude", "0.5", + Patterns::Double (0), + "The maximum amplitude of the initial sinusoidal topography. " + "Units: \\si{m}."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + AnalyticalTopography::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Topography"); + { + write_to_file = prm.get_bool ("Output to file"); + output_interval = prm.get_double ("Time between text output"); + if (this->convert_output_to_years()) + { + output_interval *= year_in_seconds; + } + analytical_solution_example = prm.get_integer ("Analytical solution of example"); + kappa = prm.get_double ("Diffusivity"); + amplitude = prm.get_double ("Initial sinusoidal topography amplitude"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Box"); + { + domain_width = prm.get_double ("X extent"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(AnalyticalTopography, + "analytical topography", + "A postprocessor intended for use with a deforming top surface. After every step " + "it loops over all the vertices on the top surface and determines the " + "maximum and minimum topography relative to a reference datum (initial " + "box height). " + "If 'Topography.Output to file' is set to true, also outputs topography " + "into text files named `topography.NNNNN' in the output directory, " + "where NNNNN is the number of the time step." + "If 'Analytical solution of example' is set to 1 or 2, the analytical solution of " + "the topography of a decaying hill is also written to file.\n" + "The file format then consists of lines with Euclidean coordinates " + "followed by the corresponding topography value." + "Topography is printed/written in meters.") + } +} diff --git a/benchmarks/diffusion_of_hill/analytical_topography.h.bak b/benchmarks/diffusion_of_hill/analytical_topography.h.bak new file mode 100644 index 00000000000..fc5ab18da29 --- /dev/null +++ b/benchmarks/diffusion_of_hill/analytical_topography.h.bak @@ -0,0 +1,113 @@ +/* + Copyright (C) 2020 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_analytical_topography_h +#define _aspect_postprocess_analytical_topography_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that outputs the surface topography to file. + * + * @ingroup Postprocessing + */ + template + class AnalyticalTopography : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Output predicted and analytical topography [m] to file. + */ + std::pair execute (TableHandler &statistics) override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + private: + /** + * Whether or not to produce text files with topography values + */ + bool write_to_file; + + /** + * Interval between the generation of text output. This parameter + * is read from the input file and consequently is not part of the + * state that needs to be saved and restored. + */ + double output_interval; + + /** + * A time (in seconds) at which the last text output was supposed + * to be produced. Used to check for the next necessary output time. + */ + double last_output_time; + + /** + * The amplitude of the sinusoidal initial topography. + */ + double amplitude; + + /** + * The diffusivity used in computing the diffusion of the surface + * topography. + */ + double kappa; + + /** + * The width (X extent) of the 2D rectangular domain. + */ + double domain_width; + + /** + * A switch to vary between different analytical solutions. + */ + unsigned int analytical_solution_example; + + }; + } +} + + +#endif diff --git a/benchmarks/doneahuerta/doneahuerta.cc.bak b/benchmarks/doneahuerta/doneahuerta.cc.bak new file mode 100644 index 00000000000..156c8926bac --- /dev/null +++ b/benchmarks/doneahuerta/doneahuerta.cc.bak @@ -0,0 +1,362 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace DoneaHuertaBenchmark + { + using namespace dealii; + + namespace AnalyticSolutions + { + + Tensor<1,2> + DoneaHuerta_velocity (const Point<2> &pos) + { + const double x = pos[0]; + const double y = pos[1]; + const double v_x = x*x*(1.-x)*(1.-x)*(2.*y-6.*y*y+4.*y*y*y) ; + const double v_y = -y*y*(1.-y)*(1.-y)*(2.*x-6.*x*x+4.*x*x*x) ; + return Point<2> (v_x,v_y); + } + + double + DoneaHuerta_pressure (const Point<2> &pos) + { + const double x = pos[0]; + return x*(1.-x)-1./6.; + } + + template + class FunctionDoneaHuerta : public Function + { + public: + FunctionDoneaHuerta () + : + Function(dim+2) + {} + + void vector_value (const Point &pos, + Vector &values) const override + { + Assert (dim == 2, ExcNotImplemented()); + Assert (values.size() >= 4, ExcInternalError()); + + const Point<2> p (pos[0], pos[1]); + + const Tensor<1,2> v = AnalyticSolutions::DoneaHuerta_velocity (p); + values[0] = v[0]; + values[1] = v[1]; + values[2] = AnalyticSolutions::DoneaHuerta_pressure (p); + } + }; + } + + + + template + class DoneaHuertaBoundary : public BoundaryVelocity::Interface, public aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + DoneaHuertaBoundary(); + + /** + * Return the boundary velocity as a function of position. + */ + Tensor<1,dim> + boundary_velocity (const types::boundary_id , + const Point &position) const override; + }; + + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @ingroup MaterialModels + */ + template + class DoneaHuertaMaterial : public MaterialModel::Interface + { + public: + /** + * @name Physical parameters used in the basic equations + * @{ + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + out.viscosities[i] = 1.; + out.densities[i] = 1; + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + } + } + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + * Incompressibility does not necessarily imply that the density is + * constant; rather, it may still depend on temperature or pressure. + * In the current context, compressibility means whether we should + * solve the continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + }; + + + template + bool + DoneaHuertaMaterial:: + is_compressible () const + { + return false; + } + + template + void + DoneaHuertaMaterial::declare_parameters (ParameterHandler &) + { + } + + + template + void + DoneaHuertaMaterial::parse_parameters (ParameterHandler &) + { + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + + template + DoneaHuertaBoundary::DoneaHuertaBoundary () + {} + + + template <> + Tensor<1,2> + DoneaHuertaBoundary<2>:: + boundary_velocity (const types::boundary_id , + const Point<2> &p) const + { + return AnalyticSolutions::DoneaHuerta_velocity (p); + } + + + template <> + Tensor<1,3> + DoneaHuertaBoundary<3>:: + boundary_velocity (const types::boundary_id , + const Point<3> &) const + { + Assert (false, ExcNotImplemented()); + return Tensor<1,3>(); + } + + /** + * Gravity model for the DoneaHuerta benchmark + */ + + template + class DoneaHuertaGravity : public aspect::GravityModel::Interface + { + public: + Tensor<1,dim> gravity_vector (const Point &pos) const override; + }; + + + template + Tensor<1,dim> + DoneaHuertaGravity:: + gravity_vector(const Point &pos) const + { + const double x=pos[0]; + const double y=pos[1]; + Tensor<1,dim> g; + g[0]= ( (12.-24.*y)*x*x*x*x + (-24.+48.*y)*x*x*x + (-48.*y+72.*y*y-48.*y*y*y+12.)*x*x + + (-2.+24.*y-72.*y*y+48.*y*y*y)*x + 1.-4.*y+12.*y*y-8.*y*y*y ); + + g[1]= ( (8.-48.*y+48.*y*y)*x*x*x + (-12.+72.*y-72*y*y)*x*x + + (4.-24.*y+48.*y*y-48.*y*y*y+24.*y*y*y*y)*x - 12.*y*y + 24.*y*y*y -12.*y*y*y*y); + return g; + } + + /** + * A postprocessor that evaluates the accuracy of the solution. + * + * The implementation of error evaluators that correspond to the + * benchmarks defined in the Donea and Huerta FEM book (see manual). + */ + template + class DoneaHuertaPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &statistics) override; + }; + + template + std::pair + DoneaHuertaPostprocessor::execute (TableHandler &) + { + std::unique_ptr> ref_func = + std::make_unique>(); + + const QGauss quadrature_formula (this->introspection().polynomial_degree.velocities+2); + + Vector cellwise_errors_u (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_p (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_ul2 (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_pl2 (this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_u(std::pair(0,dim), + dim+2); + ComponentSelectFunction comp_p(dim, dim+2); + + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_u, + quadrature_formula, + VectorTools::L1_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_p, + quadrature_formula, + VectorTools::L1_norm, + &comp_p); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_ul2, + quadrature_formula, + VectorTools::L2_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_pl2, + quadrature_formula, + VectorTools::L2_norm, + &comp_p); + + const double u_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_u, VectorTools::L1_norm); + const double p_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_p, VectorTools::L1_norm); + const double u_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_ul2, VectorTools::L2_norm); + const double p_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_pl2, VectorTools::L2_norm); + + std::ostringstream os; + + os << std::scientific << u_l1 + << ", " << p_l1 + << ", " << u_l2 + << ", " << p_l2; + + return std::make_pair("Errors u_L1, p_L1, u_L2, p_L2:", os.str()); + } + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace DoneaHuertaBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(DoneaHuertaMaterial, + "DoneaHuertaMaterial", + "A material model that corresponds to the `DoneaHuerta' benchmark. " + "See the manual for more information.") + + ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(DoneaHuertaBoundary, + "DoneaHuertaBoundary", + "Implementation of the velocity boundary conditions for the " + "`DoneaHuerta' benchmark. See the manual for more information about this " + "benchmark.") + + ASPECT_REGISTER_POSTPROCESSOR(DoneaHuertaPostprocessor, + "DoneaHuertaPostprocessor", + "A postprocessor that compares the solution of the `DoneaHuerta' benchmark " + "with the one computed by ASPECT " + "and reports the error. See the manual for more information.") + + ASPECT_REGISTER_GRAVITY_MODEL(DoneaHuertaGravity, + "DoneaHuertaGravity", + "A gravity model in corresponding to the `DoneaHuerta' benchmark. " + "See the manual for more information.") + } +} diff --git a/benchmarks/doneahuerta/doneahuerta.prm.bak b/benchmarks/doneahuerta/doneahuerta.prm.bak new file mode 100644 index 00000000000..84cf6380f7e --- /dev/null +++ b/benchmarks/doneahuerta/doneahuerta.prm.bak @@ -0,0 +1,88 @@ +############### Global parameters +# This is the manufactured solution of Donea & Huerta, +# Finite element methods for flow problems, +# Wiley, 2003. page 306 + +set Additional shared libraries = ./libdoneahuerta.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = false +set Nonlinear solver scheme = single Advection, single Stokes +set Output directory = output +set Pressure normalization = volume + +############### Parameters describing the model +# Because the temperature plays no role in this model we need not +# bother to describe temperature boundary conditions or +# the material parameters that pertain to the temperature. + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +#Boundary conditions + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = 0 : DoneaHuertaBoundary, \ + 1 : DoneaHuertaBoundary, \ + 2 : DoneaHuertaBoundary, \ + 3 : DoneaHuertaBoundary +end + +subsection Material model + set Model name = DoneaHuertaMaterial +end + +subsection Gravity model + set Model name = DoneaHuertaGravity +end + +############### Parameters describing the temperature field +# As above, there is no need to set anything for the +# temperature boundary conditions. + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the discretization +# The following parameters describe how often we want to refine +# the mesh globally and adaptively, what fraction of cells should +# be refined in each adaptive refinement step, and what refinement +# indicator to use when refining the mesh adaptively. + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Refinement fraction = 0.2 + set Strategy = velocity +end + +############### Parameters describing what to do with the solution +# The final section allows us to choose which postprocessors to +# run at the end of each time step. + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, DoneaHuertaPostprocessor + + subsection Visualization + set List of output variables = density, viscosity, strain rate, gravity + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + set Number of cheap Stokes solver steps = 0 + end +end diff --git a/benchmarks/entropy_adiabat/entropy_adiabat.prm.bak b/benchmarks/entropy_adiabat/entropy_adiabat.prm.bak new file mode 100644 index 00000000000..274e78cc5d0 --- /dev/null +++ b/benchmarks/entropy_adiabat/entropy_adiabat.prm.bak @@ -0,0 +1,184 @@ +# Adiabatic downwelling along a pipe. Initially all material starts on one +# adiabat (at constant entropy), with material inflow on another adiabat (a +# different constant entropy). The adiabatic reference profile is computed for +# this different inflow adiabat so that the difference between adiabatic +# profile and actual profile in the model is expected to go to 0 with time. The +# material data contains a discontinuous phase transition (in +# pressure-temperature space), which would make convergence of this model hard. +# Accurate results in particular for the latent heat effects would be nearly +# impossible if not for the new feature in this benchmark, which is to solve +# the advection-diffusion equation in terms of entropy instead of temperature. +# In pressure-entropy space there is no jump in entropy across the phase +# transition, and the equation can be accurately solved (in fact it is trivial +# for this example as the steady-state solution is at constant entropy +# everywhere in the model once the warmer inflowing material has replaced the +# initial material in the model). The resulting temperature for any given +# pressure-entropy is looked up in the used material data table. + +# As a benchmark this model can only test that ASPECT's results are consistent +# with the results of the thermodynamic modeling package that produced the +# entropy-pressure tables for material properties (in this case HeFESTo). This +# test is done by replacing the 'compute entropy profile' adiabatic conditions +# plugin with the 'ascii data' plugin, which will load a precomputed adiabat +# from HeFESTo instead of computing an adiabat inside ASPECT. The disadvantage +# of this approach is of course that it is only possible for those adiabats +# that have been precomputed (in this case one for 1600 K), while the 'compute +# entropy profile' plugin can compute adiabats at arbitrary entropy. + +set Additional shared libraries = ./plugins/libentropy_plugins.so +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 2.5e8 +set Output directory = output-entropy-adiabat +set Nonlinear solver scheme = iterated Advection and Stokes +set Surface pressure = 0 +set Adiabatic surface temperature = 1600.1243896484375 + +subsection Formulation + set Mass conservation = projected density field +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 13000 + set Y extent = 1300000 + set Y repetitions = 200 + end +end + +subsection Initial temperature model + # The actual initial temperature is irrelevant, because it + # is recalculated from the entropy during the first timestep. + # The value below corresponds to the entropy of 2534 J/kg/K + # used as the top boundary condition. + set Model name = function + + subsection Function + set Function expression = 1600.1243896484375 + end +end + +subsection Adiabatic conditions model + # The 'ascii data' option does not need the additional + # plugin, but is limited to the available adiabat data files. + # 'compute entropy profile' computes arbitrary adiabats + # internally, based on the data table. + # Use 'ascii data' to compare against HeFESTo adiabat. + set Model name = compute entropy profile + + subsection Compute entropy profile + # Entropy equivalent to T=1600 K according to the used table + set Surface entropy = 2534 + end + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/data/material-model/ + set Data file name = entropy-table/opxtable/1600K_adiabat.txt + end +end + +# We prescribe temperatures according to the data table. +# This output is computed in the material model. +subsection Temperature field + set Temperature method = prescribed field with diffusion +end + +# We solve the entropy equation for the compositional field with name +# 'entropy'. Temperature and density are then computed based on entropy and +# pressure. +subsection Compositional fields + set Number of fields = 2 + set Names of fields = entropy, density_field + set Types of fields = entropy, density + set Compositional field methods = field, prescribed field +end + +subsection Boundary temperature model + # No temperature boundary conditions, + # as the temperature equation is not solved + set Fixed temperature boundary indicators = top + set List of model names = initial temperature +end + +# We prescribe the entropy of the inflowing material to +# be different from the initial entropy in the model. +subsection Boundary composition model + set Fixed composition boundary indicators = top + set List of model names = function + + subsection Function + # Only the first component (entropy) matters, the other equations + # are not solved but computed from entropy. + set Function expression = 2534; 3300 + end +end + +# Prescribing downward flow through a vertical pipe with +# tangential side boundaries. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = top:function + set Tangential velocity boundary indicators = left, right + + subsection Function + set Function expression = 0; -0.01 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +# We start at a lower entropy than the one used for the +# adiabatic profile. +subsection Initial composition model + set List of model names = function + + subsection Function + # Entropy equivalent to T=1405 K according to table + set Function expression = 2360; 0.0 + end +end + +# We use a data table for orthopyroxene computed using the thermodynamic +# modeling software HeFESTo. +subsection Material model + set Model name = entropy model + + subsection Entropy model + set Data directory = $ASPECT_SOURCE_DIR/data/material-model/entropy-table/opxtable/ + set Material file name = material_table.txt + set Lateral viscosity file name = constant_lateral_vis_prefactor.txt + set Thermal conductivity formulation = constant + set Thermal conductivity = 0.1 + end + + subsection Depth dependent viscosity + set Data directory = $ASPECT_SOURCE_DIR/benchmarks/entropy_adiabat/data/ + set Data file name = constant_viscosity.txt + end +end + +subsection Mesh refinement + set Initial global refinement = 0 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, mass flux statistics, composition statistics + + subsection Visualization + set Time between graphical output = 1e7 + set List of output variables = material properties, adiabat, nonadiabatic pressure, nonadiabatic temperature + + subsection Material properties + set List of material properties = density,thermal expansivity,specific heat,viscosity, compressibility + end + end +end diff --git a/benchmarks/entropy_adiabat/entropy_combined.prm.bak b/benchmarks/entropy_adiabat/entropy_combined.prm.bak new file mode 100644 index 00000000000..c06bcf6ae60 --- /dev/null +++ b/benchmarks/entropy_adiabat/entropy_combined.prm.bak @@ -0,0 +1,42 @@ +# Downwelling along a pipe. +# This is a modification of the entropy adiabat example with added diffusion. +# According to Schubert, Turcotte and Olson (part 1, p. 194), the added +# diffusion should only affect the temperature profile above the phase transition. +# Schubert, Turcotte and Olson also give an analytical solution for the +# temperature profile. However, since they do not include adiabatic heating, this +# model does not yield the exact solution from Schubert, Turcotte and Olson. +# Instead, the temperature is slightly cooler below the phase transition due to +# the additional heat conduction along the adiabat. + +include ./entropy_adiabat.prm + +set Additional shared libraries = ./plugins/libentropy_plugins.so +set Dimension = 2 +set End time = 2.5e8 +set Output directory = output-entropy-combined +set Surface pressure = 0 +set Adiabatic surface temperature = 1600.1243896484375 + +# We start at the same entropy as the one used for the +# adiabatic profile. +subsection Initial composition model + set List of model names = function + + subsection Function + # Entropy equivalent to T=1600 K according to table + set Function expression = 2534; 0.0 + end +end + +# We increase the thermal conductivity compared to the +# entropy adiabat example. We choose a very large value +# here because the thermal diffusion effects only become +# visible for large conductivities (or slow flow). +subsection Material model + set Model name = entropy model + + subsection Entropy model + set Thermal conductivity formulation = constant + set Thermal conductivity = 50 + end +end diff --git a/benchmarks/entropy_adiabat/entropy_conduction.prm.bak b/benchmarks/entropy_adiabat/entropy_conduction.prm.bak new file mode 100644 index 00000000000..3a1c77c6b4b --- /dev/null +++ b/benchmarks/entropy_adiabat/entropy_conduction.prm.bak @@ -0,0 +1,147 @@ +# Conduction along an adiabat. Initially all material starts on one adiabat +# (at constant entropy), with no material inflow. The adiabatic reference +# profile is computed based on this initial entropy, using a look-up table +# for orthopyroxene, which has one narrow phase transition in the center of +# the model. The temperature is fixed at the top, and the bottom is set as +# an insulating boundary. Consequently, the model should cool down over +# time as heat flows out conductively through the top boundary, eventually +# reaching a constant temperature. + + +set Additional shared libraries = ./plugins/libentropy_plugins.so +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 2.5e11 +set Maximum time step = 1e7 +set Output directory = output-entropy-conduction +set Nonlinear solver scheme = iterated Advection and Stokes +set Surface pressure = 0 +set Adiabatic surface temperature = 1600.1243896484375 + +subsection Formulation + set Mass conservation = projected density field +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 13000 + set Y extent = 1300000 + set Y repetitions = 200 + end +end + +subsection Initial temperature model + # We convert the initial temperature from the + # initial entropy. + # The value below corresponds to the entropy of 2534 J/kg/K + # used as the top boundary condition and the initial condition. + set Model name = prescribed temperature +end + +subsection Adiabatic conditions model + # 'compute entropy profile' computes arbitrary adiabats + # internally, based on the data table. + set Model name = compute entropy profile + + subsection Compute entropy profile + # Entropy equivalent to T=1600 K according to the used table + set Surface entropy = 2534 + end +end + +# We prescribe temperatures according to the data table. +# This output is computed in the material model. +subsection Temperature field + set Temperature method = prescribed field with diffusion +end + +# We solve the entropy equation for the compositional field with name +# 'entropy'. Temperature and density are then computed based on entropy and +# pressure. +subsection Compositional fields + set Number of fields = 2 + set Names of fields = entropy, density_field + set Types of fields = entropy, density + set Compositional field methods = field, prescribed field +end + +subsection Boundary temperature model + # No temperature boundary conditions, + # as the temperature equation is not solved + set Fixed temperature boundary indicators = top + set List of model names = initial temperature +end + +# We prescribe the entropy at the top. +subsection Boundary composition model + set Fixed composition boundary indicators = top + set List of model names = function + + subsection Function + # Only the first component (entropy) matters, the other equations + # are not solved but computed from entropy. + set Function expression = 2534; 3300 + end +end + +# Prescribing closed boundaries. +subsection Boundary velocity model + set Tangential velocity boundary indicators = top, left, right, bottom +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +# We start at the same entropy as the one used for the +# adiabatic profile. +subsection Initial composition model + set List of model names = function + + subsection Function + # Entropy equivalent to T=1600 K according to table + set Function expression = 2534; 0.0 + end +end + +# We use a data table for orthopyroxene computed using the thermodynamic +# modeling software HeFESTo. +# We use a very large viscosity to make sure the material does not move. +subsection Material model + set Model name = entropy model + + subsection Entropy model + set Data directory = $ASPECT_SOURCE_DIR/data/material-model/entropy-table/opxtable/ + set Material file name = material_table.txt + set Maximum viscosity = 1e30 + set Minimum viscosity = 1e30 + set Lateral viscosity file name = constant_lateral_vis_prefactor.txt + set Thermal conductivity formulation = constant + set Thermal conductivity = 4.7 + end +end + +subsection Mesh refinement + set Initial global refinement = 0 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, mass flux statistics, composition statistics + + subsection Visualization + set Time between graphical output = 1e8 + set List of output variables = material properties, adiabat, nonadiabatic pressure, nonadiabatic temperature + + subsection Material properties + set List of material properties = density,thermal expansivity,specific heat,viscosity, compressibility + end + end +end diff --git a/benchmarks/entropy_adiabat/entropy_half_space.prm.bak b/benchmarks/entropy_adiabat/entropy_half_space.prm.bak new file mode 100644 index 00000000000..ac06b3691c9 --- /dev/null +++ b/benchmarks/entropy_adiabat/entropy_half_space.prm.bak @@ -0,0 +1,155 @@ +# Conduction in a boundary layer, without adiabatic effects. Initially all +# material starts at a constant temperature. Adiabatic effects are switched +# off by setting the gravity to zero. The temperature is fixed at the top, +# and the bottom is set as an insulating boundary. Consequently, the model +# should cool down over time according to the half-space cooling model. +# The temperature at the end of the model run can be compared to the +# solution of the half-space cooling model given in the compositional +# field "half_space". +# Note that density and specific heat are temperature- and, consequently, +# time-dependent, so the solution might slightly deviate from this +# reference profile. + +set Additional shared libraries = ./plugins/libentropy_plugins.so +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 1e9 +set Maximum time step = 1e6 +set Output directory = output-entropy-half-space +set Nonlinear solver scheme = iterated Advection and Stokes +set Max nonlinear iterations = 50 +set Surface pressure = 0 +set Adiabatic surface temperature = 1600.1243896484375 + +subsection Formulation + set Mass conservation = projected density field +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 13000 + set Y extent = 1300000 + set Y repetitions = 200 + end +end + +subsection Initial temperature model + # The actual initial temperature is irrelevant, because it + # is recalculated from the entropy during the first timestep. + set Model name = function + + subsection Function + set Function expression = 1500 + end +end + +subsection Adiabatic conditions model + # 'compute entropy profile' computes arbitrary adiabats + # internally, based on the data table. + set Model name = compute entropy profile + + subsection Compute entropy profile + # Entropy equivalent to T=1600 K according to the used table + set Surface entropy = 2534 + end +end + +# We prescribe temperatures according to the data table. +# This output is computed in the material model. +subsection Temperature field + set Temperature method = prescribed field with diffusion +end + +# We solve the entropy equation for the compositional field with name +# 'entropy'. Temperature and density are then computed based on entropy and +# pressure. +subsection Compositional fields + set Number of fields = 3 + set Names of fields = entropy, density_field, half_space + set Types of fields = entropy, density, generic + set Compositional field methods = field, prescribed field, static +end + +subsection Boundary temperature model + # No temperature boundary conditions, + # as the temperature equation is not solved + set Fixed temperature boundary indicators = top + set List of model names = initial temperature +end + +# We prescribe the entropy at the top. +subsection Boundary composition model + set Fixed composition boundary indicators = top + set List of model names = function + + subsection Function + # Only the first component (entropy) matters, the other equations + # are not solved but computed from entropy. + set Function expression = 2450; 3300; 1500 + end +end + +# Prescribing closed boundaries. +subsection Boundary velocity model + set Tangential velocity boundary indicators = top, left, right, bottom +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0 + end +end + +# We start at the same entropy as the one used for the +# adiabatic profile. The last compositional field gives +# the analytical solution for the temperature at the +# end of the model run based on the half-space cooling +# model. +subsection Initial composition model + set List of model names = function + + subsection Function + # Entropy equivalent to T=1600 K according to table + set Function expression = 2534; 0.0; 1600 - 100 * erfc((1300000 - y)/(2 * sqrt(4.7/(1342*3380)*3600*24*365.25*1e9))) + end +end + +# We use a data table for orthopyroxene computed using the thermodynamic +# modeling software HeFESTo. +# We use a very large viscosity to make sure the material does not move. +subsection Material model + set Model name = entropy model + + subsection Entropy model + set Data directory = $ASPECT_SOURCE_DIR/data/material-model/entropy-table/opxtable/ + set Material file name = material_table.txt + set Maximum viscosity = 1e30 + set Minimum viscosity = 1e30 + set Lateral viscosity file name = constant_lateral_vis_prefactor.txt + set Thermal conductivity formulation = constant + set Thermal conductivity = 4.7 + end +end + +subsection Mesh refinement + set Initial global refinement = 0 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, mass flux statistics, composition statistics + + subsection Visualization + set Time between graphical output = 1e8 + set List of output variables = material properties, adiabat, nonadiabatic pressure, nonadiabatic temperature + + subsection Material properties + set List of material properties = density,thermal expansivity,specific heat,viscosity, compressibility + end + end +end diff --git a/benchmarks/entropy_adiabat/plugins/entropy_advection.cc.bak b/benchmarks/entropy_adiabat/plugins/entropy_advection.cc.bak new file mode 100644 index 00000000000..61c005ec1f5 --- /dev/null +++ b/benchmarks/entropy_adiabat/plugins/entropy_advection.cc.bak @@ -0,0 +1,312 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include "entropy_advection.h" +#include + +#include +#include +#include + +namespace aspect +{ + namespace Assemblers + { + template + void + EntropyAdvectionSystem::execute (internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const + { + internal::Assembly::Scratch::AdvectionSystem &scratch = dynamic_cast&> (scratch_base); + internal::Assembly::CopyData::AdvectionSystem &data = dynamic_cast&> (data_base); + + const Introspection &introspection = this->introspection(); + const FiniteElement &fe = this->get_fe(); + + const typename Simulator::AdvectionField advection_field = *scratch.advection_field; + const std::vector &composition_descriptions = this->introspection().get_composition_descriptions(); + if (!advection_field.is_temperature() + && composition_descriptions[advection_field.compositional_variable].type != CompositionalFieldDescription::entropy) + return; + + const unsigned int n_q_points = scratch.finite_element_values.n_quadrature_points; + const unsigned int advection_dofs_per_cell = data.local_dof_indices.size(); + + const bool use_bdf2_scheme = (this->get_timestep_number() > 1); + const double time_step = this->get_timestep(); + const double old_time_step = this->get_old_timestep(); + + const double bdf2_factor = (use_bdf2_scheme)? ((2*time_step + old_time_step) / + (time_step + old_time_step)) : 1.0; + + const unsigned int solution_component = advection_field.component_index(introspection); + const FEValuesExtractors::Scalar solution_field = advection_field.scalar_extractor(introspection); + + scratch.finite_element_values[introspection.extractors.temperature].get_function_values (this->get_old_solution(), + scratch.old_temperature_values); + + for (unsigned int q=0; q= 0, + ExcMessage ("The product of density and temperature needs to be a " + "non-negative quantity.")); + + const double gamma = + scratch.heating_model_outputs.heating_source_terms[q]; + + const double field_term_for_rhs + = (use_bdf2_scheme ? + (scratch.old_field_values[q] * + (1 + time_step/old_time_step) + - + scratch.old_old_field_values[q] * + (time_step * time_step) / + (old_time_step * (time_step + old_time_step))) + : + scratch.old_field_values[q]) + * + (rho_T); + + Tensor<1,dim> current_u = scratch.current_velocity_values[q]; + // Subtract off the mesh velocity for ALE corrections if necessary + if (this->get_parameters().mesh_deformation_enabled) + current_u -= scratch.mesh_velocity_values[q]; + + // We compute the amount of diffusion based on the solution of the temperature equation. + const double diffusion_term = (scratch.material_model_inputs.temperature[q] - scratch.old_temperature_values[q]) + * scratch.material_model_outputs.densities[q] * scratch.material_model_outputs.specific_heat[q]; + + // do the actual assembly. note that we only need to loop over the advection + // shape functions because these are the only contributions we compute here + for (unsigned int i=0; i + std::vector + EntropyAdvectionSystem::compute_residual(internal::Assembly::Scratch::ScratchBase &scratch_base) const + { + internal::Assembly::Scratch::AdvectionSystem &scratch = dynamic_cast&> (scratch_base); + + const typename Simulator::AdvectionField advection_field = *scratch.advection_field; + const unsigned int n_q_points = scratch.finite_element_values.n_quadrature_points; + std::vector residuals(n_q_points,0.0); + + const std::vector &composition_descriptions = this->introspection().get_composition_descriptions(); + if (!advection_field.is_temperature() + && composition_descriptions[advection_field.compositional_variable].type != CompositionalFieldDescription::entropy) + return residuals; + + this->get_heating_model_manager().evaluate(scratch.material_model_inputs, + scratch.material_model_outputs, + scratch.heating_model_outputs); + + for (unsigned int q=0; q < n_q_points; ++q) + { + const Tensor<1,dim> u = (scratch.old_velocity_values[q] + + scratch.old_old_velocity_values[q]) / 2; + + const double dField_dt = (this->get_old_timestep() == 0.0) ? 0.0 : + ( + ((scratch.old_field_values)[q] - (scratch.old_old_field_values)[q]) + / this->get_old_timestep()); + const double u_grad_field = u * (scratch.old_field_grads[q] + + scratch.old_old_field_grads[q]) / 2; + + const double density = scratch.material_model_outputs.densities[q]; + const double gamma = scratch.heating_model_outputs.heating_source_terms[q]; + + // Because we solve the diffusion equation for the temperature before the advection equation, we can use + // the current and old temperature here, together with the current time step. + const double diffusion_term = (this->get_timestep() == 0.0) ? 0.0 + : + (scratch.material_model_inputs.temperature[q] - scratch.old_temperature_values[q]) / this->get_timestep() + * scratch.material_model_outputs.densities[q] * scratch.material_model_outputs.specific_heat[q]; + + + residuals[q] + = std::abs((density * scratch.material_model_inputs.temperature[q]) * (dField_dt + u_grad_field) - gamma - diffusion_term); + } + return residuals; + } + + + + template + std::vector + EntropyAdvectionSystem::advection_prefactors(internal::Assembly::Scratch::ScratchBase &scratch_base) const + { + internal::Assembly::Scratch::AdvectionSystem &scratch = dynamic_cast&> (scratch_base); + + std::vector prefactors(scratch.material_model_inputs.n_evaluation_points(), 0.0); + + for (unsigned int i=0; i + std::vector + EntropyAdvectionSystem::diffusion_prefactors(internal::Assembly::Scratch::ScratchBase &scratch_base) const + { + internal::Assembly::Scratch::AdvectionSystem &scratch = dynamic_cast&> (scratch_base); + + std::vector prefactors(scratch.material_model_inputs.n_evaluation_points(), 0.0); + + for (unsigned int i=0; i + void set_assemblers_entropy_advection(const SimulatorAccess &simulator_access, + Assemblers::Manager &assemblers) + { + AssertThrow (Plugins::plugin_type_matches> + (simulator_access.get_material_model()), + ExcMessage ("The entropy advection assembler can only be used with the " + "material model 'entropy model'!")); + + AssertThrow (simulator_access.get_heating_model_manager().adiabatic_heating_enabled() == false, + ExcMessage("The entropy advection assembler requires " + "that adiabatic heating is disabled.")); + + // Replace all existing assemblers for the temperature and entropy fields by the one for the entropy equation. + const unsigned int temperature_index = 0; + assemblers.advection_system[temperature_index].clear(); + assemblers.advection_system[temperature_index].emplace_back (std::make_unique>()); + assemblers.advection_system_assembler_properties[temperature_index].needed_update_flags = update_hessians; + + if (simulator_access.introspection().composition_type_exists(CompositionalFieldDescription::entropy)) + { + // Find the index of the entropy field and replace the assembler for it. + // The index of the entropy field is its index in the compositional fields plus one (for the temperature field). + const unsigned int entropy_index = simulator_access.introspection().get_indices_for_fields_of_type(CompositionalFieldDescription::entropy)[0] + + 1; + assemblers.advection_system[entropy_index].clear(); + assemblers.advection_system[entropy_index].emplace_back (std::make_unique>()); + assemblers.advection_system_assembler_properties[entropy_index].needed_update_flags = update_hessians; + } + } +} // namespace aspect + +template +void signal_connector (aspect::SimulatorSignals &signals) +{ + signals.set_assemblers.connect (&aspect::set_assemblers_entropy_advection); +} + +ASPECT_REGISTER_SIGNALS_CONNECTOR(signal_connector<2>, + signal_connector<3>) + +// explicit instantiation of the functions we implement in this file +namespace aspect +{ + namespace Assemblers + { +#define INSTANTIATE(dim) \ + template class EntropyAdvectionSystem; + + ASPECT_INSTANTIATE(INSTANTIATE) + } +} diff --git a/benchmarks/entropy_adiabat/plugins/entropy_advection.h.bak b/benchmarks/entropy_adiabat/plugins/entropy_advection.h.bak new file mode 100644 index 00000000000..1d0c41a1b67 --- /dev/null +++ b/benchmarks/entropy_adiabat/plugins/entropy_advection.h.bak @@ -0,0 +1,58 @@ +/* + Copyright (C) 2016 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_simulator_assemblers_entropy_advection_h +#define _aspect_simulator_assemblers_entropy_advection_h + + +#include +#include + +namespace aspect +{ + namespace Assemblers + { + /** + * This class assembles the terms for the matrix and right-hand-side of the entropy + * advection equation for the current cell. + */ + template + class EntropyAdvectionSystem : public Assemblers::Interface, public Assemblers::AdvectionStabilizationInterface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch, + internal::Assembly::CopyData::CopyDataBase &data) const override; + + std::vector + compute_residual(internal::Assembly::Scratch::ScratchBase &scratch) const override; + + std::vector + advection_prefactors(internal::Assembly::Scratch::ScratchBase &scratch_base) const override; + + std::vector + diffusion_prefactors(internal::Assembly::Scratch::ScratchBase &scratch_base) const override; + }; + } +} + + +#endif diff --git a/benchmarks/finite_strain/finite_strain.cc.bak b/benchmarks/finite_strain/finite_strain.cc.bak new file mode 100644 index 00000000000..7084bcac0ef --- /dev/null +++ b/benchmarks/finite_strain/finite_strain.cc.bak @@ -0,0 +1,20 @@ +/* + Copyright (C) 2011 - 2018 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include "../../cookbooks/finite_strain/finite_strain.cc" diff --git a/benchmarks/finite_strain/pure_shear.prm.bak b/benchmarks/finite_strain/pure_shear.prm.bak new file mode 100644 index 00000000000..fcfe9eb7802 --- /dev/null +++ b/benchmarks/finite_strain/pure_shear.prm.bak @@ -0,0 +1,145 @@ +# This parameter file reproduces an analytical benchmark for the evolution +# of finite strain in a model of pure shear as described (for a specific +# application) in McKenzie & Jackson (1983): "The relationship between +# strain rates, crustal thickening, paleomagnetism, finite strain and +# fault movements within a deforming zone." They show that the analytical +# solution for the deformation gradient tensor F in pure shear deformation is: +# +# F_xx = e^(u_x,x * t) +# F_xy = 0 +# F_yx = 0 +# F_yy = e^(-u_x,x * t), +# +# where u is the velocity, t is time, and a comma represents a derivative +# in that particular direction. u_x,x in this example is equivalent to +# -u_y,y so that also: F_yy = e^(u_y,y * t) which is intuitive. +# For this benchmark it is important to recognize that the deformation in +# this model is actually only "pure" pure shear at the origin, since the +# deformation field around is a mixture of pure shear and a rotational +# component. Also the value of u_x,x at the origin is not prescribed +# directly, but is a model output, because we only know velocity profiles +# for the top and right boundaries. Using the computed velocity field we +# can calculate u_x,x approximately at the origin to be 1.253, and therefore +# expect: +# F_xx (t=1.0) = 3.501 +# F_yy (t=1.0) = 0.2856 +# This parameter file tracks the finite strain in two ways, once by using +# compositional fields as illustrated in the finite strain cookbook, and +# once by using a particle particle that sits and remains at the origin. +# The results should of course be the same. +# +# Numerical results for particle tracking show excellent agreement: +# F_xx (t=1.0) = 3.50088 +# F_yy (t=1.0) = 0.285643 +# +# Numerical results for compositional fields also show good results. +# F_xx (t=1.0) = 3.49776 +# F_yy (t=1.0) = 0.286723 +# The compositional field results are slightly less accurate, probably due to +# numerical diffusion, but were found to converge against the analytical +# values with increasing resolution. + +set Additional shared libraries = ./libfinite_strain.so +set Dimension = 2 +set End time = 1.0 +set Use years in output instead of seconds = false +set Output directory = output-pure_shear + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1.0 + set Y extent = 1.0 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, bottom + set Prescribed velocity boundary indicators = top:function, right:function + + subsection Function + set Function expression = 1-y; x-1 + end +end + +subsection Material model + set Model name = finite strain + + subsection Simple model + set Reference density = 1010 + set Viscosity = 1e2 + set Thermal expansion coefficient = 0 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +subsection Compositional fields + set Number of fields = 4 + set Names of fields = strain_xx, strain_xy, strain_yx, strain_yy +end + +subsection Boundary composition model + set List of model names = initial composition +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Function expression = 1.0;0.0;0.0;1.0 + end +end + +############### Parameters describing the temperature field +# Note: The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Strategy = strain rate + set Initial global refinement = 4 + set Time steps between mesh refinement = 0 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = particles, visualization + + subsection Visualization + set List of output variables = strain rate, shear stress + set Time between graphical output = 0.05 + end + + subsection Particles + set Time between data output = 0.05 + set Data output format = vtu + end +end + +subsection Particles + set List of particle properties = integrated strain + set Particle generator name = ascii file + + subsection Generator + subsection Ascii file + set Data directory = ./ + set Data file name = pure_shear_particle.dat + end + end +end diff --git a/benchmarks/finite_strain/simple_shear.prm.bak b/benchmarks/finite_strain/simple_shear.prm.bak new file mode 100644 index 00000000000..866ca5d7822 --- /dev/null +++ b/benchmarks/finite_strain/simple_shear.prm.bak @@ -0,0 +1,133 @@ +# This parameter file reproduces an analytical benchmark for the evolution +# of finite strain in a model of simple shear as described (for a specific +# application) in McKenzie & Jackson (1983): "The relationship between +# strain rates, crustal thickening, paleomagnetism, finite strain and +# fault movements within a deforming zone." They show that the analytical +# solution for the deformation gradient tensor F in simple shear deformation is: +# +# F_xx = 1.0 +# F_xy = u_x,y * t +# F_yx = 0 +# F_yy = 1.0, +# +# where u is the velocity, t is time, and a comma represents a derivative +# in that particular direction. +# Because u_x,y = 2.0 / 1.0 is constant in the whole domain (and over time) we expect +# a constant F at any given time, and in particular: +# F_xy (t=1.0) = 2.0 +# +# This parameter file tracks the finite strain in two ways, once by using +# compositional fields as illustrated in the finite strain cookbook, and +# once by using a particle particle that sits and remains in the center of the domain. +# The results should of course be the same. +# +# Numerical results for particle tracking and compositional fields +# show equally excellent agreement: +# F_xy (t=1.0) = 2.0 + +set Additional shared libraries = ./libfinite_strain.so +set Dimension = 2 +set End time = 1.0 +set Use years in output instead of seconds = false +set Output directory = output-simple_shear + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1.0 + set Y extent = 1.0 + set X periodic = true + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = bottom:function, top:function + + subsection Function + set Function expression = if (y < 0.5, -1, 1); 0 + end +end + +subsection Material model + set Model name = finite strain + + subsection Simple model + set Reference density = 1010 + set Viscosity = 1e2 + set Thermal expansion coefficient = 0 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +subsection Compositional fields + set Number of fields = 4 + set Names of fields = strain_xx, strain_xy, strain_yx, strain_yy +end + +subsection Boundary composition model + set List of model names = initial composition +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Function expression = 1.0;0.0;0.0;1.0 + end +end + +############### Parameters describing the temperature field +# Note: The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the discretization + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Strategy = strain rate + set Initial global refinement = 4 + set Time steps between mesh refinement = 0 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = particles, visualization + + subsection Visualization + set List of output variables = strain rate + set Time between graphical output = 0.05 + end + + subsection Particles + set Time between data output = 0.05 + set Data output format = vtu + end +end + +subsection Particles + set List of particle properties = integrated strain + set Particle generator name = ascii file + + subsection Generator + subsection Ascii file + set Data directory = ./ + set Data file name = simple_shear_particle.dat + end + end +end diff --git a/benchmarks/free_surface_tractions/viscoelastic/free_surface_VE_cylinder_2D_loading.prm.bak b/benchmarks/free_surface_tractions/viscoelastic/free_surface_VE_cylinder_2D_loading.prm.bak new file mode 100644 index 00000000000..6bba7d2ad73 --- /dev/null +++ b/benchmarks/free_surface_tractions/viscoelastic/free_surface_VE_cylinder_2D_loading.prm.bak @@ -0,0 +1,169 @@ +# This model applies a surface load (using the traction +# boundary condition) on a free surface overlying +# a viscoelastic box. It approximates the analytical solution +# of Nakiboglu and Lambeck (1982) for an applied/removed +# axisymmetric cylindrical load over a viscoelastic half-space. + +# Global parameters +set Dimension = 2 +set Start time = 0 +set End time = 1500 +set Use years in output instead of seconds = true +set Nonlinear solver scheme = single Advection, single Stokes +set CFL number = 0.5 +set Maximum time step = 10 +set Output directory = output_free_surface_VE_cylinder_2D_loading +set Timing output frequency = 1 +set Pressure normalization = no + +# Model geometry (500x500 km, 50 km spacing) +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 10 + set Y repetitions = 10 + set X extent = 500e3 + set Y extent = 500e3 + end +end + +# Mesh refinement specifications +# Mesh refinement does not seem to affect +# deformation of free surface (at least in 2-D). +subsection Mesh refinement + set Initial adaptive refinement = 1 + set Initial global refinement = 1 + set Time steps between mesh refinement = 1 + set Strategy = strain rate +end + +# Element types +subsection Discretization + set Composition polynomial degree = 2 + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 1 +end + +# Formulation classification +subsection Formulation + set Enable elasticity = true +end + +subsection Mesh deformation + set Additional tangential mesh velocity boundary indicators = left,right + set Mesh deformation boundary indicators = top: free surface + + subsection Free surface + set Surface velocity projection = normal + end +end + +# Velocity boundary conditions +subsection Boundary velocity model + set Tangential velocity boundary indicators = bottom, left, right +end + +# Prescribe a fixed vertical traction on the top boundary + +subsection Boundary traction model + set Prescribed traction boundary indicators = top y: function + + subsection Function + set Variable names = x,y,t + + #set Function expression = 0; 1.e9 + -20.e3*x + set Function constants = r0=100.e3, H0=1.e3, t1=1.e3, rhoi=900, g=9.8, t0=1.e3 + + # r0 is load radius, H0 is load height, t1 is time load is fully removed, + # rhoi is density of ice/load + # option to linearly thin load beginning at time t0. + set Function expression = 0; if (xy_extent/2, traction, -traction) ; 0 + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = top y: function, bottom y: function + + subsection Function + set Variable names = x,y + set Function expression = 0;0 + end +end + +subsection Initial temperature model + set Model name = adiabatic + + subsection Adiabatic + set Age top boundary layer = 0 + + subsection Function + set Function expression = 0 + end + end +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + + # This is the test case from Mulyukova and Bercovici (2018) using + # the parameters from their figure 4 and a grain size of 1e-2 m. + set Function expression = 1e-2 + end +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = grain_size +end + +subsection Material model + set Model name = grain size + + subsection Grain size model + set Reference density = 3400 + set Thermal conductivity = 0 + set Thermal expansion coefficient = 0 + set Reference compressibility = 0 + set Viscosity = 1e18 + set Minimum viscosity = 1e16 + set Reference temperature = 1100 + set Recrystallized grain size = + set Grain growth activation energy = 3e5 + set Grain growth activation volume = 0.0 + set Grain growth rate constant = 1.6E-022 + set Grain growth exponent = 4 + set Average specific grain boundary energy = 1.0 + set Geometric constant = 3 + set Grain size evolution formulation = pinned grain damage + + # Mulyukova and Bercovici (2018) + # Diffusion creep + set Diffusion creep prefactor = 27.2e-24 # s^-1 Pa^-1 m^p + set Diffusion creep exponent = 1.0 # 1 for diffusion creep + set Diffusion creep grain size exponent = 3 + set Diffusion activation energy = 3e5 #J/mol + set Diffusion activation volume = 0 # m^3/mol + set Dislocation viscosity iteration threshold = 1e-3 + + # Dislocation creep + set Dislocation creep prefactor = 8.8e-13 # s^-1 Pa^-n + set Dislocation creep exponent = 3 + set Dislocation activation energy = 530000 # J/mol + set Dislocation activation volume = 0 # m^3/mol + set Minimum grain size = 1e-8 + + subsection Grain damage partitioning + set Minimum grain size reduction work fraction = 5e-3 + set Maximum grain size reduction work fraction = 5e-3 + end + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = composition statistics, temperature statistics, velocity statistics, visualization, material statistics, ODE statistics + + subsection Visualization + set List of output variables = viscosity, shear stress, stress, stress second invariant + set Time between graphical output = 5e3 + end +end + +subsection Nullspace removal + set Remove nullspace = net x translation +end diff --git a/benchmarks/gravity_mantle/mantle_gravity.prm.bak b/benchmarks/gravity_mantle/mantle_gravity.prm.bak new file mode 100644 index 00000000000..82754a08720 --- /dev/null +++ b/benchmarks/gravity_mantle/mantle_gravity.prm.bak @@ -0,0 +1,76 @@ +# A simple setup for testing the gravity postprocessor using the +# sample scheme 'map'. +# See the corresponding section in the manual for more information. + +# General parameters +set Dimension = 3 +set End time = 0 +set Output directory = output-gravity-mantle +set Nonlinear solver scheme = no Advection, no Stokes + +# Model geometry +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3480e3 + set Outer radius = 6251e3 + end +end + +# Material model +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3300 + set Thermal expansion coefficient = 3e-5 + end +end + +# Model initial temperature +subsection Initial temperature model + set Model name = S40RTS perturbation + + subsection S40RTS perturbation + set Initial condition file name = S40RTS.sph + set Spline knots depth file name = Spline_knots.txt + set Remove degree 0 from perturbation = false + set Vs to density scaling = 0.15 + set Thermal expansion coefficient in initial temperature scaling = 3e-5 + set Reference temperature = 0 + end +end + +# Model gravity +subsection Gravity model + set Model name = radial constant +end + +# Mesh refinement +subsection Mesh refinement + set Initial global refinement = 3 +end + +# Postprocessing +subsection Postprocess + set List of postprocessors = gravity calculation,visualization, material statistics + + subsection Visualization + set List of output variables = density, viscosity + set Time between graphical output = 0 + set Interpolate output = false + end + + subsection Gravity calculation + set Sampling scheme = map + set Minimum radius = 6621e3 + set Minimum longitude = -180 + set Maximum longitude = 179 + set Number points longitude = 180 + set Minimum latitude = -90 + set Maximum latitude = +90 + set Number points latitude = 90 + set Quadrature degree increase = 01 + end +end diff --git a/benchmarks/gravity_thick_shell/doc/thick_shell.prm.bak b/benchmarks/gravity_thick_shell/doc/thick_shell.prm.bak new file mode 100644 index 00000000000..d21edf6563d --- /dev/null +++ b/benchmarks/gravity_thick_shell/doc/thick_shell.prm.bak @@ -0,0 +1,11 @@ +subsection Postprocess + set List of postprocessors = gravity calculation,visualization + + subsection Gravity calculation + set Sampling scheme = list of points + set List of radius = 0,1e6,2e6,3e6,3.5e6,4e6,4.5e6,5e6,5.5e6,6e6,6.371e6,6.5e6,7e6,8e6,9e6,10e6 + set List of longitude = 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 + set List of latitude = 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 + set Quadrature degree increase = 1 + end +end diff --git a/benchmarks/gravity_thick_shell/thick_shell.prm.bak b/benchmarks/gravity_thick_shell/thick_shell.prm.bak new file mode 100644 index 00000000000..911dd9853f8 --- /dev/null +++ b/benchmarks/gravity_thick_shell/thick_shell.prm.bak @@ -0,0 +1,72 @@ +# A simple setup for testing the gravity postprocessor using the +# sample scheme 'list of points'. The domain is a 2891 km thick +# shell of constant density, i.e. the Earth mantle. +# An analytical solution exists for the gravitational acceleration +# and potential so that values returned by the gravity postprocessor +# can be benchmarked on a line from the center of the planet to +# 10,000 km outside. +# See the corresponding section in the manual for more information. + +# General parameters +set Dimension = 3 +set End time = 0 +set Output directory = output_shellgravity +set Nonlinear solver scheme = no Advection, no Stokes + +# Model geometry +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3480e3 + set Outer radius = 6371e3 + end +end + +# Model boundary velocity +subsection Boundary velocity model + set Zero velocity boundary indicators = top, bottom +end + +# Material model +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3300 + set Thermal expansion coefficient = 0 + end +end + +# Model gravity +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 10 + end +end + +# Mesh refinement +subsection Mesh refinement + set Initial global refinement = 4 +end + +# Postprocessing +subsection Postprocess + set List of postprocessors = gravity calculation,visualization + + subsection Visualization + set List of output variables = density + set Time between graphical output = 0 + set Interpolate output = false + end + + subsection Gravity calculation + set Sampling scheme = list of points + set List of radius = 0,1e6,2e6,3e6,3.5e6,4e6,4.5e6,5e6,5.5e6,6e6,6.371e6,6.5e6,7e6,8e6,9e6,10e6 + set List of longitude = 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 + set List of latitude = 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 + set Quadrature degree increase = 1 + end +end diff --git a/benchmarks/gravity_thin_shell/doc/thinshell_a.prm.bak b/benchmarks/gravity_thin_shell/doc/thinshell_a.prm.bak new file mode 100644 index 00000000000..aec41ce6b98 --- /dev/null +++ b/benchmarks/gravity_thin_shell/doc/thinshell_a.prm.bak @@ -0,0 +1,11 @@ +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 6266e3 + set Outer radius = 6276e3 + set Custom mesh subdivision = number of slices + set Number of slices = 1 + set Initial lateral refinement = 5 + end +end diff --git a/benchmarks/gravity_thin_shell/doc/thinshell_b.prm.bak b/benchmarks/gravity_thin_shell/doc/thinshell_b.prm.bak new file mode 100644 index 00000000000..3bf6a339c65 --- /dev/null +++ b/benchmarks/gravity_thin_shell/doc/thinshell_b.prm.bak @@ -0,0 +1 @@ +set Nonlinear solver scheme = no Advection, no Stokes diff --git a/benchmarks/gravity_thin_shell/doc/thinshell_c.prm.bak b/benchmarks/gravity_thin_shell/doc/thinshell_c.prm.bak new file mode 100644 index 00000000000..7185128e5de --- /dev/null +++ b/benchmarks/gravity_thin_shell/doc/thinshell_c.prm.bak @@ -0,0 +1,15 @@ +subsection Postprocess + set List of postprocessors = gravity calculation,visualization + + subsection Gravity calculation + set Sampling scheme = map + set Minimum radius = 6621e3 + set Minimum longitude = -180 + set Maximum longitude = 179 + set Number points longitude = 180 + set Minimum latitude = -90 + set Maximum latitude = +90 + set Number points latitude = 90 + set Quadrature degree increase = 1 + end +end diff --git a/benchmarks/gravity_thin_shell/gravity_thin_shell.prm.bak b/benchmarks/gravity_thin_shell/gravity_thin_shell.prm.bak new file mode 100644 index 00000000000..4b778bd997f --- /dev/null +++ b/benchmarks/gravity_thin_shell/gravity_thin_shell.prm.bak @@ -0,0 +1,88 @@ +# A simple setup for testing the gravity postprocessor using the +# sample scheme 'map'. The domain is a 5 km thick thin shell of constant density. +# An analytical solution exists for the gravitational acceleration +# and potential so that values returned by the gravity postprocessor +# can be benchmarked on a longitude-latitude grid at satellite orbit height. + +set Dimension = 3 +set End time = 0 +set Output directory = output_thin_shell_gravity +set Nonlinear solver scheme = no Advection, no Stokes + +# Model geometry +# The thin shell (5 km thickness) can be centered around 5 different depths, +# 0, 100, 500, 1500 and 3000 km, i.e. radii 6371, 6271, 5871, 4871 and 3371 km. +# The default depth is here 100 km while other corresponding inner and outer +# radii are commented. +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + # layer 0 km depth + #set Inner radius = 6366e3 + #set Outer radius = 6376e3 + # layer 100 km depth + set Inner radius = 6266e3 + set Outer radius = 6276e3 + + # layer 500 km depth + #set Inner radius = 5866e3 + #set Outer radius = 5876e3 + # layer 1500 km depth + #set Inner radius = 4866e3 + #set Outer radius = 4876e3 + # layer 3000 km depth + #set Inner radius = 3366e3 + #set Outer radius = 3376e3 + set Custom mesh subdivision = number of slices + set Number of slices = 1 + set Initial lateral refinement = 5 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = top, bottom +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3300 + set Thermal expansion coefficient = 0 + end +end + +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 10 + end +end + +subsection Mesh refinement + set Initial global refinement = 0 +end + +subsection Postprocess + set List of postprocessors = gravity calculation,visualization + + subsection Visualization + set List of output variables = density, viscosity, partition + set Time between graphical output = 0 + set Interpolate output = false + end + + subsection Gravity calculation + set Sampling scheme = map + set Minimum radius = 6621e3 + set Minimum longitude = -180 + set Maximum longitude = 179 + set Number points longitude = 180 + set Minimum latitude = -90 + set Maximum latitude = +90 + set Number points latitude = 90 + set Quadrature degree increase = 1 + end +end diff --git a/benchmarks/hollow_sphere/hollow_sphere.cc.bak b/benchmarks/hollow_sphere/hollow_sphere.cc.bak new file mode 100644 index 00000000000..12ebe62fc77 --- /dev/null +++ b/benchmarks/hollow_sphere/hollow_sphere.cc.bak @@ -0,0 +1,682 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + + +namespace aspect +{ + /** + * This is the "HollowSphere" benchmark defined in the following paper: + * Analytical solution for viscous incompressible Stokes flow in a spherical shell + * C. Thieulot, in prep. + */ + namespace HollowSphereBenchmark + { + using namespace dealii; + + namespace AnalyticSolutions + { + const double gammma = 1.0; + + const double R1 = 0.5; + const double R2 = 1.0; + + const double gravity = 1.0; + const double mu0=1; + const double rho_0 = 1000; + + Tensor<1,3> + hollow_sphere_velocity (const Point<3> &pos, + const double mmm) + { + + const std::array spos = + aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(pos); + + const double r=spos[0]; + const double phi=spos[1]; + const double theta=spos[2]; + + + double alpha,beta,fr,gr; + + if (mmm == -1) + { + alpha=-gammma*(pow(R2,3)-pow(R1,3))/(pow(R2,3)*log(R1)-pow(R1,3)*log(R2)); + beta=-3*gammma*(log(R2)-log(R1))/(pow(R1,3)*log(R2)-pow(R2,3)*log(R1)) ; + fr=alpha/(r*r)+beta*r; + gr=-2/(r*r)*(alpha*log(r)+beta/3*pow(r,3)+gammma); + } + else + { + alpha=gammma*(mmm+1)*(pow(R1,-3)-pow(R2,-3))/(pow(R1,-mmm-4)-pow(R2,-mmm-4)); + beta=-3*gammma*(pow(R1,mmm+1)-pow(R2,mmm+1))/(pow(R1,mmm+4)-pow(R2,mmm+4)); + fr=alpha/pow(r,mmm+3)+beta*r; + gr=-2/(r*r)*(-alpha/(mmm+1)*pow(r,-mmm-1)+beta/3*pow(r,3)+gammma); + } + + const double v_r =gr*cos(theta); + const double v_theta=fr*sin(theta); + const double v_phi =fr*sin(theta); + const double v_x=sin(theta)*cos(phi)*v_r + cos(theta)*cos(phi)*v_theta-sin(phi)*v_phi; + const double v_y=sin(theta)*sin(phi)*v_r + cos(theta)*sin(phi)*v_theta+cos(phi)*v_phi; + const double v_z=cos(theta)*v_r - sin(theta)*v_theta; + + // create a Point<3> (because it has a constructor that takes + // three doubles) and return it (it automatically converts to + // the necessary Tensor<1,3>). + return Point<3> (v_x,v_y,v_z); + } + + double + hollow_sphere_pressure (const Point<3> &pos, + const double mmm) + { + const std::array spos = + aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(pos); + + const double r=spos[0]; + const double theta=spos[2]; + + double alpha,beta,gr,hr,mur; + + + if (mmm == -1) + { + mur=mu0; + alpha=-gammma*(pow(R2,3)-pow(R1,3))/(pow(R2,3)*log(R1)-pow(R1,3)*log(R2)); + beta=-3*gammma*(log(R2)-log(R1))/(pow(R1,3)*log(R2)-pow(R2,3)*log(R1)) ; + gr=-2/(r*r)*(alpha*log(r)+beta/3*pow(r,3)+gammma); + hr=2/r*gr*mur; + } + else + { + mur=mu0*pow(r,mmm+1); + alpha=gammma*(mmm+1)*(pow(R1,-3)-pow(R2,-3))/(pow(R1,-mmm-4)-pow(R2,-mmm-4)); + beta=-3*gammma*(pow(R1,mmm+1)-pow(R2,mmm+1))/(pow(R1,mmm+4)-pow(R2,mmm+4)); + gr=-2/(r*r)*(-alpha/(mmm+1)*pow(r,-mmm-1)+beta/3*pow(r,3)+gammma); + hr=(mmm+3)/r*gr*mur; + } + + return hr*cos(theta) + rho_0 * gravity * (R2 - r); + } + + template + double + hollow_sphere_normal_traction(const Point &pos, + const double mmm) + { + Assert (dim == 3, ExcNotImplemented()); + + const double r=std::sqrt(pos[0]*pos[0]+pos[1]*pos[1]+pos[2]*pos[2]); + const double theta=std::acos(pos[2]/r); + + double alpha,beta,fr,gr; + + + if (mmm == -1) + { + alpha=-gammma*(pow(R2,3)-pow(R1,3))/(pow(R2,3)*log(R1)-pow(R1,3)*log(R2)); + beta=-3*gammma*(log(R2)-log(R1))/(pow(R1,3)*log(R2)-pow(R2,3)*log(R1)) ; + fr=alpha/(r*r)+beta*r; + gr=-2/(r*r)*(alpha*log(r)+beta/3*pow(r,3)+gammma); + } + else + { + alpha=gammma*(mmm+1)*(pow(R1,-3)-pow(R2,-3))/(pow(R1,-mmm-4)-pow(R2,-mmm-4)); + beta=-3*gammma*(pow(R1,mmm+1)-pow(R2,mmm+1))/(pow(R1,mmm+4)-pow(R2,mmm+4)); + fr=alpha/pow(r,mmm+3)+beta*r; + gr=-2/(r*r)*(-alpha/(mmm+1)*pow(r,-mmm-1)+beta/3*pow(r,3)+gammma); + } + + return -(6.*gr + 4.*fr) * cos(theta) * mu0 / r; + } + + + /** + * The exact solution for the HollowSphere benchmark. + */ + template + class FunctionHollowSphere : public Function + { + public: + FunctionHollowSphere (const double mmm) + : + Function(dim+2), + mmm_(mmm) + {} + + void vector_value (const Point &pos, + Vector &values) const override + { + Assert (dim == 3, ExcNotImplemented()); + Assert (values.size() >= 4, ExcInternalError()); + + const Point<3> p (pos[0], pos[1], pos[2]); + + const Tensor<1,3> v = AnalyticSolutions::hollow_sphere_velocity (p, mmm_); + values[0] = v[0]; + values[1] = v[1]; + values[2] = v[2]; + + values[3] = AnalyticSolutions::hollow_sphere_pressure (p, mmm_); + } + + private: + const double mmm_; + }; + } + + + + template + class HollowSphereBoundary : public BoundaryVelocity::Interface + { + public: + /** + * Constructor. + */ + HollowSphereBoundary(); + + /** + * Return the boundary velocity as a function of position. + */ + Tensor<1,dim> + boundary_velocity (const types::boundary_id , + const Point &position) const override; + + + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + + + private: + double mmm; + }; + + template + HollowSphereBoundary::HollowSphereBoundary () + : + mmm (0) + {} + + + + template <> + Tensor<1,2> + HollowSphereBoundary<2>:: + boundary_velocity (const types::boundary_id , + const Point<2> &) const + { + Assert (false, ExcNotImplemented()); + return Tensor<1,2>(); + } + + + + template <> + Tensor<1,3> + HollowSphereBoundary<3>:: + boundary_velocity (const types::boundary_id , + const Point<3> &p) const + { + return AnalyticSolutions::hollow_sphere_velocity (p, mmm); + } + + + + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @ingroup MaterialModels + */ + template + class HollowSphereMaterial : public MaterialModel::Interface + { + public: + /** + * @name Physical parameters used in the basic equations + * @{ + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + * Incompressibility does not necessarily imply that the density is + * constant; rather, it may still depend on temperature or pressure. + * In the current context, compressibility means whether we should + * solve the continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + + + /** + * Returns the viscosity value in the inclusion + */ + double get_mmm() const; + + /** + * viscosity value in the inclusion + */ + double mmm; + }; + + + + template + bool + HollowSphereMaterial:: + is_compressible () const + { + return false; + } + + + template <> + void + HollowSphereMaterial<2>:: + evaluate (const MaterialModel::MaterialModelInputs<2> &/*in*/, + MaterialModel::MaterialModelOutputs<2> &/*out*/) const + { + Assert (false, ExcNotImplemented()); + } + + + + template <> + void + HollowSphereMaterial<3>:: + evaluate (const MaterialModel::MaterialModelInputs<3> &in, + MaterialModel::MaterialModelOutputs<3> &out) const + { + const unsigned int dim = 3; + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const Point &pos = in.position[i]; + const std::array spos = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(pos); + const double r = spos[0]; + const double mu = pow(r,mmm+1); + out.viscosities[i] = mu; + + const double theta=spos[2]; + + const double gammma = 1.0; + const double R1 = 0.5; + const double R2 = 1.0; + + double alpha,beta,rho; + const double rho_0 = 1000.; + + if (mmm == -1) + { + alpha = -gammma*(pow(R2,3)-pow(R1,3))/(pow(R2,3)*log(R1)-pow(R1,3)*log(R2)); + beta = -3*gammma*(log(R2)-log(R1))/(pow(R1,3)*log(R2)-pow(R2,3)*log(R1)) ; + rho = -(alpha/pow(r,4)*(8*log(r)-6) + 8./3.*beta/r+8*gammma/pow(r,4))*cos(theta) + rho_0; + } + else + { + alpha=gammma*(mmm+1)*(pow(R1,-3)-pow(R2,-3))/(pow(R1,-mmm-4)-pow(R2,-mmm-4)); + beta=-3*gammma*(pow(R1,mmm+1)-pow(R2,mmm+1))/(pow(R1,mmm+4)-pow(R2,mmm+4)); + rho= -(2*alpha*pow(r,-4)*(mmm+3)/(mmm+1)*(mmm-1)-2*beta/3*(mmm-1)*(mmm+3)*pow(r,mmm)-mmm*(mmm+5)*2*gammma*pow(r,mmm-3) )*cos(theta) + rho_0; + } + + out.densities[i] = rho; + + out.specific_heat[i] = 0; + out.thermal_conductivities[i] = 0.0; + out.compressibilities[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + } + } + + + + template + void + HollowSphereMaterial::declare_parameters (ParameterHandler &prm) + { + //create a global section in the parameter file for parameters + //that describe this benchmark. note that we declare them here + //in the material model, but other kinds of plugins (e.g., the gravity + //model below) may also read these parameters even though they do not + //declare them + prm.enter_subsection("HollowSphere benchmark"); + { + prm.declare_entry("Viscosity parameter", "-1", + Patterns::Double (), + "Viscosity in the HollowSphere benchmark."); + } + prm.leave_subsection(); + } + + + template + void + HollowSphereMaterial::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("HollowSphere benchmark"); + { + mmm = prm.get_double ("Viscosity parameter"); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + template + void + HollowSphereBoundary::declare_parameters (ParameterHandler &) + { + //nothing to declare here. This plugin will however, read parameters + //declared by the material model in the "HollowSphere benchmark" section + } + + + template + void + HollowSphereBoundary::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("HollowSphere benchmark"); + { + mmm = prm.get_double ("Viscosity parameter"); + } + prm.leave_subsection(); + } + + + + template + double + HollowSphereMaterial::get_mmm() const + { + return mmm; + } + + + /** + * A postprocessor that evaluates the accuracy of the solution. + * + * The implementation of error evaluators that correspond to the + * benchmarks defined in the paper Duretz et al. reference above. + */ + template + class HollowSpherePostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * List the other postprocessors required by this plugin. + */ + std::list + required_other_postprocessors() const override; + + private: + /** + * Calculate the L2 dynamic topography error. + */ + double + compute_dynamic_topography_error() const; + }; + + template + std::pair + HollowSpherePostprocessor::execute (TableHandler &) + { + std::unique_ptr> ref_func; + { + const HollowSphereMaterial & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + ref_func = std::make_unique>(material_model.get_mmm()); + } + + const QGauss quadrature_formula (this->introspection().polynomial_degree.velocities+2); + + Vector cellwise_errors_u (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_p (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_ul2 (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_pl2 (this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_u(std::pair(0,dim), + dim+2); + ComponentSelectFunction comp_p(dim, dim+2); + + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_u, + quadrature_formula, + VectorTools::L1_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_p, + quadrature_formula, + VectorTools::L1_norm, + &comp_p); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_ul2, + quadrature_formula, + VectorTools::L2_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_pl2, + quadrature_formula, + VectorTools::L2_norm, + &comp_p); + + const double u_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_u, VectorTools::L1_norm); + const double p_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_p, VectorTools::L1_norm); + const double u_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_ul2, VectorTools::L2_norm); + const double p_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_pl2, VectorTools::L2_norm); + const double topo_l2 = compute_dynamic_topography_error(); + + std::ostringstream os; + + os << std::scientific << u_l1 + << ", " << p_l1 + << ", " << u_l2 + << ", " << p_l2 + << ", " << topo_l2; + + return std::make_pair("Errors u_L1, p_L1, u_L2, p_L2 topo_L2:", os.str()); + } + + /** + * Register the other postprocessor that we need: DynamicTopography + */ + template + std::list + HollowSpherePostprocessor::required_other_postprocessors() const + { + return std::list (1, "dynamic topography"); + } + + + template <> + double + HollowSpherePostprocessor<2>::compute_dynamic_topography_error () const + { + Assert (false, ExcNotImplemented()); + return 0.0; + } + + + + /** + * Integrate the difference between the analytical and numerical + * solutions for dynamic topography. + */ + template <> + double + HollowSpherePostprocessor<3>::compute_dynamic_topography_error() const + { + const unsigned int dim = 3; + const Postprocess::DynamicTopography &dynamic_topography = + this->get_postprocess_manager().template get_matching_postprocessor>(); + + const HollowSphereMaterial &material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + const double beta = material_model.get_mmm(); + + const QGauss quadrature_formula (this->introspection().polynomial_degree.velocities+2); + FEFaceValues fe_face_values(this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | update_gradients | + update_quadrature_points | update_JxW_values); + LinearAlgebra::BlockVector topo_vector = dynamic_topography.topography_vector(); + std::vector topo_values(quadrature_formula.size()); + + double l2_error = 0.; + + typename DoFHandler::active_cell_iterator + cell = this->get_dof_handler().begin_active(), + endc = this->get_dof_handler().end(); + + Point test; + test[2] = 1.0; + test[0] = 0.; + test[1] = 0.; + for (; cell!=endc; ++cell) + if (cell->is_locally_owned()) + if (cell->at_boundary()) + for (unsigned int f=0; f::faces_per_cell; ++f) + if (cell->face(f)->at_boundary() && cell->face(f)->boundary_id() == 1 /*outer surface*/) + { + fe_face_values.reinit(cell, f); + MaterialModel::MaterialModelInputs in_face(fe_face_values, cell, this->introspection(), this->get_solution()); + MaterialModel::MaterialModelOutputs out_face(fe_face_values.n_quadrature_points, this->n_compositional_fields()); + in_face.requested_properties = MaterialModel::MaterialProperties::density; + fe_face_values[this->introspection().extractors.temperature].get_function_values(topo_vector, topo_values); + this->get_material_model().evaluate(in_face, out_face); + + for (unsigned int q=0; q < quadrature_formula.size(); ++q) + { + const Point p = fe_face_values.quadrature_point(q); + const double analytic_normal_stress = AnalyticSolutions::hollow_sphere_normal_traction(p, beta); + const double gravity = this->get_gravity_model().gravity_vector(p).norm(); + const double density = out_face.densities[q]; + const double diff = -analytic_normal_stress / gravity / density - topo_values[q]; + l2_error += (diff*diff) * fe_face_values.JxW(q); + } + } + const double total_l2_error = Utilities::MPI::sum(l2_error,this->get_mpi_communicator()); + return std::sqrt(total_l2_error); + } + + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace HollowSphereBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(HollowSphereMaterial, + "HollowSphereMaterial", + "A material model that corresponds to the `HollowSphere' benchmark. " + "See the manual for more information.") + + ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(HollowSphereBoundary, + "HollowSphereBoundary", + "Implementation of the velocity boundary conditions for the " + "`HollowSphere' benchmark. See the manual for more information about this " + "benchmark.") + + ASPECT_REGISTER_POSTPROCESSOR(HollowSpherePostprocessor, + "HollowSpherePostprocessor", + "A postprocessor that compares the solution of the `HollowSphere' benchmark " + "with the one computed by ASPECT " + "and reports the error. See the manual for more information.") + } +} diff --git a/benchmarks/hollow_sphere/hollow_sphere.prm.bak b/benchmarks/hollow_sphere/hollow_sphere.prm.bak new file mode 100644 index 00000000000..b7678faba23 --- /dev/null +++ b/benchmarks/hollow_sphere/hollow_sphere.prm.bak @@ -0,0 +1,103 @@ +# The 3D HollowSphere benchmark, for which an +# analytical solution is available (Thieulot, in prep). + + +############### Global parameters + +set Additional shared libraries = ./libhollow_sphere.so +set Dimension = 3 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = false +set Nonlinear solver scheme = no Advection, iterated Stokes +set Output directory = output +set Pressure normalization = surface + +############### Parameters describing the model +# The setup is a 3D shell +# Because the temperature plays no role in this model we need not +# bother to describe temperature boundary conditions or +# the material parameters that pertain to the temperature. + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 0.5 + set Outer radius = 1.0 + set Cells along circumference = 12 + end +end + +#Boundary conditions + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = bottom : HollowSphereBoundary, \ + top : HollowSphereBoundary +end + +subsection Material model + set Model name = HollowSphereMaterial +end + +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 1.0 + end +end + +subsection HollowSphere benchmark + #Viscosity parameter is m + set Viscosity parameter = 3 +end + +############### Parameters describing the temperature field +# As above, there is no need to set anything for the +# temperature boundary conditions. + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the discretization +# The following parameters describe how often we want to refine +# the mesh globally and adaptively, what fraction of cells should +# be refined in each adaptive refinement step, and what refinement +# indicator to use when refining the mesh adaptively. + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 4 + set Refinement fraction = 0.2 + set Strategy = velocity +end + +#subsection Discretization +#set Stokes velocity polynomial degree = 1 +#set Use locally conservative discretization = true +#end + +############### Parameters describing what to do with the solution +# The final section allows us to choose which postprocessors to +# run at the end of each time step. + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, HollowSpherePostprocessor, memory statistics, dynamic topography + + subsection Visualization + set List of output variables = density, viscosity, strain rate, dynamic topography, gravity + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-6 + set Number of cheap Stokes solver steps = 0 + end +end diff --git a/benchmarks/inclusion/adaptive.prm.base.bak b/benchmarks/inclusion/adaptive.prm.base.bak new file mode 100644 index 00000000000..c539065b2ad --- /dev/null +++ b/benchmarks/inclusion/adaptive.prm.base.bak @@ -0,0 +1,72 @@ +############### Global parameters + +set Additional shared libraries = ./libinclusion.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Pressure normalization = volume +set Nonlinear solver scheme = no Advection, iterated Stokes +set Use years in output instead of seconds = false + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 2 + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left : InclusionBoundary, \ + right : InclusionBoundary, \ + bottom: InclusionBoundary, \ + top : InclusionBoundary +end + +subsection Material model + set Model name = InclusionMaterial + + subsection Inclusion + set Viscosity jump = 1e3 + end +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = perturbed box +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = false +end + +subsection Mesh refinement + set Initial adaptive refinement = 13 + set Initial global refinement = 4 + set Strategy = velocity#viscosity + set Run postprocessors on initial refinement = true + set Coarsening fraction = 0.0 + set Refinement fraction = 0.5 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = InclusionPostprocessor, visualization + + subsection Visualization + set List of output variables = viscosity + set Time between graphical output = 0 + end +end diff --git a/benchmarks/inclusion/compositional_fields/inclusion_compositional_fields.cc.bak b/benchmarks/inclusion/compositional_fields/inclusion_compositional_fields.cc.bak new file mode 100644 index 00000000000..0ba0f0693a5 --- /dev/null +++ b/benchmarks/inclusion/compositional_fields/inclusion_compositional_fields.cc.bak @@ -0,0 +1,51 @@ +/* + Copyright (C) 2011 - 2018 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include "inclusion_compositional_fields.h" + + + +// explicit instantiations +namespace aspect +{ + namespace InclusionBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(InclusionCompositionalMaterial, + "InclusionCompositionalMaterial", + "A material model that corresponds to the 'Inclusion' benchmark " + "defined in Duretz et al., G-Cubed, 2011. using " + "compositional fields.") + + ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(InclusionBoundary, + "InclusionBoundary", + "Implementation of the velocity boundary conditions for the " + "``inclusion'' benchmark. See the manual and the Kronbichler, Heister " + "and Bangerth paper on ASPECT for more information about this " + "benchmark.") + + ASPECT_REGISTER_POSTPROCESSOR(InclusionPostprocessor, + "InclusionPostprocessor", + "A postprocessor that compares the solution of the benchmarks from " + "the Duretz et al., G-Cubed, 2011, paper with the one computed by ASPECT " + "and reports the error. Specifically, it can compute the errors for " + "the SolCx, SolKz and inclusion benchmarks. The postprocessor inquires " + "which material model is currently being used and adjusts " + "which exact solution to use accordingly.") + } +} diff --git a/benchmarks/inclusion/compositional_fields/inclusion_compositional_fields.h.bak b/benchmarks/inclusion/compositional_fields/inclusion_compositional_fields.h.bak new file mode 100644 index 00000000000..b8d29972826 --- /dev/null +++ b/benchmarks/inclusion/compositional_fields/inclusion_compositional_fields.h.bak @@ -0,0 +1,34 @@ +#ifndef ASPECT_INCLUSION_COMPOSITIONAL_FIELDS_H +#define ASPECT_INCLUSION_COMPOSITIONAL_FIELDS_H + +#include "../inclusion.h" + + + +namespace aspect +{ + namespace InclusionBenchmark + { + using namespace dealii; + + template + class InclusionCompositionalMaterial : public InclusionMaterial + { + public: + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + out.viscosities[i] = in.composition[i][0]; + out.densities[i] = 0; + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + } + } + }; + } +} +#endif diff --git a/benchmarks/inclusion/compositional_fields/inclusion_compositional_fields.prm.bak b/benchmarks/inclusion/compositional_fields/inclusion_compositional_fields.prm.bak new file mode 100644 index 00000000000..0a368f998f3 --- /dev/null +++ b/benchmarks/inclusion/compositional_fields/inclusion_compositional_fields.prm.bak @@ -0,0 +1,91 @@ +# A description of the SolVI or Inclusion benchmark using +# compositional fields for which a known solution is available. +# See the manual for more information. + +############### Global parameters + +set Additional shared libraries = ./libinclusion_compositional_fields.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Pressure normalization = volume +set Nonlinear solver scheme = no Advection, iterated Stokes + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 2 + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left : InclusionBoundary, \ + right : InclusionBoundary, \ + bottom: InclusionBoundary, \ + top : InclusionBoundary +end + +subsection Material model + set Model name = InclusionCompositionalMaterial + + subsection Inclusion + set Viscosity jump = 1e3 + end +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = perturbed box +end + +############### Parameters describing the discretization + +subsection Discretization + set Composition polynomial degree = 1 + set Stokes velocity polynomial degree = 2 + set Use discontinuous composition discretization = true + set Use locally conservative discretization = false +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = viscosity_comp + set Compositional field methods = field +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = eta_b=1e3, rmax=0.2 + set Function expression = if((x-1.0)*(x-1.0)+(z-1.0)*(z-1.0)<=0.04,eta_b,1.0) + end +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, InclusionPostprocessor + + subsection Visualization + set Output format = vtu + set Number of grouped files = 1 + set Time between graphical output = 0 + set List of output variables = density, viscosity + end +end diff --git a/benchmarks/inclusion/compositional_fields/inclusion_particles.prm.bak b/benchmarks/inclusion/compositional_fields/inclusion_particles.prm.bak new file mode 100644 index 00000000000..41aa2dc74df --- /dev/null +++ b/benchmarks/inclusion/compositional_fields/inclusion_particles.prm.bak @@ -0,0 +1,119 @@ +# A description of the SolVI or Inclusion benchmark using +# active particles for which a known solution is available. +# See the manual for more information. + +############### Global parameters + +set Additional shared libraries = ./libinclusion_compositional_fields.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Pressure normalization = volume +set Nonlinear solver scheme = single Advection, single Stokes + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 2 + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left : InclusionBoundary, \ + right : InclusionBoundary, \ + bottom: InclusionBoundary, \ + top : InclusionBoundary +end + +subsection Material model + set Model name = InclusionCompositionalMaterial + + subsection Inclusion + set Viscosity jump = 1e3 + end +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + + +subsection Initial temperature model + set Model name = perturbed box +end + +############### Parameters describing the discretization + +subsection Discretization + set Composition polynomial degree = 2 + set Stokes velocity polynomial degree = 2 + set Use discontinuous composition discretization = true + set Use locally conservative discretization = false +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = viscosity_comp + set Compositional field methods = particles + set Mapped particle properties = viscosity_comp:function +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = eta_b=1e3, rmax=0.2 + set Function expression = if((x-1.0)*(x-1.0)+(z-1.0)*(z-1.0)<=0.04,eta_b,1.0) + end +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = particles, visualization, InclusionPostprocessor + + subsection Visualization + set Output format = vtu + set Number of grouped files = 1 + set Time between graphical output = 0 + set List of output variables = density, viscosity + end + + subsection Particles + set Time between data output = 0 + set Data output format = vtu + end +end + +subsection Particles + set List of particle properties = function + set Integration scheme = rk2 + set Interpolation scheme = cell average + set Maximum particles per cell = 16384 + set Update ghost particles = true + set Particle generator name = reference cell + + subsection Function + set Variable names = x,z + set Function constants = eta_b=1e3, rmax=0.2 + set Function expression = if((x-1.0)*(x-1.0)+(z-1.0)*(z-1.0)<=0.04,eta_b,1.0) + end + + subsection Generator + subsection Reference cell + set Number of particles per cell per direction = 4 + end + end +end diff --git a/benchmarks/inclusion/doc/inclusion.prm.bak b/benchmarks/inclusion/doc/inclusion.prm.bak new file mode 100644 index 00000000000..d9a6f297152 --- /dev/null +++ b/benchmarks/inclusion/doc/inclusion.prm.bak @@ -0,0 +1,62 @@ +############### Global parameters + +set Additional shared libraries = ./libinclusion.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output +set Pressure normalization = volume + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 2 + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left : InclusionBoundary, \ + right : InclusionBoundary, \ + bottom: InclusionBoundary, \ + top : InclusionBoundary +end + +subsection Material model + set Model name = InclusionMaterial + + subsection Inclusion + set Viscosity jump = 1e3 + end +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = perturbed box +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = false +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 6 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = InclusionPostprocessor, visualization +end diff --git a/benchmarks/inclusion/global.prm.base.bak b/benchmarks/inclusion/global.prm.base.bak new file mode 100644 index 00000000000..176659deda1 --- /dev/null +++ b/benchmarks/inclusion/global.prm.base.bak @@ -0,0 +1,63 @@ +############### Global parameters + +set Additional shared libraries = ./libinclusion.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Pressure normalization = volume +set Nonlinear solver scheme = no Advection, iterated Stokes +set Use years in output instead of seconds = false + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 2 + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left : InclusionBoundary, \ + right : InclusionBoundary, \ + bottom: InclusionBoundary, \ + top : InclusionBoundary +end + +subsection Material model + set Model name = InclusionMaterial + + subsection Inclusion + set Viscosity jump = 1e3 + end +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = perturbed box +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = false +end + +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 0 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = InclusionPostprocessor, visualization +end diff --git a/benchmarks/inclusion/inclusion.cc.bak b/benchmarks/inclusion/inclusion.cc.bak new file mode 100644 index 00000000000..d8ac9d6b466 --- /dev/null +++ b/benchmarks/inclusion/inclusion.cc.bak @@ -0,0 +1,50 @@ +/* + Copyright (C) 2011 - 2018 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include "inclusion.h" + + + +// explicit instantiations +namespace aspect +{ + namespace InclusionBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(InclusionMaterial, + "InclusionMaterial", + "A material model that corresponds to the 'Inclusion' benchmark " + "defined in Duretz et al., G-Cubed, 2011.") + + ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(InclusionBoundary, + "InclusionBoundary", + "Implementation of the velocity boundary conditions for the " + "``inclusion'' benchmark. See the manual and the Kronbichler, Heister " + "and Bangerth paper on ASPECT for more information about this " + "benchmark.") + + ASPECT_REGISTER_POSTPROCESSOR(InclusionPostprocessor, + "InclusionPostprocessor", + "A postprocessor that compares the solution of the benchmarks from " + "the Duretz et al., G-Cubed, 2011, paper with the one computed by ASPECT " + "and reports the error. Specifically, it can compute the errors for " + "the SolCx, SolKz and inclusion benchmarks. The postprocessor inquires " + "which material model is currently being used and adjusts " + "which exact solution to use accordingly.") + } +} diff --git a/benchmarks/inclusion/inclusion.h.bak b/benchmarks/inclusion/inclusion.h.bak new file mode 100644 index 00000000000..9c9a0bb8ed9 --- /dev/null +++ b/benchmarks/inclusion/inclusion.h.bak @@ -0,0 +1,356 @@ +#ifndef ASPECT_INCLUSION_H +#define ASPECT_INCLUSION_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + + +namespace aspect +{ + /** + * This is the "Pure shear/Inclusion" benchmark defined in the following paper: + * @code + * @Article{DMGT11, + * author = {T. Duretz and D. A. May and T. V. Gerya and P. J. Tackley}, + * title = {Discretization errors and free surface stabilization in the + * finite difference and marker-in-cell method for applied + * geodynamics: {A} numerical study}, + * journal = {Geochemistry Geophysics Geosystems}, + * year = 2011, + * volume = 12, + * pages = {Q07004/1--26}} + * @endcode + * + * The results are published in Kronbichler, Heister and Bangerth paper. + */ + namespace InclusionBenchmark + { + using namespace dealii; + + namespace AnalyticSolutions + { + // based on http://geodynamics.org/hg/cs/AMR/Discontinuous_Stokes with permission + void _Inclusion(double pos[2], double r_inclusion, double eta, double *vx, double *vy, double *p) + { + const double min_eta = 1.0; + const double max_eta = eta; + const double epsilon = 1; //strain rate + const double A(min_eta*(max_eta-min_eta)/(max_eta+min_eta)); + std::complex phi, psi, dphi; + const double offset[2]= {1.0, 1.0}; + double r2_inclusion = r_inclusion * r_inclusion; + + double x = pos[0]-offset[0]; + double y = pos[1]-offset[1]; + double r2 = x*x+y*y; + + std::complex z(x,y); + if (r2 v = (phi - z*conj(dphi) - conj(psi))/(2.0*visc); + *vx=v.real(); + *vy=v.imag(); + *p=-2*epsilon*dphi.real(); + } + + + + /** + * The exact solution for the Inclusion benchmark. + */ + template + class FunctionInclusion : public Function + { + public: + FunctionInclusion (double eta_B, + const unsigned int n_compositional_fields) + : Function(dim+2+n_compositional_fields), eta_B_(eta_B) {} + + void vector_value (const Point &p, + Vector &values) const override + { + double pos[2]= {p(0),p(1)}; + AnalyticSolutions::_Inclusion + (pos,0.2,eta_B_, &values[0], &values[1], &values[2]); + } + + private: + double eta_B_; + }; + } + + + + template + class InclusionBoundary : public BoundaryVelocity::Interface + { + public: + /** + * Constructor. + */ + InclusionBoundary() : eta_B(1e3) {} + + /** + * Return the boundary velocity as a function of position. + */ + Tensor<1,dim> + boundary_velocity (const types::boundary_id , + const Point &position) const override + { + Assert (dim == 2, ExcNotImplemented()); + + double pos[2]= {position(0),position(1)}; + + Tensor<1,dim> velocity; + double pressure; + AnalyticSolutions::_Inclusion + (pos,0.2,eta_B, &velocity[0], &velocity[1], &pressure); + + return velocity; + }; + + private: + double eta_B; + }; + + + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @ingroup MaterialModels + */ + template + class InclusionMaterial : public MaterialModel::Interface + { + public: + /** + * @name Physical parameters used in the basic equations + * @{ + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const Point &pos = in.position[i]; + double r2 = (pos[0]-1.0)*(pos[0]-1.0) + (pos[1]-1.0)*(pos[1]-1.0); + + out.viscosities[i] = (r2<0.2*0.2)? eta_B : 1.0; + + out.densities[i] = 0; + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + out.entropy_derivative_pressure[i] = 0.0; + out.entropy_derivative_temperature[i] = 0.0; + } + } + + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + * Incompressibility does not necessarily imply that the density is + * constant; rather, it may still depend on temperature or pressure. + * In the current context, compressibility means whether we should + * solve the continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + bool is_compressible () const override + { + return false; + } + /** + * @} + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Inclusion"); + { + prm.declare_entry ("Viscosity jump", "1e3", + Patterns::Double (0.), + "Viscosity in the Inclusion."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Inclusion"); + { + eta_B = prm.get_double ("Viscosity jump"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + + + /** + * Returns the viscosity value in the inclusion + */ + double get_eta_B() const + { + return eta_B; + } + + private: + /** + * viscosity value in the inclusion + */ + double eta_B; + }; + + + + /** + * A postprocessor that evaluates the accuracy of the solution. + * + * The implementation of error evaluators that correspond to the + * benchmarks defined in the paper Duretz et al. reference above. + */ + template + class InclusionPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &/*statistics*/) override + { + AssertThrow(Plugins::plugin_type_matches>(this->get_material_model()), + ExcMessage("Postprocessor only works with the inclusion material model.")); + + const InclusionMaterial & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + std::unique_ptr> ref_func + = std::make_unique>( + material_model.get_eta_B(), + this->n_compositional_fields()); + + const QGauss quadrature_formula (this->introspection().polynomial_degree.velocities+2); + + Vector cellwise_errors_u (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_p (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_ul2 (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_pl2 (this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_u(std::pair(0,dim), + this->get_fe().n_components()); + ComponentSelectFunction comp_p(dim, + this->get_fe().n_components()); + + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_u, + quadrature_formula, + VectorTools::L1_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_p, + quadrature_formula, + VectorTools::L1_norm, + &comp_p); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_ul2, + quadrature_formula, + VectorTools::L2_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_pl2, + quadrature_formula, + VectorTools::L2_norm, + &comp_p); + + const double u_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_u, VectorTools::L1_norm); + const double p_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_p, VectorTools::L1_norm); + const double u_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_ul2, VectorTools::L2_norm); + const double p_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_pl2, VectorTools::L2_norm); + + // Compute stokes unknowns, do not include temperature + types::global_dof_index n_stokes_dofs = this->introspection().system_dofs_per_block[this->introspection().block_indices.velocities]; + if (this->introspection().block_indices.velocities != this->introspection().block_indices.pressure) + n_stokes_dofs += this->introspection().system_dofs_per_block[this->introspection().block_indices.pressure]; + + std::ostringstream os; + os << n_stokes_dofs << "; " + << std::scientific << u_l1 + << ", " << p_l1 + << ", " << u_l2 + << ", " << p_l2; + + return std::make_pair("DoFs; Errors u_L1, p_L1, u_L2, p_L2:", os.str()); + } + }; + } +} +#endif diff --git a/benchmarks/infill_density/infill_ascii.prm b/benchmarks/infill_density/infill_ascii.prm index dbed3116c5c..aad1f865492 100644 --- a/benchmarks/infill_density/infill_ascii.prm +++ b/benchmarks/infill_density/infill_ascii.prm @@ -72,9 +72,9 @@ subsection Discretization set Use discontinuous composition discretization = true subsection Stabilization parameters - set Use limiter for discontinuous composition solution = true set Global composition maximum = 1.e13, 1.e13, 1.e13, 1.0 set Global composition minimum = -1.e13, -1.e13, -1.e13, 0.0 + set Limiter for discontinuous composition solution = bound preserving end end diff --git a/benchmarks/infill_density/infill_ascii.prm.bak b/benchmarks/infill_density/infill_ascii.prm.bak new file mode 100644 index 00000000000..dbed3116c5c --- /dev/null +++ b/benchmarks/infill_density/infill_ascii.prm.bak @@ -0,0 +1,217 @@ +# This model demonstrates ASPECT's ability to be used to +# model load induced flexure from a topographic feature +# on top of the lithosphere. The model uses the viscoelastic +# material model and is composed of an 'elastic' high viscosity +# lithosphere and a low viscosity mantle beneath the elastic +# lithosphere. A time dependent axisymmetric box load is applied +# to the top boundary using ASCII files, with the center of the load +# at the left boundary of the 2D cartesian model domain. The model +# is run for 120'000 years, which is equivalent to 40*tm: +# tm = eta_m / mu +# eta_m = mantle viscosity +# mu = elastic shear modulus +# tm is the time scale of viscous stress relaxation for the mantle. +# This allows for virtually all stresses in the mantle to be relaxed +# and for the elastic lithosphere to be fully compensating the load. +# The analytic solution for this setup is outlined in the Generic +# Mapping Tools function grdflexure: +# + +# Global parameters +set Additional shared libraries = ./libinfill_density.so +set Dimension = 2 +set Start time = 0 +set End time = 120e3 +set Use years in output instead of seconds = true +set Nonlinear solver scheme = single Advection, single Stokes +set CFL number = 0.1 +set Maximum time step = 750 +set Output directory = output +set Pressure normalization = no + +# Model geometry (1200x1200 km, 80 km spacing in x direction, 40km spacing in y direction) +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 15 + set Y repetitions = 30 + set X extent = 1200e3 + set Y extent = 1200e3 + end +end + +# Mesh refinement specifications +# Refine the mesh in the uppermost part of the model +# to better capture lithospheric response to the load. +# (10x5km mesh in the lithosphere) +subsection Mesh refinement + set Initial adaptive refinement = 2 + set Initial global refinement = 1 + set Time steps between mesh refinement = 1 + set Minimum refinement level = 0 + set Strategy = minimum refinement function, strain rate + + subsection Minimum refinement function + set Coordinate system = cartesian + set Variable names = x,y,t + set Function expression = if(y>=1050e3, 3, 0) + end +end + +# Element types +subsection Discretization + set Composition polynomial degree = 2 + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 1 + set Use locally conservative discretization = true + set Use discontinuous temperature discretization = false + + # Discontinuous (DG) elements are used for compositional fields to more accurately track + # the lithosphere-asthenosphere boundary. + set Use discontinuous composition discretization = true + + subsection Stabilization parameters + set Use limiter for discontinuous composition solution = true + set Global composition maximum = 1.e13, 1.e13, 1.e13, 1.0 + set Global composition minimum = -1.e13, -1.e13, -1.e13, 0.0 + end +end + +# Formulation classification +subsection Formulation + set Enable elasticity = true +end + +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + set Additional tangential mesh velocity boundary indicators = left, right + + subsection Free surface + set Surface velocity projection = normal + end +end + +# Velocity boundary conditions +# The left boundary is set to free slip to allow the lithosphere +# to vertically deform along this boundary and act as mirror plane +# for the other 'half' of the load. +subsection Boundary velocity model + set Tangential velocity boundary indicators = bottom, left +end + +# Prescribe a fixed vertical traction on the top boundary +# The right boundary is open in order to allow outflow of the +# mantle as lithospheric flexure pushes the mantle to the right. +subsection Boundary traction model + set Prescribed traction boundary indicators = top y: infill ascii data, right: initial lithostatic pressure + + subsection Infill ascii data + set Rock density = 2000 + set Sediment density = 2000 + set Height for specifying rock infill = 0 + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/benchmarks/infill_density/data/ + set First data file model time = 0 + set Data file name = box_2d_%s.%d.txt + set Data file time step = 750 + end + end + + subsection Initial lithostatic pressure + set Representative point = 1200e3, 0 + end +end + +# Number and name of compositional fields +subsection Compositional fields + set Number of fields = 4 + set Names of fields = ve_stress_xx, ve_stress_yy, ve_stress_xy, lithosphere +end + +#Spatial domain of different compositional fields +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = + set Function expression = 0; 0; 0; if(y>=1125e3, 1, 0) + end +end + +#Composition boundary conditions +subsection Boundary composition model + set Allow fixed composition on outflow boundaries = false + set List of model names = initial composition +end + +# Temperature boundary conditions +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top, left, right + set List of model names = initial temperature +end + +# Temperature initial conditions +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 293 + end +end + +# Material model +subsection Material model + set Model name = viscoelastic + + subsection Viscoelastic + set Densities = 3300 + + # The first valueis assigned to the mantle and the next three are assigned to the compositional + # fields representing viscoelastic stresses, but significantly these values are not used in the + # viscosity calculation (i.e., only values representing lithologies are used). Respectively, the + # fourth and fifth values are assigned to the compositional fields representing the lithosphere. + set Viscosities = 1.e21, 1.e21, 1.e21, 1.e21, 1.e26 + set Elastic shear moduli = 1.e10 + set Use fixed elastic time step = true + set Fixed elastic time step = 7500 + set Viscosity averaging scheme = harmonic + end +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +# Post processing +subsection Postprocess + set List of postprocessors = basic statistics, temperature statistics, topography, velocity statistics, visualization + + subsection Visualization + set List of output variables = material properties, strain rate, shear stress, boundary indicators + set Number of grouped files = 1 + set Time between graphical output = 7500 + set Interpolate output = true + + subsection Material properties + set List of material properties = viscosity + end + end + + subsection Topography + set Output to file = true + set Time between text output = 7500 + end +end + +# Termination criteria +subsection Termination criteria + set Termination criteria = end time +end diff --git a/benchmarks/infill_density/infill_ascii_data.cc.bak b/benchmarks/infill_density/infill_ascii_data.cc.bak new file mode 100644 index 00000000000..92c66e10a1d --- /dev/null +++ b/benchmarks/infill_density/infill_ascii_data.cc.bak @@ -0,0 +1,267 @@ +/* + Copyright (C) 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace BoundaryTraction + { + using namespace dealii; + + /** + * A class that implements prescribed traction boundary conditions determined + * from pressures given in an AsciiData input file. + * + * @ingroup BoundaryTractions + */ + template + class InfillAsciiData : public Utilities::AsciiDataBoundary, public Interface + { + public: + /** + * Constructor. + */ + InfillAsciiData (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataBoundary::initialize; + + /** + * Return the boundary traction as a function of position. The + * (outward) normal vector to the domain is also provided as + * a second argument. + */ + Tensor<1,dim> + boundary_traction (const types::boundary_id surface_boundary_id, + const Point &position, + const Tensor<1,dim> &normal_vector) const override; + + /** + * A function that is called at the beginning of each time step to + * indicate what the model time is for which the boundary values will + * next be evaluated. For the current class, the function passes to + * the parsed function what the current time is. + */ + void + update () override; + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + types::boundary_id surface_boundary_id; + double rock_density; + double sediment_density; + double crustal_density; + double rock_infill_height; + }; + + template + InfillAsciiData::InfillAsciiData () + : + surface_boundary_id(numbers::invalid_unsigned_int) + {} + + + template + void + InfillAsciiData::initialize () + { + surface_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + std::set surface_boundary_set; + surface_boundary_set.insert(surface_boundary_id); + + // The input ascii table contains one data column (Traction [Pa]) due to + // the load in addition to the coordinate columns. + Utilities::AsciiDataBoundary::initialize(surface_boundary_set, + 1); + } + + + template + Tensor<1,dim> + InfillAsciiData:: + boundary_traction (const types::boundary_id surface_boundary_id, + const Point &position, + const Tensor<1,dim> &normal_vector) const + { + const double load = Utilities::AsciiDataBoundary::get_data_component(surface_boundary_id, + position, + 0); + Tensor<1, dim> traction = normal_vector; + const double gravity_norm = this->get_gravity_model().gravity_vector(position).norm(); + const double elevation = this->get_geometry_model().height_above_reference_surface(position); + + // Check if the load at the current point has a height which exceeds the + // 'rock_infill height'. The assumption is that the values taken from the + // ASCII file are specifying the part of the load that is above the undeformed + // reference surface. If we consider a seamount as the load, the ASCII + // file takes the bathymetry of the seamount and provides it as a traction. + // However, the volcanic rock comprising the seamount also fills in the + // flexural moat, providing an additional traction. Since it is much harder to + // specify this traction, 'rock_infill_height' determines where the rock_density + // that the seamount is made of will infill the flexural moat, and where + // sediment_density will infill the flexural moat. For this test, this + // variable is not that important given the idealized load, but this is useful + // when using more complicated bathymetry maps where small scale seafloor + // features makes it unrealistic to set rock_infill_height=0. + if (load >= rock_infill_height*gravity_norm*rock_density) + { + traction = (-load + elevation*gravity_norm*rock_density) * normal_vector; + } + else + { + traction = (-load + elevation*gravity_norm*sediment_density) * normal_vector; + } + return traction; + } + + + template + void + InfillAsciiData::update() + { + Interface::update (); + Utilities::AsciiDataBoundary::update(); + } + + + template + void + InfillAsciiData::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary traction model"); + { + // Utilities::AsciiDataBoundary::declare_parameters(prm, + // "$ASPECT_SOURCE_DIR/tests/infill_density/", + // "box_2d_%s.%d.txt"); + prm.enter_subsection("Infill ascii data"); + { + Utilities::AsciiDataBoundary::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/tests/infill_density/", + "box_2d_%s.%d.txt"); + prm.declare_entry ("Rock density", "2800", + Patterns::Double(0.), + "Density of the volcanic edifice that infills the flexural moat."); + prm.declare_entry ("Sediment density", "2300", + Patterns::Double(0.), + "Density of the sediment that infills the flexural moat."); + prm.declare_entry ("Height for specifying rock infill", "500", + Patterns::Double(0.), + "If the load defined in the ASCII file has a height equal to or greater than " + "the Height for specifying rock infill, then the infill material will be rock, " + "otherwise it will be sediment"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + InfillAsciiData::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary traction model"); + { + // Utilities::AsciiDataBoundary::parse_parameters(prm); + prm.enter_subsection("Infill ascii data"); + { + Utilities::AsciiDataBoundary::parse_parameters(prm); + rock_density = prm.get_double("Rock density"); + sediment_density = prm.get_double("Sediment density"); + rock_infill_height = prm.get_double("Height for specifying rock infill"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryTraction + { + ASPECT_REGISTER_BOUNDARY_TRACTION_MODEL(InfillAsciiData, + "infill ascii data", + "Implementation of a model in which the boundary " + "traction is derived from files containing pressure data " + "in ascii format. This model differs from the normal ascii data " + "model as the pressure given in the data file is summed with another " + "traction that depends on the current state of flexure in the model. " + "The traction sum is applied normal to the surface of a given boundary, " + "pointing inwards. Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example `# POINTS: 3 3'. " + "The order of the data columns " + "has to be `x', `Pressure [Pa]' in a 2d model and " + " `x', `y', `Pressure [Pa]' in a 3d model, which means that " + "there has to be a single column " + "containing the pressure. " + "Note that the data in the input " + "files need to be sorted in a specific order: " + "the first coordinate needs to ascend first, " + "followed by the second in order to " + "assign the correct data to the prescribed coordinates. " + "If you use a spherical model, " + "then the data will still be handled as Cartesian, " + "however the assumed grid changes. `x' will be replaced by " + "the radial distance of the point to the bottom of the model, " + "`y' by the azimuth angle and `z' by the polar angle measured " + "positive from the north pole. The grid will be assumed to be " + "a latitude-longitude grid. Note that the order " + "of spherical coordinates is `r', `phi', `theta' " + "and not `r', `theta', `phi', since this allows " + "for dimension independent expressions.") + } +} diff --git a/benchmarks/king2dcompressible/ala.prm.bak b/benchmarks/king2dcompressible/ala.prm.bak new file mode 100644 index 00000000000..0bb0a4f018a --- /dev/null +++ b/benchmarks/king2dcompressible/ala.prm.bak @@ -0,0 +1,184 @@ +# At the top, we define the number of space dimensions we would like to +# work in: +set Dimension = 2 + +# We can use a large CFL number because we are only interested in the +# steady state solution. +set CFL number = 5.0 +set Additional shared libraries = ./plugin/libking.so + +# This is the non-dimensionalized surface temperature, which is the +# ratio of the dimensional surface temperature T_surf = 273 K and +# the temperature change across the domain DeltaT = 3000 K. +set Adiabatic surface temperature = 0.091 +set Use years in output instead of seconds = false +set End time = 10 +set Output directory = output +set Pressure normalization = surface +set Surface pressure = 0 + +subsection Discretization + subsection Stabilization parameters + set alpha = 2 + set beta = 0.005 + set cR = 0.033 + end +end + +subsection Termination criteria + set Checkpoint on termination = true + set Termination criteria = end time, steady state velocity + + subsection Steady state velocity + set Maximum relative deviation = 1e-7 + set Time in steady state = 1 + end +end + +# In this section we define the adiabatic profiles of temperature, +# pressure and density. The temperature and density profiles are +# equivalent to the reference profiles bar(T) and bar(rho) defined +# in the King 2010 benchmark. +# gamma is the grueneisen parameter, which defines the compressibility +# of the material, and we have to choose the same value for gamma as +# in the material model below. +subsection Adiabatic conditions model + set Model name = function + + subsection Function + set Function constants = Di=1.0, gamma=1.0 + set Function expression = 0.091*exp(depth*Di); gamma/Di*(exp(depth*Di/gamma)-1); exp(depth*Di/gamma) # T,p,rho + set Variable names = depth + end +end + +# The King benchmark uses the anelastic liquid approximation. +subsection Formulation + set Formulation = anelastic liquid approximation +end + +# The benchmark is defined in terms of the nondimensional numbers +# Di (dissipation number) and Ra (Rayleigh number). +# As ASPECT uses physical properties instead of these dimensionless +# numbers in its equations, we replicate the benchmark formulation +# by using a new material model that fixes all of the material +# constants to 1, except for the thermal expansivity, which is set +# to Di, and the viscosity, which is set to Di/Ra. +subsection Material model + set Model name = king material + + subsection King model + set Reference density = 1 + set Reference specific heat = 1 + + # The value of the Rayleigh number Ra. + set Ra = 1e4 + + # The dissipation number Di determines the slope of the + # adiabatic/reference temperature profile. + # For the Boussinesq approximation, Di would be zero. + set Di = 1.0 + set b = 0 + set c = 0 + set gamma = 1.0 + end +end + +# The model domain is the unit square. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +# We choose a linear initial temperature profile that +# matches the boundary conditions defined below plus +# a small perturbation: +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = p=0.01, L=1, pi=3.1415926536, k=1 + set Function expression = 1* ((1.0-z/L) + p*cos(k*pi*x/L/1.0)*sin(pi*z/L)) +0.091 + end +end + +# We prescibe the adiabatic surface temperature as top temperature +# and the (nondimensional) temperature change across the boundary +# is set to 1 (with no flux conditions at the sides). +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = box + + subsection Box + set Top temperature = 0.091 + set Bottom temperature = 1.091 + set Left temperature = 0 + set Right temperature = 0 + end +end + +# The velocity boundary conditions are free slip on all boundaries. +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, top, bottom +end + +# This subsection describes which heating models we want to use. +# This benchmark includes adiabatic heating and shear heating. +subsection Heating model + set List of model names = adiabatic heating, shear heating + + subsection Adiabatic heating + # A flag indicating whether the adiabatic heating should be simplified + # from $\alpha T (\mathbf u \cdot \nabla p)$ + # to $ \alpha \rho T (\mathbf u \cdot \mathbf g) $. + set Use simplified adiabatic heating = true + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +# As we are only interested in the steady state, we start on a +# coarse mesh and refine once the solution is close to steady state. +subsection Mesh refinement + set Initial global refinement = 3 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 + set Coarsening fraction = 0.0 + set Refinement fraction = 1.0 +end + +# In addition to some general postprocessing, we output +# velocity statistics (needed for the root mean square velocity), +# temperature statistics (needed for the average temperature), +# heat flux statistics using the CBF method (needed for the Nusselt number) and +# heating statistics (needed for shear and adiabatic heating). +# We also include a simpler heat flux statistics postprocessor +# that illustrates the superiority of the CBF method in the default +# heat flux statistics postprocessor. +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, heat flux statistics gradient, visualization, depth average, heating statistics + + subsection Visualization + set Time between graphical output = 1e-2 + set List of output variables = material properties, adiabat, thermal conductivity, heating, artificial viscosity + end +end + +# We would like the benchmark to converge to very high accuracy, +# so we tighten the linear solver tolerance compared to default of 1e-7. +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-9 + end +end diff --git a/benchmarks/king2dcompressible/plugin/code.cc.bak b/benchmarks/king2dcompressible/plugin/code.cc.bak new file mode 100644 index 00000000000..f0099ccc8ad --- /dev/null +++ b/benchmarks/king2dcompressible/plugin/code.cc.bak @@ -0,0 +1,250 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include + +#include +#include +#include + + +namespace aspect +{ + using namespace dealii; + + /** + * This benchmark is from the article + * @code + * @article{KLKLZTTK10, + * title={A community benchmark for 2-{D} {C}artesian compressible + * convection in the {E}arth's mantle}, + * author={King, Scott D and Lee, Changyeol and Van Keken, Peter E + * and Leng, Wei and Zhong, Shijie and Tan, Eh and Tosi, Nicola + * and Kameyama, Masanori C}, + * journal={Geophysical Journal International}, + * volume={180}, + * number={1}, + * pages={73--87}, + * year={2010}, + * publisher={Oxford University Press} + * } + * @endcode + */ + + + namespace MaterialModel + { + + template + class Material : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + + /** + * Evaluate material properties. + */ + void evaluate(const MaterialModelInputs &in, + MaterialModelOutputs &out) const override + { + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const Point position = in.position[i]; + const double temperature = in.temperature[i]; + const double pressure = in.pressure[i]; + + const double depth = 1.0-position(dim-1); + + out.viscosities[i] = ((Di==0.0)?1.0:Di)/Ra*exp(-b*(temperature- this->get_adiabatic_conditions().temperature(position))+c*depth); + + out.specific_heat[i] = reference_specific_heat; + out.thermal_conductivities[i] = 1.0; + out.thermal_expansion_coefficients[i] = (Di==0.0)?1.0:Di; + + double rho = reference_rho * exp(depth * Di/gamma); + rho *= 1.0 - out.thermal_expansion_coefficients[i] * (temperature - this->get_adiabatic_conditions().temperature(position)) + + (tala?0.0:1.0)*Di*gamma + * (pressure - this->get_adiabatic_conditions().pressure(position)); + + out.densities[i] = rho; + + out.compressibilities[i] = 0.0; + out.entropy_derivative_pressure[i] = 0.0; + out.entropy_derivative_temperature[i] = 0.0; + // Change in composition due to chemical reactions at the + // given positions. The term reaction_terms[i][c] is the + // change in compositional field c at point i. + for (unsigned int c=0; c + void + Material::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("King model"); + { + prm.declare_entry ("Reference density", "3300", + Patterns::Double (0), + "Reference density $\\rho_0$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Ra", "1e4", + Patterns::Double (0), + ""); + prm.declare_entry ("Di", "0.0", + Patterns::Double (0), + ""); + prm.declare_entry ("gamma", "1.0", + Patterns::Double (0), + ""); + prm.declare_entry ("Reference specific heat", "1250", + Patterns::Double (0), + "The value of the specific heat $cp$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("b", "6.907755279", + Patterns::Double (0), + ""); + prm.declare_entry ("c", "0", + Patterns::Double (0), + ""); + prm.declare_entry ("Use TALA", "false", + Patterns::Bool (), + "Whether to use the TALA instead of the ALA " + "approximation."); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + Material::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("King model"); + { + reference_rho = prm.get_double ("Reference density"); + b = prm.get_double ("b"); + c = prm.get_double ("c"); + Di = prm.get_double ("Di"); + Ra = prm.get_double ("Ra"); + gamma = prm.get_double ("gamma"); + + tala = prm.get_bool ("Use TALA"); + + reference_specific_heat = prm.get_double ("Reference specific heat"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::temperature; + this->model_dependence.density = NonlinearDependence::none; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + } + } + +} + + + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(Material, + "king material", + "A simple compressible material model based on a benchmark " + "from the paper of King et al. (2010). It uses the " + "nondimensional numbers Di, Ra and gamma to define material " + "properties.") + } + +} diff --git a/benchmarks/layeredflow/layeredflow.cc.bak b/benchmarks/layeredflow/layeredflow.cc.bak new file mode 100644 index 00000000000..2f1c3bc6fac --- /dev/null +++ b/benchmarks/layeredflow/layeredflow.cc.bak @@ -0,0 +1,404 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace LayeredFlowBenchmark + { + using namespace dealii; + + namespace AnalyticSolutions + { + + Tensor<1,2> + LayeredFlow_velocity (const Point<2> &pos, + const double beta, + const double epsilon) + { + const double y0 = 1./3.; + const double yplus=(1.+y0)/beta; + const double yminus=(1.-y0)/beta; + const double C1 = 2.*numbers::PI / + ( beta*std::log(beta*beta+pow(1.+y0,2.0))-2.*(1.+y0)*std::atan(yplus) + - beta*std::log(beta*beta+pow(1.-y0,2.0))+2.*(1.-y0)*std::atan(yminus) + + 2.*numbers::PI*(1.+2.*epsilon) ); + + const double C2 = ( beta*std::log( beta*beta+std::pow(1+y0,2.) )- 2.*(1.+y0)*std::atan(yplus) + + numbers::PI*(1.+2.*epsilon) )*C1 ; + const double y = pos[1]-1.0; + const double v_x = (-beta*C1*std::log(beta*beta+std::pow(y-y0,2.0))+2.*(y-y0)*C1*std::atan((y-y0)/beta) + + numbers::PI*(1.+2.*epsilon)*y*C1+C2)/(2.*numbers::PI); + const double v_y = 0; + return Point<2> (v_x,v_y); + } + + double + LayeredFlow_pressure (const Point<2> &, + const double &, + const double) + { + return 0; + } + + + template + class FunctionLayeredFlow : public Function + { + public: + FunctionLayeredFlow (const double beta, const double epsilon) + : + Function(dim+2), + beta_(beta), + epsilon_(epsilon) + {} + + void vector_value (const Point &pos, + Vector &values) const override + { + Assert (dim == 2, ExcNotImplemented()); + Assert (values.size() >= 4, ExcInternalError()); + + const Point<2> p (pos[0], pos[1]); + + const Tensor<1,2> v = AnalyticSolutions::LayeredFlow_velocity (p, beta_, epsilon_); + values[0] = v[0]; + values[1] = v[1]; + values[2] = AnalyticSolutions::LayeredFlow_pressure (p, beta_, epsilon_); + } + + private: + const double beta_; + const double epsilon_; + }; + } + + + template + class LayeredFlowBoundary : public BoundaryVelocity::Interface, public aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + LayeredFlowBoundary(); + + /** + * Return the boundary velocity as a function of position. + */ + Tensor<1,dim> + boundary_velocity (const types::boundary_id , + const Point &position) const override; + + private: + const double beta; + const double epsilon; + }; + + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * @ingroup MaterialModels + */ + template + class LayeredFlowMaterial : public MaterialModel::Interface + { + public: + /** + * @name Physical parameters used in the basic equations + * @{ + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const Point &pos = in.position[i]; + + const double y = pos[1]-1.0; + const double y0 = 1./3.; + out.viscosities[i] = 1.0/(std::atan((y-y0)/beta)/numbers::PI + 0.5 + epsilon); + out.densities[i] = 1; + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + } + } + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + * Incompressibility does not necessarily imply that the density is + * constant; rather, it may still depend on temperature or pressure. + * In the current context, compressibility means whether we should + * solve the continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + + + /** + * Returns the viscosity value in the inclusion + */ + double get_beta() const; + double get_epsilon() const; + + /** + * viscosity value in the inclusion + */ + double beta; + double epsilon; + }; + + + template + bool + LayeredFlowMaterial:: + is_compressible () const + { + return false; + } + + template + void + LayeredFlowMaterial::declare_parameters (ParameterHandler &prm) + { + //create a global section in the parameter file for parameters + //that describe this benchmark. note that we declare them here + //in the material model, but other kinds of plugins (e.g., the gravity + //model below) may also read these parameters even though they do not + //declare them + prm.enter_subsection("LayeredFlow benchmark"); + { + prm.declare_entry("Viscosity parameter beta", "1", + Patterns::Double (), + "Viscosity parameter beta in the LayeredFlow benchmark."); + prm.declare_entry("Viscosity parameter epsilon", "0.1", + Patterns::Double (), + "Viscosity parameter epsilon in the LayeredFlow benchmark."); + } + prm.leave_subsection(); + } + + + template + void + LayeredFlowMaterial::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("LayeredFlow benchmark"); + { + beta = prm.get_double ("Viscosity parameter beta"); + epsilon = prm.get_double ("Viscosity parameter epsilon"); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + + template + double + LayeredFlowMaterial::get_beta() const + { + return beta; + } + + template + double + LayeredFlowMaterial::get_epsilon() const + { + return epsilon; + } + + template + LayeredFlowBoundary::LayeredFlowBoundary () + : + beta (0), + epsilon (0) + {} + + + + template <> + Tensor<1,2> + LayeredFlowBoundary<2>:: + boundary_velocity (const types::boundary_id , + const Point<2> &p) const + { + const LayeredFlowMaterial<2> & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + return AnalyticSolutions::LayeredFlow_velocity (p, material_model.get_beta(), + material_model.get_epsilon()); + } + + + + template <> + Tensor<1,3> + LayeredFlowBoundary<3>:: + boundary_velocity (const types::boundary_id , + const Point<3> &) const + { + Assert (false, ExcNotImplemented()); + return Tensor<1,3>(); + } + + + /** + * A postprocessor that evaluates the accuracy of the solution. + * + * The implementation of error evaluators that correspond to the + * benchmarks defined in the manual. + */ + template + class LayeredFlowPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &statistics) override; + }; + + template + std::pair + LayeredFlowPostprocessor::execute (TableHandler &) + { + std::unique_ptr> ref_func; + { + const LayeredFlowMaterial & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + ref_func = std::make_unique>(material_model.get_beta(), + material_model.get_epsilon()); + } + + const QGauss quadrature_formula (this->introspection().polynomial_degree.velocities+2); + + Vector cellwise_errors_u (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_p (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_ul2 (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_pl2 (this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_u(std::pair(0,dim), + dim+2); + ComponentSelectFunction comp_p(dim, dim+2); + + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_ul2, + quadrature_formula, + VectorTools::L2_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_pl2, + quadrature_formula, + VectorTools::L2_norm, + &comp_p); + + const double u_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_ul2, VectorTools::L2_norm); + const double p_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_pl2, VectorTools::L2_norm); + + std::ostringstream os; + os << std::scientific << u_l2 + << ", " << p_l2; + + return std::make_pair("Errors u_L2, p_L2:", os.str()); + } + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace LayeredFlowBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(LayeredFlowMaterial, + "LayeredFlowMaterial", + "A material model that corresponds to the `LayeredFlow' benchmark. " + "See the manual for more information.") + + ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(LayeredFlowBoundary, + "LayeredFlowBoundary", + "Implementation of the velocity boundary conditions for the " + "`LayeredFlow' benchmark. See the manual for more information about this " + "benchmark.") + + ASPECT_REGISTER_POSTPROCESSOR(LayeredFlowPostprocessor, + "LayeredFlowPostprocessor", + "A postprocessor that compares the solution of the `LayeredFlow' benchmark " + "with the one computed by ASPECT " + "and reports the error. See the manual for more information.") + } +} diff --git a/benchmarks/layeredflow/layeredflow.prm.bak b/benchmarks/layeredflow/layeredflow.prm.bak new file mode 100644 index 00000000000..b0152284960 --- /dev/null +++ b/benchmarks/layeredflow/layeredflow.prm.bak @@ -0,0 +1,94 @@ +############### Global parameters + +set Additional shared libraries = ./liblayeredflow.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = false +set Nonlinear solver scheme = single Advection, single Stokes +set Output directory = output +set Pressure normalization = volume + +############### Parameters describing the model +# Because the temperature plays no role in this model we need not +# bother to describe temperature boundary conditions or +# the material parameters that pertain to the temperature. + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 2 + end +end + +#Boundary conditions + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = 0 : LayeredFlowBoundary, \ + 1 : LayeredFlowBoundary, \ + 2 : LayeredFlowBoundary, \ + 3 : LayeredFlowBoundary +end + +subsection Material model + set Model name = LayeredFlowMaterial +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0 + end +end + +subsection LayeredFlow benchmark + set Viscosity parameter beta = 0.001 + set Viscosity parameter epsilon = 0.05 +end + +############### Parameters describing the temperature field +# As above, there is no need to set anything for the +# temperature boundary conditions. + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the discretization +# The following parameters describe how often we want to refine +# the mesh globally and adaptively, what fraction of cells should +# be refined in each adaptive refinement step, and what refinement +# indicator to use when refining the mesh adaptively. + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 4 + set Refinement fraction = 0.2 + set Strategy = velocity +end + +############### Parameters describing what to do with the solution +# The final section allows us to choose which postprocessors to +# run at the end of each time step. + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, LayeredFlowPostprocessor + + subsection Visualization + set List of output variables = viscosity, strain rate + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + set Number of cheap Stokes solver steps = 0 + end +end diff --git a/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_t.prm.bak b/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_t.prm.bak new file mode 100644 index 00000000000..ca7b64af468 --- /dev/null +++ b/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_t.prm.bak @@ -0,0 +1,134 @@ +# Like the poiseuille_2d.prm test and based on the nonlinear channel +# flow benchmark. This is used to test the velocity boundary conditions +# of the Newton Stokes solver. + +set Output directory = results/b1SNL_BTt_NS_ST1e-20_UFSfalse_NSP-SPD_NSA-SPD_C0_g6_ag0_AEWfalse_UDStrue_SF9e-1_NLT1e-14_ABT1e-2_LT1e-5_mLT9e-1_I150_P5_EW1_theta1_LS0_RSMtrue_AV-1_phi0_vel0_BV1e19_n5 +set Dimension = 2 +set CFL number = 1.0 +set Maximum time step = 1 +set End time = 0 +set Start time = 0 +set Adiabatic surface temperature = 0 +set Surface pressure = 0 +set Use years in output instead of seconds = false +set Nonlinear solver scheme = iterated Advection and Newton Stokes +set Max nonlinear iterations = 150 +set Nonlinear solver tolerance = 1e-14 +set Additional shared libraries = libsimple_nonlinear.so + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-5 + end + + subsection Newton solver parameters + set Max pre-Newton nonlinear iterations = 5 + set Nonlinear Newton solver switch tolerance = 1e-20 + set Max Newton line search iterations = 0 + set Maximum linear Stokes solver tolerance = 9e-1 + set Use Newton residual scaling method = true + set Use Newton failsafe = false + set Stabilization preconditioner = SPD + set Stabilization velocity block = SPD + end +end + +subsection Boundary temperature model + set List of model names = box + set Fixed temperature boundary indicators = 2, 3 + + subsection Box + set Left temperature = 0 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 10e3 + set Y extent = 8e3 + set Y repetitions = 1 + end +end + +subsection Material model + set Model name = simple nonlinear + + subsection Simple nonlinear + set Minimum viscosity = 1e19 + set Maximum viscosity = 1e25 + set Stress exponent = 5 + set Viscosity averaging p = 10000 + set Viscosity prefactor = 1e-37 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 6 +end + +subsection Boundary traction model + set Prescribed traction boundary indicators = 2 y: function, 3 y: function # pressure bc: Prescribe a horizontal traction on the vertical boundaries + + subsection Function + set Variable names = x,z + + # We want to prescribe a pressure of 2 at the left boundary + # and -2 at the right boundary. + # The traction in this case is defined as: + # tau = - pressure * normal_vector. + # On the left boundary, the outward pointing normal vector is + # (-1;0). On the right (1;0). + # Therefore: + # Left boundary: tau = - pressure(left) (-1;0) = - (2) (-1;0) = (2;0). + # Right boundary: tau = - pressure(right) (1;0) = - (-2) (1;0) = (2;0). + # Conveniently, the traction is the same on both boundaries. + set Function expression = 0;if(z>0,0,1e9) + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = 0, 1 + set Prescribed velocity boundary indicators = 2 x: function, 3 x: function # pressure bc: Prescribe a zero vertical velocity component on the vertical boundaries + + subsection Function + set Function constants = n = 5 + set Variable names = x,z + + # For velocity boundary conditions both are used, for pressure boundary conditions only the first (x) component + set Function expression = 0;(1e-37/(n+1))*((1e9/8e3)^n)*(((5e3)^(n+1))-((x-(5e3))^(n+1))); + end +end + +subsection Postprocess + set List of postprocessors = velocity statistics, pressure statistics, mass flux statistics, visualization #, depth average + + subsection Depth average + set List of output variables = viscosity + end + + subsection Visualization + set List of output variables = material properties,strain rate, spd factor + + # set Output format = gnuplot + set Time between graphical output = 2 + end +end diff --git a/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_t_gmg.prm.bak b/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_t_gmg.prm.bak new file mode 100644 index 00000000000..9350829516d --- /dev/null +++ b/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_t_gmg.prm.bak @@ -0,0 +1,21 @@ +# Like the newton_solver_benchmark_set/nonlinear_channel_flow/input_t.prm +# benchmark, but use GMG instead. + +include $ASPECT_SOURCE_DIR/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_t.prm + +set Additional shared libraries = libsimple_nonlinear.so +set Output directory = results/output-t-gmg + +subsection Material model + set Material averaging = harmonic average +end + +subsection Solver parameters + subsection Matrix Free + set Output details = true + end + + subsection Stokes solver parameters + set Stokes solver type = block GMG + end +end diff --git a/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v.prm b/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v.prm index 37534cc3107..7b80ff14209 100644 --- a/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v.prm +++ b/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v.prm @@ -2,7 +2,7 @@ # flow benchmark. This is used to test the velocity boundary conditions # of the Newton Stokes solver. -set Output directory = a2_itIMPES_ST1e-20_UFSfalse_NSP-SPD_NSA-none_C0_g6_ag0_AEWfalse_SF9e-1_NLT1e-14_ABT1e-2_LT1e-5_mLT9e-1_I150_P3_EW1_theta1_LS5_RSMfalse_AV-1_n5 +set Output directory = a2_itsingle Advection, single Stokes_ST1e-20_UFSfalse_NSP-SPD_NSA-none_C0_g6_ag0_AEWfalse_SF9e-1_NLT1e-14_ABT1e-2_LT1e-5_mLT9e-1_I150_P3_EW1_theta1_LS5_RSMfalse_AV-1_n5 set Dimension = 2 set CFL number = 1.0 set Maximum time step = 1 diff --git a/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v.prm.bak b/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v.prm.bak new file mode 100644 index 00000000000..37534cc3107 --- /dev/null +++ b/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v.prm.bak @@ -0,0 +1,133 @@ +# Like the poiseuille_2d.prm test and based on the nonlinear channel +# flow benchmark. This is used to test the velocity boundary conditions +# of the Newton Stokes solver. + +set Output directory = a2_itIMPES_ST1e-20_UFSfalse_NSP-SPD_NSA-none_C0_g6_ag0_AEWfalse_SF9e-1_NLT1e-14_ABT1e-2_LT1e-5_mLT9e-1_I150_P3_EW1_theta1_LS5_RSMfalse_AV-1_n5 +set Dimension = 2 +set CFL number = 1.0 +set Maximum time step = 1 +set End time = 0 +set Start time = 0 +set Adiabatic surface temperature = 0 +set Surface pressure = 0 +set Use years in output instead of seconds = false +set Nonlinear solver scheme = iterated Advection and Stokes #Newton Stokes +set Max nonlinear iterations = 150 +set Nonlinear solver tolerance = 1e-14 +set Additional shared libraries = libsimple_nonlinear.so + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-15 + end + + subsection Newton solver parameters + set Max pre-Newton nonlinear iterations = 3 + set Nonlinear Newton solver switch tolerance = 1e-20 + set Max Newton line search iterations = 5 + set Maximum linear Stokes solver tolerance = 9e-1 + set Use Newton residual scaling method = false + set Use Newton failsafe = false + set Stabilization preconditioner = SPD + set Stabilization velocity block = none + end +end + +subsection Boundary temperature model + set List of model names = box + set Fixed temperature boundary indicators = 2, 3 + + subsection Box + set Left temperature = 0 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 10e3 + set Y extent = 8e3 + set Y repetitions = 1 + end +end + +subsection Material model + set Model name = simple nonlinear + + subsection Simple nonlinear + set Minimum viscosity = 1e19 + set Maximum viscosity = 1e24 + set Stress exponent = 5 + set Viscosity averaging p = 10000 + set Viscosity prefactor = 1e-37 + set Use deviator of strain-rate = false + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 6 +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = 0, 1 + set Prescribed velocity boundary indicators = 2: function, 3: function # velocity bc + + subsection Function + set Function constants = n = 5 + set Variable names = x,z + + # For velocity boundary conditions both are used, for pressure boundary conditions only the first (x) component + set Function expression = 0;(1e-37/(n+1))*((1e9/8e3)^n)*(((5e3)^(n+1))-(abs(x-(5e3))^(n+1))); + end +end + +subsection Boundary traction model + subsection Function + set Variable names = x,z + + # We want to prescribe a pressure of 2 at the left boundary + # and -2 at the right boundary. + # The traction in this case is defined as: + # tau = - pressure * normal_vector. + # On the left boundary, the outward pointing normal vector is + # (-1;0). On the right (1;0). + # Therefore: + # Left boundary: tau = - pressure(left) (-1;0) = - (2) (-1;0) = (2;0). + # Right boundary: tau = - pressure(right) (1;0) = - (-2) (1;0) = (2;0). + # Conveniently, the traction is the same on both boundaries. + set Function expression = 0;if(z>0,0,1e9) + end +end + +subsection Postprocess + set List of postprocessors = velocity statistics, pressure statistics, mass flux statistics, visualization #, depth average + + subsection Depth average + set List of output variables = viscosity + end + + subsection Visualization + set List of output variables = material properties,strain rate#, spd factor + + # set Output format = gnuplot + set Time between graphical output = 2 + end +end diff --git a/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v_gmg.prm.bak b/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v_gmg.prm.bak new file mode 100644 index 00000000000..de4a4b69a82 --- /dev/null +++ b/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v_gmg.prm.bak @@ -0,0 +1,21 @@ +# Like the newton_solver_benchmark_set/nonlinear_channel_flow/input_v.prm +# benchmark, but use GMG instead. + +include $ASPECT_SOURCE_DIR/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/input_v.prm + +set Additional shared libraries = libsimple_nonlinear.so +set Output directory = results/output-v-gmg + +subsection Material model + set Material averaging = harmonic average +end + +subsection Solver parameters + subsection Matrix Free + set Output details = true + end + + subsection Stokes solver parameters + set Stokes solver type = block GMG + end +end diff --git a/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/simple_nonlinear.cc.bak b/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/simple_nonlinear.cc.bak new file mode 100644 index 00000000000..8f72dd39357 --- /dev/null +++ b/benchmarks/newton_solver_benchmark_set/nonlinear_channel_flow/simple_nonlinear.cc.bak @@ -0,0 +1,404 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include + +#include + +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model based on a simple power law rheology and + * implementing the derivatives needed for the Newton method. + * + * Power law equation to compute the viscosity $\eta$ per composition: + * $\eta = A^{\frac{-1}{n}} * \left(2.0 * \dot\varepsilon_{II}\right) + * ^{\frac{1}{n}-1}$ where $A$ is the prefactor, $\dot\varepsion$ is + * the strain-rate, II indicates the square root of the second invariant + * defined as $\frac{1}{2} \dot\varepsilon_{ij} \dot\varepsilon_{ij}$, + * and $n$ is the stress exponent. + * + * The viscosities per composition are averaged using the + * utilities weighted p-norm function. The volume fractions are used + * as weights for the averaging. + * + * @ingroup MaterialModels + */ + template + class SimpleNonlinear : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * This material model is incompressible. + */ + bool is_compressible () const override; + + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * For calculating density by thermal expansivity. Units: $\\si{\\kelvin}$ + */ + double reference_temperature; + + /** + * Defining a minimum strain rate stabilizes the viscosity calculation, + * which involves a division by the strain rate. Units: $\\si{\\per\\second}$. + */ + std::vector min_strain_rate; + std::vector min_viscosity; + std::vector max_viscosity; + + std::vector thermal_diffusivity; + std::vector heat_capacity; + + + std::vector densities; + std::vector thermal_expansivities; + + + std::vector viscosity_prefactor; + std::vector stress_exponent; + + unsigned int n_fields; + /** + * averaging parameters used for the power exponent + * in the Utilities::weighted_p_norm_average and + * Utilities::derivative_of_weighted_p_norm_average. + */ + double viscosity_averaging_p; + + bool use_deviator_of_strain_rate; + }; + } +} + + + +using namespace dealii; + +namespace aspect +{ + + namespace MaterialModel + { + template + void + SimpleNonlinear:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + //set up additional output for the derivatives + MaterialModelDerivatives *derivatives = out.template get_additional_output>(); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const double temperature = in.temperature[i]; + + // Averaging composition-field dependent properties + // Compositions + //This assert may be help when designing tests for this material model + AssertThrow(in.composition[i].size()+1 == n_fields, + ExcMessage("Number of compositional fields + 1 not equal to number of fields given in input file.")); + + const std::vector volume_fractions = MaterialUtilities::compute_composition_fractions(in.composition[i]); + double density = 0.0; + for (unsigned int c=0; c < volume_fractions.size(); ++c) + { + //not strictly correct if thermal expansivities are different, since we are interpreting + //these compositions as volume fractions, but the error introduced should not be too bad. + const double temperature_factor = (1.0 - thermal_expansivities[c] * (temperature - reference_temperature)); + density += volume_fractions[c] * densities[c] * temperature_factor; + } + + // thermal expansivities + double thermal_expansivity = 0.0; + for (unsigned int c=0; c < volume_fractions.size(); ++c) + thermal_expansivity += volume_fractions[c] * thermal_expansivities[c]; + + // Specific heat at the given positions. + double specific_heat = 0.0; + for (unsigned int c=0; c < volume_fractions.size(); ++c) + specific_heat += volume_fractions[c] * heat_capacity[c]; + + // Thermal conductivity at the given positions. + double thermal_conductivities = 0.0; + for (unsigned int c=0; c < volume_fractions.size(); ++c) + thermal_conductivities += volume_fractions[c] * thermal_diffusivity[c] * heat_capacity[c] * densities[c]; + + // calculate effective viscosity + if (in.requests_property(MaterialProperties::viscosity)) + { + // This function calculates viscosities assuming that all the compositional fields + // experience the same strain rate (isostrain). Since there is only one process in + // this material model (a general powerlaw) we do not need to worry about how to + // distribute the strain-rate and stress over the processes. + std::vector composition_viscosities(volume_fractions.size()); + + std::vector> composition_viscosities_derivatives(volume_fractions.size()); + + for (unsigned int c=0; c < volume_fractions.size(); ++c) + { + // If strain rate is zero (like during the first time step) set it to some very small number + // to prevent a division-by-zero, and a floating point exception. + // Otherwise, calculate the square-root of the norm of the second invariant of the deviatoric- + // strain rate (often simplified as epsilondot_ii) + const SymmetricTensor<2,dim> edot = use_deviator_of_strain_rate ? deviator(in.strain_rate[i]) : in.strain_rate[i]; + const double edot_ii_strict = std::sqrt(0.5*edot*edot); + const double edot_ii = 2.0 * std::max(edot_ii_strict, min_strain_rate[c]); + + const double stress_exponent_inv = 1/stress_exponent[c]; + composition_viscosities[c] = std::max(std::min(std::pow(viscosity_prefactor[c],-stress_exponent_inv) * std::pow(edot_ii,stress_exponent_inv-1), max_viscosity[c]), min_viscosity[c]); + Assert(dealii::numbers::is_finite(composition_viscosities[c]), ExcMessage ("Error: Viscosity is not finite.")); + if (derivatives != nullptr) + { + if (edot_ii_strict > min_strain_rate[c] && composition_viscosities[c] < max_viscosity[c] && composition_viscosities[c] > min_viscosity[c]) + { + composition_viscosities_derivatives[c] = (stress_exponent_inv-1) * composition_viscosities[c] * (1.0/(edot*edot)) * edot; + + if (use_deviator_of_strain_rate == true) + composition_viscosities_derivatives[c] = composition_viscosities_derivatives[c] * deviator_tensor(); + } + else + { + composition_viscosities_derivatives[c] = 0; + } + } + } + + out.viscosities[i] = Utilities::weighted_p_norm_average(volume_fractions, composition_viscosities, viscosity_averaging_p); + Assert(dealii::numbers::is_finite(out.viscosities[i]), ExcMessage ("Error: Averaged viscosity is not finite.")); + + if (derivatives != nullptr) + { + derivatives->viscosity_derivative_wrt_strain_rate[i] = Utilities::derivative_of_weighted_p_norm_average(out.viscosities[i],volume_fractions, composition_viscosities, composition_viscosities_derivatives, viscosity_averaging_p); + + for (unsigned int x = 0; x < dim; x++) + for (unsigned int y = 0; y < dim; y++) + Assert (dealii::numbers::is_finite(derivatives->viscosity_derivative_wrt_strain_rate[i][x][y]), + ExcMessage ("Averaged viscosity to strain-rate devrivative is not finite.")); + + derivatives->viscosity_derivative_wrt_pressure[i] = 0; + + } + } + out.densities[i] = density; + out.thermal_expansion_coefficients[i] = thermal_expansivity; + // Specific heat at the given positions. + out.specific_heat[i] = specific_heat; + // Thermal conductivity at the given positions. + out.thermal_conductivities[i] = thermal_conductivities; + // Compressibility at the given positions. + // The compressibility is given as + // $\frac 1\rho \frac{\partial\rho}{\partial p}$. + out.compressibilities[i] = 0.0; + // Pressure derivative of entropy at the given positions. + out.entropy_derivative_pressure[i] = 0.0; + // Temperature derivative of entropy at the given positions. + out.entropy_derivative_temperature[i] = 0.0; + // Change in composition due to chemical reactions at the + // given positions. The term reaction_terms[i][c] is the + // change in compositional field c at point i. + for (unsigned int c=0; c < in.composition[i].size(); ++c) + out.reaction_terms[i][c] = 0.0; + } + } + + template + bool + SimpleNonlinear:: + is_compressible () const + { + return false; + } + + template + void + SimpleNonlinear::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Compositional fields"); + { + prm.declare_entry ("Number of fields", "0", + Patterns::Integer (0), + "The number of fields that will be advected along with the flow field, excluding " + "velocity, pressure and temperature."); + } + prm.leave_subsection(); + prm.enter_subsection("Material model"); + { + prm.enter_subsection ("Simple nonlinear"); + { + // Reference and minimum/maximum values + prm.declare_entry ("Reference temperature", "293.", Patterns::Double(0.), + "For calculating density by thermal expansivity. Units: \\si{\\kelvin}"); + prm.declare_entry ("Minimum strain rate", "1.96e-40", Patterns::List(Patterns::Double(0.)), + "Stabilizes strain dependent viscosity. Units: \\si{\\per\\second}"); + prm.declare_entry ("Minimum viscosity", "1e10", Patterns::List(Patterns::Double(0.)), + "Lower cutoff for effective viscosity. Units: \\si{\\pascal\\second}"); + prm.declare_entry ("Maximum viscosity", "1e28", Patterns::List(Patterns::Double(0.)), + "Upper cutoff for effective viscosity. Units: \\si{\\pascal\\second}"); + prm.declare_entry ("Effective viscosity coefficient", "1.0", Patterns::List(Patterns::Double(0.)), + "Scaling coefficient for effective viscosity."); + + // Equation of state parameters + prm.declare_entry ("Thermal diffusivity", "0.8e-6", Patterns::List(Patterns::Double(0.)), + "Units: \\si{\\meter\\squared\\per\\second}"); + prm.declare_entry ("Heat capacity", "1.25e3", Patterns::List(Patterns::Double(0.)), + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}"); + prm.declare_entry ("Densities", "3300.", + Patterns::List(Patterns::Double(0.)), + "List of densities, $\\rho$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of compositional fields. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}"); + prm.declare_entry ("Thermal expansivities", "3.5e-5", + Patterns::List(Patterns::Double(0.)), + "List of thermal expansivities for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of compositional fields. " + "If only one value is given, then all use the same value. Units: \\si{\\per\\kelvin}"); + + + // SimpleNonlinear creep parameters + prm.declare_entry ("Viscosity prefactor", "1e-37", + Patterns::List(Patterns::Double(0)), + "List of viscosity prefactors, $A$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of compositional fields. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\pascal}$^{-n_{\\text{dislocation}}}$ \\si{\\meter}$^{n_{\\text{dislocation}}/m_{\\text{dislocation}}}$ \\si{\\per\\second}"); + prm.declare_entry ("Stress exponent", "3.", + Patterns::List(Patterns::Double(0.)), + "List of stress exponents, $n_dislocation$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of compositional fields. " + "If only one value is given, then all use the same value. Units: None"); + + // averaging parameters + prm.declare_entry ("Viscosity averaging p", "-1.", + Patterns::Double(), + "This is the p value in the generalized weighed average equation: " + " $\\text{mean} = \\frac{1}{k}(\\sum_{i=1}^k \\big(c_i \\eta_{\\text{eff}_i}^p)\\big)^{\\frac{1}{p}}$. " + " Units: \\si{\\pascal\\second}"); + + // strain-rate deviator parameter + prm.declare_entry ("Use deviator of strain-rate", "true", + Patterns::Bool(), + "This value determines whether to use the deviator of the strain-rate in computing the viscosity, " + "or simply the strain rate $\\varepsilon(\\mathbf u)$."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + SimpleNonlinear::parse_parameters (ParameterHandler &prm) + { + // Can't use this->n_compositional_fields(), because some + // tests never initialize the simulator, but uses the material + // model directly. + prm.enter_subsection ("Compositional fields"); + { + n_fields = prm.get_integer ("Number of fields")+1; + } + prm.leave_subsection(); + + prm.enter_subsection("Material model"); + { + prm.enter_subsection ("Simple nonlinear"); + { + + // Reference and minimum/maximum values + reference_temperature = prm.get_double("Reference temperature"); + min_strain_rate = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Minimum strain rate"))),n_fields,"Minimum strain rate"); + min_viscosity = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get ("Minimum viscosity"))),n_fields,"Minimum viscosity"); + max_viscosity = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get ("Maximum viscosity"))),n_fields,"Maximum viscosity"); + + // Equation of state parameters + thermal_diffusivity = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Thermal diffusivity"))),n_fields,"Thermal diffusivity"); + heat_capacity = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Heat capacity"))),n_fields,"Heat capacity"); + + // Compositional parameters + densities = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Densities"))),n_fields,"Densities"); + thermal_expansivities = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Thermal expansivities"))),n_fields,"Thermal expansivities"); + + // Rheological parameters + viscosity_prefactor = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Viscosity prefactor"))),n_fields,"Viscosity prefactor"); + stress_exponent = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Stress exponent"))),n_fields,"Stress exponent"); + + // averaging parameters + viscosity_averaging_p = prm.get_double("Viscosity averaging p"); + + use_deviator_of_strain_rate = prm.get_bool ("Use deviator of strain-rate"); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::strain_rate | NonlinearDependence::compositional_fields; + this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(SimpleNonlinear, + "simple nonlinear", + "A material model based on a simple power law rheology and implementing the derivatives " + "needed for the Newton method. " + "Power law equation to compute the viscosity $\\eta$ per composition comes from the book Introduction " + "to Geodynamic Modelling by Taras Gerya (2010): " + "$\\eta = A^{\\frac{-1}{n}} * \\left(2.0 * \\dot\\varepsilon_{II}\\right)^{\\frac{1}{n}-1}$ " + "where $A$ is the prefactor, $\\dot\\varepsion$ is the strain-rate, II indicates the square " + "root of the second invariant defined as $\\frac{1}{2} \\dot\\varepsilon_{ij} \\dot\\varepsilon_{ij}$, " + "and $n$ is the stress exponent. " + "The viscosities per composition are averaged using the utilities weighted " + "p-norm function. The volume fractions are used as weights for the averaging. ") + } +} diff --git a/benchmarks/newton_solver_benchmark_set/spiegelman_et_al_2016/drucker_prager_compositions.cc.bak b/benchmarks/newton_solver_benchmark_set/spiegelman_et_al_2016/drucker_prager_compositions.cc.bak new file mode 100644 index 00000000000..e1a213fc455 --- /dev/null +++ b/benchmarks/newton_solver_benchmark_set/spiegelman_et_al_2016/drucker_prager_compositions.cc.bak @@ -0,0 +1,671 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . + */ + + +/** + * This material model is specifically designed for the + * Spiegelman benchmark as reproduced in the Fraters (2019) + * paper on Newton solvers. It is not meant to be used for + * general purpose models. For more details see that paper. + */ + +#ifndef __aspect__model_drucker_prager_compositions_h +#define __aspect__model_drucker_prager_compositions_h + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * The same material model as Drucker Prager, but this one supports multiple + * compositions. Designed to run the Spiegelman et al. 2016 benchmark. + * + * The model is considered incompressible, following the definition + * described in Interface::is_compressible. + * + * The viscosity is computed according to the Drucker Prager frictional + * plasticity criterion based on a user-defined internal angle of friction $\phi$ + * and cohesion $C$. In 3D: + * $\sigma_y = \frac{6 C \cos(\phi)}{\sqrt(3) (3+\sin(\phi))} + + * \frac{6 P \sin(\phi)}{\sqrt(3) (3+\sin(\phi))}$, + * where $P$ is the pressure. + * See for example Zienkiewicz, O. C., Humpheson, C. and Lewis, R. W. (1975), + * Géotechnique 25, No. 4, 671-689. + * With this formulation we circumscribe instead of inscribe the Mohr Coulomb + * yield surface. + * In 2D the Drucker Prager yield surface is the same + * as the Mohr Coulomb surface: + * $\sigma_y = P \sin(\phi) + C \cos(\phi)$. + * Note that in 2D for $\phi=0$, these criteria + * revert to the von Mises criterion (no pressure dependence). + * See for example Thieulot, C. (2011), PEPI 188, 47-68. + * + * Note that we enforce the pressure to be positive in the computation of + * the yield strength by replacing it with + * a zero value whenever it is negative to prevent negative + * yield strengths and viscosities. + * We then use the computed yield strength to scale back the viscosity on + * to the yield surface using the Viscosity Rescaling Method described in + * Kachanov, L. M. (2004), Fundamentals of the Theory of Plasticity, + * Dover Publications, Inc. + * + * To avoid numerically unfavourably large (or even negative) viscosity ranges, + * we cut off the viscosity with a user-defined minimum and maximum viscosity: + * $\eta_eff = \max(\min(eta,max_visc),min_visc)$. + * + * Note that this model uses the formulation that assumes an incompressible + * medium despite the fact that the density follows the law + * $\rho(T)=\rho_0(1-\beta(T-T_{\text{ref}}))$. + * + * + * @ingroup MaterialModels + */ + + template + class DruckerPragerCompositions : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + double compute_second_invariant(const SymmetricTensor<2,dim> strain_rate, const double min_strain_rate) const; + + double compute_viscosity(const double edot_ii,const double pressure,const int comp, const double prefactor,const bool regularize, const double min_visc, const double max_visc) const; + + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + * + * This material model is incompressible. + */ + bool is_compressible () const override; + + double reference_density () const; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + private: + + double reference_T; + std::vector reference_T_list; + + /** + * Defining a minimum strain rate stabilizes the viscosity calculation, + * which involves a division by the strain rate. Units: $\\si{\\per\\second}$. + */ + bool use_deviator_of_strain_rate; + std::vector min_strain_rate; + std::vector min_visc; + std::vector max_visc; + std::vector veff_coefficient; + double ref_visc; + double reference_compressibility; + std::vector ref_visc_list; + + std::vector thermal_diffusivity; + std::vector heat_capacity; + + + std::vector densities; + std::vector thermal_expansivities; + + std::vector cohesion; + std::vector phi; + + std::vector prefactor; + std::vector stress_exponent; + + unsigned int n_fields; + // averaging parameters + double viscosity_averaging_p; + + bool use_analytical_derivative; + + //optimize variables + const double sqrt_3 = std::sqrt(3); + const double sqrt_half = std::sqrt(0.5); + std::vector sin_phi; + std::vector cos_phi; + + + + }; + + } +} + +#endif + +#include +#include + +using namespace dealii; + +namespace aspect +{ + namespace + { + std::vector + get_vector_double (const std::string ¶meter, const unsigned int n_fields, ParameterHandler &prm) + { + std::vector parameter_list; + parameter_list = Utilities::string_to_double(Utilities::split_string_list(prm.get (parameter))); + if (parameter_list.size() == 1) + parameter_list.resize(n_fields, parameter_list[0]); + + AssertThrow(parameter_list.size() == n_fields, + ExcMessage("Length of " + parameter + " list (size "+ std::to_string(parameter_list.size()) +") must be either one," + " or n_compositional_fields+1 (= " + std::to_string(n_fields) + ").")); + + return parameter_list; + } + } + + namespace MaterialModel + { + + template + double + DruckerPragerCompositions:: + compute_second_invariant(const SymmetricTensor<2,dim> strain_rate, const double min_strain_rate) const + { + const double edot_ii_strict = std::sqrt(strain_rate*strain_rate); + const double edot_ii = std::max(edot_ii_strict, min_strain_rate*min_strain_rate); + return edot_ii; + } + + template + double + DruckerPragerCompositions:: + compute_viscosity(const double edot_ii,const double pressure,const int comp,const double prefactor,const bool regularize, const double min_visc, const double max_visc) const + { + double viscosity; + if (comp == 0) + { + const double strength = ( (dim==3) + ? + ( 6.0 * cohesion[comp] * cos_phi[comp] + 6.0 * std::max(pressure,0.0) * sin_phi[comp] ) + / ( sqrt_3 * ( 3.0 + sin_phi[comp] ) ) + : + cohesion[comp] * cos_phi[comp] + std::max(pressure,0.0) * sin_phi[comp] ); + + // Rescale the viscosity back onto the yield surface + if (strength != 0 && edot_ii != 0) + viscosity = strength / ( 2.0 * sqrt_half * edot_ii ); + else + viscosity = ref_visc; + if (regularize == true) + viscosity = ref_visc*viscosity / (ref_visc + viscosity); + } + else + { + viscosity = prefactor; + } + + return std::max(std::min(viscosity,max_visc),min_visc); + } + + template + void + DruckerPragerCompositions:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + //set up additional output for the derivatives + MaterialModelDerivatives *derivatives; + derivatives = out.template get_additional_output>(); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const double temperature = in.temperature[i]; + const double pressure = in.pressure[i]; + + // Averaging composition-field dependent properties + // Compositions + //This assert may be help when designing tests for this material model + AssertThrow(in.composition[i].size()+1 == n_fields, + ExcMessage("Number of compositional fields + 1 not equal to number of fields given in input file.")); + + const std::vector volume_fractions = MaterialUtilities::compute_composition_fractions(in.composition[i]); + double density = 0.0; + for (unsigned int c=0; c < volume_fractions.size(); ++c) + { + const double temperature_factor = (1 - thermal_expansivities[c] * (temperature - reference_T)); + density += volume_fractions[c] * densities[c] * std::exp(reference_compressibility * pressure) * temperature_factor; + } + + // thermal expansivities + double thermal_expansivity = 0.0; + for (unsigned int c=0; c < volume_fractions.size(); ++c) + thermal_expansivity += volume_fractions[c] * thermal_expansivities[c]; + + // Specific heat at the given positions. + double specific_heat = 0.0; + for (unsigned int c=0; c < volume_fractions.size(); ++c) + specific_heat += volume_fractions[c] * heat_capacity[c]; + + // Thermal conductivity at the given positions. + double thermal_conductivities = 0.0; + for (unsigned int c=0; c < volume_fractions.size(); ++c) + thermal_conductivities += volume_fractions[c] * thermal_diffusivity[c] * heat_capacity[c] * densities[c]; + + // calculate effective viscosity + if (in.requests_property(MaterialProperties::viscosity)) + { + // This function calculates viscosities assuming that all the compositional fields + // experience the same strain rate (isostrain). Since there is only one process in + // this material model (a general powerlaw) we do not need to worry about how to + // distribute the strain-rate and stress over the processes. + std::vector composition_viscosities(volume_fractions.size()); + std::vector> composition_viscosities_derivatives(volume_fractions.size()); + std::vector composition_dviscosities_dpressure(volume_fractions.size()); + + const SymmetricTensor<2,dim> deviator_strain_rate = use_deviator_of_strain_rate ? deviator(in.strain_rate[i]) : in.strain_rate[i]; + + for (unsigned int c=0; c < volume_fractions.size(); ++c) + { + // If strain rate is zero (like during the first time step) set it to some very small number + // to prevent a division-by-zero, and a floating point exception. + // Otherwise, calculate the square-root of the norm of the second invariant of the deviatoric- + // strain rate (often simplified as epsilondot_ii) + + const double edot_ii = compute_second_invariant(deviator_strain_rate, min_strain_rate[c]); + + // Find effective viscosities for each of the individual phases + // Viscosities should have same number of entries as compositional fields + + // Regularized Drucker Prager viscosity (see Spiegelman et al, 2016) + composition_viscosities[c] = compute_viscosity(edot_ii,pressure,c,prefactor[c],true,min_visc[c],max_visc[c]); + + Assert(dealii::numbers::is_finite(composition_viscosities[c]),ExcMessage ("Error: Viscosity is not finite.")); + + if (derivatives != nullptr) + { + if (use_analytical_derivative) + { + //analytic + if (c == 0 && composition_viscosities[c] <= max_visc[c] && composition_viscosities[c] >= min_visc[c]) + { + const double drucker_prager_viscosity = compute_viscosity(edot_ii,pressure,c,prefactor[c],false,min_visc[c],max_visc[c]); + const double regulaization_adjustment = (ref_visc * ref_visc) + / (ref_visc * ref_visc + 2.0 * ref_visc * drucker_prager_viscosity + + drucker_prager_viscosity * drucker_prager_viscosity); + + composition_viscosities_derivatives[c] = -regulaization_adjustment * + (drucker_prager_viscosity / (edot_ii * edot_ii)) * deviator_strain_rate; + + if (use_deviator_of_strain_rate == true) + composition_viscosities_derivatives[c]*deviator_tensor(); + + composition_dviscosities_dpressure[c] = regulaization_adjustment * + ((dim == 3) + ? + 6 * sin_phi[c] / (sqrt_3 * (3.0 + sin_phi[c]) * 2.0 * sqrt_half * edot_ii) + : + sin_phi[c] / (2.0 * sqrt_half * edot_ii)); + } + else + { + composition_viscosities_derivatives[c] = 0; + composition_dviscosities_dpressure[c] = 0; + } + } + else + { + // finite difference + const double finite_difference_accuracy = 1e-7; + // For each independent component, compute the derivative. + for (unsigned int component = 0; component < SymmetricTensor<2,dim>::n_independent_components; ++component) + { + // compute which of the independent index of the strain-rate tensor we are now looking at. + const TableIndices<2> strain_rate_indices = SymmetricTensor<2,dim>::unrolled_to_component_indices (component); + + // add a small difference to one independent component of the strain-rate tensor + const SymmetricTensor<2,dim> strain_rate_difference_plus = deviator_strain_rate + std::max(edot_ii, min_strain_rate[c]*min_strain_rate[c]) * finite_difference_accuracy + * Utilities::nth_basis_for_symmetric_tensors(component); + const double second_invariant_strain_rate_difference_plus = compute_second_invariant(strain_rate_difference_plus, min_strain_rate[c]); + const double eta_component_plus = compute_viscosity(second_invariant_strain_rate_difference_plus,pressure,c,prefactor[c],true,min_visc[c],max_visc[c]); + + // compute the difference between the viscosity with and without the strain-rate difference. + double viscosity_derivative = eta_component_plus - composition_viscosities[c]; + if (viscosity_derivative != 0) + { + // when the difference is non-zero, divide by the difference. + viscosity_derivative /= std::max(edot_ii, min_strain_rate[c]*min_strain_rate[c]) * finite_difference_accuracy; + } + + composition_viscosities_derivatives[c][strain_rate_indices] = viscosity_derivative; + } + + /** + * Now compute the finite difference derivative of the viscoisty to the pressure + */ + double pressure_difference = in.pressure[i] + (std::fabs(in.pressure[i]) * finite_difference_accuracy); + + double pressure_difference_eta = compute_viscosity(edot_ii, pressure_difference,c,prefactor[c],true,min_visc[c],max_visc[c]); + double deriv_pressure = pressure_difference_eta - composition_viscosities[c]; + + + if (pressure_difference_eta != 0) + { + if (in.pressure[i] != 0) + { + deriv_pressure /= std::fabs(in.pressure[i]) * finite_difference_accuracy; + } + else + { + deriv_pressure = 0; + } + } + + composition_dviscosities_dpressure[c] = deriv_pressure; + } + } + } + out.viscosities[i] = Utilities::weighted_p_norm_average(volume_fractions, composition_viscosities, viscosity_averaging_p); + Assert(dealii::numbers::is_finite(out.viscosities[i]),ExcMessage ("Error: Averaged viscosity is not finite.")); + + if (derivatives != nullptr) + { + derivatives->viscosity_derivative_wrt_strain_rate[i] = Utilities::derivative_of_weighted_p_norm_average(out.viscosities[i],volume_fractions, composition_viscosities, composition_viscosities_derivatives, viscosity_averaging_p); + derivatives->viscosity_derivative_wrt_pressure[i] = Utilities::derivative_of_weighted_p_norm_average(out.viscosities[i],volume_fractions, composition_viscosities, composition_dviscosities_dpressure, viscosity_averaging_p); + + +#ifdef DEBUG + for (int x = 0; x < dim; x++) + for (int y = 0; y < dim; y++) + if (!dealii::numbers::is_finite(derivatives->viscosity_derivative_wrt_strain_rate[i][x][y])) + std::cout << "Error: Averaged viscosity to strain-rate devrivative is not finite." << std::endl; + + if (!dealii::numbers::is_finite(derivatives->viscosity_derivative_wrt_pressure[i])) + { + std::cout << "Error: Averaged viscosity to pressure devrivative is not finite. " << std::endl; + for (unsigned int c=0; c < volume_fractions.size(); ++c) + std::cout << composition_dviscosities_dpressure[c] << ','; + std::cout << std::endl; + } + Assert(dealii::numbers::is_finite(derivatives->viscosity_derivative_wrt_pressure[i]),ExcMessage ("Error: Averaged dviscosities_dpressure is not finite.")); + for (int x = 0; x < dim; x++) + for (int y = 0; y < dim; y++) + Assert(dealii::numbers::is_finite(derivatives->viscosity_derivative_wrt_strain_rate[i][x][y]),ExcMessage ("Error: Averaged dviscosities_dstrain_rate is not finite.")); +#endif + } + } + out.densities[i] = density; + out.thermal_expansion_coefficients[i] = thermal_expansivity; + // Specific heat at the given positions. + out.specific_heat[i] = specific_heat; + // Thermal conductivity at the given positions. + out.thermal_conductivities[i] = thermal_conductivities; + // Compressibility at the given positions. + // The compressibility is given as + // $\frac 1\rho \frac{\partial\rho}{\partial p}$. + out.compressibilities[i] = reference_compressibility; + // Pressure derivative of entropy at the given positions. + out.entropy_derivative_pressure[i] = 0.0; + // Temperature derivative of entropy at the given positions. + out.entropy_derivative_temperature[i] = 0.0; + // Change in composition due to chemical reactions at the + // given positions. The term reaction_terms[i][c] is the + // change in compositional field c at point i. + for (unsigned int c=0; c < in.composition[i].size(); ++c) + out.reaction_terms[i][c] = 0.0; + } + } + + template + double + DruckerPragerCompositions:: + reference_density () const + { + return densities[0]; + } + + template + bool + DruckerPragerCompositions:: + is_compressible () const + { + return (reference_compressibility != 0); + } + + template + void + DruckerPragerCompositions::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Compositional fields"); + { + prm.declare_entry ("Number of fields", "0", + Patterns::Integer(0), + "The number of fields that will be advected along with the flow field, excluding " + "velocity, pressure and temperature."); + prm.declare_entry ("Conductivities", "2.25", + Patterns::List (Patterns::Double(0.)), + "A list of thermal conductivities equal to the number of " + "compositional fields."); + prm.declare_entry ("Heat capacities", "1250.", + Patterns::List (Patterns::Double(0.)), + "A list of heat capacities equal to the number of " + "compositional fields."); + prm.declare_entry ("Reference temperatures", "0.", + Patterns::List (Patterns::Double(0.)), + "A list of reference temperatures equal to the number of " + "compositional fields."); + prm.declare_entry ("Reference densities", "2700.", + Patterns::List (Patterns::Double(0.)), + "A list of reference densities equal to the number of " + "compositional fields."); + prm.declare_entry ("Thermal expansivities", "3.5e-5", + Patterns::List(Patterns::Double(0.)), + "List of thermal expansivities for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of compositional fields. " + "If only one value is given, then all use the same value. Units: \\si{\\per\\kelvin}"); + prm.declare_entry ("Stress exponents", "1.", + Patterns::List (Patterns::Double(0.)), + "A list of stress exponents equal to the number of " + "compositional fields."); + prm.declare_entry ("Cohesions", "1e20", + Patterns::List (Patterns::Double(0.)), + "A list of initial viscosities equal to the number of " + "compositional fields."); + prm.declare_entry ("Angles of internal friction", "30.", + Patterns::List (Patterns::Double(0.)), + "A list of initial viscosities equal to the number of " + "compositional fields."); + prm.declare_entry ("Initial viscosities", "1e21", + Patterns::List (Patterns::Double(0.)), + "A list of initial viscosities equal to the number of " + "compositional fields."); + prm.declare_entry ("Viscous prefactors", "1e21", + Patterns::List (Patterns::Double(0.)), + "A list of viscous viscosities equal to the number of " + "compositional fields."); + + } + prm.leave_subsection(); + + prm.enter_subsection("Material model"); + { + prm.enter_subsection ("Drucker prager compositions"); + { + // Reference and minimum/maximum values + prm.declare_entry ("Reference temperature", "293.", Patterns::Double(0.), + "For calculating density by thermal expansivity. Units: \\si{\\kelvin}"); + prm.declare_entry ("Minimum strain rate", "1.4e-20", Patterns::List(Patterns::Double(0.)), + "Stabilizes strain dependent viscosity. Units: \\si{\\per\\second}"); + prm.declare_entry ("Minimum viscosity", "1e10", Patterns::List(Patterns::Double(0.)), + "Lower cutoff for effective viscosity. Units: \\si{\\pascal\\second}"); + prm.declare_entry ("Maximum viscosity", "1e28", Patterns::List(Patterns::Double(0.)), + "Upper cutoff for effective viscosity. Units: \\si{\\pascal\\second}"); + prm.declare_entry ("Effective viscosity coefficient", "1.0", Patterns::List(Patterns::Double(0.)), + "Scaling coefficient for effective viscosity."); + prm.declare_entry ("Reference viscosity", "1e22", Patterns::List(Patterns::Double(0.)), + "Reference viscosity for nondimensionalization. Units: \\si{\\pascal\\second}"); + prm.declare_entry ("Reference compressibility", "4e-12", Patterns::Double(0.), + "The value of the reference compressibility. Units: \\si{\\per\\pascal}."); + + // averaging parameters + prm.declare_entry ("Viscosity averaging p", "-1", + Patterns::Double(), + "This is the p value in the generalized weighed average eqation: " + " mean = \\frac{1}{k}(\\sum_{i=1}^k \\big(c_i \\eta_{\\text{eff}_i}^p)\\big)^{\\frac{1}{p}}. " + " Units: \\si{\\pascal\\second}"); + + // finite difference versus analytical + prm.declare_entry ("Use analytical derivative", "false", + Patterns::Bool(), + "A bool indicating whether to use finite differences to compute the derivative or to use " + "the analytical derivative."); + + prm.declare_entry ("Use deviator of strain-rate", "true", + Patterns::Bool(), + "Todo."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + DruckerPragerCompositions::parse_parameters (ParameterHandler &prm) + { + // can't use this->n_compositional_fields(), because some + // tests never initiate the simulator, but uses the material + // model directly. + prm.enter_subsection ("Compositional fields"); + { + n_fields = prm.get_integer ("Number of fields")+1; + //AssertThrow(n_fields > 0, ExcMessage("This material model needs at least one compositional field.")) + reference_T_list = get_vector_double("Reference temperatures",n_fields,prm); + ref_visc_list = get_vector_double ("Initial viscosities",n_fields,prm); + thermal_diffusivity = get_vector_double("Conductivities",n_fields,prm); + heat_capacity = get_vector_double("Heat capacities",n_fields,prm); + + // ---- Compositional parameters + densities = get_vector_double("Reference densities",n_fields,prm); + thermal_expansivities = get_vector_double("Thermal expansivities",n_fields,prm); + + // Rheological parameters + cohesion = get_vector_double("Cohesions",n_fields,prm); + phi = get_vector_double("Angles of internal friction",n_fields,prm); + + sin_phi.resize(n_fields); + cos_phi.resize(n_fields); + for (unsigned int c = 0; c < n_fields; ++c) + { + sin_phi[c] = std::sin(phi[c] * constants::degree_to_radians); + cos_phi[c] = std::cos(phi[c] * constants::degree_to_radians); + } + + prefactor = get_vector_double("Viscous prefactors",n_fields,prm); + stress_exponent = get_vector_double("Stress exponents",n_fields,prm); + } + prm.leave_subsection(); + + prm.enter_subsection("Material model"); + { + prm.enter_subsection ("Drucker prager compositions"); + { + + // Reference and minimum/maximum values + reference_T = prm.get_double("Reference temperature"); + ref_visc = prm.get_double ("Reference viscosity"); + min_strain_rate = get_vector_double("Minimum strain rate",n_fields,prm); + min_visc = get_vector_double ("Minimum viscosity",n_fields,prm); + max_visc = get_vector_double ("Maximum viscosity",n_fields,prm); + veff_coefficient = get_vector_double ("Effective viscosity coefficient",n_fields,prm); + reference_compressibility = prm.get_double ("Reference compressibility"); + use_deviator_of_strain_rate = prm.get_bool ("Use deviator of strain-rate"); + + + // averaging parameters + viscosity_averaging_p = prm.get_double("Viscosity averaging p"); + + use_analytical_derivative = prm.get_bool("Use analytical derivative"); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::strain_rate | NonlinearDependence::compositional_fields; + this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(DruckerPragerCompositions, + "drucker prager compositions", + " An implementation of a viscous rheology including diffusion" + " and dislocation creep allowing for different compositions." + " Designed for testing the Spiegelman et al. (2016) benchmark." + " Compositional fields can each be assigned individual" + " activation energies, reference densities, thermal expansivities," + " and stress exponents. The effective viscosity is defined as" + " \n\n" + " \\[v_\\text{eff} = \\left(\\frac{1}{v_\\text{eff}^\\text{diff}}+" + " \\frac{1}{v_\\text{eff}^\\text{dis}}\\right)^{-1}\\]" + " where" + " \\[v_\\text{i} = 0.5 * A^{-\\frac{1}{n_i}} d^\\frac{m_i}{n_i}" + " \\dot{\\varepsilon_i}^{\\frac{1-n_i}{n_i}}" + " \\exp\\left(\\frac{E_i^* + PV_i^*}{n_iRT}\\right)\\]" + " \n\n" + " where $d$ is grain size, $i$ corresponds to diffusion or dislocation creep," + " $\\dot{\\varepsilon}$ is the square root of the second invariant of the" + " strain rate tensor, $R$ is the gas constant, $T$ is temperature, " + " and $P$ is pressure." + " $A_i$ are prefactors, $n_i$ and $m_i$ are stress and grain size exponents" + " $E_i$ are the activation energies and $V_i$ are the activation volumes." + " \n\n" + " The ratio of diffusion to dislocation strain rate is found by Newton's" + " method, iterating to find the stress which satisfies the above equations." + " The value for the components of this formula and additional" + " parameters are read from the parameter file in subsection" + " 'Material model/SimpleNonlinear'.") + } +} diff --git a/benchmarks/newton_solver_benchmark_set/spiegelman_et_al_2016/input.prm.bak b/benchmarks/newton_solver_benchmark_set/spiegelman_et_al_2016/input.prm.bak new file mode 100644 index 00000000000..a35e871b3ca --- /dev/null +++ b/benchmarks/newton_solver_benchmark_set/spiegelman_et_al_2016/input.prm.bak @@ -0,0 +1,137 @@ +set Additional shared libraries = ./libdrucker_prager_compositions.so +set Use years in output instead of seconds = false +set Nonlinear solver scheme = iterated Advection and Newton Stokes +set Max nonlinear iterations = 150 +set Nonlinear solver tolerance = 1e-14 +set Pressure normalization = no + +subsection Solver parameters + subsection Stokes solver parameters + set Number of cheap Stokes solver steps = 0 + set Linear solver tolerance = 1e-5 + end + + subsection Newton solver parameters + set Max pre-Newton nonlinear iterations = 5 + set SPD safety factor = 0.9 + set Nonlinear Newton solver switch tolerance = 1e-20 # + set Max Newton line search iterations = 0 + set Maximum linear Stokes solver tolerance = 9e-1 + set Use Newton residual scaling method = false + set Use Newton failsafe = false + set Stabilization preconditioner = SPD + set Stabilization velocity block = SPD + end +end + +subsection Initial temperature model + set Model name = function +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = H = 30e3 + + # The function below lays out the composition structure as described in the Spiegelman paper. + # It generates a composition at the bottom which has a square with round eges sticking out in + # the center. + set Function expression = if(z < 0.25 * H,1, \ +if(z < (0.25+(1/12)-0.02)*H & x > (2-(1/12))*H & x < (2+(1/12))*H,1, \ +if(z < (0.25+(1/12))*H & (x > (2-(1/12)+0.02)*H & x < (2+(1/12)-0.02)*H | (x-(2-(1/12)+0.02)*H)^2 + (z-(0.25+(1/12)-0.02)*H)^2 < (0.02*H)^2 | (x-(2+(1/12)-0.02)*H)^2 + (z-(0.25+(1/12)-0.02)*H)^2 < (0.02*H)^2),1, \ +if(z < (0.25+0.02)*H && x > (2-(1/12)-0.02)*H && x < (2+(1/12)+0.02)*H && ((x-(2-(1/12)-0.02)*H)^2 + (z-(0.25+0.02)*H)^2 > (0.02*H)^2 && (x-(2+(1/12)+0.02)*H)^2 + (z-(0.25+0.02)*H)^2 > (0.02*H)^2),1,0)))) + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 120e3 + set Y extent = 30e3 + set X repetitions = 4 + end +end + +subsection Compositional fields + set Number of fields = 1 + + #parameters for all rheologies + set Conductivities = 2.25, 2.25 + set Heat capacities = 1250, 1250 + set Reference temperatures = 0, 0 + set Reference densities = 2700.0, 2700.0 + + #plastic parameters + set Cohesions = 1e8,0 + set Angles of internal friction = 30,0 + + #Dislocation parameters + set Stress exponents = 50, 1 + set Initial viscosities = 1e20, 1e21 + + # the first value is ignored by the specific drucker prager compositions material model + # in this benchmark folder, so set it to a nonsensical value: 0. + set Viscous prefactors = 0, 1e21 +end + +subsection Material model + set Model name = drucker prager compositions + + subsection Drucker prager compositions + set Maximum viscosity = 1e24 + set Minimum viscosity = 1e21 + set Viscosity averaging p = -1 + set Use deviator of strain-rate = true + set Use analytical derivative = false + set Reference viscosity = 5e24 + set Reference compressibility = 0 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Strategy = strain rate +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = +end + +subsection Boundary velocity model + # Prescribe a horizontal traction on the vertical boundaries + set Tangential velocity boundary indicators = 2 + set Zero velocity boundary indicators = + + # Prescribe a zero vertical velocity component on the vertical boundaries + set Prescribed velocity boundary indicators = 0 x:function,1 x:function + + subsection Function + set Variable names = x,z + set Function expression = if(x<60e3,7.92219116e-11,-7.92219116e-11);0 + end +end + +subsection Boundary traction model + set Prescribed traction boundary indicators = +end + +subsection Postprocess + set List of postprocessors = velocity statistics, pressure statistics, mass flux statistics, visualization + + subsection Visualization + set List of output variables = material properties,strain rate, spd factor + set Interpolate output = false + end +end diff --git a/benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input.prm b/benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input.prm index b6cca66b629..86379ea1226 100644 --- a/benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input.prm +++ b/benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input.prm @@ -146,9 +146,9 @@ end # - Vrms over the whole domain (velocity statistics) # - Vrms along the surface (velocity boundary statistics) # - Vmax along the surface (velocity boundary statistics) -# - average rate of viscous dissipation (tosi viscous dissipation statistics) -# - average rate of work against gravity (tosi viscous dissipation statistics) -# - percentage error difference work and dissipation (tosi viscous dissipation statistics) +# - average rate of viscous dissipation (tosi heating statistics) +# - average rate of work against gravity (tosi heating statistics) +# - percentage error difference work and dissipation (tosi heating statistics) # # Tosi et al. (2015) also report depth averages; averages for viscosity # and temperature are produced every 0.05 units of time. diff --git a/benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input.prm.bak b/benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input.prm.bak new file mode 100644 index 00000000000..b6cca66b629 --- /dev/null +++ b/benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input.prm.bak @@ -0,0 +1,168 @@ +# A description of viscoplastic convection in a 2d box as +# described in Tosi et al. (2015). + +# We add the necessary plugins through a shared library +set Additional shared libraries = $ASPECT_SOURCE_DIR/benchmarks/tosi_et_al_2015_gcubed/libtosi_benchmark.so + +# This is a 2D benchmark. +set Dimension = 2 + +# We run the model from time = 0 to time = 1 and to handle +# the nonlinearity of the viscosity correctly, we use +# the iterated Advection and Stokes nonlinear solver and skip the cheap +# Stokes solves. +set Use years in output instead of seconds = false +set End time = 0.01 +set Output directory = Case4_3_T15_NS_analytical_9e-1_release +set Nonlinear solver scheme = iterated Advection and Newton Stokes +set Max nonlinear iterations = 30 +set Nonlinear solver tolerance = 1e-7 + +# We choose a zero average pressure +# at the surface of the domain (for the current geometry, the +# surface is defined as the top boundary). +set Pressure normalization = surface +set Surface pressure = 0 + +subsection Solver parameters + subsection Stokes solver parameters + set Number of cheap Stokes solver steps = 200 + set Linear solver tolerance = 1e-6 + end + + subsection Newton solver parameters + set Max pre-Newton nonlinear iterations = 5 + set SPD safety factor = 0.9 + set Nonlinear Newton solver switch tolerance = 1e-20 + set Max Newton line search iterations = 0 + set Maximum linear Stokes solver tolerance = 9e-1 + set Use Newton residual scaling method = false + set Use Newton failsafe = false + set Stabilization preconditioner = SPD + set Stabilization velocity block = SPD + end +end + +# Our model domain is the unit square. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +# We prescribe a linear temperature profile that +# matches the boundary conditions defined below plus +# a small perturbation with amplitude A. +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = A=0.01, pi=3.1415926536 + set Function expression = (1.0-z) + A*cos(pi*x)*sin(pi*z) + end +end + +# The top and bottom boundary carry a prescribed boundary temperature, whereas +# all other parts of the boundary are insulated (i.e., no heat flux through +# these boundaries; this is also often used to specify symmetry boundaries). +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + # The temperature at the bottom is set to 1; at the top to 0. + subsection Box + set Bottom temperature = 1 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +subsection Boundary velocity model + # Here, all four sides of the box allow tangential + # unrestricted flow but with a zero normal component: + set Tangential velocity boundary indicators = left, right, bottom, top +end + +# Gravity is vertical and of magnitude 1e8. +# //TODO elaborate on scaling/rayleigh +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1e8 + end +end + +subsection Material model + set Model name = TosiMaterial + + subsection Tosi benchmark + set Reference density = 1 + set Reference specific heat = 1 + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1e-06 + set Thermal viscosity parameter = 1e5 + set Pressure viscosity parameter = 10 + set Yield stress = 1 + set Nonlinear viscosity constant = 1e-3 + set Initial viscosity = 1e-1 + set Minimum viscosity = 1e-6 + set Maximum viscosity = 10 + end +end + +# The settings above all pertain to the description of the +# continuous partial differential equations we want to solve. +# The following section deals with the discretization of +# this problem, namely the kind of mesh we want to compute +# on. We here use a globally refined mesh without +# adaptive mesh refinement. +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +# The final part is to specify what ASPECT should do with the +# solution once computed at the end of every time step. The +# process of evaluating the solution is called `postprocessing' +# and we choose to compute velocity and temperature statistics, +# statistics about the heat flux through the boundaries of the +# domain, and to generate graphical output files for later +# visualization. These output files are created every time +# a time step crosses time points separated by 0.05. Given +# our start time (0.0) and final time (1.0) this means that +# we will obtain 20 output files. +# +# The statistics file includes the data reported in Tosi et al. (2015): +# - average temperature (temperature statistics) +# - top and bottom Nusselt numbers (heat flux statistics) +# - Vrms over the whole domain (velocity statistics) +# - Vrms along the surface (velocity boundary statistics) +# - Vmax along the surface (velocity boundary statistics) +# - average rate of viscous dissipation (tosi viscous dissipation statistics) +# - average rate of work against gravity (tosi viscous dissipation statistics) +# - percentage error difference work and dissipation (tosi viscous dissipation statistics) +# +# Tosi et al. (2015) also report depth averages; averages for viscosity +# and temperature are produced every 0.05 units of time. +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, visualization , depth average, velocity boundary statistics #, tosi dissipation and work statistics, depth average, velocity boundary statistics + + subsection Depth average + set List of output variables = temperature, viscosity + set Time between graphical output = 0.05 + set Number of zones = 10 + end + + subsection Visualization + set List of output variables = material properties, strain rate, gravity + set Time between graphical output = 0.05 + end +end diff --git a/benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input_gmg.prm.bak b/benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input_gmg.prm.bak new file mode 100644 index 00000000000..d76f0ae4e05 --- /dev/null +++ b/benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input_gmg.prm.bak @@ -0,0 +1,23 @@ +# Same as the newton_solver_benchmark_set/tosi_et_al_2015/input.prm +# benchmark but using GMG instead. + +# We add the necessary plugins through a shared library +set Additional shared libraries = $ASPECT_SOURCE_DIR/benchmarks/tosi_et_al_2015_gcubed/libtosi_benchmark.so + +include $ASPECT_SOURCE_DIR/benchmarks/newton_solver_benchmark_set/tosi_et_al_2015/input.prm + +set Output directory = output-gmg + +subsection Solver parameters + subsection Matrix Free + set Output details = true + end + + subsection Stokes solver parameters + set Stokes solver type = block GMG + end +end + +subsection Material model + set Material averaging = harmonic average +end diff --git a/benchmarks/nsinker/nsinker.cc.bak b/benchmarks/nsinker/nsinker.cc.bak new file mode 100644 index 00000000000..c031bdea433 --- /dev/null +++ b/benchmarks/nsinker/nsinker.cc.bak @@ -0,0 +1,352 @@ +/* + Copyright (C) 2022 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include + +#include +#include + + +namespace aspect +{ + /** + * This is the "NSinker" benchmark as defined in Rudi et al. (2017), + * which is based on May et al. (2014). It creates a number of + * spherical high-viscosity, high-density sinking spheres in a box + * geometry that provide a challenge for the Stokes preconditioner. + * The difficulty of the problem is determined by the number of + * sinkers and the viscosity contrast between sinkers and + * background. + */ + namespace NSinkerBenchmark + { + using namespace dealii; + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @ingroup MaterialModels + */ + template + class NSinkerMaterial : public MaterialModel::Interface + { + public: + /** + * Constructor + */ + NSinkerMaterial (); + + /** + * @name Physical parameters used in the basic equations + * @{ + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + const double sqrt_dynamic_viscosity_ratio = std::sqrt(dynamic_viscosity_ratio); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const double chi = inside_outside_factor(in.position[i]); + out.viscosities[i] = (sqrt_dynamic_viscosity_ratio - 1./sqrt_dynamic_viscosity_ratio)*(1-chi) + 1./sqrt_dynamic_viscosity_ratio; + out.densities[i] = sinker_density * (1.0 - chi); + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + } + } + + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + * Incompressibility does not necessarily imply that the density is + * constant; rather, it may still depend on temperature or pressure. + * In the current context, compressibility means whether we should + * solve the continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + bool is_compressible () const override + { + return false; + } + /** + * @} + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("NSinker"); + { + prm.declare_entry ("Dynamic viscosity ratio", "1e3", + Patterns::Double (0), + "Viscosity in the sinkers."); + prm.declare_entry ("Sinker density", "10", + Patterns::Double (0), + "Density in the sinkers."); + prm.declare_entry ("Number of sinkers", "4", + Patterns::Integer (0,75), + "Number of sinking spheres."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("NSinker"); + { + dynamic_viscosity_ratio = prm.get_double ("Dynamic viscosity ratio"); + sinker_density = prm.get_double ("Sinker density"); + n_sinkers = prm.get_integer ("Number of sinkers"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + + + private: + /** + * Ratio of viscosities between sinkers and background material. + */ + double dynamic_viscosity_ratio; + + /** + * Sinker density. For a gravity of 1 this corresponds to + * the size of the right-hand-side forcing term. + */ + double sinker_density; + + /** + * Number of sinking spheres. + */ + unsigned int n_sinkers; + + /** + * Centers for the sinkers provided by Cedric Thielot (pers. comm. from Dave May) + */ + std::vector> centers; + + /** + * Parameters for evaluating viscosity + */ + double delta; + double omega; + + /** + * Return a factor that indicates whether a point is inside or + * outside the sinker spheres. The function can be thought of + * as a 1 (outside) vs 0 (inside) factor, but is in reality a + * smoothed version of this that takes into account the + * distance from the centers of the sinkers. + */ + double inside_outside_factor (const Point &p) const; + }; + + + template + NSinkerMaterial::NSinkerMaterial () + { + delta = 200.0; + omega = 0.1; + + centers.resize(75); + centers[0] = Point<3>(2.4257829890e-01, 1.3469574514e-02, 3.8313885004e-01); + centers[1] = Point<3>(4.1465269048e-01, 6.7768972864e-02, 9.9312692973e-01); + centers[2] = Point<3>(4.8430804651e-01, 7.6533776604e-01, 3.1833815403e-02); + centers[3] = Point<3>(3.0935481671e-02, 9.3264044027e-01, 8.8787953411e-01); + centers[4] = Point<3>(5.9132973039e-01, 4.7877868473e-01, 8.3335433660e-01); + centers[5] = Point<3>(1.8633519681e-01, 7.3565270739e-01, 1.1505317181e-01); + centers[6] = Point<3>(6.9865863058e-01, 3.5560411138e-01, 6.3830000658e-01); + centers[7] = Point<3>(9.0821050755e-01, 2.9400041480e-01, 2.6497158886e-01); + centers[8] = Point<3>(3.7749399775e-01, 5.4162011554e-01, 9.2818150340e-03); + centers[9] = Point<3>(8.5247022139e-01, 4.6701098395e-01, 5.3607231962e-02); + centers[10] = Point<3>(9.7674759057e-01, 1.9675474344e-01, 8.5697294067e-01); + centers[11] = Point<3>(1.4421375987e-01, 8.0066218823e-01, 7.2939761948e-01); + centers[12] = Point<3>(9.8579064709e-01, 1.8340570954e-01, 4.9976021075e-01); + centers[13] = Point<3>(4.6986202126e-01, 9.7099129947e-01, 4.5077026191e-01); + centers[14] = Point<3>(9.5791877292e-02, 9.7408164664e-01, 3.9023506101e-01); + centers[15] = Point<3>(6.8067035576e-01, 2.6669318800e-02, 2.3124107450e-01); + centers[16] = Point<3>(4.6873909443e-01, 9.7960100555e-02, 4.1541002524e-01); + centers[17] = Point<3>(7.9629418710e-01, 3.1640260216e-01, 7.7853444953e-01); + centers[18] = Point<3>(8.2849331472e-01, 4.8714042059e-01, 3.6904878000e-01); + centers[19] = Point<3>(6.0284549678e-01, 2.4264360789e-02, 8.1111178631e-01); + centers[20] = Point<3>(3.5579259291e-01, 8.0610905439e-01, 2.7487712366e-01); + centers[21] = Point<3>(8.5981739865e-01, 9.5101905612e-01, 7.7727618477e-01); + centers[22] = Point<3>(6.8083745971e-01, 8.3518540665e-01, 9.6112961413e-01); + centers[23] = Point<3>(7.0542474869e-01, 7.3751226102e-02, 5.3685709440e-01); + centers[24] = Point<3>(9.5718558131e-01, 4.1806501915e-01, 4.1877679639e-01); + centers[25] = Point<3>(3.8161700050e-01, 8.3692747440e-01, 2.4006224854e-01); + centers[26] = Point<3>(7.2621119848e-01, 4.3161282150e-01, 1.1669089744e-01); + centers[27] = Point<3>(2.2391322592e-01, 3.0958795748e-01, 2.4480139429e-01); + centers[28] = Point<3>(3.7703382754e-01, 8.0753940242e-01, 3.1473643301e-01); + centers[29] = Point<3>(7.7522956709e-01, 2.8333410774e-01, 9.9634871585e-01); + centers[30] = Point<3>(6.3286731189e-01, 6.0091089904e-01, 5.0948022423e-01); + centers[31] = Point<3>(8.3412860373e-01, 1.9944285005e-01, 3.5980841627e-02); + centers[32] = Point<3>(7.3000523063e-01, 1.9791117972e-01, 2.9319749786e-01); + centers[33] = Point<3>(7.7034656693e-01, 2.1475035521e-01, 3.0922000730e-01); + centers[34] = Point<3>(6.0662675677e-02, 5.5759010630e-01, 4.1691651960e-01); + centers[35] = Point<3>(1.1594487686e-01, 6.8554530558e-01, 9.5995079957e-01); + centers[36] = Point<3>(2.7973348288e-02, 1.4806467395e-01, 5.2297503060e-01); + centers[37] = Point<3>(6.4133927209e-01, 9.8914607800e-01, 5.7813295237e-01); + centers[38] = Point<3>(6.8053043246e-01, 6.7497840462e-01, 3.6204645148e-01); + centers[39] = Point<3>(9.1470996426e-01, 5.3036934674e-01, 9.1761070439e-01); + centers[40] = Point<3>(2.8310876353e-01, 2.0898862472e-01, 4.7181570645e-01); + centers[41] = Point<3>(8.0657831198e-01, 1.6168943288e-01, 5.1429839456e-01); + centers[42] = Point<3>(8.1311740159e-01, 6.4168478858e-02, 4.7962416312e-01); + centers[43] = Point<3>(4.3309508843e-02, 9.0291512474e-01, 2.9450144167e-01); + centers[44] = Point<3>(6.8573011443e-01, 6.6033273035e-02, 8.2121989495e-01); + centers[45] = Point<3>(2.4277445452e-01, 3.1025718772e-01, 4.9255406554e-01); + centers[46] = Point<3>(3.5617944848e-01, 3.0799053857e-01, 3.9698166931e-01); + centers[47] = Point<3>(7.0916077621e-02, 8.8651657239e-01, 6.8403214295e-01); + centers[48] = Point<3>(5.2822650202e-01, 9.0281945043e-01, 6.8650344000e-01); + centers[49] = Point<3>(6.3316007640e-02, 1.5214040370e-01, 2.3765034985e-02); + centers[50] = Point<3>(4.1894298765e-01, 1.7479340461e-01, 7.5275125343e-01); + centers[51] = Point<3>(4.9031640053e-01, 7.4774375406e-01, 3.2927456281e-01); + centers[52] = Point<3>(1.1757708859e-01, 1.1812786251e-01, 3.7498524244e-01); + centers[53] = Point<3>(3.7696964032e-01, 7.2874483733e-01, 1.4480990830e-02); + centers[54] = Point<3>(3.8201288152e-01, 4.9049964756e-01, 8.2757658503e-01); + centers[55] = Point<3>(7.9664661586e-02, 9.2396727806e-01, 1.1804237828e-01); + centers[56] = Point<3>(9.3825167927e-01, 1.9597347043e-01, 7.2611756191e-01); + centers[57] = Point<3>(8.5786301170e-01, 1.0363770514e-01, 8.3891028205e-01); + centers[58] = Point<3>(5.6511039453e-01, 8.1040084307e-01, 4.0696941614e-01); + centers[59] = Point<3>(9.3497714490e-01, 1.6087440083e-01, 8.1605472361e-01); + centers[60] = Point<3>(4.3173963829e-01, 2.4810082244e-01, 8.3052277138e-01); + centers[61] = Point<3>(5.9621858625e-01, 6.4577903070e-01, 6.0816894547e-01); + centers[62] = Point<3>(4.9546643556e-01, 3.0438243752e-01, 7.5562733447e-01); + centers[63] = Point<3>(8.2861043319e-01, 4.5555055302e-01, 4.3814466774e-01); + centers[64] = Point<3>(8.9743076959e-01, 1.1894442752e-01, 9.8993320995e-02); + centers[65] = Point<3>(6.9884936497e-01, 5.6127713367e-01, 3.8478565932e-01); + centers[66] = Point<3>(9.2576270966e-02, 9.2938612771e-01, 1.9264837596e-01); + centers[67] = Point<3>(8.4125479722e-01, 9.6937695284e-01, 3.1844636161e-01); + centers[68] = Point<3>(1.2799954700e-01, 2.8838638276e-01, 9.0993508972e-01); + centers[69] = Point<3>(2.7905288352e-01, 4.1813262758e-02, 7.5550716964e-01); + centers[70] = Point<3>(8.0900019305e-01, 8.6624463269e-01, 9.7354159503e-01); + centers[71] = Point<3>(3.1358765965e-01, 4.6779574243e-01, 2.4304298462e-01); + centers[72] = Point<3>(8.2344259034e-01, 5.9961585635e-01, 7.4369772512e-01); + centers[73] = Point<3>(3.2766604253e-01, 8.3176720460e-02, 9.5114077951e-01); + centers[74] = Point<3>(8.2308128282e-01, 5.2712029523e-01, 3.1080186614e-01); + } + + + + template <> + double + NSinkerMaterial<2>::inside_outside_factor (const Point<2> &p) const + { + double chi = 1.0; + + for (unsigned int s=0; s(centers[s](0), centers[s](1))); + double temp = 1-std::exp(-delta* + std::pow(std::max(0.0,dist-omega/2.0),2)); + chi *= temp; + } + return chi; + } + + + + template <> + double + NSinkerMaterial<3>::inside_outside_factor (const Point<3> &p) const + { + double chi = 1.0; + + for (unsigned int s=0; s +void signal_connector (aspect::SimulatorSignals &signals) +{ + signals.modify_pressure_scaling.connect(&pressure_scaling_signal); +} + +ASPECT_REGISTER_SIGNALS_CONNECTOR(signal_connector<2>, + signal_connector<3>) + + +namespace aspect +{ + namespace NSinkerBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(NSinkerMaterial, + "nsinker", + "A material model that corresponds to the 'NSinker' benchmark " + "defined in May et al., G-Cubed, 2015. We here implement the " + "version defined in Rudi et al., SIAM Journal on Scientific " + "Computing, 2017. Number of sinkers and viscosity ratio can be chosen " + "as input parameters.") + } +} diff --git a/benchmarks/nsinker/nsinker.prm b/benchmarks/nsinker/nsinker.prm index 3e7adb91f88..0716eaac90a 100644 --- a/benchmarks/nsinker/nsinker.prm +++ b/benchmarks/nsinker/nsinker.prm @@ -13,7 +13,6 @@ set Nonlinear solver scheme = no Advection, single Stokes set Max nonlinear iterations = 1 set Use years in output instead of seconds = false - # Follow as closely as possible the parameters from Rudi et al. (2017) subsection Solver parameters subsection Stokes solver parameters @@ -25,8 +24,9 @@ subsection Solver parameters set Use weighted BFBT for Schur complement = false set Krylov method for cheap solver steps = GMRES end + subsection AMG parameters - set AMG aggregation threshold = 0.02 + set AMG aggregation threshold = 0.02 end end diff --git a/benchmarks/nsinker/nsinker.prm.bak b/benchmarks/nsinker/nsinker.prm.bak new file mode 100644 index 00000000000..3e7adb91f88 --- /dev/null +++ b/benchmarks/nsinker/nsinker.prm.bak @@ -0,0 +1,84 @@ +# This is the "NSinker" benchmark defined in May et al. (2015,G3) in the +# implementation of Rudi et al., (2017, SIAM J.Sci.Comp.). It creates a number +# of spherical high-viscosity, high-density sinking spheres in a box geometry +# that provide a challenge for the Stokes preconditioner. The difficulty of the +# problem is determined by the number of sinkers and the viscosity contrast +# between sinkers and background. + +set Additional shared libraries = ./libnsinker.so +set Dimension = 3 +set End time = 0 +set Pressure normalization = volume +set Nonlinear solver scheme = no Advection, single Stokes +set Max nonlinear iterations = 1 +set Use years in output instead of seconds = false + + +# Follow as closely as possible the parameters from Rudi et al. (2017) +subsection Solver parameters + subsection Stokes solver parameters + set Use full A block as preconditioner = true + set Number of cheap Stokes solver steps = 500 + set Maximum number of expensive Stokes solver steps = 1000 + set Linear solver tolerance = 1e-6 + set GMRES solver restart length = 100 + set Use weighted BFBT for Schur complement = false + set Krylov method for cheap solver steps = GMRES + end + subsection AMG parameters + set AMG aggregation threshold = 0.02 + end +end + +subsection Discretization + set Use locally conservative discretization = false +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + set Z extent = 1 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = left,right,bottom,top,front,back +end + +subsection Material model + set Model name = nsinker + set Material averaging = none + + subsection NSinker + set Number of sinkers = 8 + set Dynamic viscosity ratio = 1e4 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +subsection Initial temperature model + set Model name = function +end + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization + + subsection Visualization + set List of output variables = material properties + end +end diff --git a/benchmarks/nsinker/nsinker_2d.prm.bak b/benchmarks/nsinker/nsinker_2d.prm.bak new file mode 100644 index 00000000000..070b9bdef40 --- /dev/null +++ b/benchmarks/nsinker/nsinker_2d.prm.bak @@ -0,0 +1,72 @@ +# This is a 2D version of the original 3D "NSinker" problem. + +set Additional shared libraries = ./libnsinker.so +set Dimension = 2 +set End time = 0 +set Pressure normalization = volume +set Nonlinear solver scheme = no Advection, single Stokes +set Max nonlinear iterations = 1 +set Use years in output instead of seconds = false + +# Follow as closely as possible the parameters from Rudi et al. (2017) +subsection Solver parameters + subsection Stokes solver parameters + set Use full A block as preconditioner = true + set Number of cheap Stokes solver steps = 0 + set Maximum number of expensive Stokes solver steps = 1000 + set Linear solver tolerance = 1e-6 + set GMRES solver restart length = 100 + end +end + +subsection Discretization + set Use locally conservative discretization = true +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left,right,bottom +end + +subsection Material model + set Model name = nsinker + set Material averaging = none + + subsection NSinker + set Number of sinkers = 1 + set Dynamic viscosity ratio = 1e4 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +subsection Initial temperature model + set Model name = function +end + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization + + subsection Visualization + set List of output variables = material properties + end +end diff --git a/benchmarks/nsinker/nsinker_bfbt.prm b/benchmarks/nsinker/nsinker_bfbt.prm index ed104447980..7de5ffda08f 100644 --- a/benchmarks/nsinker/nsinker_bfbt.prm +++ b/benchmarks/nsinker/nsinker_bfbt.prm @@ -14,10 +14,9 @@ set Nonlinear solver scheme = no Advection, single Stokes set Max nonlinear iterations = 1 set Use years in output instead of seconds = false - # Follow as closely as possible the parameters from Rudi et al. (2017) subsection Solver parameters - subsection Stokes solver parameters + subsection Stokes solver parameters set Use full A block as preconditioner = true set Number of cheap Stokes solver steps = 500 set Maximum number of expensive Stokes solver steps = 1000 @@ -26,8 +25,9 @@ subsection Solver parameters set Use weighted BFBT for Schur complement = true set Krylov method for cheap solver steps = GMRES end + subsection AMG parameters - set AMG aggregation threshold = 0.02 + set AMG aggregation threshold = 0.02 end end diff --git a/benchmarks/nsinker/nsinker_bfbt.prm.bak b/benchmarks/nsinker/nsinker_bfbt.prm.bak new file mode 100644 index 00000000000..ed104447980 --- /dev/null +++ b/benchmarks/nsinker/nsinker_bfbt.prm.bak @@ -0,0 +1,85 @@ +# This is the "NSinker" benchmark defined in May et al. (2015,G3) in the +# implementation of Rudi et al., (2017, SIAM J.Sci.Comp.). It creates a number +# of spherical high-viscosity, high-density sinking spheres in a box geometry +# that provide a challenge for the Stokes preconditioner. The difficulty of the +# problem is determined by the number of sinkers and the viscosity contrast +# between sinkers and background. In this benchmark, we use the +# weighted BFBT preconditioner introduced by Rudi et al., (2017). + +set Additional shared libraries = ./libnsinker.so +set Dimension = 3 +set End time = 0 +set Pressure normalization = volume +set Nonlinear solver scheme = no Advection, single Stokes +set Max nonlinear iterations = 1 +set Use years in output instead of seconds = false + + +# Follow as closely as possible the parameters from Rudi et al. (2017) +subsection Solver parameters + subsection Stokes solver parameters + set Use full A block as preconditioner = true + set Number of cheap Stokes solver steps = 500 + set Maximum number of expensive Stokes solver steps = 1000 + set Linear solver tolerance = 1e-6 + set GMRES solver restart length = 100 + set Use weighted BFBT for Schur complement = true + set Krylov method for cheap solver steps = GMRES + end + subsection AMG parameters + set AMG aggregation threshold = 0.02 + end +end + +subsection Discretization + set Use locally conservative discretization = false +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + set Z extent = 1 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = left,right,bottom,top,front,back +end + +subsection Material model + set Model name = nsinker + set Material averaging = none + + subsection NSinker + set Number of sinkers = 8 + set Dynamic viscosity ratio = 1e4 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +subsection Initial temperature model + set Model name = function +end + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization + + subsection Visualization + set List of output variables = material properties + end +end diff --git a/benchmarks/nsinker/nsinker_gmg.prm.bak b/benchmarks/nsinker/nsinker_gmg.prm.bak new file mode 100644 index 00000000000..aa4817332bf --- /dev/null +++ b/benchmarks/nsinker/nsinker_gmg.prm.bak @@ -0,0 +1,92 @@ +# This is the "NSinker" benchmark defined in May et al. (2015,G3) in the +# implementation of Rudi et al., (2017, SIAM J.Sci.Comp.). It creates a number +# of spherical high-viscosity, high-density sinking spheres in a box geometry +# that provide a challenge for the Stokes preconditioner. The difficulty of the +# problem is determined by the number of sinkers and the viscosity contrast +# between sinkers and background. + +set Additional shared libraries = ./libnsinker.so +set Dimension = 3 +set End time = 0 +set Pressure normalization = volume +set Nonlinear solver scheme = no Advection, single Stokes +set Max nonlinear iterations = 1 +set Use years in output instead of seconds = false +set Output directory = output-gmg + +# Follow as closely as possible the parameters from Rudi et al. (2017) +subsection Solver parameters + subsection Matrix Free + set Output details = true + end + + subsection Stokes solver parameters + set Stokes solver type = block GMG + set Number of cheap Stokes solver steps = 200 + set Maximum number of expensive Stokes solver steps = 0 + set Linear solver tolerance = 1e-6 + set GMRES solver restart length = 100 + end +end + +subsection Discretization + set Use locally conservative discretization = false +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + set Z extent = 1 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = left,right,bottom,top,front,back +end + +subsection Material model + set Model name = nsinker + set Material averaging = harmonic average + + subsection NSinker + set Number of sinkers = 4 + set Dynamic viscosity ratio = 1e4 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +subsection Initial temperature model + set Model name = function +end + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 5 + set Adapt by fraction of cells = true + set Strategy = velocity + set Run postprocessors on initial refinement = true + set Coarsening fraction = 0.0 + set Refinement fraction = 0.147 #0.14285714285 +end + +subsection Postprocess + set List of postprocessors = memory statistics, visualization + + subsection Memory statistics + set Output peak virtual memory (VmPeak) = true + end + + subsection Visualization + set List of output variables = viscosity + end +end diff --git a/benchmarks/nsinker_spherical_shell/amg.prm.bak b/benchmarks/nsinker_spherical_shell/amg.prm.bak new file mode 100644 index 00000000000..64b627b59c4 --- /dev/null +++ b/benchmarks/nsinker_spherical_shell/amg.prm.bak @@ -0,0 +1,20 @@ +# This is the "Spherical Shell NSinker" benchmark +# +# This file uses the AMG instead of GMG solver + +set Additional shared libraries = ./libnsinker_spherical_shell.so + +include gmg.prm + +set Dimension = 3 +set Output directory = output-amg + +subsection Solver parameters + subsection Stokes solver parameters + set Stokes solver type = block AMG + set Number of cheap Stokes solver steps = 2000 + set Maximum number of expensive Stokes solver steps = 0 + set Linear solver tolerance = 1e-6 + set GMRES solver restart length = 100 + end +end diff --git a/benchmarks/nsinker_spherical_shell/gmg.prm.bak b/benchmarks/nsinker_spherical_shell/gmg.prm.bak new file mode 100644 index 00000000000..58a4eab153b --- /dev/null +++ b/benchmarks/nsinker_spherical_shell/gmg.prm.bak @@ -0,0 +1,86 @@ +# This is the "Spherical Shell NSinker" benchmark + +set Additional shared libraries = ./libnsinker_spherical_shell.so +set Dimension = 3 +set End time = 0 +set Pressure normalization = volume +set Nonlinear solver scheme = no Advection, single Stokes +set Use years in output instead of seconds = false +set Output directory = output-gmg + +subsection Solver parameters + subsection Matrix Free + set Output details = true + end + + subsection Stokes solver parameters + set Stokes solver type = block GMG + set Number of cheap Stokes solver steps = 2000 + set Maximum number of expensive Stokes solver steps = 0 + set Linear solver tolerance = 1e-6 + set GMRES solver restart length = 200 + end +end + +subsection Discretization + set Use locally conservative discretization = false +end + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 0.54 + set Outer radius = 1.0 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = top,bottom +end + +subsection Material model + set Model name = nsinker + set Material averaging = harmonic average + + subsection NSinker + set Number of sinkers = 5 + set Dynamic viscosity ratio = 1e2 + set Sinker density = 10 + set Transition zone viscosity jump = 100 + end +end + +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 1 + end +end + +subsection Initial temperature model + set Model name = function +end + +subsection Mesh refinement + set Initial global refinement = 2 + set Initial adaptive refinement = 5 + set Adapt by fraction of cells = true + set Strategy = velocity + set Run postprocessors on initial refinement = true + set Coarsening fraction = 0.0 + set Refinement fraction = 0.147 +end + +subsection Postprocess + set List of postprocessors = memory statistics, visualization + + subsection Memory statistics + set Output peak virtual memory (VmPeak) = true + end + + subsection Visualization + set List of output variables = viscosity + end +end diff --git a/benchmarks/nsinker_spherical_shell/nsinker.cc.bak b/benchmarks/nsinker_spherical_shell/nsinker.cc.bak new file mode 100644 index 00000000000..9ae67327596 --- /dev/null +++ b/benchmarks/nsinker_spherical_shell/nsinker.cc.bak @@ -0,0 +1,349 @@ +/* + Copyright (C) 2022 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include + +#include +#include + + +namespace aspect +{ + /** + * This is the "Spherical Shell NSinker" benchmark. + */ + namespace NSinkerBenchmark + { + using namespace dealii; + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @ingroup MaterialModels + */ + template + class NSinkerMaterial : public MaterialModel::Interface + { + public: + /** + * Constructor + */ + NSinkerMaterial (); + + /** + * @name Physical parameters used in the basic equations + * @{ + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + const double sqrt_dynamic_viscosity_ratio = std::sqrt(dynamic_viscosity_ratio); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const double chi = inside_outside_factor(in.position[i]); + out.viscosities[i] = (sqrt_dynamic_viscosity_ratio - 1./sqrt_dynamic_viscosity_ratio)*(1-chi) + 1./sqrt_dynamic_viscosity_ratio; + if (in.position[i].norm()<0.89583) // below "660km"? + out.viscosities[i] *= transition_zone_jump; + out.densities[i] = sinker_density * (1.0 - chi); + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + } + } + + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + * Incompressibility does not necessarily imply that the density is + * constant; rather, it may still depend on temperature or pressure. + * In the current context, compressibility means whether we should + * solve the continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + bool is_compressible () const override + { + return false; + } + /** + * @} + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("NSinker"); + { + prm.declare_entry ("Dynamic viscosity ratio", "1e3", + Patterns::Double (0), + "Viscosity in the sinkers."); + prm.declare_entry ("Sinker density", "10", + Patterns::Double (0), + "Density in the sinkers."); + prm.declare_entry ("Number of sinkers", "4", + Patterns::Integer (0,31), + "Number of sinking spheres."); + prm.declare_entry ("Transition zone viscosity jump", "1.0", + Patterns::Double (0), + "The factor by which the viscosity increases below the base of the " + "transition zone at a depth of 660km."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("NSinker"); + { + dynamic_viscosity_ratio = prm.get_double ("Dynamic viscosity ratio"); + sinker_density = prm.get_double ("Sinker density"); + n_sinkers = prm.get_integer ("Number of sinkers"); + transition_zone_jump = prm.get_double("Transition zone viscosity jump"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + + + private: + /** + * Ratio of viscosities between sinkers and background material. + */ + double dynamic_viscosity_ratio; + + /** + * Sinker density. For a gravity of 1 this corresponds to + * the size of the right-hand-side forcing term. + */ + double sinker_density; + + /** + * Magnitude of the jump of viscosity when going below the transition zone. + */ + double transition_zone_jump; + + /** + * Number of sinking spheres. + */ + unsigned int n_sinkers; + + /** + * Centers for the sinkers provided by Cedric Thielot (pers. comm. from Dave May) + */ + std::vector> centers; + + /** + * Parameters for evaluating viscosity + */ + double delta; + double omega; + + /** + * Return a factor that indicates whether a point is inside or + * outside the sinker spheres. The function can be thought of + * as a 1 (outside) vs 0 (inside) factor, but is in reality a + * smoothed version of this that takes into account the + * distance from the centers of the sinkers. + */ + double inside_outside_factor (const Point &p) const; + }; + + + template + NSinkerMaterial::NSinkerMaterial () + { + delta = 2*200.0; + omega = 2*0.1; + + // The original 75 randomly placed sinkers from the nsinker benchmark: + centers.resize(75); + centers[0] = Point<3>(2.4257829890e-01, 1.3469574514e-02, 3.8313885004e-01); + centers[1] = Point<3>(4.1465269048e-01, 6.7768972864e-02, 9.9312692973e-01); + centers[2] = Point<3>(4.8430804651e-01, 7.6533776604e-01, 3.1833815403e-02); + centers[3] = Point<3>(3.0935481671e-02, 9.3264044027e-01, 8.8787953411e-01); + centers[4] = Point<3>(5.9132973039e-01, 4.7877868473e-01, 8.3335433660e-01); + centers[5] = Point<3>(1.8633519681e-01, 7.3565270739e-01, 1.1505317181e-01); + centers[6] = Point<3>(6.9865863058e-01, 3.5560411138e-01, 6.3830000658e-01); + centers[7] = Point<3>(9.0821050755e-01, 2.9400041480e-01, 2.6497158886e-01); + centers[8] = Point<3>(3.7749399775e-01, 5.4162011554e-01, 9.2818150340e-03); + centers[9] = Point<3>(8.5247022139e-01, 4.6701098395e-01, 5.3607231962e-02); + centers[10] = Point<3>(9.7674759057e-01, 1.9675474344e-01, 8.5697294067e-01); + centers[11] = Point<3>(1.4421375987e-01, 8.0066218823e-01, 7.2939761948e-01); + centers[12] = Point<3>(9.8579064709e-01, 1.8340570954e-01, 4.9976021075e-01); + centers[13] = Point<3>(4.6986202126e-01, 9.7099129947e-01, 4.5077026191e-01); + centers[14] = Point<3>(9.5791877292e-02, 9.7408164664e-01, 3.9023506101e-01); + centers[15] = Point<3>(6.8067035576e-01, 2.6669318800e-02, 2.3124107450e-01); + centers[16] = Point<3>(4.6873909443e-01, 9.7960100555e-02, 4.1541002524e-01); + centers[17] = Point<3>(7.9629418710e-01, 3.1640260216e-01, 7.7853444953e-01); + centers[18] = Point<3>(8.2849331472e-01, 4.8714042059e-01, 3.6904878000e-01); + centers[19] = Point<3>(6.0284549678e-01, 2.4264360789e-02, 8.1111178631e-01); + centers[20] = Point<3>(3.5579259291e-01, 8.0610905439e-01, 2.7487712366e-01); + centers[21] = Point<3>(8.5981739865e-01, 9.5101905612e-01, 7.7727618477e-01); + centers[22] = Point<3>(6.8083745971e-01, 8.3518540665e-01, 9.6112961413e-01); + centers[23] = Point<3>(7.0542474869e-01, 7.3751226102e-02, 5.3685709440e-01); + centers[24] = Point<3>(9.5718558131e-01, 4.1806501915e-01, 4.1877679639e-01); + centers[25] = Point<3>(3.8161700050e-01, 8.3692747440e-01, 2.4006224854e-01); + centers[26] = Point<3>(7.2621119848e-01, 4.3161282150e-01, 1.1669089744e-01); + centers[27] = Point<3>(2.2391322592e-01, 3.0958795748e-01, 2.4480139429e-01); + centers[28] = Point<3>(3.7703382754e-01, 8.0753940242e-01, 3.1473643301e-01); + centers[29] = Point<3>(7.7522956709e-01, 2.8333410774e-01, 9.9634871585e-01); + centers[30] = Point<3>(6.3286731189e-01, 6.0091089904e-01, 5.0948022423e-01); + centers[31] = Point<3>(8.3412860373e-01, 1.9944285005e-01, 3.5980841627e-02); + centers[32] = Point<3>(7.3000523063e-01, 1.9791117972e-01, 2.9319749786e-01); + centers[33] = Point<3>(7.7034656693e-01, 2.1475035521e-01, 3.0922000730e-01); + centers[34] = Point<3>(6.0662675677e-02, 5.5759010630e-01, 4.1691651960e-01); + centers[35] = Point<3>(1.1594487686e-01, 6.8554530558e-01, 9.5995079957e-01); + centers[36] = Point<3>(2.7973348288e-02, 1.4806467395e-01, 5.2297503060e-01); + centers[37] = Point<3>(6.4133927209e-01, 9.8914607800e-01, 5.7813295237e-01); + centers[38] = Point<3>(6.8053043246e-01, 6.7497840462e-01, 3.6204645148e-01); + centers[39] = Point<3>(9.1470996426e-01, 5.3036934674e-01, 9.1761070439e-01); + centers[40] = Point<3>(2.8310876353e-01, 2.0898862472e-01, 4.7181570645e-01); + centers[41] = Point<3>(8.0657831198e-01, 1.6168943288e-01, 5.1429839456e-01); + centers[42] = Point<3>(8.1311740159e-01, 6.4168478858e-02, 4.7962416312e-01); + centers[43] = Point<3>(4.3309508843e-02, 9.0291512474e-01, 2.9450144167e-01); + centers[44] = Point<3>(6.8573011443e-01, 6.6033273035e-02, 8.2121989495e-01); + centers[45] = Point<3>(2.4277445452e-01, 3.1025718772e-01, 4.9255406554e-01); + centers[46] = Point<3>(3.5617944848e-01, 3.0799053857e-01, 3.9698166931e-01); + centers[47] = Point<3>(7.0916077621e-02, 8.8651657239e-01, 6.8403214295e-01); + centers[48] = Point<3>(5.2822650202e-01, 9.0281945043e-01, 6.8650344000e-01); + centers[49] = Point<3>(6.3316007640e-02, 1.5214040370e-01, 2.3765034985e-02); + centers[50] = Point<3>(4.1894298765e-01, 1.7479340461e-01, 7.5275125343e-01); + centers[51] = Point<3>(4.9031640053e-01, 7.4774375406e-01, 3.2927456281e-01); + centers[52] = Point<3>(1.1757708859e-01, 1.1812786251e-01, 3.7498524244e-01); + centers[53] = Point<3>(3.7696964032e-01, 7.2874483733e-01, 1.4480990830e-02); + centers[54] = Point<3>(3.8201288152e-01, 4.9049964756e-01, 8.2757658503e-01); + centers[55] = Point<3>(7.9664661586e-02, 9.2396727806e-01, 1.1804237828e-01); + centers[56] = Point<3>(9.3825167927e-01, 1.9597347043e-01, 7.2611756191e-01); + centers[57] = Point<3>(8.5786301170e-01, 1.0363770514e-01, 8.3891028205e-01); + centers[58] = Point<3>(5.6511039453e-01, 8.1040084307e-01, 4.0696941614e-01); + centers[59] = Point<3>(9.3497714490e-01, 1.6087440083e-01, 8.1605472361e-01); + centers[60] = Point<3>(4.3173963829e-01, 2.4810082244e-01, 8.3052277138e-01); + centers[61] = Point<3>(5.9621858625e-01, 6.4577903070e-01, 6.0816894547e-01); + centers[62] = Point<3>(4.9546643556e-01, 3.0438243752e-01, 7.5562733447e-01); + centers[63] = Point<3>(8.2861043319e-01, 4.5555055302e-01, 4.3814466774e-01); + centers[64] = Point<3>(8.9743076959e-01, 1.1894442752e-01, 9.8993320995e-02); + centers[65] = Point<3>(6.9884936497e-01, 5.6127713367e-01, 3.8478565932e-01); + centers[66] = Point<3>(9.2576270966e-02, 9.2938612771e-01, 1.9264837596e-01); + centers[67] = Point<3>(8.4125479722e-01, 9.6937695284e-01, 3.1844636161e-01); + centers[68] = Point<3>(1.2799954700e-01, 2.8838638276e-01, 9.0993508972e-01); + centers[69] = Point<3>(2.7905288352e-01, 4.1813262758e-02, 7.5550716964e-01); + centers[70] = Point<3>(8.0900019305e-01, 8.6624463269e-01, 9.7354159503e-01); + centers[71] = Point<3>(3.1358765965e-01, 4.6779574243e-01, 2.4304298462e-01); + centers[72] = Point<3>(8.2344259034e-01, 5.9961585635e-01, 7.4369772512e-01); + centers[73] = Point<3>(3.2766604253e-01, 8.3176720460e-02, 9.5114077951e-01); + centers[74] = Point<3>(8.2308128282e-01, 5.2712029523e-01, 3.1080186614e-01); + + // First rescale their location from [0,1] to [-1,1]: + for (auto &p: centers) + for (int d=0; d<3; ++d) + p[d] = p[d]*2.0-1.0; + + // Now erase all points with center outside our shell. This + // means some of them are not fully inside the domain, but this is ok. + auto e = std::remove_if(centers.begin(), centers.end(), [](const Point<3> &p) + { + return (p.norm()<0.54) || (p.norm()>1.0); + }); + centers.erase(e, centers.end()); + } + + + + template <> + double + NSinkerMaterial<2>::inside_outside_factor (const Point<2> &p) const + { + double chi = 1.0; + + for (unsigned int s=0; s(centers[s](0), centers[s](1))); + double temp = 1-std::exp(-delta* + std::pow(std::max(0.0,dist-omega/2.0),2)); + chi *= temp; + } + return chi; + } + + + + template <> + double + NSinkerMaterial<3>::inside_outside_factor (const Point<3> &p) const + { + double chi = 1.0; + + for (unsigned int s=0; s. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + template + class ExponentialDecay : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + static void declare_parameters (ParameterHandler &prm); + void parse_parameters(ParameterHandler &prm) override; + + bool is_compressible () const override; + + void create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + private: + + /** + * Pointer to the material model used as the base model + */ + std::unique_ptr> base_model; + + /** + * Parameters determining the initial decay rate. + */ + double half_life; + }; + } + + namespace HeatingModel + { + using namespace dealii; + + template + class ExponentialDecayHeating : public HeatingModel::Interface, public ::aspect::SimulatorAccess + { + public: + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + static void declare_parameters (ParameterHandler &prm); + + void parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Parameter determining the decay rate. + */ + double half_life; + }; + } +} + +namespace aspect +{ + namespace MaterialModel + { + template + bool + ExponentialDecay:: + is_compressible () const + { + return base_model->is_compressible(); + } + + + template + void + ExponentialDecay:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + AssertThrow(this->introspection().n_compositional_fields == 1, + ExcMessage("Exponential decay model needs exactly one compositional field.")); + + // Fill material model outputs using the base model. + base_model->evaluate(in,out); + const double time_scale = this->convert_output_to_years() ? year_in_seconds : 1.0; + + for (unsigned int q=0; q < in.n_evaluation_points(); ++q) + for (unsigned int c=0; c < this->introspection().n_compositional_fields; ++c) + out.reaction_terms[q][c] = 0.0; + + // fill melt reaction rates if they exist + ReactionRateOutputs *reaction_out = out.template get_additional_output>(); + + if (reaction_out != nullptr) + { + for (unsigned int q=0; q < in.n_evaluation_points(); ++q) + { + // dC/dt = - z * lambda * C + const double decay_constant = half_life > 0.0 ? log(2.0) / half_life : 0.0; + const double z = in.position[q](1); + reaction_out->reaction_rates[q][0] = - decay_constant * z / time_scale * in.composition[q][0]; + } + } + } + + + template + void + ExponentialDecay::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Exponential decay"); + { + prm.declare_entry("Base model","composition reaction", + Patterns::Selection(MaterialModel::get_valid_model_names_pattern()), + "The name of a material model that will be modified by a position " + "dependent melting rate. Valid values for this parameter " + "are the names of models that are also valid for the " + "``Material models/Model name'' parameter. See the documentation for " + "that for more information."); + prm.declare_entry ("Half life", "0", + Patterns::Double (0), + "Time required for a compositional field to reduce to half its " + "initial value. Units: Years if the " + "'Use years in output instead of seconds' parameter is set; " + "seconds otherwise."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + ExponentialDecay:: + parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Exponential decay"); + { + AssertThrow( prm.get("Base model") != "reaction rate function", + ExcMessage("You may not use ``reaction rate function'' as the base model for " + "a reaction rate function model.") ); + + // create the base model and initialize its SimulatorAccess base + // class; it will get a chance to read its parameters below after we + // leave the current section + base_model = create_material_model(prm.get("Base model")); + if (auto s = dynamic_cast*>(base_model.get())) + s->initialize_simulator (this->get_simulator()); + + half_life = prm.get_double ("Half life"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // After parsing the parameters for the exponential decay material model, + // also parse the parameters related to the base model. + base_model->parse_parameters(prm); + this->model_dependence = base_model->get_model_dependence(); + } + + + template + void + ExponentialDecay::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points, this->n_compositional_fields())); + } + } + } + + + namespace HeatingModel + { + template + void + ExponentialDecayHeating:: + evaluate (const MaterialModel::MaterialModelInputs &in, + const MaterialModel::MaterialModelOutputs & /*out*/, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + Assert(heating_model_outputs.heating_source_terms.size() == in.n_evaluation_points(), + ExcMessage ("Heating outputs need to have the same number of entries as the material model inputs.")); + + const double time_scale = this->convert_output_to_years() ? year_in_seconds : 1.0; + + for (unsigned int q=0; q 0.0 ? log(2.0) / half_life : 0.0; + const double z = in.position[q](1); + heating_model_outputs.rates_of_temperature_change[q] = - decay_constant * z / time_scale * in.composition[q][0]; + + heating_model_outputs.heating_source_terms[q] = 0.0; + heating_model_outputs.lhs_latent_heat_terms[q] = 0.0; + } + } + + + template + void + ExponentialDecayHeating::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Exponential decay heating"); + { + prm.declare_entry ("Half life", "0", + Patterns::Double (0), + "Time required for the temperature to reduce to half of its " + "initial value. Units: Years if the " + "'Use years in output instead of seconds' parameter is set; " + "seconds otherwise."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + ExponentialDecayHeating::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Exponential decay heating"); + { + half_life = prm.get_double ("Half life"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + + + template + class RefFunction : public Function + { + public: + RefFunction () : Function(dim+3) {} + + void vector_value (const Point &p, + Vector &values) const override + { + double x = p(0); + double z = p(1); + double t = this->get_time(); + + values[0] = 0.0; // velocity x + values[1] = 0.0; // velocity z + values[2] = 0.0; // pressure + values[3] = sin(2*numbers::PI*(x-t*0.01))*exp(-log(2.0)/10.0*z*t); // temperature + values[4] = sin(2*numbers::PI*(x-t*0.01))*exp(-log(2.0)/10.0*z*t); // composition + } + }; + + + + template + class ExponentialDecayBoundary : public BoundaryComposition::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Return the boundary composition as a function of position. + */ + double + boundary_composition (const types::boundary_id boundary_indicator, + const Point &position, + const unsigned int compositional_field) const override; + }; + + + template + double + ExponentialDecayBoundary:: + boundary_composition (const types::boundary_id /*boundary_indicator*/, + const Point &p, + const unsigned int /*compositional_field*/) const + { + double x = p(0); + double z = p(1); + const double time_scale = this->convert_output_to_years() ? year_in_seconds : 1.0; + + double t = this->get_time() / time_scale; + + return sin(2*numbers::PI*(x-t*0.01))*exp(-log(2.0)/10.0*z*t); + } + + + + template + class ExponentialDecayBoundaryTemperature : public BoundaryTemperature::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Return the boundary composition as a function of position. + */ + double + boundary_temperature (const types::boundary_id boundary_indicator, + const Point &position) const override; + + double minimal_temperature (const std::set &fixed_boundary_ids) const override; + + double maximal_temperature (const std::set &fixed_boundary_ids) const override; + }; + + + template + double + ExponentialDecayBoundaryTemperature:: + boundary_temperature (const types::boundary_id /*boundary_indicator*/, + const Point &p) const + { + double x = p(0); + double z = p(1); + const double time_scale = this->convert_output_to_years() ? year_in_seconds : 1.0; + + double t = this->get_time() / time_scale; + + return sin(2*numbers::PI*(x-t*0.01))*exp(-log(2.0)/10.0*z*t); + } + + template + double + ExponentialDecayBoundaryTemperature:: + minimal_temperature (const std::set &/*fixed_boundary_ids*/) const + { + return 0.0; + } + + + + template + double + ExponentialDecayBoundaryTemperature:: + maximal_temperature (const std::set &/*fixed_boundary_ids*/) const + { + return 1.0; + } + + + + /** + * A postprocessor that evaluates the accuracy of the solution + * by using the L2 norm. + */ + template + class ExponentialDecayPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + ExponentialDecayPostprocessor(); + + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &statistics) override; + + double max_error; + double max_error_T; + }; + + template + ExponentialDecayPostprocessor::ExponentialDecayPostprocessor () + { + max_error = 0.0; + max_error_T = 0.0; + } + + template + std::pair + ExponentialDecayPostprocessor::execute (TableHandler & /*statistics*/) + { + AssertThrow (this->n_compositional_fields() == 1, ExcInternalError()); + + RefFunction ref_func; + ref_func.set_time(this->get_time()); + + const QGauss quadrature_formula (this->get_fe().base_element(this->introspection().base_elements.velocities).degree+2); + + const unsigned int n_total_comp = this->introspection().n_components; + + Vector cellwise_errors_composition (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_temperature (this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_C(this->introspection().component_indices.compositional_fields[0], n_total_comp); + ComponentSelectFunction comp_T(this->introspection().component_indices.temperature, n_total_comp); + + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_composition, + quadrature_formula, + VectorTools::L2_norm, + &comp_C); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_temperature, + quadrature_formula, + VectorTools::L2_norm, + &comp_T); + + const double current_error = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_composition, VectorTools::L2_norm); + max_error = std::max(max_error, current_error); + + const double current_error_T = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_temperature, VectorTools::L2_norm); + max_error_T = std::max(max_error_T, current_error_T); + + std::ostringstream os; + os << std::scientific + << "time=" << this->get_time() + << " ndofs= " << this->get_solution().size() + << " C_L2_current= " << current_error + << " C_L2_max= " << max_error + << " T_L2_current= " << current_error_T + << " T_L2_max= " << max_error_T + ; + + return std::make_pair("Errors", os.str()); + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(ExponentialDecay, + "exponential decay", + "A material model that can be derived from any of the other " + "material model and that will replace the reaction rate by a " + "function that models exponential decay. The half life can be " + "chosen as an input parameter.") + } + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(ExponentialDecayHeating, + "exponential decay heating", + "A heating model that will use a model for exponential decay as " + "the heating reaction rate. The half life can be chosen as an " + "input parameter.") + + } + ASPECT_REGISTER_BOUNDARY_COMPOSITION_MODEL(ExponentialDecayBoundary, + "ExponentialDecayBoundary", + "A boundary composition model that prescribes the analytical " + "solution for an initially sinusoidal field that is advected " + "and decays over time.") + + ASPECT_REGISTER_BOUNDARY_TEMPERATURE_MODEL(ExponentialDecayBoundaryTemperature, + "ExponentialDecayBoundary", + "A boundary composition model that prescribes the analytical " + "solution for an initially sinusoidal field that is advected " + "and decays over time.") + + ASPECT_REGISTER_POSTPROCESSOR(ExponentialDecayPostprocessor, + "ExponentialDecayPostprocessor", + "A postprocessor that compares the solution " + "to the analytical solution for exponential decay.") +} diff --git a/benchmarks/operator_splitting/doc/exponential_decay.part.1.prm.bak b/benchmarks/operator_splitting/doc/exponential_decay.part.1.prm.bak new file mode 100644 index 00000000000..767dd3beb7d --- /dev/null +++ b/benchmarks/operator_splitting/doc/exponential_decay.part.1.prm.bak @@ -0,0 +1,15 @@ +set Additional shared libraries = ./libexponential_decay.so +set Dimension = 2 +set Start time = 0 +set End time = 100 + +# We use a new solver scheme option that enables the operator split. +set Nonlinear solver scheme = single Advection, single Stokes +set Use operator splitting = true +set Maximum time step = 10 + +subsection Solver parameters + subsection Operator splitting parameters + set Reaction time step = 0.0005 + end +end diff --git a/benchmarks/operator_splitting/doc/exponential_decay.part.2.prm.bak b/benchmarks/operator_splitting/doc/exponential_decay.part.2.prm.bak new file mode 100644 index 00000000000..7a74c690dce --- /dev/null +++ b/benchmarks/operator_splitting/doc/exponential_decay.part.2.prm.bak @@ -0,0 +1,38 @@ +# Both initial temperature and composition are set to 1, +# and will decay starting from this value. +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = 1.0 + end +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = 1.0 + end +end + +# We choose material and heating models that let temperature +# and composition decay over time, and that is implemented in +# a plugin. +subsection Heating model + set List of model names = exponential decay heating + + subsection Exponential decay heating + set Half life = 10 + end +end + +subsection Material model + set Model name = exponential decay + + subsection Exponential decay + set Half life = 10 + end +end diff --git a/benchmarks/operator_splitting/exponential_decay/exponential_decay.base.prm.bak b/benchmarks/operator_splitting/exponential_decay/exponential_decay.base.prm.bak new file mode 100644 index 00000000000..f2b055294b7 --- /dev/null +++ b/benchmarks/operator_splitting/exponential_decay/exponential_decay.base.prm.bak @@ -0,0 +1,121 @@ +######################################################### +# This is a benchmark case that tests the operator split +# solver scheme, which can use a different time step to +# compute reactions between compositional fields than +# the time step used for advection. +# In this test case, there is no advection, and we start +# from a composition (and temperature) that is 1 everywhere +# in the domain and then decays over time, following the +# equations for exponential decay. + +# We use a plugin that implements the reactions for exponential +# decay. +set Additional shared libraries = ./libexponential_decay.so +set Dimension = 2 +set Start time = 0 +set End time = 100 +set Use years in output instead of seconds = false + +# We use a new solver scheme option that enables the operator split. +set Nonlinear solver scheme = single Advection, single Stokes +set Use operator splitting = true +set Maximum time step = 10 + +# As we split the time-stepping of advection and reactions, +# there are now two different time steps in the model: +# We control the advection time step using the 'Maximum time step' +# parameter (as this benchmark has no driving force, and hence very +# low velocities, we can not use the CFL number), and the reaction +# time step using the 'Reaction time step' parameter. +# We will vary both parameters in different model runs. +subsection Solver parameters + subsection Operator splitting parameters + set Reaction time step = 0.0005 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = 0, 1, 2, 3 +end + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Gravity model + set Model name = vertical +end + +# Both initial temperature and composition are set to 1, +# and will decay starting from this value. +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = 1.0 + end +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = 1.0 + end +end + +# We choose material and heating models that let temperature +# and composition decay over time, and that is implemented in +# a plugin. +subsection Heating model + set List of model names = exponential decay heating + + subsection Exponential decay heating + set Half life = 10 + end +end + +subsection Material model + set Model name = exponential decay + + subsection Exponential decay + set Half life = 10 + end + + subsection Composition reaction model + set Thermal conductivity = 0 + set Thermal expansion coefficient = 1e-4 + set Viscosity = 1e5 + set Density differential for compositional field 1 = 0 + end +end + +# As composition and temperature do not depend on x or y, +# we can use a coarse resolution. +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 3 + set Time steps between mesh refinement = 0 +end + +# We output some statistics about the composition, and make +# use of a postprocessor that computes errors compared to the +# analytical solution for exponential decay. +subsection Postprocess + set List of postprocessors = composition statistics, visualization, ExponentialDecayPostprocessor + + subsection Visualization + set Time between graphical output = 0 + end +end diff --git a/benchmarks/operator_splitting/exponential_decay/exponential_decay.cc.bak b/benchmarks/operator_splitting/exponential_decay/exponential_decay.cc.bak new file mode 100644 index 00000000000..d856eec21fb --- /dev/null +++ b/benchmarks/operator_splitting/exponential_decay/exponential_decay.cc.bak @@ -0,0 +1,402 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + template + class ExponentialDecay : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + static void declare_parameters (ParameterHandler &prm); + + void parse_parameters(ParameterHandler &prm) override; + + bool is_compressible () const override; + + void create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + private: + + /** + * Pointer to the material model used as the base model + */ + std::unique_ptr> base_model; + + /** + * Parameter determining the decay rate. + */ + double half_life; + }; + } + + namespace HeatingModel + { + using namespace dealii; + + template + class ExponentialDecayHeating : public HeatingModel::Interface, public ::aspect::SimulatorAccess + { + public: + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + static void declare_parameters (ParameterHandler &prm); + + void parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Parameter determining the decay rate. + */ + double half_life; + }; + } +} + +namespace aspect +{ + namespace MaterialModel + { + template + bool + ExponentialDecay:: + is_compressible () const + { + return base_model->is_compressible(); + } + + + template + void + ExponentialDecay:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + AssertThrow(this->introspection().n_compositional_fields == 1, + ExcMessage("Exponential decay model needs exactly one compositional field.")); + + // Fill material model outputs using the base model. + base_model->evaluate(in,out); + const double time_scale = this->convert_output_to_years() ? year_in_seconds : 1.0; + + for (unsigned int q=0; q < in.n_evaluation_points(); ++q) + for (unsigned int c=0; c < this->introspection().n_compositional_fields; ++c) + out.reaction_terms[q][c] = 0.0; + + // fill melt reaction rates if they exist + ReactionRateOutputs *reaction_out = out.template get_additional_output>(); + + if (reaction_out != nullptr) + { + for (unsigned int q=0; q < in.n_evaluation_points(); ++q) + { + // dC/dt = - lambda * C + const double decay_constant = half_life > 0.0 ? log(2.0) / half_life : 0.0; + reaction_out->reaction_rates[q][0] = - decay_constant / time_scale * in.composition[q][0]; + } + } + } + + + template + void + ExponentialDecay::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Exponential decay"); + { + prm.declare_entry("Base model","composition reaction", + Patterns::Selection(MaterialModel::get_valid_model_names_pattern()), + "The name of a material model that will be modified by a position " + "dependent melting rate. Valid values for this parameter " + "are the names of models that are also valid for the " + "``Material models/Model name'' parameter. See the documentation for " + "that for more information."); + prm.declare_entry ("Half life", "0", + Patterns::Double (0), + "Time required for a compositional field to reduce to half its " + "initial value. Units: Years if the " + "'Use years in output instead of seconds' parameter is set; " + "seconds otherwise."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + ExponentialDecay:: + parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Exponential decay"); + { + AssertThrow( prm.get("Base model") != "reaction rate function", + ExcMessage("You may not use ``reaction rate function'' as the base model for " + "a reaction rate function model.") ); + + // create the base model and initialize its SimulatorAccess base + // class; it will get a chance to read its parameters below after we + // leave the current section + base_model = create_material_model(prm.get("Base model")); + if (auto s = dynamic_cast*>(base_model.get())) + s->initialize_simulator (this->get_simulator()); + + half_life = prm.get_double ("Half life"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // After parsing the parameters for the exponential decay material model, + // also parse the parameters related to the base model. + base_model->parse_parameters(prm); + this->model_dependence = base_model->get_model_dependence(); + } + + + template + void + ExponentialDecay::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points, this->n_compositional_fields())); + } + } + } + + + + namespace HeatingModel + { + template + void + ExponentialDecayHeating:: + evaluate (const MaterialModel::MaterialModelInputs &in, + const MaterialModel::MaterialModelOutputs & /*out*/, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + Assert(heating_model_outputs.heating_source_terms.size() == in.n_evaluation_points(), + ExcMessage ("Heating outputs need to have the same number of entries as the material model inputs.")); + + const double time_scale = this->convert_output_to_years() ? year_in_seconds : 1.0; + + for (unsigned int q=0; q 0.0 ? log(2.0) / half_life : 0.0; + heating_model_outputs.rates_of_temperature_change[q] = - decay_constant / time_scale * in.composition[q][0]; + + heating_model_outputs.heating_source_terms[q] = 0.0; + heating_model_outputs.lhs_latent_heat_terms[q] = 0.0; + } + } + + + template + void + ExponentialDecayHeating::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Exponential decay heating"); + { + prm.declare_entry ("Half life", "0", + Patterns::Double (0), + "Time required for the temperature to reduce to half of its " + "initial value. Units: Years if the " + "'Use years in output instead of seconds' parameter is set; " + "seconds otherwise."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + ExponentialDecayHeating::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Exponential decay heating"); + { + half_life = prm.get_double ("Half life"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + + + + template + class RefFunction : public Function + { + public: + RefFunction () : Function(dim+3) {} + void vector_value (const Point &/*position*/, + Vector &values) const override + { + values[0] = 0.0; // velocity x + values[1] = 0.0; // velocity z + values[2] = 0.0; // pressure + values[3] = exp(-log(2.0)/10.0*this->get_time()); // temperature + values[4] = exp(-log(2.0)/10.0*this->get_time()); // composition + } + }; + + + + /** + * A postprocessor that evaluates the accuracy of the solution + * by using the L2 norm. + */ + template + class ExponentialDecayPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + ExponentialDecayPostprocessor(); + + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &statistics) override; + + double max_error; + double max_error_T; + }; + + template + ExponentialDecayPostprocessor::ExponentialDecayPostprocessor () + { + max_error = 0.0; + max_error_T = 0.0; + } + + template + std::pair + ExponentialDecayPostprocessor::execute (TableHandler & /*statistics*/) + { + AssertThrow (this->n_compositional_fields() == 1, ExcInternalError()); + + RefFunction ref_func; + ref_func.set_time(this->get_time()); + + const QGauss quadrature_formula (this->get_fe().base_element(this->introspection().base_elements.velocities).degree+2); + + const unsigned int n_total_comp = this->introspection().n_components; + + Vector cellwise_errors_composition (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_temperature (this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_C(this->introspection().component_indices.compositional_fields[0], n_total_comp); + ComponentSelectFunction comp_T(this->introspection().component_indices.temperature, n_total_comp); + + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_composition, + quadrature_formula, + VectorTools::L2_norm, + &comp_C); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_temperature, + quadrature_formula, + VectorTools::L2_norm, + &comp_T); + + const double current_error = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_composition, VectorTools::L2_norm); + max_error = std::max(max_error, current_error); + + const double current_error_T = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_temperature, VectorTools::L2_norm); + max_error_T = std::max(max_error_T, current_error_T); + + std::ostringstream os; + os << std::scientific + << "time=" << this->get_time() + << " ndofs= " << this->get_solution().size() + << " C_L2_current= " << current_error + << " C_L2_max= " << max_error + << " T_L2_current= " << current_error_T + << " T_L2_max= " << max_error_T + ; + + return std::make_pair("Errors", os.str()); + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(ExponentialDecay, + "exponential decay", + "A material model that can be derived from any of the other " + "material model and that will replace the reaction rate by a " + "function that models exponential decay. The half life can be " + "chosen as an input parameter.") + + } + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(ExponentialDecayHeating, + "exponential decay heating", + "A heating model that will use a model for exponential decay as " + "the heating reaction rate. The half life can be chosen as an " + "input parameter.") + + } + ASPECT_REGISTER_POSTPROCESSOR(ExponentialDecayPostprocessor, + "ExponentialDecayPostprocessor", + "A postprocessor that compares the solution " + "to the analytical solution for exponential decay.") +} diff --git a/benchmarks/particle_integration_scheme/circle.prm b/benchmarks/particle_integration_scheme/circle.prm index 83ac384ab47..3b7a17da328 100644 --- a/benchmarks/particle_integration_scheme/circle.prm +++ b/benchmarks/particle_integration_scheme/circle.prm @@ -5,7 +5,7 @@ set Use years in output instead of seconds = false set CFL number = 1.0 set Output directory = circle_euler_1.0 set Timing output frequency = 100 -set Nonlinear solver scheme = Advection only +set Nonlinear solver scheme = single Advection, no Stokes subsection Geometry model set Model name = box diff --git a/benchmarks/particle_integration_scheme/circle.prm.bak b/benchmarks/particle_integration_scheme/circle.prm.bak new file mode 100644 index 00000000000..83ac384ab47 --- /dev/null +++ b/benchmarks/particle_integration_scheme/circle.prm.bak @@ -0,0 +1,78 @@ +set Dimension = 2 +set Start time = 0 +set End time = 1.0 +set Use years in output instead of seconds = false +set CFL number = 1.0 +set Output directory = circle_euler_1.0 +set Timing output frequency = 100 +set Nonlinear solver scheme = Advection only + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 4 + set Y extent = 4 + set Box origin X coordinate = -2 + set Box origin Y coordinate = -2 + end +end + +subsection Prescribed Stokes solution + set Model name = function + + subsection Velocity function + set Variable names = x,y,t + set Function expression = 2 * pi * (1+0.0*sin(t))*-y; 2 * pi * (1+0.0*sin(t))*x + end +end + +subsection Initial temperature model + set Model name = function +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0 + end +end + +subsection Material model + set Model name = simple +end + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, particles + + subsection Visualization + set Output format = vtu + set Time between graphical output = 1 + end + + subsection Particles + set Time between data output = 0.1 + set Data output format = ascii + end +end + +subsection Particles + set Particle generator name = ascii file + set Integration scheme = rk2 + + subsection Generator + subsection Ascii file + set Data directory = $ASPECT_SOURCE_DIR/benchmarks/particle_integration_scheme/ + set Data file name = particle.dat + end + end +end diff --git a/benchmarks/particle_integration_scheme/euler.part.prm.bak b/benchmarks/particle_integration_scheme/euler.part.prm.bak new file mode 100644 index 00000000000..bc430c393c8 --- /dev/null +++ b/benchmarks/particle_integration_scheme/euler.part.prm.bak @@ -0,0 +1,6 @@ +subsection Postprocess +end + +subsection Particles + set Integration scheme = euler +end diff --git a/benchmarks/particle_integration_scheme/rk2.part.prm.bak b/benchmarks/particle_integration_scheme/rk2.part.prm.bak new file mode 100644 index 00000000000..f68ef89b515 --- /dev/null +++ b/benchmarks/particle_integration_scheme/rk2.part.prm.bak @@ -0,0 +1,6 @@ +subsection Postprocess +end + +subsection Particles + set Integration scheme = rk2 +end diff --git a/benchmarks/particle_integration_scheme/rk4.part.prm.bak b/benchmarks/particle_integration_scheme/rk4.part.prm.bak new file mode 100644 index 00000000000..1158abaf34f --- /dev/null +++ b/benchmarks/particle_integration_scheme/rk4.part.prm.bak @@ -0,0 +1,6 @@ +subsection Postprocess +end + +subsection Particles + set Integration scheme = rk4 +end diff --git a/benchmarks/polydiapirs/polydiapirs.prm.bak b/benchmarks/polydiapirs/polydiapirs.prm.bak new file mode 100644 index 00000000000..b473530e640 --- /dev/null +++ b/benchmarks/polydiapirs/polydiapirs.prm.bak @@ -0,0 +1,96 @@ +# This is the setup of a polydiapirs experiment, i.e. +# multiwavelength gravity structures. +# It consists of three layers of Newtonian fluids +# set in motion by gravitational instability, as in +# case II of Weinberg and Schmeling 1992. + +set Dimension = 2 +set Start time = 0 +set End time = 250 +set Use years in output instead of seconds = false +set CFL number = 1. +set Maximum time step = 0.1 +set Output directory = output_polydiapirs + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2.24 + set Y extent = 1.0000 + set X repetitions = 2 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right,top + set Zero velocity boundary indicators = bottom +end + +subsection Material model + set Model name = multicomponent + + subsection Multicomponent + set Densities = 100, 90, 89 + set Viscosities = 100, 1, 1 + set Viscosity averaging scheme = harmonic + set Thermal expansivities = 0 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +############### Parameters describing the temperature field +# Note: The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the compositional field +# Note: The compositional field is what drives the flow +# in this example + +subsection Compositional fields + set Number of fields = 2 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = if( (z< 0.25 + (rand()-0.5)/5000. && z>=0.125+(rand()-0.5)/5000.) ,1 , 0 ) ; if (z<0.125+(rand ()-0.5)/5000., 1 , 0) + end +end + +############### Parameters describing the discretization + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Strategy = composition + set Initial global refinement = 7 + set Time steps between mesh refinement = 0 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, composition statistics, material statistics, global statistics, Stokes residual + + subsection Visualization + set List of output variables = viscosity,density, strain rate + set Output format = vtu + set Time between graphical output = 5 + end +end diff --git a/benchmarks/rayleigh_taylor_instability/blank.prm.bak b/benchmarks/rayleigh_taylor_instability/blank.prm.bak new file mode 100644 index 00000000000..51699401b79 --- /dev/null +++ b/benchmarks/rayleigh_taylor_instability/blank.prm.bak @@ -0,0 +1,52 @@ +set Additional shared libraries = ./librayleigh_taylor_instability.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output +set Pressure normalization = volume +set Use years in output instead of seconds = false + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 512e3 + set Y extent = 512e3 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right + set Zero velocity boundary indicators = bottom, top +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +############### Parameters describing the temperature field +# Note: The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics + + subsection Visualization + set Output format = vtu + set Time between graphical output = 0 + set List of output variables = density, viscosity, strain rate + end +end diff --git a/benchmarks/rayleigh_taylor_instability/rayleigh_taylor_instability.cc.bak b/benchmarks/rayleigh_taylor_instability/rayleigh_taylor_instability.cc.bak new file mode 100644 index 00000000000..879c094ac89 --- /dev/null +++ b/benchmarks/rayleigh_taylor_instability/rayleigh_taylor_instability.cc.bak @@ -0,0 +1,199 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace RTinstabilityBenchmark + { + using namespace dealii; + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @ingroup MaterialModels + */ + template + class RTinstabilityMaterial : public MaterialModel::Interface + { + public: + /** + * @name Physical parameters used in the basic equations + * @{ + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const Point &pos = in.position[i]; + + if ( pos[1]< 256e3 + amplitude*std::cos(pos[0]/lambda*2.0*numbers::PI)) + { + out.viscosities[i] = eta2; + out.densities[i] = rho2; + } + else + { + out.viscosities[i] = eta1; + out.densities[i] = rho1; + } + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + } + } + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + * Incompressibility does not necessarily imply that the density is + * constant; rather, it may still depend on temperature or pressure. + * In the current context, compressibility means whether we should + * solve the continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("RTinstability"); + { + prm.declare_entry ("eta1", "1e21", + Patterns::Double (0), + "Viscosity of the mantle."); + prm.declare_entry ("eta2", "1e23", + Patterns::Double (0), + "Viscosity in the inclusion."); + prm.declare_entry ("rho1", "3200", + Patterns::Double (0), + "density of the mantle."); + prm.declare_entry ("rho2", "3232", + Patterns::Double (0), + "density in the inclusion."); + prm.declare_entry ("amplitude", "1000", + Patterns::Double (0), + "perturbation amplitude."); + prm.declare_entry ("lambda", "256e3", + Patterns::Double (0), + "perturbation wavelength."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("RTinstability"); + { + eta1 = prm.get_double ("eta1"); + eta2 = prm.get_double ("eta2"); + rho1 = prm.get_double ("rho1"); + rho2 = prm.get_double ("rho2"); + amplitude = prm.get_double ("amplitude"); + lambda = prm.get_double ("lambda"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + private: + double eta1; + double eta2; + double rho1; + double rho2; + double amplitude; + double lambda; + + }; + + + template + bool + RTinstabilityMaterial:: + is_compressible () const + { + return false; + } + + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace RTinstabilityBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(RTinstabilityMaterial, + "RTinstabilityMaterial", + "A material model that corresponds to the `RTinstability' benchmark. " + "See the manual for more information.") + } +} diff --git a/benchmarks/rayleigh_taylor_instability/rayleigh_taylor_instability.prm.bak b/benchmarks/rayleigh_taylor_instability/rayleigh_taylor_instability.prm.bak new file mode 100644 index 00000000000..7a0a18a736a --- /dev/null +++ b/benchmarks/rayleigh_taylor_instability/rayleigh_taylor_instability.prm.bak @@ -0,0 +1,75 @@ +set Additional shared libraries = ./librayleigh_taylor_instability.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output +set Pressure normalization = volume +set Use years in output instead of seconds = false + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 512e3 + set Y extent = 512e3 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right + set Zero velocity boundary indicators = bottom, top +end + +subsection Material model + set Model name = RTinstabilityMaterial + + subsection RTinstability + set eta1 = 1e21 + set eta2 = 1e21 + set rho1 = 3300 + set rho2 = 3000 + set amplitude = 4000 + set lambda = 256e3 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +############### Parameters describing the temperature field +# Note: The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the discretization + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 6 + set Strategy = density + set Refinement fraction = 0.5 + set Run postprocessors on initial refinement = true +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics + + subsection Visualization + set Output format = vtu + set Time between graphical output = 0 + set List of output variables = density, viscosity, strain rate + end +end diff --git a/benchmarks/rayleigh_taylor_instability_free_surface/kaus_rayleigh_taylor_instability.prm b/benchmarks/rayleigh_taylor_instability_free_surface/kaus_rayleigh_taylor_instability.prm index 08f66c0330c..96cbf4deadc 100644 --- a/benchmarks/rayleigh_taylor_instability_free_surface/kaus_rayleigh_taylor_instability.prm +++ b/benchmarks/rayleigh_taylor_instability_free_surface/kaus_rayleigh_taylor_instability.prm @@ -27,9 +27,9 @@ subsection Discretization set Use discontinuous composition discretization = true subsection Stabilization parameters - set Use limiter for discontinuous composition solution = true set Global composition maximum = 1 set Global composition minimum = 0 + set Limiter for discontinuous composition solution = bound preserving end end diff --git a/benchmarks/rayleigh_taylor_instability_free_surface/kaus_rayleigh_taylor_instability.prm.bak b/benchmarks/rayleigh_taylor_instability_free_surface/kaus_rayleigh_taylor_instability.prm.bak new file mode 100644 index 00000000000..08f66c0330c --- /dev/null +++ b/benchmarks/rayleigh_taylor_instability_free_surface/kaus_rayleigh_taylor_instability.prm.bak @@ -0,0 +1,158 @@ +# Input file for the 2D Rayleigh Taylor benchmark described +# in Kaus et al. (2010, 10.1016/j.pepi.2010.04.007). +# The benchmark considers a denser, more viscous layer +# overlying lighter, less viscous mantle. The interface +# between the layers is perturbed, leading to drips along +# the vertical domain boundaries. A free surface allows +# for the development of surface topography. + +############### Global parameters +set Dimension = 2 +set Start time = 0 +set End time = 6e6 + +# For a timestep of 2500 yr and no stabilization, +# the model is stable. For a timestep of 10000 yr, +# it is not ("drunken sailor"). +set Maximum time step = 100e2 +set Use years in output instead of seconds = true +set CFL number = 0.5 +set Output directory = output_nostab_10000 +set Nonlinear solver scheme = single Advection, single Stokes +set Pressure normalization = no + +############## Element types +# Use dicontinuous composition elements for a sharp interface +subsection Discretization + set Use discontinuous composition discretization = true + + subsection Stabilization parameters + set Use limiter for discontinuous composition solution = true + set Global composition maximum = 1 + set Global composition minimum = 0 + end +end + +############### Geometry +# We consider a 2D box of 500x500 km +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 500e3 + set Y extent = 500e3 + end +end + +############### Boundary conditions +# Vertical boundaries are free slip, +# the bottom boundary is no slip, +# and the top boundary is a free surface. + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right + set Zero velocity boundary indicators = bottom +end + +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + set Additional tangential mesh velocity boundary indicators = left, right + + subsection Free surface + # We test the stability of the free surface + # for a timestep of 2500 and 10000 yr with + # (0.5) and without (0.0) stabilization. + set Free surface stabilization theta = 0.0 + + # We compare the vertical and normal projection of + # the free surface. + #set Surface velocity projection = normal + set Surface velocity projection = vertical + end +end + +############### Material properties +# No temperature effects. +# The top layer is denser and more viscous. +subsection Material model + set Model name = simple + + subsection Simple model + set Viscosity = 1.0e20 + set Composition viscosity prefactor = 10 + set Reference temperature = 1.0 + set Reference density = 3200.0 + set Density differential for compositional field 1 = 100 + set Thermal expansion coefficient = 0.0 + set Thermal conductivity = 2.7 + set Reference specific heat = 1250 + end +end + +############## Gravity +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +############### Parameters describing the temperature field +# We ignore any temperature effects. +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom, left, right + set List of model names = initial temperature +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the compositional fields +# We include one compositional field plus the background material. +# The material interface is sinusoidally perturbed with an amplitude +# A of 5 km. + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Function constants = A=5000, W=250e3, C=250e3 + set Function expression = if(y>400e3+A*cos(pi*(x-C)/W),1,0) + end +end + +############### Mesh refinement +# The Kaus paper considers a resolution of 50x50 elements. +# We use 64x64. +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 6 + set Time steps between mesh refinement = 0 +end + +############### Parameters describing what to do with the solution +# We monitor the topography over time. +subsection Postprocess + set List of postprocessors = visualization, topography, composition statistics, maximum depth of field, velocity statistics + + subsection Visualization + set Time between graphical output = 1.0e5 + set List of output variables = viscosity, density + set Output mesh velocity = true + end + + subsection Topography + set Output to file = true + set Time between text output = 2.e5 + end +end diff --git a/benchmarks/rayleigh_taylor_instability_free_surface/rose_rayleigh_taylor_instability.prm.bak b/benchmarks/rayleigh_taylor_instability_free_surface/rose_rayleigh_taylor_instability.prm.bak new file mode 100644 index 00000000000..fad2de9f2ff --- /dev/null +++ b/benchmarks/rayleigh_taylor_instability_free_surface/rose_rayleigh_taylor_instability.prm.bak @@ -0,0 +1,49 @@ +# Input file for the 2D Rayleigh Taylor benchmark described +# in Rose et al. (2017, 10.1016/j.pepi.2016.11.007). +# The benchmark considers a denser, more viscous layer +# overlying lighter, less viscous mantle. The interface +# between the layers is perturbed, leading to drips along +# the vertical domain boundaries. A free surface allows +# for the development of surface topography. +# Compared to the setup in Kaus et al. (2010), the resolution +# of the layer interface is higher and therefore a timestep +# of 5000 yr is still stable without free surface stabilization, +# while a timestep of 10,000 yr is not. + +############### Global parameters +set Dimension = 2 + +include $ASPECT_SOURCE_DIR/benchmarks/rayleigh_taylor_instability_free_surface/kaus_rayleigh_taylor_instability.prm + +set Start time = 0 +set Maximum time step = 1e5 +set End time = 6e6 +set CFL number = 0.2 +set Output directory = output_Rose_stab_CFL02 + +############### Boundary conditions +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + set Additional tangential mesh velocity boundary indicators = left, right + + subsection Free surface + set Free surface stabilization theta = 0.5 + set Surface velocity projection = vertical + end +end + +############### Mesh refinement +# The Rose et al. (2017) paper considers a maximum local resolution +# of ~1 km by using global and adaptive mesh refinement. +subsection Mesh refinement + set Initial adaptive refinement = 4 + set Initial global refinement = 5 + set Refinement fraction = 0.95 + set Coarsening fraction = 0.05 + set Strategy = composition, boundary + set Time steps between mesh refinement = 5 + + subsection Boundary + set Boundary refinement indicators = top + end +end diff --git a/benchmarks/rigid_shear/instantaneous/rigid_shear.prm.bak b/benchmarks/rigid_shear/instantaneous/rigid_shear.prm.bak new file mode 100644 index 00000000000..a60074dacad --- /dev/null +++ b/benchmarks/rigid_shear/instantaneous/rigid_shear.prm.bak @@ -0,0 +1,87 @@ +# A description of the "Rigid shear" benchmark for which a known solution +# is available. See Gassmoeller et al. "Evaluating +# the Accuracy of Hybrid Finite Element/Particle-In-Cell Methods for +# Modeling Incompressible Stokes Flow" for a discussion. + +set Additional shared libraries = ../plugin/librigid_shear.so +set Dimension = 2 +set End time = 0.0 +set Output directory = output +set Pressure normalization = no +set Nonlinear solver scheme = no Advection, single Stokes +set Use years in output instead of seconds = false + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Compositional fields + set Names of fields = density_comp + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Function expression = sin(pi*x)*sin(pi*y) + 2.0 + end +end + +subsection Material model + set Model name = rigid shear +end + +subsection Rigid shear benchmark + set Use analytical density = true + set Use transient solution = false +end + +subsection Gravity model + set Model name = rigid shear +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = + set List of model names = +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = (x<0.5) ? 0.4 : 0.6 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, rigid shear + + subsection Visualization + set Time between graphical output = 0.0 + set List of output variables = material properties + end +end + +# Increase Stokes solver accuracy to ensure convergence to +# very low error values +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + end +end diff --git a/benchmarks/rigid_shear/plugin/rigid_shear.cc.bak b/benchmarks/rigid_shear/plugin/rigid_shear.cc.bak new file mode 100644 index 00000000000..903b0ce97ee --- /dev/null +++ b/benchmarks/rigid_shear/plugin/rigid_shear.cc.bak @@ -0,0 +1,378 @@ +/* + Copyright (C) 2019 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + + +namespace aspect +{ + using namespace dealii; + + namespace RigidShearBenchmark + { + /** + * This is the "Rigid shear" benchmark based on a suggestion in the following paper: + * @code + * @Article{KKSCND97, + * author = {P. E. van Keken and S. D. King and H. Schmeling and U. R. Christensen and D. Neumeister and M.-P. Doin}, + * title = {A comparison of methods for the modeling of thermochemical convection}, + * journal = {J. Geoph. Res.}, + * year = 1997, + * volume = 102, + * pages = {22477--22495}} + * @endcode + * + * The results of the modification are published in Gassmoeller, + * Lokavarapu, Bangerth, Puckett, 2019, "Evaluating the Accuracy of Hybrid + * Finite Element/Particle-In-Cell Methods for Modeling Incompressible + * Stokes Flow". + */ + namespace AnalyticSolutions + { + double + phase_function(const double t) + { + return std::exp(t)-1.; + } + + template + double + density(const Point &p, + const double t, + const bool transient) + { + const double pi = numbers::PI; + const double phase = (transient == true) ? phase_function(t) : 0.0; + + return std::sin(pi*(p[0]-phase)) * std::sin(pi*p[1]) + 2.0; + } + + /** + * The exact solution for the Rigid Shear benchmark. + */ + template + class FunctionRigidShear : public Function + { + public: + FunctionRigidShear(const unsigned int n_components, + const bool transient) + : Function(n_components), + transient(transient) {} + + void vector_value(const Point &p, + Vector &values) const override + { + const double pi = numbers::PI; + const double t = this->get_time(); + const double phase = (transient == true) ? phase_function(t) : 0.0; + + values[0] = std::sin(pi*(p[0]-phase)) * std::cos(pi*p[1]); + + if (transient == true) + values[0] += std::exp(t); + + values[1] = -std::cos(pi*(p[0]-phase)) * std::sin(pi*p[1]); + values[2] = 2.0 * pi * std::cos(pi*(p[0]-phase)) * std::cos(pi*p[1]); + values[4] = density(p,t,transient); + return; + } + + private: + bool transient; + }; + } + + + + /** + * A material model for the stationary form of the rigid shear benchmark. All properties + * are defined in dependence of position. + */ + template + class RigidShearMaterial : public MaterialModel::Interface, public SimulatorAccess + { + public: + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + const double t = (this->simulator_is_past_initialization()) ? this->get_time() : 0.0; + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + if (use_analytical_density == true) + out.densities[i] = AnalyticSolutions::density(in.position[i],t,use_transient_flow_solution); + else + out.densities[i] = in.composition[i][0]; + + out.viscosities[i] = 1.0; + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0.0; + out.thermal_conductivities[i] = 0.0; + + for (unsigned int c=0; c to use as density."); + + prm.declare_entry("Use transient solution", "false", + Patterns::Bool(), + "Whether to use the transient flow solution, or to use the " + "default steady-state solution."); + } + prm.leave_subsection(); + } + + void + parse_parameters(ParameterHandler &prm) override + { + prm.enter_subsection("Rigid shear benchmark"); + { + use_analytical_density = prm.get_bool ("Use analytical density"); + use_transient_flow_solution = prm.get_bool ("Use transient solution"); + } + prm.leave_subsection(); + + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + bool use_analytical_density; + bool use_transient_flow_solution; + }; + + + + + /** + * Gravity model for the Rigid shear benchmark + */ + template + class RigidShearGravity : public aspect::GravityModel::Interface, public aspect::SimulatorAccess + { + public: + Tensor<1,dim> gravity_vector (const Point &pos) const override + { + const double pi = numbers::PI; + const double t = (this->simulator_is_past_initialization()) ? this->get_time() : 0.0; + + const RigidShearMaterial & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + const bool transient = material_model.use_transient_solution(); + const double phase = (transient == true) ? AnalyticSolutions::phase_function(t) : 0.0; + + const double forcing_term = - 4.0 * pi * pi * std::cos(pi*(pos[0] - phase)) * std::sin(pi*pos[1]); + + Tensor<1,dim> gravity; + gravity[0] = 0.0; + gravity[1] = forcing_term / AnalyticSolutions::density(pos,t,transient); + + return gravity; + } + }; + + /** + * A postprocessor that evaluates the accuracy of the solution. + * + * The implementation of error evaluators that correspond to the + * benchmarks defined in the paper Gassmoeller et al. referenced above. + */ + template + class RigidShearPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Generate error output for velocity, pressure, and density. + */ + std::pair + execute(TableHandler &statistics) override + { + const RigidShearMaterial & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + AnalyticSolutions::FunctionRigidShear ref_func(this->introspection().n_components, + material_model.use_transient_solution()); + ref_func.set_time(this->get_time()); + + AssertThrow(Plugins::plugin_type_matches>(this->get_material_model()), + ExcMessage( + "Postprocessor RigidShearPostprocessor only works with the material model RigidShearMaterial.")); + + const QGauss quadrature_formula(this->introspection().polynomial_degree.velocities + 2); + + Vector cellwise_errors_u(this->get_triangulation().n_active_cells()); + Vector cellwise_errors_p(this->get_triangulation().n_active_cells()); + Vector cellwise_errors_ul2(this->get_triangulation().n_active_cells()); + Vector cellwise_errors_pl2(this->get_triangulation().n_active_cells()); + Vector cellwise_errors_rhol2(this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_u(std::pair(0, dim), + this->get_fe().n_components()); + ComponentSelectFunction comp_p(dim, + this->get_fe().n_components()); + ComponentSelectFunction comp_rho(dim+2, + this->get_fe().n_components()); + + VectorTools::integrate_difference(this->get_mapping(), this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_u, + quadrature_formula, + VectorTools::L1_norm, + &comp_u); + VectorTools::integrate_difference(this->get_mapping(), this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_p, + quadrature_formula, + VectorTools::L1_norm, + &comp_p); + VectorTools::integrate_difference(this->get_mapping(), this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_ul2, + quadrature_formula, + VectorTools::L2_norm, + &comp_u); + VectorTools::integrate_difference(this->get_mapping(), this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_pl2, + quadrature_formula, + VectorTools::L2_norm, + &comp_p); + VectorTools::integrate_difference(this->get_mapping(), this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_rhol2, + quadrature_formula, + VectorTools::L2_norm, + &comp_rho); + + const double u_l1 = Utilities::MPI::sum(cellwise_errors_u.l1_norm(), this->get_mpi_communicator()); + const double p_l1 = Utilities::MPI::sum(cellwise_errors_p.l1_norm(), this->get_mpi_communicator()); + const double u_l2 = std::sqrt( + Utilities::MPI::sum(cellwise_errors_ul2.norm_sqr(), this->get_mpi_communicator())); + const double p_l2 = std::sqrt( + Utilities::MPI::sum(cellwise_errors_pl2.norm_sqr(), this->get_mpi_communicator())); + const double rho_l2 = std::sqrt( + Utilities::MPI::sum(cellwise_errors_rhol2.norm_sqr(), this->get_mpi_communicator())); + + statistics.add_value ("u_L2", + u_l2); + statistics.set_precision ("u_L2", 14); + statistics.set_scientific ("u_L2", true); + + statistics.add_value ("p_L2", + p_l2); + statistics.set_precision ("p_L2", 14); + statistics.set_scientific ("p_L2", true); + + statistics.add_value ("rho_L2", + rho_l2); + statistics.set_precision ("rho_L2", 14); + statistics.set_scientific ("rho_L2", true); + + std::ostringstream os; + os << std::scientific << u_l1 + << ", " << p_l1 + << ", " << u_l2 + << ", " << p_l2 + << ", " << rho_l2; + + return std::make_pair("Errors u_L1, p_L1, u_L2, p_L2, rho_L2:", os.str()); + } + }; + } +} + +// explicit instantiations +namespace aspect +{ + namespace RigidShearBenchmark + { + ASPECT_REGISTER_GRAVITY_MODEL(RigidShearGravity, + "rigid shear", + "A gravity model.") + + ASPECT_REGISTER_MATERIAL_MODEL(RigidShearMaterial, + "rigid shear", + "A material model for the stationary form of the rigid shear benchmark. All properties " + "are defined in dependence of position.") + + ASPECT_REGISTER_POSTPROCESSOR(RigidShearPostprocessor, + "rigid shear", + "The implementation of error evaluators that correspond to the " + "benchmarks defined in the paper Gassmoeller et al. referenced above.") + } +} diff --git a/benchmarks/rigid_shear/steady-state/rigid_shear.prm.bak b/benchmarks/rigid_shear/steady-state/rigid_shear.prm.bak new file mode 100644 index 00000000000..ec607b5004c --- /dev/null +++ b/benchmarks/rigid_shear/steady-state/rigid_shear.prm.bak @@ -0,0 +1,110 @@ +# A description of the time-dependent "Rigid shear" benchmark for which a known +# solution is available. See Gassmoeller et al. "Evaluating the Accuracy of +# Hybrid Finite Element/Particle-In-Cell Methods for Modeling Incompressible +# Stokes Flow" for a discussion. + +set Additional shared libraries = ../plugin/librigid_shear.so +set Dimension = 2 +set End time = 0.1 +set Output directory = output +set Pressure normalization = no +set Nonlinear solver scheme = single Advection, single Stokes +set Use years in output instead of seconds = false + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Discretization + set Use discontinuous composition discretization = true +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = density_comp + set Compositional field methods = particles + set Mapped particle properties = density_comp:function +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Function expression = sin(pi*x)*sin(pi*y) + 2.0 + end +end + +subsection Material model + set Model name = rigid shear +end + +subsection Rigid shear benchmark + set Use analytical density = false + set Use transient solution = false +end + +subsection Gravity model + set Model name = rigid shear +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = + set List of model names = +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = (x<0.5) ? 0.4 : 0.6 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 3 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, particles, rigid shear + + subsection Visualization + set Time between graphical output = 0.1 + set List of output variables = material properties, gravity + end + + subsection Particles + set Time between data output = 0.1 + set Data output format = vtu + end +end + +subsection Particles + set List of particle properties = function + set Integration scheme = rk2 + set Interpolation scheme = bilinear least squares + set Update ghost particles = true + set Minimum particles per cell = 9 + set Maximum particles per cell = 16384 + set Particle generator name = reference cell + + subsection Function + set Function expression = sin(pi*x)*sin(pi*y) + 2.0 + end + + subsection Generator + subsection Reference cell + set Number of particles per cell per direction = 9 + end + end +end diff --git a/benchmarks/rigid_shear/transient/rigid_shear.prm.bak b/benchmarks/rigid_shear/transient/rigid_shear.prm.bak new file mode 100644 index 00000000000..6ce240c74c3 --- /dev/null +++ b/benchmarks/rigid_shear/transient/rigid_shear.prm.bak @@ -0,0 +1,134 @@ +# A description of the time-dependent "Rigid shear" benchmark for which a known +# solution is available. See Gassmoeller et al. "Benchmarking the accuracy of +# higher order particle methods in geodynamic models of transient flow" for a +# discussion. + +set Additional shared libraries = ../plugin/librigid_shear.so +set Dimension = 2 +set End time = 1.098612289 +set Output directory = output +set Pressure normalization = volume +set Nonlinear solver scheme = single Advection, single Stokes +set Use years in output instead of seconds = false + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set X repetitions = 2 + set Y extent = 1 + set X periodic = true + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + + #set Stokes solver type = block GMG + set Krylov method for cheap solver steps = IDR(s) + end +end + +subsection Discretization + set Use discontinuous composition discretization = true +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = bottom: function, top: function + + subsection Function + set Function expression = sin(pi*(x-exp(t)+1))*cos(pi*y) + exp(t); 0 + end +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = density_comp + + #set Compositional field methods = particles + #set Mapped particle properties = density_comp:function +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Function expression = sin(pi*x)*sin(pi*y) + 2 + end +end + +subsection Material model + set Material averaging = harmonic average only viscosity + set Model name = rigid shear +end + +subsection Rigid shear benchmark + set Use analytical density = false + set Use transient solution = true +end + +subsection Gravity model + set Model name = rigid shear +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = + set List of model names = +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = (x<0.5) ? 0.4 : 0.6 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 3 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, rigid shear + + subsection Visualization + set Time between graphical output = 0.1 + set List of output variables = material properties, gravity + end + + subsection Particles + set Time between data output = 0.1 + set Data output format = vtu + end +end + +subsection Particles + set List of particle properties = function + set Integration scheme = rk2 + set Interpolation scheme = bilinear least squares + set Update ghost particles = true + set Minimum particles per cell = 12 + set Maximum particles per cell = 16384 + set Particle generator name = random uniform + set Load balancing strategy = add particles + + subsection Function + set Function expression = sin(pi*x)*sin(pi*y) + 2 + end + + subsection Interpolator + subsection Quadratic least squares + set Use boundary extrapolation = true + end + end + + subsection Generator + subsection Probability density function + set Number of particles = 8192 + end + end +end diff --git a/benchmarks/shear_bands/magmatic_shear_bands.prm.bak b/benchmarks/shear_bands/magmatic_shear_bands.prm.bak new file mode 100644 index 00000000000..0696dfdb4f9 --- /dev/null +++ b/benchmarks/shear_bands/magmatic_shear_bands.prm.bak @@ -0,0 +1,146 @@ +# Listing of Parameters +# --------------------- +# Set up the magmatic shear bands testcase +# for Newtonian rheology and analyze it using +# the relations given in Spiegelman (2003): +# Linear analysis of melt band formation by +# simple shear, Geochemistry, Geophysics, +# Geosystems, 4(9), 8615. + +set Additional shared libraries = ./libshear_bands.so +set Adiabatic surface temperature = 1623 +set CFL number = 0.5 +set Nonlinear solver scheme = iterated Advection and Stokes +set Output directory = output +set Max nonlinear iterations = 5 +set Nonlinear solver tolerance = 1e-5 +set Dimension = 2 +set End time = 0 +set Pressure normalization = surface +set Surface pressure = 0 +set Resume computation = false +set Start time = 0 +set Use years in output instead of seconds = true + +subsection Discretization + subsection Stabilization parameters + set beta = 0.0005 + end +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = porosity +end + +subsection Boundary composition model + set List of model names = initial composition +end + +# we apply simple shear here, so that the top and bottom boundaries +# move with the same speed u0, but in opposite directions +subsection Boundary velocity model + set Prescribed velocity boundary indicators = 2:function, 3:function + + subsection Function + set Function constants = u0=5e2,ymid=0.0005 + set Function expression = u0*(y/ymid-1.0);0 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 0.004 + set Y extent = 0.001 + set X periodic = true + set X repetitions = 4 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + # Magnitude of the gravity vector in $m/s^2$. The direction is always + # radially outward from the center of the earth. + set Magnitude = 0.0 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function constants = l=64000 + set Function expression = 0.0 + set Variable names = x,y + end +end + +subsection Initial composition model + set Model name = plane wave melt bands initial condition + + subsection Plane wave melt bands initial condition + set Wave amplitude = 1e-4 + set Initial band angle = 30 + set Wave number = 4000 + end +end + +subsection Material model + set Model name = shear bands material + + subsection Shear bands material + set Dislocation creep exponent = 1.0 + set Porosity exponent = -1.0 + set Compaction viscosity exponent = 1.0 + set Permeability exponent = 2 + end +end + +subsection Boundary fluid pressure model + set Plugin name = density + + subsection Density + set Density formulation = solid density + end +end + +subsection Mesh refinement + set Coarsening fraction = 0.0 + set Refinement fraction = 0.0 + set Initial adaptive refinement = 0 + set Initial global refinement = 8 + set Strategy = composition + set Time steps between mesh refinement = 0 +end + +subsection Melt settings + set Include melt transport = true +end + +subsection Postprocess + set List of postprocessors = visualization,composition statistics,velocity statistics, shear bands growth rate + + subsection Visualization + set List of output variables = density, viscosity, thermal expansivity, strain rate, melt material properties + set Number of grouped files = 0 + set Output format = vtu + set Time between graphical output = 0 + + subsection Melt material properties + set List of properties = fluid density, permeability, fluid viscosity, compaction viscosity + end + end +end + +subsection Solver parameters + set Composition solver tolerance = 1e-24 + set Temperature solver tolerance = 1e-20 + + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + end +end diff --git a/benchmarks/shear_bands/shear_bands.cc.bak b/benchmarks/shear_bands/shear_bands.cc.bak new file mode 100644 index 00000000000..370bc5a9afb --- /dev/null +++ b/benchmarks/shear_bands/shear_bands.cc.bak @@ -0,0 +1,846 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace aspect +{ + /** + * This is the "Shear bands" benchmark defined in the following paper: + * @code + * @Article{DMGT11, + * author = {R. F. Katz and M. Spiegelman and B. Holtzman}, + * title = {The dynamics of melt and shear localization in + * partially molten aggregates}, + * journal = {Nature}, + * year = 2006, + * volume = 442, + * pages = {676-679} + * @endcode + * + * Magmatic shear bands are generated by a combination of porosity- and + * strain-rate dependent viscosity in a simple shear regime; and the + * angle of the shear bands is measured. + * + */ + namespace ShearBands + { + using namespace dealii; + + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @ingroup MaterialModels + */ + template + class ShearBandsMaterial : public MaterialModel::MeltInterface, + public ::aspect::SimulatorAccess + { + public: + bool is_compressible () const override + { + return false; + } + + double reference_viscosity () const + { + return eta_0; + } + + double reference_darcy_coefficient () const override + { + return reference_permeability * pow(0.01, permeability_exponent) / eta_f; + } + + + double + get_background_porosity () const; + + double + get_reference_compaction_viscosity () const; + + double + get_porosity_exponent () const; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + void evaluate(const typename MaterialModel::Interface::MaterialModelInputs &in, + typename MaterialModel::Interface::MaterialModelOutputs &out) const override + { + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + const double strain_rate_dependence = (1.0 - dislocation_creep_exponent) / dislocation_creep_exponent; + + for (unsigned int i=0; i shear_strain_rate = in.strain_rate[i] + - 1./dim * trace(in.strain_rate[i]) * unit_symmetric_tensor(); + const double second_strain_rate_invariant = std::sqrt(std::abs(second_invariant(shear_strain_rate))); + + if (std::abs(second_strain_rate_invariant) > 1e-30) + out.viscosities[i] *= std::pow(second_strain_rate_invariant,strain_rate_dependence); + } + + + out.densities[i] = reference_rho_s; + out.thermal_expansion_coefficients[i] = 0.0; + out.specific_heat[i] = 1.0; + out.thermal_conductivities[i] = 0.0; + out.compressibilities[i] = 0.0; + for (unsigned int c=0; c *melt_out = out.template get_additional_output>(); + + if (melt_out != nullptr) + for (unsigned int i=0; icompaction_viscosities[i] = xi_0 * pow(porosity/background_porosity,-compaction_viscosity_exponent); + melt_out->fluid_viscosities[i]= eta_f; + melt_out->permeabilities[i]= reference_permeability * std::pow(porosity,permeability_exponent); + melt_out->fluid_densities[i]= reference_rho_f; + melt_out->fluid_density_gradients[i] = 0.0; + } + } + + private: + double reference_rho_s; + double reference_rho_f; + double eta_0; + double xi_0; + double eta_f; + double reference_permeability; + double dislocation_creep_exponent; + double alpha; + double background_porosity; + double compaction_viscosity_exponent; + double permeability_exponent; + }; + + template + double + ShearBandsMaterial::get_background_porosity () const + { + return background_porosity; + } + + template + double + ShearBandsMaterial::get_reference_compaction_viscosity () const + { + return xi_0; + } + + template + double + ShearBandsMaterial::get_porosity_exponent () const + { + return alpha; + } + + + template + void + ShearBandsMaterial::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Shear bands material"); + { + prm.declare_entry ("Reference solid density", "3000", + Patterns::Double (0), + "Reference density of the solid $\\rho_{s,0}$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference melt density", "3000", + Patterns::Double (0), + "Reference density of the melt/fluid$\\rho_{f,0}$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference shear viscosity", "1.41176e7", + Patterns::Double (0), + "The value of the constant viscosity $\\eta_0$ of the solid matrix. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Reference compaction viscosity", "1.41176e8", + Patterns::Double (0), + "The value of the constant volumetric viscosity $\\xi_0$ of the solid matrix. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Reference melt viscosity", "100.0", + Patterns::Double (0), + "The value of the constant melt viscosity $\\eta_f$. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Reference permeability", "5e-9", + Patterns::Double(), + "Reference permeability of the solid host rock." + "Units: \\si{\\meter\\squared}."); + prm.declare_entry ("Dislocation creep exponent", "6.0", + Patterns::Double(0), + "Power-law exponent $n_{dis}$ for dislocation creep. " + "Units: none."); + prm.declare_entry ("Porosity exponent", "-27.0", + Patterns::Double(), + "Exponent $\alpha$ for the exponential porosity-dependence " + "of the viscosity. " + "Units: none."); + prm.declare_entry ("Background porosity", "0.05", + Patterns::Double (0), + "Background porosity used in the viscosity law. Units: none."); + prm.declare_entry ("Compaction viscosity exponent", "0.0", + Patterns::Double(0), + "Power-law exponent $m$ for the compaction viscosity. " + "Units: none."); + prm.declare_entry ("Permeability exponent", "3.0", + Patterns::Double(0), + "Power-law exponent $n$ for the porosity-dependence of permeability. " + "Units: none."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + ShearBandsMaterial::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Shear bands material"); + { + reference_rho_s = prm.get_double ("Reference solid density"); + reference_rho_f = prm.get_double ("Reference melt density"); + eta_0 = prm.get_double ("Reference shear viscosity"); + xi_0 = prm.get_double ("Reference compaction viscosity"); + eta_f = prm.get_double ("Reference melt viscosity"); + reference_permeability = prm.get_double ("Reference permeability"); + dislocation_creep_exponent = prm.get_double ("Dislocation creep exponent"); + alpha = prm.get_double ("Porosity exponent"); + background_porosity = prm.get_double ("Background porosity"); + compaction_viscosity_exponent = prm.get_double ("Compaction viscosity exponent"); + permeability_exponent = prm.get_double ("Permeability exponent"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + /** + * An initial conditions model for the shear bands benchmark + * that implements a background porosity plus white noise with + * a certain amplitude. + */ + template + class ShearBandsInitialCondition : public InitialComposition::Interface, + public ::aspect::SimulatorAccess + { + public: + + /** + * Return the initial porosity as a function of position. + */ + double + initial_composition (const Point &position, const unsigned int n_comp) const override; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Initialization function. + */ + void + initialize () override; + + private: + double noise_amplitude; + double background_porosity; + std::array grid_intervals; + std::unique_ptr> interpolate_noise; + }; + + + + template + void + ShearBandsInitialCondition::initialize () + { + AssertThrow(Plugins::plugin_type_matches>(this->get_material_model()), + ExcMessage("Initial condition shear bands only works with the material model shear bands.")); + + const ShearBandsMaterial & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + background_porosity = material_model.get_background_porosity(); + + AssertThrow(noise_amplitude < background_porosity, + ExcMessage("Amplitude of the white noise must be smaller " + "than the background porosity.")); + + Point extents; + TableIndices size_idx; + for (unsigned int d=0; d white_noise; + white_noise.TableBase::reinit(size_idx); + std::array,dim> grid_extents; + + AssertThrow(Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage("Initial condition shear bands only works with the box geometry model.")); + + const GeometryModel::Box & + geometry_model + = Plugins::get_plugin_as_type>(this->get_geometry_model()); + + extents = geometry_model.get_extents(); + + for (unsigned int d=0; d idx; + + for (unsigned int i=0; i> (grid_extents, + grid_intervals, + white_noise); + } + + + template + double + ShearBandsInitialCondition:: + initial_composition (const Point &position, const unsigned int /*n_comp*/) const + { + return background_porosity + interpolate_noise->value(position); + } + + + template + void + ShearBandsInitialCondition::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + prm.enter_subsection("Shear bands initial condition"); + { + prm.declare_entry ("Noise amplitude", "0.0005", + Patterns::Double (0), + "Amplitude of the white noise added to the initial " + "porosity. Units: none."); + prm.declare_entry ("Grid intervals for noise X", "100", + Patterns::Integer (0), + "Grid intervals in X directions for the white noise added to " + "the initial background porosity that will then be interpolated " + "to the model grid. " + "Units: none."); + prm.declare_entry ("Grid intervals for noise Y", "25", + Patterns::Integer (0), + "Grid intervals in Y directions for the white noise added to " + "the initial background porosity that will then be interpolated " + "to the model grid. " + "Units: none."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + ShearBandsInitialCondition::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + prm.enter_subsection("Shear bands initial condition"); + { + noise_amplitude = prm.get_double ("Noise amplitude"); + grid_intervals[0] = prm.get_integer ("Grid intervals for noise X"); + grid_intervals[1] = prm.get_integer ("Grid intervals for noise Y"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + /** + * An initial conditions model for the plane wave melt bands benchmark + * that implements a background porosity plus a plave wave in the porosity + * field with a certain amplitude. + */ + template + class PlaneWaveMeltBandsInitialCondition : public InitialComposition::Interface, + public ::aspect::SimulatorAccess + { + public: + + /** + * Return the initial porosity as a function of position. + */ + double + initial_composition (const Point &position, const unsigned int n_comp) const override; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Initialization function. + */ + void + initialize () override; + + double + get_wave_amplitude () const; + + double + get_wave_number () const; + + double + get_initial_band_angle () const; + + private: + double amplitude; + double background_porosity; + double wave_number; + double initial_band_angle; + }; + + + + template + void + PlaneWaveMeltBandsInitialCondition::initialize () + { + AssertThrow(Plugins::plugin_type_matches>(this->get_material_model()), + ExcMessage("Initial condition shear bands only works with the material model shear bands.")); + + const ShearBandsMaterial & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + background_porosity = material_model.get_background_porosity(); + + AssertThrow(amplitude < 1.0, + ExcMessage("Amplitude of the melt bands must be smaller " + "than the background porosity.")); + } + + + template + double + PlaneWaveMeltBandsInitialCondition::get_wave_amplitude () const + { + return amplitude; + } + + template + double + PlaneWaveMeltBandsInitialCondition::get_wave_number () const + { + return wave_number; + } + + template + double + PlaneWaveMeltBandsInitialCondition::get_initial_band_angle () const + { + return initial_band_angle; + } + + + template + double + PlaneWaveMeltBandsInitialCondition:: + initial_composition (const Point &position, const unsigned int /*n_comp*/) const + { + return background_porosity * (1.0 + amplitude * cos(wave_number*position[0]*sin(initial_band_angle) + + wave_number*position[1]*cos(initial_band_angle))); + } + + + template + void + PlaneWaveMeltBandsInitialCondition::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + prm.enter_subsection("Plane wave melt bands initial condition"); + { + prm.declare_entry ("Wave amplitude", "1e-4", + Patterns::Double (0), + "Amplitude of the plane wave added to the initial " + "porosity. Units: none."); + prm.declare_entry ("Wave number", "2000", + Patterns::Double (0), + "Wave number of the plane wave added to the initial " + "porosity. Is multiplied by 2 pi internally. " + "Units: 1/m."); + prm.declare_entry ("Initial band angle", "30", + Patterns::Double (0), + "Initial angle of the plane wave added to the initial " + "porosity. Units: degrees."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + PlaneWaveMeltBandsInitialCondition::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + prm.enter_subsection("Plane wave melt bands initial condition"); + { + amplitude = prm.get_double ("Wave amplitude"); + wave_number = 2.0 * numbers::PI * prm.get_double ("Wave number"); + initial_band_angle = 2.0 * numbers::PI / 360.0 * prm.get_double ("Initial band angle"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + + /** + * A postprocessor that evaluates the angle of the shear bands. + */ + template + class ShearBandsPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &statistics) override; + }; + + + template + std::pair + ShearBandsPostprocessor::execute (TableHandler &/*statistics*/) + { + // write output that can be used to calculate the angle of the shear bands + const unsigned int max_lvl = this->get_triangulation().n_global_levels(); + + std::stringstream output; + output.precision (16); + output << std::scientific; + + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + // write header + output << "x y porosity" << std::endl; + } + + // we want to have equidistant points in the output + const QMidpoint<1> mp_rule; + const QIterated quadrature_formula (mp_rule, 2); + const unsigned int n_q_points = quadrature_formula.size(); + + FEValues fe_values (this->get_mapping(), this->get_fe(), quadrature_formula, + update_JxW_values | update_values | update_quadrature_points); + + std::vector porosity_values (quadrature_formula.size()); + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + + fe_values.reinit (cell); + fe_values[this->introspection().extractors.compositional_fields[porosity_idx]].get_function_values (this->get_solution(), porosity_values); + + for (unsigned int q = 0; q < n_q_points; ++q) + { + output << fe_values.quadrature_point (q) (0) << " " + << fe_values.quadrature_point (q) (1) << " " + << porosity_values[q] << std::endl; + } + } + + std::string filename = this->get_output_directory() + "shear_bands_" + + Utilities::int_to_string(max_lvl) + + ".csv"; + + Utilities::collect_and_write_file_content(filename, output.str(), this->get_mpi_communicator()); + + return std::make_pair("writing:", filename); + } + + + + /** + * A postprocessor that evaluates the groeth rate of the shear bands. + * + * The implementation of error evaluators correspond to the + * benchmarks defined in the paper: + * Laura Alisic, John F. Rudge, Richard F. Katz, Garth N. Wells, Sander Rhebergen: + * "Compaction around a rigid, circular inclusion in partially molten rock." + * Journal of Geophysical Research: Solid Earth 119.7 (2014): 5903-5920. + */ + template + class ShearBandsGrowthRate : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Initialization function. Take references to the material model and + * initial conditions model to get the parameters necessary for computing + * the analytical solution for the growth rate and store them. + */ + void + initialize () override; + + private: + double amplitude; + double background_porosity; + double initial_band_angle; + double eta_0; + double xi_0; + double alpha; + }; + + + template + void + ShearBandsGrowthRate::initialize () + { + AssertThrow(Plugins::plugin_type_matches>(this->get_material_model()), + ExcMessage("Postprocessor shear bands growth rate only works with the material model shear bands.")); + + const ShearBandsMaterial & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + background_porosity = material_model.get_background_porosity(); + eta_0 = material_model.reference_viscosity(); + xi_0 = material_model.get_reference_compaction_viscosity(); + alpha = material_model.get_porosity_exponent(); + + const PlaneWaveMeltBandsInitialCondition &initial_composition + = this->get_initial_composition_manager().template + get_matching_initial_composition_model> (); + + amplitude = initial_composition.get_wave_amplitude(); + initial_band_angle = initial_composition.get_initial_band_angle(); + } + + + template + std::pair + ShearBandsGrowthRate::execute (TableHandler &/*statistics*/) + { + // compute analytical melt band growth rate + const double time = this->get_time(); + const Point upper_boundary_point = this->get_geometry_model().representative_point(0.0); + const Point lower_boundary_point = this->get_geometry_model().representative_point(this->get_geometry_model().maximal_depth()); + + types::boundary_id upper_boundary = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + types::boundary_id lower_boundary = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); + + const BoundaryVelocity::Manager &bm = this->get_boundary_velocity_manager(); + const double max_velocity = bm.boundary_velocity(upper_boundary, upper_boundary_point).norm(); + const double min_velocity = bm.boundary_velocity(lower_boundary, lower_boundary_point).norm(); + + const double strain_rate = 0.5 * (max_velocity + min_velocity) / this->get_geometry_model().maximal_depth(); + const double theta = std::atan(std::sin(initial_band_angle) / (std::cos(initial_band_angle) - time * strain_rate/sqrt(2.0) * std::sin(initial_band_angle))); + const double analytical_growth_rate = - eta_0 / (xi_0 + 4.0/3.0 * eta_0) * alpha * (1.0 - background_porosity) + * 2.0 * strain_rate * std::sin(2.0 * theta); + + // integrate velocity divergence + const QGauss quadrature_formula (this->get_fe() + .base_element(this->introspection().base_elements.velocities).degree+1); + const unsigned int n_q_points = quadrature_formula.size(); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_gradients | + update_quadrature_points | + update_JxW_values); + std::vector velocity_divergences(n_q_points); + std::vector> position(n_q_points); + + double local_velocity_divergence_max = 0.0; + double local_velocity_divergence_min = 0.0; + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + fe_values[this->introspection().extractors.velocities].get_function_divergences (this->get_solution(), + velocity_divergences); + position = fe_values.get_quadrature_points(); + + for (unsigned int q = 0; q < n_q_points; ++q) + { + const double relative_depth = this->get_geometry_model().depth(position[q]) / this->get_geometry_model().maximal_depth(); + const double relative_x = 0.25 * position[q](0) / this->get_geometry_model().maximal_depth(); + if (relative_depth < 0.55 && relative_depth > 0.45 && relative_x < 0.75 && relative_x > 0.25) + { + local_velocity_divergence_max = std::max (velocity_divergences[q], local_velocity_divergence_max); + local_velocity_divergence_min = std::min (velocity_divergences[q], local_velocity_divergence_min); + } + } + } + + const double global_velocity_divergence_max + = Utilities::MPI::max (local_velocity_divergence_max, this->get_mpi_communicator()); + const double global_velocity_divergence_min + = Utilities::MPI::min (local_velocity_divergence_min, this->get_mpi_communicator()); + + // compute modelled melt band growth rate + const double numerical_growth_rate = (0 <= initial_band_angle && initial_band_angle < numbers::PI /2. + ? + (1.0 - background_porosity) / (amplitude * background_porosity) * global_velocity_divergence_max + : + (1.0 - background_porosity) / (amplitude * background_porosity) * global_velocity_divergence_min); + + const double relative_error = (analytical_growth_rate != 0.0) ? + std::abs(numerical_growth_rate - analytical_growth_rate)/analytical_growth_rate + : + 1.0; + + // compute and output error + std::ostringstream os; + os << std::scientific << initial_band_angle + << ", " << analytical_growth_rate + << ", " << numerical_growth_rate + << ", " << relative_error; + + return std::make_pair("Initial angle, Analytical growth rate, Modelled growth rate, Error:", os.str()); + } + + + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace ShearBands + { + ASPECT_REGISTER_MATERIAL_MODEL(ShearBandsMaterial, + "shear bands material", + "A material model that corresponds to the setup to" + "generate magmatic shear bands described in Katz et al., " + "Nature, 2006.") + + ASPECT_REGISTER_POSTPROCESSOR(ShearBandsPostprocessor, + "shear bands statistics", + "A postprocessor that writes output for the porosity field, " + "which can be used to calculate the angle of the shear " + "bands in the model.") + + ASPECT_REGISTER_POSTPROCESSOR(ShearBandsGrowthRate, + "shear bands growth rate", + "A postprocessor computes the growth rate of melt bands as " + "presicted from linear stability analysis (Spiegelman, 2003), " + "and compares modelled and analytical solution.") + + ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(ShearBandsInitialCondition, + "shear bands initial condition", + "Composition is set to background porosity plus " + "white noise.") + + ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(PlaneWaveMeltBandsInitialCondition, + "plane wave melt bands initial condition", + "Composition is set to background porosity plus " + "plane wave.") + } +} diff --git a/benchmarks/shear_bands/shear_bands.prm.bak b/benchmarks/shear_bands/shear_bands.prm.bak new file mode 100644 index 00000000000..7ded4bef6be --- /dev/null +++ b/benchmarks/shear_bands/shear_bands.prm.bak @@ -0,0 +1,130 @@ +# Listing of Parameters +# --------------------- +# Set up the magmatic shear bands testcase +# with non-linear rheology after Katz et al., +# 2006: The dynamics of melt and shear +# localization in partially molten aggregates. + +set Additional shared libraries = ./libshear_bands.so +set Adiabatic surface temperature = 1623 +set Nonlinear solver scheme = iterated Advection and Stokes +set Output directory = output +set Max nonlinear iterations = 50 +set Nonlinear solver tolerance = 1e-5 +set Dimension = 2 +set End time = 3.125e-8 +set Pressure normalization = surface +set Surface pressure = 0 +set Resume computation = false +set Start time = 0 +set Use years in output instead of seconds = true + +# we want to have a similar contribution of velocity and strain rate +# in the stabilization. Velocities are on the order of 1e-3 and cell +# size * strain rate (which is used in the stabilization and scaled +# by the parameter gamma) is on the order of 1e-5, so we set gamma to +# 100. +subsection Discretization + set Composition polynomial degree = 1 + + subsection Stabilization parameters + set beta = 0.05 + set gamma = 100 + set Use artificial viscosity smoothing = true + end +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = porosity +end + +subsection Boundary composition model + set List of model names = initial composition +end + +# we apply simple shear here, so that the top and bottom boundaries +# move with the same speed u0, but in opposite directions +subsection Boundary velocity model + set Prescribed velocity boundary indicators = 2:function, 3:function + + subsection Function + set Function constants = u0=3.2e4,ymid=0.0005 + set Function expression = u0*(y/ymid-1.0);0 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 0.004 + set Y extent = 0.001 + set X periodic = true + set X repetitions = 4 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + # Magnitude of the gravity vector in $m/s^2$. The direction is always + # radially outward from the center of the earth. + set Magnitude = 0.0 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function constants = l=64000 + set Function expression = 0.0 + set Variable names = x,y + end +end + +subsection Initial composition model + set Model name = shear bands initial condition +end + +subsection Material model + set Model name = shear bands material +end + +subsection Boundary fluid pressure model + set Plugin name = density +end + +subsection Mesh refinement + set Coarsening fraction = 0.0 + set Refinement fraction = 0.0 + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Strategy = composition + set Time steps between mesh refinement = 0 +end + +subsection Melt settings + set Include melt transport = true +end + +subsection Postprocess + set List of postprocessors = visualization,composition statistics,velocity statistics,shear bands statistics + + subsection Visualization + set List of output variables = density, viscosity, thermal expansivity, strain rate, melt material properties, artificial viscosity composition + set Number of grouped files = 0 + set Output format = vtu + set Time between graphical output = 0 + + subsection Artificial viscosity composition + set Name of compositional field = porosity + end + + subsection Melt material properties + set List of properties = fluid density, permeability, fluid viscosity, compaction viscosity + end + end +end diff --git a/benchmarks/sinking_block/blank.prm.bak b/benchmarks/sinking_block/blank.prm.bak new file mode 100644 index 00000000000..30107e52825 --- /dev/null +++ b/benchmarks/sinking_block/blank.prm.bak @@ -0,0 +1,58 @@ +# This is the common core prm file for the sinking block benchmark. +# It is used by the run_benchmark script which runs the benchmark +# for various viscosity ratios and density differences. +# This file cannot be used by aspect - see instead sinking_block.prm + +set Additional shared libraries = ./libsinking_block.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Pressure normalization = volume + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 512e3 + set Y extent = 512e3 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +############### Parameters describing the temperature field +# Note: The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, point values, matrix statistics + + subsection Point values + set Evaluation points = 256e3,384e3 + end + + subsection Visualization + set Output format = vtu + set Time between graphical output = 0 + set List of output variables = density, viscosity + end +end diff --git a/benchmarks/sinking_block/sinking_block.cc.bak b/benchmarks/sinking_block/sinking_block.cc.bak new file mode 100644 index 00000000000..16d038841ee --- /dev/null +++ b/benchmarks/sinking_block/sinking_block.cc.bak @@ -0,0 +1,232 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace SinkingBlockBenchmark + { + using namespace dealii; + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @ingroup MaterialModels + */ + template + class SinkingBlockMaterial : public MaterialModel::Interface + { + public: + /** + * @name Physical parameters used in the basic equations + * @{ + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const Point &pos = in.position[i]; + if (method==0) + { + if ( std::abs(pos[0]-256e3)<64e3 && std::abs(pos[1]-384e3)<64e3) + { + out.viscosities[i] = eta2; + out.densities[i] = rho2; + } + else + { + out.viscosities[i] = eta1; + out.densities[i] = rho1; + } + } + else if (method==1) + { + if ( std::abs(pos[0]-256e3)<64e3 && std::abs(pos[1]-384e3)<64e3) + { + out.viscosities[i] = eta2; + out.densities[i] = rho2-rho1; + } + else + { + out.viscosities[i] = eta1; + out.densities[i] = 0; + } + } + else if (method==2) + { + if ( std::abs(pos[1]-384e3)<64e3) + { + if ( std::abs(pos[0]-256e3)<64e3) // in block + { + out.viscosities[i] = eta2; + out.densities[i] = 0.75*(rho2-rho1); + } + else // left and right of block + { + out.viscosities[i] = eta1; + out.densities[i] = -0.25*(rho2-rho1); + } + } + else + { + out.viscosities[i] = eta1; + out.densities[i] = 0; + } + } + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + } + } + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + * Incompressibility does not necessarily imply that the density is + * constant; rather, it may still depend on temperature or pressure. + * In the current context, compressibility means whether we should + * solve the continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("SinkingBlock"); + { + prm.declare_entry ("eta1", "1e21", + Patterns::Double (0), + "Viscosity of the mantle."); + prm.declare_entry ("eta2", "1e23", + Patterns::Double (0), + "Viscosity in the Inclusion."); + prm.declare_entry ("rho1", "3200", + Patterns::Double (0), + "density of the mantle."); + prm.declare_entry ("rho2", "3232", + Patterns::Double (0), + "density in the Inclusion."); + prm.declare_entry ("method", "0", + Patterns::Integer (0,2), + "density field treatment. Acceptable values are " + "0 (full densities), 1 (reduced densities), and " + "2 (vertically averaged density profile is removed" + " --see Thieulot and Bangerth, In prep."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("SinkingBlock"); + { + eta1 = prm.get_double ("eta1"); + eta2 = prm.get_double ("eta2"); + rho1 = prm.get_double ("rho1"); + rho2 = prm.get_double ("rho2"); + method = prm.get_integer ("method"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + private: + double eta1; + double eta2; + double rho1; + double rho2; + int method; + + }; + + + template + bool + SinkingBlockMaterial:: + is_compressible () const + { + return false; + } + + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace SinkingBlockBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(SinkingBlockMaterial, + "SinkingBlockMaterial", + "A material model that corresponds to the `SinkingBlock' benchmark. " + "See the manual for more information.") + } +} diff --git a/benchmarks/sinking_block/sinking_block.prm.bak b/benchmarks/sinking_block/sinking_block.prm.bak new file mode 100644 index 00000000000..3d1e1348fd5 --- /dev/null +++ b/benchmarks/sinking_block/sinking_block.prm.bak @@ -0,0 +1,71 @@ +# This is the standalone prm file for the sinking block benchmark. + +set Additional shared libraries = ./libsinking_block.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output-block +set Pressure normalization = volume + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 512e3 + set Y extent = 512e3 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Material model + set Model name = SinkingBlockMaterial + + subsection SinkingBlock + set eta1 = 1e21 + set eta2 = 1e22 + set rho1 = 3200 + set rho2 = 3208 + set method = 0 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +############### Parameters describing the temperature field +# Note: The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the discretization + +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 0 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics + + subsection Visualization + set Output format = vtu + set Time between graphical output = 0 + set List of output variables = density, viscosity + end +end diff --git a/benchmarks/slab_detachment/slab_detachment.prm.bak b/benchmarks/slab_detachment/slab_detachment.prm.bak new file mode 100644 index 00000000000..eacb778f226 --- /dev/null +++ b/benchmarks/slab_detachment/slab_detachment.prm.bak @@ -0,0 +1,152 @@ +# Input file for the Detachment benchmark of +# Schmalholz 2011 as performed in the paper of Glerum et al. 2017. +# It considers a 2D box with a lithosphere of nonlinear rheology +# and a vertically hanging slab that necks over time. + +set Dimension = 2 +set End time = 7.8894e14 #seconds = 25My +set Use years in output instead of seconds = true +set Output directory = output_slab_detachment + +#set Nonlinear solver scheme = iterated Advection and Newton Stokes +set Nonlinear solver scheme = iterated Advection and Stokes +set Nonlinear solver tolerance = 1e-6 +set Max nonlinear iterations = 50 +set CFL number = 1 + +# A 2D rectangle of 1000x660 km. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1000000.0 + set Y extent = 660000.0 + set X repetitions = 100 + set Y repetitions = 66 + end +end + +# Vertical gravity. +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +# setting up DG for composition(s) +#subsection Discretization +# set Use discontinuous composition discretization = true +# subsection Stabilization parameters +# set Use limiter for discontinuous composition solution = true +# set Global composition maximum = 1. +# set Global composition minimum = 0. +# end +#end + +# there are two compositions, one background (mantle) and one additional (slab) +subsection Compositional fields + set Number of fields = 1 + set Names of fields = slab +end + +# Dislocation rheology set to linear viscosity in the mantle. +# Temperature effects are not considered. + +subsection Material model + set Material averaging = harmonic average + set Model name = visco plastic + + subsection Visco Plastic + set Reference temperature = 273 + set Minimum strain rate = 1.e-20 + set Reference strain rate = 1.e-15 + set Minimum viscosity = 1e21 + set Maximum viscosity = 1e25 + set Viscosity averaging scheme = harmonic + set Thermal diffusivities = 0, 0 + set Heat capacities = 750., 750. + set Densities = 3150, 3300 + set Thermal expansivities = 0, 0 + set Viscous flow law = dislocation + set Prefactors for dislocation creep = 1e-21, 1.22773766e-48 + set Stress exponents for dislocation creep = 1, 4 + set Activation energies for dislocation creep = 0, 0 + set Activation volumes for dislocation creep = 0, 0 + + # cohesion set really high to generate very large plastic + # viscosities which will not be taken into account + # by the material model. + set Angles of internal friction = 0 , 0 + set Cohesions = 1e15, 1e15 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +#free slip boundary conditions on the top and bottom, +# no slip on left and right boundaries +subsection Boundary velocity model + set Tangential velocity boundary indicators = bottom, top + set Zero velocity boundary indicators = left, right +end + +# Temperature effects are not considered, +# so we set everything to zero. +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 273 # cannot be zero!!! + end +end + +# Description of the initial compositional fields mantle and slab +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = if((x<460000.0&z<580000.0)|(z<330000.0&x>=460000.0&x<540000.0)|(z<580000.0&x>=540000.0),0,1) + end +end + +# We output the solution every 1 My and monitor the velocity +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, particles + + subsection Visualization + set Time between graphical output = 1e6 + set List of output variables = strain rate, viscosity, density + end + + subsection Particles + set Time between data output = 1e6 + set Data output format = ascii + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-7 + set Number of cheap Stokes solver steps = 0 + end +end + +# We read a file with 22 initial particle locations and +# output the new particle locations over time to an ascii file. +subsection Particles + set Particle generator name = ascii file + + subsection Generator + subsection Ascii file + set Data directory = $ASPECT_SOURCE_DIR/benchmarks/slab_detachment/ + set Data file name = initial_particle_location.dat + end + end +end diff --git a/benchmarks/solcx/compositional_fields/solcx_compositional_fields.cc.bak b/benchmarks/solcx/compositional_fields/solcx_compositional_fields.cc.bak new file mode 100644 index 00000000000..4c98e51cf63 --- /dev/null +++ b/benchmarks/solcx/compositional_fields/solcx_compositional_fields.cc.bak @@ -0,0 +1,46 @@ +/* + Copyright (C) 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include "solcx_compositional_fields.h" + + + +// explicit instantiations +namespace aspect +{ + namespace InclusionBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(SolCxCompositionalMaterial, + "SolCxCompositionalMaterial", + "A material model that corresponds to the 'SolCx' benchmark " + "as defined in Duretz et al., G-Cubed, 2011 using " + "compositional fields. ") + + + ASPECT_REGISTER_POSTPROCESSOR(SolCxPostprocessor, + "SolCxPostprocessor", + "A postprocessor that compares the solution of the benchmarks from " + "the Duretz et al., G-Cubed, 2011, paper with the one computed by ASPECT " + "and reports the error. Specifically, it can compute the errors for " + "the SolCx, SolKz and inclusion benchmarks. The postprocessor inquires " + "which material model is currently being used and adjusts " + "which exact solution to use accordingly.") + } +} diff --git a/benchmarks/solcx/compositional_fields/solcx_compositional_fields.h.bak b/benchmarks/solcx/compositional_fields/solcx_compositional_fields.h.bak new file mode 100644 index 00000000000..40eafb19602 --- /dev/null +++ b/benchmarks/solcx/compositional_fields/solcx_compositional_fields.h.bak @@ -0,0 +1,34 @@ +#ifndef ASPECT_SOLCX_COMPOSITIONAL_FIELDS_H +#define ASPECT_SOLCX_COMPOSITIONAL_FIELDS_H + +#include "../solcx.h" + + + +namespace aspect +{ + namespace InclusionBenchmark + { + using namespace dealii; + + template + class SolCxCompositionalMaterial : public SolCxMaterial + { + public: + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + out.densities[i] = in.composition[i][0]; + out.viscosities[i] = in.composition[i][1]; + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + } + } + }; + } +} +#endif diff --git a/benchmarks/solcx/compositional_fields/solcx_compositional_fields.prm b/benchmarks/solcx/compositional_fields/solcx_compositional_fields.prm index 724762bcdfb..959a224769a 100644 --- a/benchmarks/solcx/compositional_fields/solcx_compositional_fields.prm +++ b/benchmarks/solcx/compositional_fields/solcx_compositional_fields.prm @@ -70,7 +70,6 @@ subsection Discretization set Use locally conservative discretization = true subsection Stabilization parameters - set Use limiter for discontinuous composition solution = true # apply the limiter to the DG solutions set Global composition maximum = 1, 1e6 set Global composition minimum = -1, 1 end diff --git a/benchmarks/solcx/compositional_fields/solcx_compositional_fields.prm.bak b/benchmarks/solcx/compositional_fields/solcx_compositional_fields.prm.bak new file mode 100644 index 00000000000..724762bcdfb --- /dev/null +++ b/benchmarks/solcx/compositional_fields/solcx_compositional_fields.prm.bak @@ -0,0 +1,95 @@ +# A description of the SolCX benchmark for which a known solution +# is available. See the manual for more information. + +set Additional shared libraries = ./libsolcx_compositional_fields.so + +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output +set Pressure normalization = volume +set Nonlinear solver scheme = no Advection, iterated Stokes + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Material model + set Model name = SolCxCompositionalMaterial + + subsection SolCx + set Viscosity jump = 1e6 + end +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = perturbed box +end + +subsection Compositional fields + set Number of fields = 2 + set Names of fields = density_comp, viscosity_comp + set Compositional field methods = field, field +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x, z + set Function constants = pi=3.1415926536, eta_b=1e6, background_density=0.0 + set Function expression = background_density - sin(pi*z) * cos(pi*x); if(x<=0.5, 1, eta_b) + end +end + +############### Parameters describing the discretization + +subsection Discretization + set Composition polynomial degree = 2 + set Stokes velocity polynomial degree = 2 + set Use discontinuous composition discretization = true + set Use locally conservative discretization = true + + subsection Stabilization parameters + set Use limiter for discontinuous composition solution = true # apply the limiter to the DG solutions + set Global composition maximum = 1, 1e6 + set Global composition minimum = -1, 1 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, SolCxPostprocessor + + subsection Visualization + set Output format = vtu + set Number of grouped files = 1 + set Time between graphical output = 0 + set List of output variables = density, viscosity + end +end diff --git a/benchmarks/solcx/compositional_fields/solcx_particles.prm b/benchmarks/solcx/compositional_fields/solcx_particles.prm index 624d2616aaa..d12d68df74c 100644 --- a/benchmarks/solcx/compositional_fields/solcx_particles.prm +++ b/benchmarks/solcx/compositional_fields/solcx_particles.prm @@ -55,7 +55,6 @@ subsection Discretization set Use discontinuous composition discretization = true subsection Stabilization parameters - set Use limiter for discontinuous composition solution = false # apply the limiter to the DG solutions end end diff --git a/benchmarks/solcx/compositional_fields/solcx_particles.prm.bak b/benchmarks/solcx/compositional_fields/solcx_particles.prm.bak new file mode 100644 index 00000000000..624d2616aaa --- /dev/null +++ b/benchmarks/solcx/compositional_fields/solcx_particles.prm.bak @@ -0,0 +1,128 @@ +# A description of the SolCX benchmark using active particles +# to interpolate both density and viscosity onto the compositional +# field for which a known solution is available. See the manual +# for more information. + +set Additional shared libraries = ./libsolcx_compositional_fields.so + +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output +set Pressure normalization = volume + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Material model + set Model name = SolCxCompositionalMaterial + + subsection SolCx + set Viscosity jump = 1e6 + end +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + + +subsection Initial temperature model + set Model name = perturbed box +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = true + set Use discontinuous composition discretization = true + + subsection Stabilization parameters + set Use limiter for discontinuous composition solution = false # apply the limiter to the DG solutions + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 +end + +subsection Compositional fields + set Number of fields = 2 + set Names of fields = density_comp, viscosity_comp + set Compositional field methods = particles, particles + + # In the source code, we assumed that density is being carried + # on compositional field 1 (at index 0) and viscosity is being + # carried on compositional field 2 (at index 1). If this order + # is changed, then the evaluate() function in solcx_compositional_fields.h + # must also be changed. + set Mapped particle properties = density_comp:function[0], viscosity_comp:function[1] +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = pi=3.1415926, eta_b=1e6, background_density=0.0 + set Function expression = background_density - sin(pi*y) * cos(pi*x); if(x<0.5, 1, eta_b) + end +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = particles, visualization, SolCxPostprocessor + + subsection Visualization + set Output format = vtu + set Number of grouped files = 1 + set Time between graphical output = 0 + set List of output variables = density, viscosity + end + + subsection Particles + set Time between data output = 0 + set Data output format = vtu + end +end + +subsection Particles + set List of particle properties = function + set Integration scheme = rk2 + set Interpolation scheme = cell average + set Maximum particles per cell = 16384 + set Update ghost particles = true + set Particle generator name = reference cell + + subsection Function + set Number of components = 2 + set Variable names = x, y + set Function constants = pi=3.1415926, eta_b=1e6, background_density=0.0 + set Function expression = background_density - sin(pi*y) * cos(pi*x); if(x<0.5, 1, eta_b) + end + + subsection Generator + subsection Reference cell + set Number of particles per cell per direction = 4 + end + end +end diff --git a/benchmarks/solcx/doc/solcx.prm.bak b/benchmarks/solcx/doc/solcx.prm.bak new file mode 100644 index 00000000000..fa9a9331c43 --- /dev/null +++ b/benchmarks/solcx/doc/solcx.prm.bak @@ -0,0 +1,60 @@ +set Additional shared libraries = ./libsolcx.so + +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output +set Pressure normalization = volume + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Material model + set Model name = SolCxMaterial + + subsection SolCx + set Viscosity jump = 1e6 + end +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = perturbed box +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = false +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 4 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = SolCxPostprocessor, visualization +end diff --git a/benchmarks/solcx/solcx.cc.bak b/benchmarks/solcx/solcx.cc.bak new file mode 100644 index 00000000000..96081618aad --- /dev/null +++ b/benchmarks/solcx/solcx.cc.bak @@ -0,0 +1,44 @@ +/* + Copyright (C) 2011 - 2018 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include "solcx.h" + + + +// explicit instantiations +namespace aspect +{ + namespace InclusionBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(SolCxMaterial, + "SolCxMaterial", + "A material model that corresponds to the 'SolCx' benchmark " + "defined in Duretz et al., G-Cubed, 2011.") + + + ASPECT_REGISTER_POSTPROCESSOR(SolCxPostprocessor, + "SolCxPostprocessor", + "A postprocessor that compares the solution of the benchmarks from " + "the Duretz et al., G-Cubed, 2011, paper with the one computed by ASPECT " + "and reports the error. Specifically, it can compute the errors for " + "the SolCx, SolKz and inclusion benchmarks. The postprocessor inquires " + "which material model is currently being used and adjusts " + "which exact solution to use accordingly.") + } +} diff --git a/benchmarks/solcx/solcx.h.bak b/benchmarks/solcx/solcx.h.bak new file mode 100644 index 00000000000..0e7c8100a48 --- /dev/null +++ b/benchmarks/solcx/solcx.h.bak @@ -0,0 +1,3189 @@ +#ifndef ASPECT_SOLCX_H +#define ASPECT_SOLCX_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + + +namespace aspect +{ + /** + * This is the "Sol Cx" benchmark defined in the following paper: + * @code + * @Article{DMGT11, + * author = {T. Duretz and D. A. May and T. V. Gerya and P. J. Tackley}, + * title = {Discretization errors and free surface stabilization in the + * finite difference and marker-in-cell method for applied + * geodynamics: {A} numerical study}, + * journal = {Geochemistry Geophysics Geosystems}, + * year = 2011, + * volume = 12, + * pages = {Q07004/1--26}} + * @endcode + * + * The results are published in Kronbichler, Heister and Bangerth paper. + */ + namespace InclusionBenchmark + { + using namespace dealii; + + namespace AnalyticSolutions + { + // based on http://geodynamics.org/hg/cs/AMR/Discontinuous_Stokes with permission + // The following code has been taken from http://www.underworldproject.org/, + // release 1.7.0. As mentioned in the Underworld Manual, this code has been + // released under the GNU General Public License (GPL). + + void _Velic_solCx( + double pos[], + double _eta_A, double _eta_B, /* Input parameters: density, viscosity A, viscosity B */ + double _x_c, int _n, /* Input parameters: viscosity jump location, wavenumber in x */ + double vel[], double *presssure, + double total_stress[], double strain_rate[]) + { + const double PI = numbers::PI; + double Z, u1, u2, u3, u4, u5, u6, ZA, ZB; + double sum1, sum2, sum3, sum4, sum5, sum6, x, z, xc; + double _C1A, _C2A, _C3A, _C4A, _C1B, _C2B, _C3B, _C4B, _C1, _C2, _C3, _C4; + int n, nx; + + double t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, t21, t22, t23, t24, t25, t26, t27, t28, t29, t30, t31, t32, t33, t34, t35, t36, t37, t38, t39, t40; + double t41, t42, t43, t44, t45, t46, t47, t48, t49, t50, t51, t52, t53, t54, t55, t56, t57, t58, t59, t60, t61, t62, t63, t64, t65, t66, t67, t68, t69, t70, t71, t72, t73, t74, t75, t76, t77, t78, t79, t80; + double t81, t82, t83, t84, t85, t86, t87, t88, t89, t90, t91, t92, t93, t94, t95, t96, t97, t98, t99, t100, t101, t102, t103, t104, t105, t106, t107, t108, t109, t110, t111, t112, t113, t115, t116, t117, t118, t119, t120; + double t121, t122, t123, t124, t125, t126, t127, t128, t129, t130, t131, t132, t133, t134, t135, t136, t137, t138, t139, t140, t141, t142, t143, t144, t145, t146, t147, t148, t149, t150, t151, t152, t153, t154, t155, t156, t157, t158, t159, t160; + double t161, t162, t163, t164, t165, t166, t167, t168, t169, t170, t171, t172, t173, t174, t175, t176, t177, t178, t179, t180, t181, t182, t183, t184, t186, t187, t188, t189, t190, t191, t192, t193, t194, t195, t196, t197, t198, t199; + double t201, t202, t203, t204, t206, t207, t208, t209, t210, t211, t212, t213, t215, t216, t217, t218, t219, t220, t221, t222, t223, t224, t225, t226, t227, t228, t229, t230, t231, t232, t233, t234, t235, t236, t237, t238, t239, t240; + double t241, t242, t243, t244, t245, t246, t247, t248, t249, t250, t251, t252, t253, t254, t255, t256, t257, t258, t259, t260, t261, t262, t263, t264, t265, t267, t268, t269, t270, t272, t273, t274, t275, t276, t277, t278, t279, t280; + double t281, t282, t283, t284, t285, t286, t288, t289, t290, t291, t292, t295, t296, t297, t298, t299, t300, t301, t303, t304, t305, t307, t308, t310, t311, t312, t313, t314, t315, t316, t317, t318, t319, t320; + double t321, t322, t323, t324, t325, t326, t327, t328, t329, t330, t331, t332, t334, t335, t336, t337, t338, t339, t340, t341, t342, t344, t345, t346, t347, t348, t349, t350, t351, t352, t353, t354, t355, t356, t358, t359, t360; + double t361, t362, t363, t364, t365, t366, t367, t368, t369, t370, t371, t372, t373, t374, t375, t376, t377, t378, t379, t380, t381, t382, t383, t384, t385, t386, t387, t389, t390, t391, t393, t394, t395, t396, t397, t398; + double t401, t402, t403, t404, t405, t406, t407, t408, t409, t410, t411, t412, t413, t414, t415, t416, t417, t418, t419, t421, t422, t423, t424, t425, t426, t427, t428, t429, t430, t431, t432, t433, t434, t436, t437, t438, t439, t440; + double t441, t442, t443, t444, t445, t446, t447, t448, t450, t451, t453, t454, t455, t456, t457, t458, t459, t461, t462, t463, t464, t465, t466, t468, t469, t470, t471, t474, t475, t478, t480; + double t482, t483, t484, t485, t488, t489, t490, t492, t493, t495, t497, t498, t499, t501, t502, t503, t504, t505, t507, t508, t509, t510, t511, t512, t513, t515, t518, t520; + double t522, t525, t527, t528, t529, t530, t532, t533, t534, t535, t536, t538, t539, t541, t542, t544, t545, t546, t547, t548, t549, t550, t551, t552, t553, t554, t555, t556, t557, t560; + double t561, t562, t563, t564, t567, t568, t571, t573, t575, t576, t578, t579, t583, t590, t591, t594, t595, t596, t597, t598, t600; + double t601, t602, t604, t606, t607, t608, t611, t613, t615, t616, t617, t619, t621, t623, t624, t625, t626, t627, t629, t630, t632, t633, t634, t638, t639, t640; + double t641, t642, t643, t644, t645, t647, t648, t649, t650, t651, t652, t653, t654, t655, t656, t657, t658, t659, t660, t662, t663, t665, t666, t667, t668, t670, t671, t672, t673, t674, t675, t676, t679, t680; + double t682, t683, t684, t685, t686, t688, t689, t690, t691, t693, t694, t695, t696, t697, t698, t699, t700, t701, t702, t704, t705, t708, t709, t711, t712, t713, t714, t717, t718, t719; + double t721, t722, t723, t726, t727, t728, t730, t733, t734, t735, t736, t737, t738, t739, t740, t741, t744, t745, t746, t749, t750, t752, t753, t754, t755, t757, t758, t759, t760; + double t761, t762, t763, t764, t766, t767, t768, t770, t771, t772, t773, t774, t775, t776, t777, t778, t780, t781, t782, t785, t786, t789, t790, t791, t792, t793, t794, t795, t796, t797, t798, t800; + double t801, t806, t807, t808, t809, t811, t812, t817, t818, t819, t821, t822, t824, t827, t828, t830, t834, t835, t837, t840; + double t842, t843, t844, t845, t846, t849, t850, t853, t854, t855, t857, t858, t859, t860, t863, t864, t867, t868, t869, t873, t874, t877, t878, t879, t880; + double t884, t888, t891, t894, t900, t901, t903, t904, t907, t908, t909, t911, t914, t915, t916, t919, t920; + double t923, t924, t925, t926, t927, t929, t932, t935, t937, t939, t942, t943, t944, t945, t947, t948, t949, t950, t952, t953, t954, t955, t956, t957; + double t961, t964, t965, t966, t967, t968, t969, t971, t972, t974, t977, t978, t981, t983, t987, t988, t992, t993, t994, t997, t998; + double t1001, t1003, t1005, t1006, t1009, t1010, t1012, t1013, t1015, t1016, t1017, t1018, t1020, t1021, t1029, t1031, t1032, t1033, t1040; + double t1041, t1042, t1044, t1047, t1050, t1054, t1055, t1057, t1058, t1063, t1068, t1069, t1070, t1079, t1080; + double t1088, t1089, t1091, t1092, t1094, t1096, t1101, t1102, t1103, t1104, t1105, t1108, t1112, t1113, t1118, t1119, t1120; + double t1121, t1122, t1123, t1124, t1125, t1126, t1127, t1128, t1129, t1130, t1132, t1133, t1134, t1135, t1138, t1139, t1140, t1141, t1142, t1145, t1146, t1148, t1149, t1150, t1153, t1154, t1156, t1157, t1158, t1159; + double t1161, t1162, t1165, t1166, t1170, t1171, t1172, t1173, t1175, t1176, t1178, t1180, t1181, t1182, t1185, t1189, t1192, t1193, t1195, t1196, t1199; + double t1201, t1203, t1209, t1210, t1211, t1213, t1214, t1218, t1221, t1224, t1225, t1226, t1228, t1233, t1234, t1235, t1236, t1237, t1240; + double t1241, t1242, t1243, t1244, t1245, t1248, t1251, t1252, t1257, t1258, t1259, t1260, t1263, t1268, t1269, t1272, t1280; + double t1282, t1283, t1284, t1285, t1287, t1288, t1289, t1292, t1293, t1296, t1297, t1300, t1304, t1307, t1310, t1311, t1312, t1316, t1317, t1320; + double t1321, t1323, t1328, t1330, t1331, t1332, t1333, t1336, t1338, t1343, t1344, t1346, t1349, t1350, t1354; + double t1366, t1369, t1370, t1371, t1376, t1378, t1380, t1383, t1386, t1387, t1388, t1391, t1393, t1399; + double t1411, t1412, t1420, t1427; + double t1450, t1456, t1468, t1472, t1474, t1478; + double t1504, t1511; + double t1545; + double t1564, t1583; + + + /* del_rho = sin(n*Pi*z)*cos(nx*Pi*x) n=nx gives only non-zero terms*/ + n = _n; /* only one n in Fourier series because del_rho has cos term */ + nx = 1; /* can set these two to whatever we like */ + + ZA = _eta_A; /* left column viscosity */ + ZB = _eta_B; /* right column viscosity */ + xc = _x_c; + + x = pos[0]; + z = pos[1]; + + sum1 = 0.0; + sum2 = 0.0; + sum3 = 0.0; + sum4 = 0.0; + sum5 = 0.0; + sum6 = 0.0; + + // Note that there is no Fourier sum here. + /****************************************************************************************/ + _C1A = 0; + /****************************************************************************************/ + t1 = nx * 0.3141592654e1; + t2 = sin(t1); + t3 = nx * t2; + t4 = n * n; + t5 = t4 * t4; + t6 = 0.3141592654e1 * 0.3141592654e1; + t8 = t3 * t5 * t6; + t9 = ZA * xc; + t12 = exp(xc * n * 0.3141592654e1); + t13 = t12 * t12; + t15 = n * 0.3141592654e1; + t16 = exp(t15); + t17 = t16 * t16; + t18 = t17 * t16; + t19 = ZB * t13 * t18; + t20 = t9 * t19; + t23 = ZA * ZA; + t24 = nx * nx; + t25 = t24 * nx; + t26 = t23 * t25; + t28 = t13 * t13; + t29 = t28 * t13; + t33 = nx * ZB; + t34 = t1 * xc; + t35 = sin(t34); + t36 = t4 * n; + t37 = t35 * t36; + t38 = t33 * t37; + t39 = 0.3141592654e1 * ZA; + t40 = t13 * t12; + t41 = t17 * t40; + t45 = ZB * ZB; + t46 = t45 * t24; + t47 = t46 * t4; + t48 = 0.3141592654e1 * xc; + t49 = t13 * t17; + t53 = xc * xc; + t54 = t36 * t53; + t56 = t54 * t6 * t45; + t57 = cos(t34); + t58 = t57 * t24; + t59 = t28 * t12; + t60 = t17 * t59; + t61 = t58 * t60; + t64 = t25 * t2; + t65 = t64 * t15; + t72 = nx * t23; + t74 = t72 * t2 * t5; + t75 = t6 * t53; + t76 = t16 * t29; + t80 = t23 * n; + t81 = t80 * 0.3141592654e1; + t82 = t18 * t28; + t86 = nx * t5; + t87 = t23 * t6; + t89 = xc * t2; + t90 = t13 * t18; + t91 = t89 * t90; + t94 = t28 * t28; + t96 = t24 * n; + t98 = t4 * t45; + t99 = t98 * 0.3141592654e1; + t100 = t58 * t41; + t104 = 0.3141592654e1 * t25; + t105 = ZA * n * t104; + t106 = t2 * ZB; + t110 = t17 * t17; + t111 = ZA * t110; + t116 = n * t28; + t122 = t64 * t4 * t6; + t126 = t23 * t29 * t4; + t128 = t24 * xc; + t132 = t36 * t23; + t133 = t6 * t57; + t135 = t128 * t41; + t138 = t6 * xc; + t142 = t72 * t2; + t147 = 0.4e1 * t8 * t20 - 0.2e1 * t26 * t2 * t16 * t29 - 0.8e1 * t38 * t39 * t41 + 0.4e1 * t47 * t48 * t49 - + 0.8e1 * t56 * t61 - 0.4e1 * t65 * t20 + 0.2e1 * t26 * t2 * t18 * t28 - 0.4e1 * t74 * t75 * t76 - + 0.2e1 * t81 * t64 * t82 - 0.4e1 * t86 * t87 * t91 - t23 * t94 * t96 + 0.8e1 * t99 * t100 - + 0.2e1 * t105 * t106 * t82 - 0.4e1 * t38 * t48 * t111 * t12 + 0.2e1 * t116 * ZB * t111 * t24 + + 0.4e1 * t122 * t20 + 0.4e1 * t126 * 0.3141592654e1 * t17 * t128 + 0.8e1 * t132 * t133 * t135 + + 0.4e1 * t74 * t138 * t76 - 0.2e1 * t142 * t4 * t18 * t28; + t149 = ZA * t25 * t2; + t150 = ZB * t28; + t154 = t35 * t5; + t155 = t72 * t154; + t156 = t75 * t41; + t159 = nx * ZA; + t160 = t2 * t36; + t161 = t159 * t160; + t162 = 0.3141592654e1 * ZB; + t163 = t28 * t16; + t167 = t23 * t57; + t168 = t167 * t24; + t169 = n * t110; + t170 = t169 * t40; + t173 = ZA * ZB; + t174 = t173 * t90; + t177 = t36 * 0.3141592654e1; + t181 = t80 * t104; + t184 = n * t17; + t188 = t17 * t29; + t190 = t4 * 0.3141592654e1; + t191 = t190 * t24; + t206 = t138 * t60; + t209 = t23 * t4; + t211 = t209 * t6 * t25; + t212 = t89 * t76; + t216 = ZB * t16 * t29; + t217 = t9 * t216; + t220 = ZB * t110; + t221 = ZA * t24; + t222 = t221 * n; + t225 = t132 * t75; + t232 = t45 * t28; + t233 = t110 * t24; + t234 = t233 * n; + t236 = t209 * 0.3141592654e1; + t237 = t17 * xc; + t239 = t237 * t13 * t24; + t242 = -0.2e1 * t149 * t150 * t16 - 0.8e1 * t155 * t156 - 0.2e1 * t161 * t162 * t163 + 0.2e1 * t168 * t170 + + 0.2e1 * t65 * t174 - 0.2e1 * t142 * t177 * t76 + 0.4e1 * t181 * t91 - 0.4e1 * t168 * t184 * t59 - + 0.4e1 * t188 * t23 * t191 + 0.4e1 * t38 * t48 * ZA * t17 * t40 + 0.4e1 * t49 * t23 * t191 + + 0.2e1 * t26 * t2 * t13 * t18 - 0.8e1 * t155 * t206 + 0.4e1 * t211 * t212 - 0.4e1 * t8 * t217 + + 0.2e1 * t220 * t222 - 0.8e1 * t225 * t100 + 0.2e1 * t142 * t4 * t16 * t29 + t232 * t234 - + 0.4e1 * t236 * t239; + t244 = nx * t45; + t245 = t244 * t37; + t246 = t110 * t40; + t251 = t237 * t59; + t256 = t64 * t90; + t260 = t36 * t45 * t133; + t263 = t45 * t57; + t264 = t263 * t24; + t265 = t169 * t12; + t269 = t6 * t36; + t270 = t17 * t24; + t274 = t110 * t13; + t276 = t190 * t128; + t279 = nx * t36; + t281 = t28 * t40; + t282 = t281 * t35; + t286 = t138 * t41; + t289 = t75 * t60; + t296 = t190 * t173; + t305 = t86 * t45 * t35; + t312 = t33 * t154; + t313 = t6 * ZA; + t324 = t232 * t270; + t327 = -0.2e1 * t245 * t48 * t246 + 0.4e1 * t159 * t37 * t162 * t251 + 0.4e1 * t209 * t75 * t256 + + 0.8e1 * t260 * t135 + 0.2e1 * t264 * t265 + 0.32e2 * t9 * t150 * t269 * t270 + + 0.4e1 * t274 * t23 * t276 + 0.2e1 * t279 * t45 * t282 * t48 + 0.8e1 * t155 * t286 + + 0.8e1 * t155 * t289 - 0.8e1 * t150 * ZA * t96 * t17 + 0.8e1 * t296 * t61 - + 0.2e1 * t105 * t106 * t163 - 0.2e1 * t81 * t256 - 0.8e1 * t305 * t156 - + 0.4e1 * t33 * t282 * t177 * t9 - 0.16e2 * t312 * t313 * t237 * t40 - 0.4e1 * t168 * t184 * t40 + + 0.2e1 * t168 * t265 + 0.16e2 * t269 * t53 * t324; + t328 = t3 * t4; + t331 = t72 * t37; + t332 = t48 * t60; + t335 = n * t94; + t345 = t72 * t35; + t349 = t173 * t57; + t355 = t53 * t17; + t364 = t54 * t6 * ZB; + t365 = t28 * t17; + t369 = xc * ZB; + t370 = t269 * t369; + t371 = ZA * t57; + t373 = t371 * t270 * t40; + t385 = nx * t35; + t396 = t4 * xc; + t397 = t396 * t162; + t415 = t37 * t48; + t418 = -0.32e2 * t364 * t365 * t221 - 0.16e2 * t370 * t373 - 0.4e1 * t331 * t48 * t41 + + 0.4e1 * t86 * t23 * t53 * t6 * t2 * t90 + 0.2e1 * t385 * t177 * t23 * xc * t246 + + 0.16e2 * t132 * t53 * t6 * t28 * t270 - 0.4e1 * t397 * t371 * t233 * t12 - + 0.12e2 * t173 * t58 * t190 * t251 + 0.2e1 * t385 * t36 * 0.3141592654e1 * t23 * xc * t59 - + 0.8e1 * t99 * t61 - 0.2e1 * t244 * t59 * t415; + t427 = t371 * t270 * t59; + t439 = t209 * t48; + t440 = t110 * t12; + t441 = t58 * t440; + t447 = t36 * xc; + t455 = t48 * t440; + t471 = ZB * t17; + t492 = 0.12e2 * t397 * t373 - 0.4e1 * t122 * t217 + 0.16e2 * t364 * t427 + + 0.16e2 * t312 * t313 * t355 * t40 - 0.8e1 * t279 * t39 * t35 * ZB * t60 + 0.2e1 * t439 * t441 - + 0.2e1 * t81 * t64 * t163 + 0.8e1 * t447 * t87 * t61 + 0.2e1 * t23 * t59 * t57 * t276 + + 0.2e1 * t245 * t455 - 0.4e1 * t349 * t96 * t440 - 0.16e2 * t370 * t427 + 0.4e1 * t181 * t212 - + 0.16e2 * t365 * t23 * t269 * t128 + 0.16e2 * t86 * t138 * ZA * t35 * t471 * t59 + + 0.8e1 * t305 * t289 - 0.4e1 * t439 * t100 + 0.2e1 * ZB * t25 * t2 * ZA * t18 * t28 + + 0.2e1 * t142 * t4 * t28 * t16 - 0.8e1 * t56 * t100; + t499 = ZA * t53 * t19; + t505 = t396 * 0.3141592654e1; + t518 = t173 * t53 * t16 * t29; + t533 = t23 * t28; + t535 = t188 * t45; + t538 = t24 * t4; + t545 = t3 * t177; + t546 = t173 * t76; + t555 = t45 * t110; + t557 = t72 * t160; + t561 = -0.8e1 * t225 * t61 - 0.2e1 * t161 * t162 * t82 + t533 * t234 + 0.4e1 * t535 * t191 + + 0.4e1 * t167 * t538 * t332 + 0.4e1 * t349 * t96 * t60 + 0.2e1 * t545 * t546 - 0.2e1 * t264 * t170 + + 0.4e1 * t397 * t281 * ZA * t58 - t555 * t96 - 0.4e1 * t557 * t48 * t76; + t567 = t396 * 0.3141592654e1 * t45; + t568 = t58 * t246; + t597 = t58 * n; + t615 = t13 * t45; + t616 = t615 * t233; + t619 = t94 * t45; + t621 = t45 * t59; + t625 = 0.2e1 * t149 * t216 + 0.2e1 * t567 * t568 - 0.16e2 * t269 * xc * t324 - + 0.2e1 * t236 * xc * t281 * t58 - 0.2e1 * t142 * t177 * t90 - 0.8e1 * t567 * t100 + + 0.2e1 * t65 * t546 - 0.8e1 * t305 * t206 + 0.2e1 * n * t45 * t281 * t57 * t24 - t23 * t110 * t96 - + 0.8e1 * t296 * t100 + 0.2e1 * t23 * t281 * t597 + 0.4e1 * t545 * t20 + + 0.2e1 * t159 * t2 * t4 * ZB * t163 - 0.4e1 * t557 * t48 * t90 + 0.4e1 * t122 * t518 + + 0.8e1 * t263 * t538 * t332 - 0.4e1 * t505 * t616 - t619 * t96 - 0.2e1 * t621 * t57 * t276; + t626 = t49 * t45; + t660 = t29 * t45; + t685 = 0.2e1 * t545 * t174 - 0.4e1 * t126 * 0.3141592654e1 * t24 * xc - 0.4e1 * t47 * t48 * t188 + + 0.4e1 * t505 * t660 * t24 - 0.2e1 * t142 * t177 * t163 - 0.2e1 * t142 * t4 * t13 * t18 + + 0.8e1 * t260 * t128 * t60 - 0.2e1 * t328 * t546 - 0.2e1 * t26 * t2 * t28 * t16 + + 0.4e1 * t545 * t217 - 0.4e1 * t209 * t138 * t256; + t690 = t6 * 0.3141592654e1; + t691 = ZA * t690; + t693 = t24 * t24; + t694 = t693 * xc; + t695 = t188 * t694; + t698 = t23 * ZA; + t699 = t698 * t690; + t700 = t699 * t5; + t704 = t5 * t4; + t705 = t691 * t704; + t709 = t691 * t5; + t713 = t5 * n; + t714 = t713 * ZB; + t718 = t698 * t6; + t719 = t713 * t28; + t722 = t699 * t704; + t726 = t713 * t94; + t733 = t713 * t45; + t736 = t87 * t36; + t740 = -0.4e1 * t691 * t98 * t695 + 0.8e1 * t700 * t270 * t13 + 0.4e1 * t705 * t660 * xc + + 0.8e1 * t709 * t660 * t128 + 0.2e1 * t87 * t714 * t110 + t718 * t719 * t110 - + 0.4e1 * t722 * t237 * t13 - t313 * t726 * t45 - 0.4e1 * t699 * t704 * xc * t29 + t313 * t733 * t28 + + 0.4e1 * t736 * t150 * t233; + t746 = t313 * t36; + t752 = t6 * t6; + t753 = t23 * t752; + t759 = t698 * t752; + t760 = t759 * t36; + t761 = t17 * t693; + t762 = xc * t28; + t763 = t761 * t762; + t766 = t87 * t713; + t773 = t699 * t4; + t774 = t110 * t693; + t775 = xc * t13; + t785 = t704 * t17; + t789 = -0.16e2 * t736 * t150 * t270 + t718 * t116 * t693 - 0.2e1 * t746 * t555 * t24 + 0.4e1 * t705 * t535 + + 0.64e2 * t753 * t713 * t17 * t150 * t128 - 0.16e2 * t760 * t763 + 0.2e1 * t766 * t150 * t110 + + 0.4e1 * t722 * t274 * xc + 0.4e1 * t773 * t774 * t775 - 0.8e1 * t766 * t150 * t17 + + 0.8e1 * t700 * t233 * t775 + 0.4e1 * t699 * t785 * t13; + t791 = t691 * t4; + t792 = t45 * t693; + t793 = t49 * t792; + t796 = t759 * t713; + t797 = t53 * t28; + t798 = t270 * t797; + t801 = t87 * n; + t818 = t5 * t36; + t819 = t753 * t818; + t827 = t753 * t36 * ZB; + t830 = xc * t45; + t834 = -0.4e1 * t791 * t793 + 0.32e2 * t796 * t798 + 0.2e1 * t801 * ZB * t693 * t110 + + 0.2e1 * t718 * t36 * t28 * t24 - 0.8e1 * t700 * t128 * t29 - 0.8e1 * t700 * t239 - + 0.8e1 * t801 * t150 * t761 + 0.32e2 * t819 * t365 * t369 - 0.64e2 * t753 * t714 * t798 + + 0.32e2 * t827 * t763 + 0.4e1 * t705 * t830 * t49; + t842 = xc * t29; + t843 = t270 * t842; + t849 = t759 * t818; + t853 = t691 * t396; + t857 = t691 * t5 * t45; + t869 = t313 * n; + t874 = -0.2e1 * t718 * t36 * t94 * t24 - 0.4e1 * t773 * t761 * t29 + 0.8e1 * t700 * t843 + + 0.2e1 * t87 * t726 * ZB + 0.16e2 * t849 * t797 * t17 + 0.4e1 * t853 * t793 + 0.8e1 * t857 * t239 + + 0.2e1 * t801 * t150 * t693 - 0.8e1 * t700 * t270 * t29 - 0.8e1 * t709 * t49 * t46 - + t869 * t619 * t693 + t869 * t232 * t693; + t877 = ZA * t752; + t878 = t877 * t818; + t911 = 0.16e2 * t878 * t53 * t45 * t365 - 0.4e1 * t699 * t785 * t29 - 0.4e1 * t705 * t188 * t830 + + 0.2e1 * t801 * t94 * t693 * ZB - 0.8e1 * t857 * t843 - t718 * t726 + 0.4e1 * t773 * t761 * t13 - + 0.4e1 * t705 * t775 * t555 + 0.2e1 * t746 * t232 * t233 - 0.16e2 * t878 * t830 * t365 - + 0.2e1 * t746 * t619 * t24; + t916 = t110 * t28; + t945 = t28 * t693 * t45 * t17; + t948 = 0.32e2 * t877 * t733 * t798 + 0.2e1 * t718 * t36 * t916 * t24 - 0.4e1 * t705 * t626 + + t718 * n * t916 * t693 - t869 * t792 * t110 - 0.4e1 * t773 * t761 * t775 + t718 * t719 + + 0.2e1 * t746 * t232 * t24 - 0.16e2 * t849 * t365 * xc - t718 * t713 * t110 - + 0.4e1 * t773 * t694 * t29 + 0.16e2 * t877 * t54 * t945; + t974 = t761 * t797; + t987 = 0.4e1 * t773 * t695 + 0.4e1 * t736 * t150 * t24 + 0.4e1 * t722 * t842 * t17 - + 0.16e2 * t877 * t447 * t945 + 0.2e1 * t87 * t714 * t28 + t313 * t713 * t916 * t45 - + 0.4e1 * t853 * t615 * t774 - 0.32e2 * t877 * t713 * xc * t324 + 0.16e2 * t760 * t974 + + 0.4e1 * t736 * t94 * t24 * ZB + t869 * t792 * t916 - 0.8e1 * t691 * t5 * xc * t616; + t1021 = -t718 * t169 * t693 - 0.32e2 * t827 * t974 + 0.2e1 * t801 * t150 * t774 + + 0.4e1 * t791 * t188 * t792 + 0.4e1 * t736 * t220 * t24 + 0.4e1 * t791 * t842 * t792 + + 0.8e1 * t709 * t660 * t270 - t718 * t335 * t693 - 0.2e1 * t718 * t36 * t110 * t24 - + 0.32e2 * t819 * t797 * t471 - t313 * t733 * t110 - 0.32e2 * t796 * t270 * t762; + + _C2A = (t147 - 0.4e1 * t65 * t217 + t418 + 0.2e1 * t150 * t222 + t327 - 0.2e1 * t149 * t19 + + 0.2e1 * t335 * ZB * t24 * ZA - 0.16e2 * t312 * t313 * t355 * t59 - 0.4e1 * t281 * ZB * ZA * t597 - + 0.2e1 * t505 * t45 * t281 * t58 - 0.4e1 * t211 * t2 * t53 * t76 + 0.8e1 * t305 * t286 - + 0.4e1 * t122 * t499 - 0.4e1 * t331 * t332 + 0.8e1 * t345 * t177 * t60 - 0.2e1 * t142 * t177 * t82 + + 0.2e1 * t72 * t281 * t415 + 0.4e1 * t349 * t96 * t41 - 0.2e1 * t81 * t64 * t76 + + 0.2e1 * t58 * t80 * t59 + 0.8e1 * t345 * t177 * t41 - 0.4e1 * t8 * t499 + t242 + 0.4e1 * t8 * t518 + + t625 + t685 + 0.2e1 * t328 * t174 + 0.2e1 * t331 * t455 - 0.2e1 * t33 * t2 * t4 * ZA * t82 - + 0.4e1 * t626 * t191 + 0.16e2 * t364 * t373 - 0.2e1 * t621 * t597 - 0.2e1 * t439 * t568 + t492 + + t533 * t96 + t232 * t96 + 0.2e1 * t567 * t441 + t561) / + (t740 + t789 + t834 + t874 + t911 + t948 + t987 + t1021); + /****************************************************************************************/ + t1 = n * n; + t2 = t1 * n; + t3 = t2 * 0.3141592654e1; + t4 = t3 * xc; + t5 = ZB * ZB; + t7 = exp(n * 0.3141592654e1); + t8 = t7 * t7; + t9 = t5 * t8; + t12 = exp(xc * n * 0.3141592654e1); + t13 = t12 * t12; + t14 = t13 * t13; + t15 = t14 * t13; + t19 = nx * nx; + t21 = nx * 0.3141592654e1; + t22 = sin(t21); + t23 = t19 * nx * t22; + t24 = t23 * 0.3141592654e1; + t25 = ZA * ZB; + t26 = t7 * t15; + t27 = t25 * t26; + t30 = t21 * xc; + t31 = sin(t30); + t32 = t31 * nx; + t33 = t32 * n; + t34 = ZA * ZA; + t35 = t8 * t8; + t36 = t34 * t35; + t40 = t2 * t34; + t41 = 0.3141592654e1 * t8; + t42 = t41 * t15; + t45 = t1 * t5; + t46 = t14 * t14; + t49 = t19 * t5; + t51 = t19 * t46; + t53 = t19 * t34; + t55 = t8 * t7; + t56 = t13 * t55; + t57 = t25 * t56; + t60 = t2 * nx; + t61 = 0.3141592654e1 * 0.3141592654e1; + t63 = t60 * t31 * t61; + t64 = xc * xc; + t65 = ZA * t64; + t66 = ZB * t8; + t67 = t14 * t12; + t68 = t66 * t67; + t69 = t65 * t68; + t72 = -0.4e1 * t4 * t9 * t15 + 0.4e1 * t24 * t27 + 0.4e1 * t33 * t36 * t12 - 0.4e1 * t40 * t42 - t45 * t46 + + t45 * t14 - t49 * t14 + t51 * t5 - t53 * t14 + 0.4e1 * t24 * t57 + 0.32e2 * t63 * t69; + t73 = t1 * nx; + t75 = t73 * t31 * 0.3141592654e1; + t76 = t8 * t67; + t77 = t25 * t76; + t80 = t1 * t1; + t81 = t80 * t34; + t83 = t61 * t14; + t87 = t1 * t19; + t88 = cos(t30); + t90 = t87 * t88 * t61; + t91 = t5 * t64; + t92 = t13 * t12; + t93 = t8 * t92; + t94 = t91 * t93; + t100 = ZB * t64 * ZA * t8 * t92; + t103 = n * t19; + t105 = t103 * t88 * 0.3141592654e1; + t106 = ZA * xc; + t107 = ZB * t35; + t109 = t106 * t107 * t12; + t112 = t34 * xc; + t113 = t112 * t93; + t116 = t35 * t14; + t118 = t1 * ZA; + t119 = ZB * t14; + t122 = t1 * t46; + t125 = t19 * ZB; + t126 = t35 * ZA; + t127 = t125 * t126; + t129 = t1 * ZB; + t132 = -0.16e2 * t75 * t77 + 0.16e2 * t81 * t64 * t83 * t8 + 0.16e2 * t90 * t94 - 0.32e2 * t90 * t100 + + 0.8e1 * t105 * t109 - 0.8e1 * t75 * t113 + t45 * t116 + 0.2e1 * t118 * t119 + 0.2e1 * t122 * t25 - + 0.2e1 * t127 + 0.2e1 * t129 * t126; + t134 = t1 * t34; + t136 = t34 * t64; + t137 = t136 * t76; + t141 = t91 * t76; + t145 = t103 * t34; + t146 = 0.3141592654e1 * xc; + t147 = t8 * t13; + t153 = t14 * ZA; + t156 = xc * t5; + t157 = t156 * t93; + t160 = t103 * t5; + t162 = t146 * t8 * t15; + t166 = t34 * t7 * t15; + t169 = t134 * t116 - 0.16e2 * t63 * t137 - t49 * t116 - 0.16e2 * t63 * t141 - t53 * t116 + + 0.4e1 * t145 * t146 * t147 - 0.2e1 * t51 * t25 - 0.2e1 * t125 * t153 - 0.16e2 * t75 * t157 + + 0.4e1 * t160 * t162 - 0.4e1 * t24 * t166; + t170 = t106 * t68; + t177 = t35 * t92; + t178 = t112 * t177; + t181 = t156 * t76; + t186 = t35 * t12; + t187 = t112 * t186; + t193 = t5 * 0.3141592654e1; + t206 = t34 * t14; + t207 = t206 * t7; + t210 = -0.32e2 * t63 * t170 + 0.32e2 * t90 * t170 + 0.8e1 * t75 * t109 + 0.4e1 * t105 * t178 - + 0.16e2 * t75 * t181 - 0.16e2 * t90 * t113 - 0.4e1 * t75 * t187 + 0.16e2 * t90 * t141 - + 0.4e1 * t103 * t15 * t193 * xc + 0.16e2 * t73 * t22 * t34 * t146 * t26 + + 0.4e1 * t32 * n * t34 * t67 + 0.4e1 * t24 * t207; + t217 = t106 * t66 * t92; + t226 = t88 * t19 * n; + t227 = 0.3141592654e1 * t34; + t229 = t227 * xc * t67; + t232 = t73 * t31; + t234 = t146 * t5 * t67; + t238 = t61 * ZB; + t239 = t14 * t8; + t240 = t238 * t239; + t243 = t136 * t93; + t246 = -0.8e1 * t33 * t25 * t186 + 0.32e2 * t90 * t217 - t45 * t35 + t53 * t35 - t134 * t35 - t134 * t46 + + t134 * t14 - 0.4e1 * t226 * t229 + 0.4e1 * t232 * t234 + 0.32e2 * t87 * t65 * t240 + + 0.16e2 * t63 * t243; + t247 = t14 * t92; + t249 = t227 * t247 * xc; + t254 = t73 * t22; + t259 = t60 * t22 * t61; + t260 = t112 * t26; + t264 = t146 * t247 * t5; + t268 = xc * t14; + t274 = t5 * t14; + t275 = t274 * t8; + t280 = n * nx; + t281 = t280 * t22; + t282 = t55 * t14; + t283 = t25 * t282; + t290 = ZA * t247 * xc * ZB; + t295 = t22 * nx * t1 * 0.3141592654e1; + t298 = -0.4e1 * t232 * t249 + 0.8e1 * t105 * t217 - 0.4e1 * t254 * t227 * t26 - 0.8e1 * t259 * t260 - + 0.4e1 * t232 * t264 - 0.16e2 * t81 * t61 * t268 * t8 + 0.16e2 * t80 * t64 * t61 * t275 - + 0.4e1 * t232 * t229 + 0.8e1 * t281 * t283 - 0.4e1 * t105 * t187 + 0.8e1 * t75 * t290 + + 0.4e1 * t295 * t27; + t301 = t61 * t5; + t307 = t87 * t34; + t312 = t61 * xc; + t313 = t312 * t239; + t317 = t34 * t55 * t14; + t329 = ZB * t13 * t55; + t330 = t65 * t329; + t337 = -0.16e2 * t87 * t64 * t301 * t239 - 0.32e2 * t90 * t69 - 0.16e2 * t307 * t64 * t61 * t239 + + 0.16e2 * t307 * t313 + 0.4e1 * t24 * t317 + t53 * t46 + t49 * t35 - 0.32e2 * t63 * t100 - + 0.4e1 * t280 * t31 * t34 * t247 + 0.8e1 * t259 * t330 - 0.4e1 * t280 * t31 * t247 * t5; + t340 = t5 * t35; + t344 = t25 * t93; + t356 = t41 * t13; + t360 = t23 * n * t61; + t363 = t25 * t64 * t7 * t15; + t366 = t156 * t177; + t369 = t14 * t7; + t370 = t25 * t369; + t373 = t156 * t186; + t378 = 0.4e1 * t24 * t283 + 0.4e1 * t33 * t340 * t12 - 0.16e2 * t75 * t344 - 0.4e1 * t280 * t31 * t5 * t67 + + 0.8e1 * t33 * t25 * t247 + 0.32e2 * t63 * t217 + 0.4e1 * t40 * t356 - 0.8e1 * t360 * t363 + + 0.4e1 * t75 * t366 + 0.4e1 * t295 * t370 - 0.4e1 * t75 * t373 - 0.4e1 * t105 * t366; + t382 = t112 * t76; + t387 = t80 * t61; + t391 = t136 * t26; + t409 = 0.16e2 * t63 * t382 + 0.4e1 * t226 * t234 - 0.16e2 * t387 * xc * t275 + 0.8e1 * t259 * t391 - + 0.16e2 * t105 * t344 + 0.4e1 * t226 * t264 - 0.8e1 * t105 * t170 + 0.16e2 * t232 * t193 * t76 + + 0.8e1 * t360 * t330 - 0.8e1 * t105 * t290 + 0.16e2 * t90 * t243; + t423 = t153 * t8; + t426 = t34 * t13; + t427 = t426 * t55; + t430 = t34 * t8; + t437 = t80 * ZA; + t441 = 0.4e1 * t145 * t42 - 0.16e2 * t90 * t157 + 0.24e2 * t75 * t217 + 0.4e1 * t226 * t249 + + 0.4e1 * t254 * t227 * t282 + 0.4e1 * t160 * t356 - 0.8e1 * t129 * t423 - 0.8e1 * t281 * t427 - + 0.8e1 * t33 * t430 * t67 + 0.8e1 * t33 * t430 * t92 + 0.32e2 * t437 * ZB * t313; + t453 = t106 * ZB * t7 * t15; + t456 = t2 * t5; + t459 = t112 * t56; + t462 = t126 * t14; + t474 = t40 * 0.3141592654e1; + t475 = xc * t8; + t480 = t146 * t13 * t35; + t483 = -0.4e1 * t103 * xc * t193 * t147 + 0.16e2 * t87 * t61 * t156 * t239 + 0.8e1 * t259 * t453 - + 0.4e1 * t456 * t356 + 0.8e1 * t259 * t459 - 0.2e1 * t125 * t462 - 0.8e1 * t281 * t207 + + 0.16e2 * t295 * t459 - 0.8e1 * t60 * t22 * ZA * t312 * t329 + 0.4e1 * t474 * t475 * t15 + + 0.4e1 * t160 * t480; + t497 = t136 * t56; + t504 = t9 * t13; + t509 = t475 * t13; + t512 = -0.8e1 * t105 * t113 - 0.4e1 * t254 * t227 * t56 + 0.8e1 * t281 * t57 + 0.4e1 * t295 * t283 + + 0.2e1 * t129 * t462 + 0.4e1 * t24 * t370 - 0.8e1 * t360 * t497 - 0.4e1 * t24 * t427 - + 0.4e1 * t145 * t162 + 0.4e1 * t4 * t504 - 0.8e1 * t281 * t370 - 0.4e1 * t474 * t509; + t528 = t5 * t13; + t529 = t528 * t35; + t532 = t106 * t329; + t542 = -0.16e2 * t295 * t453 - 0.32e2 * t437 * t64 * t240 + 0.8e1 * t281 * t317 + 0.24e2 * t75 * t170 - + 0.4e1 * t75 * t178 + 0.8e1 * t360 * t453 - 0.4e1 * t4 * t529 - 0.16e2 * t295 * t532 - + 0.8e1 * t33 * t344 - 0.16e2 * t90 * t181 + 0.4e1 * t33 * t340 * t92; + t557 = t146 * t15; + t562 = xc * t15; + t563 = t562 * t5; + t573 = 0.16e2 * t232 * t193 * t93 - 0.8e1 * t259 * t363 - 0.8e1 * t259 * t497 + 0.8e1 * t33 * t77 + + 0.8e1 * t360 * t391 + 0.4e1 * t254 * t227 * t369 + 0.4e1 * t145 * t557 + 0.8e1 * t281 * t166 + + 0.4e1 * t3 * t563 + 0.8e1 * t105 * t382 - 0.4e1 * t145 * t480 - 0.4e1 * t33 * t36 * t92; + t600 = 0.4e1 * t456 * t42 - 0.8e1 * t360 * t260 - 0.4e1 * t40 * t557 - 0.4e1 * t105 * t373 + + 0.16e2 * t226 * t227 * t93 - 0.16e2 * t90 * t382 - 0.4e1 * t145 * t356 - 0.16e2 * t63 * t157 - + 0.32e2 * t87 * t25 * t313 - 0.16e2 * t226 * t227 * t76 - 0.16e2 * t63 * t113; + t623 = xc * t13; + t627 = 0.8e1 * t125 * t423 - 0.8e1 * t360 * t532 + 0.16e2 * t90 * t137 - 0.4e1 * t160 * t42 + + 0.16e2 * t63 * t94 + 0.16e2 * t63 * t181 - 0.8e1 * t281 * t27 - 0.8e1 * t75 * t382 + + 0.8e1 * t360 * t459 + 0.4e1 * t295 * t57 + 0.16e2 * t105 * t77 + 0.4e1 * t474 * t623 * t35; + t632 = t61 * 0.3141592654e1; + t633 = t632 * t8; + t634 = t80 * n; + t638 = t632 * t634; + t639 = t638 * xc; + t642 = t61 * t34; + t643 = t122 * t19; + t649 = t61 * t61; + t650 = t649 * t1; + t652 = t19 * t19; + t653 = t14 * t652; + t654 = t653 * t9; + t657 = t14 * t1; + t658 = t657 * t19; + t665 = t632 * t34; + t666 = t665 * t2; + t667 = t8 * t19; + t668 = t667 * t623; + t674 = t665 * n; + t675 = t652 * xc; + t682 = 0.8e1 * t633 * t426 * t634 - 0.8e1 * t639 * t529 - 0.4e1 * t642 * t643 + 0.2e1 * t642 * t116 * t80 + + 0.32e2 * t650 * t64 * t654 + 0.4e1 * t301 * t658 + 0.4e1 * t387 * t46 * ZA * ZB - + 0.16e2 * t666 * t668 - 0.16e2 * t666 * t667 * t15 - 0.8e1 * t674 * t675 * t15 + + 0.4e1 * t238 * t153 * t80; + t683 = t46 * t652; + t686 = t633 * t15; + t691 = t35 * t80; + t698 = t35 * t652; + t705 = t14 * t80; + t708 = t61 * t35; + t717 = -0.2e1 * t642 * t683 - 0.8e1 * t686 * t5 * t634 * xc - 0.2e1 * t301 * t691 + 0.8e1 * t638 * t563 - + 0.2e1 * t642 * t691 - 0.2e1 * t642 * t698 - 0.2e1 * t301 * t698 - 0.2e1 * t301 * t683 + + 0.2e1 * t642 * t705 + 0.2e1 * t708 * t274 * t80 + 0.2e1 * t301 * t653 - 0.2e1 * t642 * t80 * t46; + t727 = t61 * t46; + t737 = t649 * t34; + t738 = t737 * t1; + t739 = t8 * t652; + t740 = t739 * t268; + t746 = t61 * ZA; + t754 = t632 * n * xc; + t758 = 0.2e1 * t301 * t705 + 0.2e1 * t642 * t653 - 0.8e1 * t665 * xc * t634 * t15 - + 0.2e1 * t727 * t5 * t80 - 0.32e2 * t650 * xc * t654 + 0.2e1 * t301 * t698 * t14 - + 0.32e2 * t738 * t740 + 0.8e1 * t674 * t739 * t562 + 0.4e1 * t746 * t119 * t652 + + 0.8e1 * t674 * t698 * t623 - 0.8e1 * t754 * t528 * t698; + t762 = t633 * t13; + t764 = t5 * n * t652; + t767 = t80 * t1; + t768 = t649 * t767; + t772 = t649 * ZA; + t773 = t772 * t129; + t777 = t35 * t1 * t19; + t780 = t632 * t5; + t781 = t780 * t15; + t786 = t698 * ZA; + t790 = t64 * t14; + t800 = t649 * t8; + t809 = 0.4e1 * t238 * t126 * t80 - 0.8e1 * t762 * t764 - 0.32e2 * t768 * xc * t275 + 0.64e2 * t773 * t740 - + 0.4e1 * t301 * t777 - 0.8e1 * t781 * n * t8 * t675 + 0.4e1 * t238 * t786 + + 0.32e2 * t768 * t34 * t790 * t8 - 0.8e1 * t633 * t528 * t634 + 0.8e1 * t754 * t528 * t739 + + 0.128e3 * t800 * t119 * t80 * t19 * t106 + 0.8e1 * t674 * t739 * t13; + t812 = t649 * t80; + t817 = t83 * ZB; + t824 = t746 * ZB; + t828 = t800 * t14; + t855 = -0.64e2 * t812 * xc * t274 * t667 + 0.4e1 * t817 * t786 + 0.4e1 * t727 * ZA * t652 * ZB - + 0.32e2 * t824 * t657 * t667 - 0.32e2 * t828 * t34 * t767 * xc - 0.8e1 * t633 * t15 * t34 * t634 - + 0.8e1 * t674 * t739 * t15 + 0.32e2 * t768 * t64 * t275 + 0.4e1 * t708 * t14 * t307 + + 0.2e1 * t708 * t206 * t652 + 0.8e1 * t632 * t35 * t13 * t34 * t634 * xc; + t858 = t35 * t19; + t873 = t2 * t8; + t878 = t61 * t1; + t901 = -0.16e2 * t632 * t2 * xc * t528 * t858 + 0.8e1 * t824 * t658 + 0.4e1 * t301 * t14 * t777 - + 0.8e1 * t665 * t634 * t509 - 0.8e1 * t674 * t739 * t623 - 0.16e2 * t781 * t873 * t19 * xc + + 0.8e1 * t878 * t14 * t127 + 0.8e1 * t878 * ZA * t51 * ZB + 0.8e1 * t686 * t764 + + 0.8e1 * t665 * xc * t634 * t15 * t8 + 0.8e1 * t633 * t15 * t5 * t634 + + 0.4e1 * t387 * t14 * t107 * ZA; + t903 = t739 * t790; + t923 = t737 * t80; + t924 = t667 * t790; + t927 = t780 * t2; + t937 = t15 * t19 * xc; + t943 = 0.32e2 * t738 * t903 + 0.16e2 * t781 * t873 * t19 + 0.8e1 * t754 * t15 * t652 * t5 + + 0.16e2 * t666 * t858 * t623 + 0.64e2 * t828 * t25 * t767 * xc - 0.16e2 * t762 * t456 * t19 + + 0.64e2 * t923 * t924 + 0.16e2 * t927 * t668 - 0.64e2 * t768 * ZA * t790 * t66 - + 0.64e2 * t773 * t903 + 0.16e2 * t927 * t937 + 0.16e2 * t666 * t667 * t562; + t977 = 0.64e2 * t812 * t5 * t924 + 0.8e1 * t639 * t504 + 0.8e1 * t238 * t35 * t118 * t19 + + 0.4e1 * t642 * t658 - 0.16e2 * t817 * t437 * t8 - 0.128e3 * t772 * ZB * t80 * t924 + + 0.16e2 * t666 * t667 * t13 - 0.4e1 * t301 * t643 - 0.16e2 * t824 * t653 * t8 - 0.4e1 * t642 * t777 - + 0.64e2 * t923 * t667 * t268 - 0.16e2 * t666 * t937; + + _C3A = (t72 + t132 + t169 + t210 + t246 + t298 + t337 + t378 + t409 + t441 + t483 + t512 + t542 + t573 + + t600 + t627) / (t682 + t717 + t758 + t809 + t855 + t901 + t943 + t977); + /****************************************************************************************/ + _C4A = 0; + /****************************************************************************************/ + t1 = nx * 0.3141592654e1; + t2 = t1 * xc; + t3 = cos(t2); + t4 = nx * nx; + t6 = n * 0.3141592654e1; + t7 = t3 * t4 * t6; + t8 = ZA * ZB; + t9 = exp(t6); + t10 = t9 * t9; + t11 = xc * n; + t13 = exp(t11 * 0.3141592654e1); + t14 = t13 * t13; + t15 = t14 * t13; + t16 = t14 * t14; + t17 = t16 * t15; + t18 = t10 * t17; + t19 = t8 * t18; + t22 = sin(t2); + t23 = nx * t22; + t24 = t23 * n; + t25 = ZB * ZB; + t30 = n * n; + t31 = t30 * n; + t32 = t31 * nx; + t33 = 0.3141592654e1 * 0.3141592654e1; + t35 = t32 * t22 * t33; + t36 = ZA * ZA; + t37 = t36 * xc; + t38 = t16 * t13; + t39 = t10 * t38; + t40 = t37 * t39; + t43 = sin(t1); + t44 = nx * t43; + t45 = t30 * 0.3141592654e1; + t46 = t44 * t45; + t47 = ZA * xc; + t49 = ZB * t16 * t9; + t54 = t4 * nx * t43; + t55 = xc * xc; + t57 = t54 * t30 * t55; + t58 = t33 * 0.3141592654e1; + t59 = t58 * t25; + t60 = t16 * t9; + t61 = t59 * t60; + t64 = xc * t25; + t65 = t14 * t9; + t66 = t64 * t65; + t70 = t44 * t31 * t33; + t71 = t37 * t65; + t74 = t10 * t15; + t75 = t64 * t74; + t78 = t25 * t10; + t83 = t54 * n * t33; + t84 = t55 * t25; + t85 = t10 * t9; + t86 = t14 * t85; + t87 = t84 * t86; + t90 = t30 * t30; + t92 = t44 * t90 * t58; + t93 = t55 * xc; + t94 = t93 * t25; + t95 = t85 * t16; + t96 = t94 * t95; + t102 = t23 * t45; + t103 = t10 * t10; + t104 = ZB * t103; + t106 = t47 * t104 * t15; + t111 = t54 * 0.3141592654e1; + t112 = t25 * t85; + t113 = t112 * t16; + t115 = t8 * t39; + t118 = t16 * t14; + t119 = t85 * t118; + t120 = t37 * t119; + t123 = t16 * t16; + t124 = t36 * t123; + t125 = t124 * t9; + t127 = -0.8e1 * t7 * t19 + 0.2e1 * t24 * t25 * t13 * t10 - 0.16e2 * t35 * t40 - 0.16e2 * t46 * t47 * t49 - + 0.8e1 * t57 * t61 + 0.4e1 * t46 * t66 + 0.2e1 * t70 * t71 - 0.16e2 * t35 * t75 + + 0.6e1 * t24 * t78 * t38 - 0.2e1 * t83 * t87 - 0.8e1 * t92 * t96 - 0.8e1 * t46 * t37 * t95 - + 0.12e2 * t102 * t106 + 0.2e1 * t83 * t71 + t111 * t113 + 0.8e1 * t7 * t115 + 0.2e1 * t83 * t120 + + t111 * t125; + t128 = t37 * t74; + t131 = t44 * n; + t133 = t25 * t9 * t118; + t136 = t36 * t14; + t137 = t136 * t9; + t140 = t30 * t4; + t142 = t140 * t3 * t33; + t143 = t64 * t39; + t147 = t30 * nx * t43; + t148 = 0.3141592654e1 * t36; + t149 = t9 * t118; + t153 = t44 * t31 * ZA; + t154 = t33 * xc; + t155 = t154 * t49; + t160 = ZA * t17 * xc * ZB; + t163 = t103 * t13; + t164 = t64 * t163; + t170 = t44 * t90 * t55; + t171 = t58 * ZB; + t172 = ZA * t16; + t174 = t171 * t172 * t9; + t177 = t36 * t55; + t178 = t177 * t149; + t181 = t54 * t11; + t182 = t33 * t25; + t186 = t25 * t14; + t187 = t186 * t9; + t193 = t186 * t85; + t198 = ZB * t55; + t199 = ZA * t103; + t201 = t198 * t199 * t15; + t204 = 0.2e1 * t7 * t128 - 0.2e1 * t131 * t133 - 0.2e1 * t131 * t137 + 0.16e2 * t142 * t143 - + t147 * t148 * t149 + 0.8e1 * t153 * t155 - 0.4e1 * t7 * t160 + 0.2e1 * t7 * t164 + + 0.10e2 * t102 * t40 + 0.16e2 * t170 * t174 + 0.2e1 * t83 * t178 - 0.2e1 * t181 * t182 * t65 - + t111 * t187 - 0.2e1 * t70 * t87 + 0.4e1 * t102 * t160 - 0.2e1 * t131 * t193 - 0.16e2 * t142 * t75 + + 0.16e2 * t35 * t201; + t210 = t32 * t22; + t211 = t33 * t55; + t212 = t25 * t38; + t213 = t211 * t212; + t216 = n * nx; + t217 = t22 * t25; + t222 = ZB * t85 * t16; + t226 = t23 * t30; + t227 = t13 * t10; + t228 = t148 * t227; + t233 = t37 * t163; + t237 = n * t4 * t3; + t238 = t148 * t74; + t241 = t64 * t86; + t245 = t148 * xc * t15; + t248 = t112 * t118; + t250 = t22 * t36; + t256 = 0.3141592654e1 * t25; + t257 = t256 * t39; + t262 = t38 * t103; + t263 = t37 * t262; + t267 = t148 * t17 * xc; + t270 = -0.6e1 * t7 * t143 - 0.4e1 * t24 * t19 - 0.8e1 * t210 * t213 - 0.2e1 * t216 * t217 * t15 - + 0.32e2 * t153 * t211 * t222 + 0.4e1 * t226 * t228 + 0.16e2 * t142 * t201 + 0.2e1 * t7 * t233 - + 0.4e1 * t237 * t238 - 0.2e1 * t83 * t241 - 0.2e1 * t237 * t245 + t111 * t248 + + 0.2e1 * t216 * t250 * t15 - 0.2e1 * t131 * t125 - 0.4e1 * t226 * t257 + t147 * t148 * t95 - + 0.2e1 * t102 * t263 + 0.2e1 * t237 * t267; + t273 = t37 * t149; + t277 = t47 * t104 * t13; + t285 = t31 * t36; + t286 = t44 * t285; + t291 = t25 * t123 * t9; + t304 = 0.3141592654e1 * xc; + t305 = t304 * t212; + t312 = t256 * t18; + t315 = t8 * t60; + t319 = t54 * t30 * t58; + t323 = t90 * t36; + t324 = t44 * t323; + t325 = t55 * t58; + t326 = t325 * t60; + t329 = 0.2e1 * t102 * t164 + 0.2e1 * t83 * t273 - 0.4e1 * t102 * t277 - 0.2e1 * t7 * t263 + + 0.4e1 * t24 * t8 * t17 - 0.4e1 * t286 * t154 * t60 - 0.2e1 * t131 * t291 - t147 * t148 * t119 + + 0.2e1 * t24 * t78 * t17 + 0.2e1 * t54 * t85 * 0.3141592654e1 * ZA * ZB - 0.4e1 * t226 * t305 - + 0.2e1 * t70 * t66 + t147 * t256 * t95 + 0.4e1 * t237 * t312 + 0.2e1 * t111 * t315 - + 0.8e1 * t319 * t96 - t111 * t193 - 0.8e1 * t324 * t326; + t332 = t8 * t95; + t335 = t136 * t85; + t337 = t256 * t227; + t340 = t177 * t119; + t346 = t37 * t86; + t351 = t103 * t15; + t352 = t177 * t351; + t355 = t64 * t119; + t358 = t8 * t227; + t361 = t85 * 0.3141592654e1; + t365 = t84 * t39; + t372 = ZB * t10; + t373 = t372 * t38; + t374 = t47 * t373; + t379 = t177 * t39; + t384 = -0.2e1 * t46 * t332 + t111 * t335 + 0.4e1 * t237 * t337 - 0.2e1 * t83 * t340 + + 0.16e2 * t286 * t211 * t95 + 0.2e1 * t70 * t346 - 0.8e1 * t170 * t61 - 0.8e1 * t142 * t352 - + 0.2e1 * t83 * t355 - 0.4e1 * t24 * t358 + 0.2e1 * t147 * t361 * t8 + 0.8e1 * t35 * t365 - + 0.2e1 * t226 * t267 + 0.8e1 * t102 * t115 - 0.12e2 * t102 * t374 + 0.16e2 * t142 * t40 - + 0.8e1 * t142 * t379 + 0.4e1 * t237 * t228; + t386 = t54 * t30 * t93; + t387 = ZA * t85; + t389 = t171 * t387 * t16; + t394 = t64 * t60; + t398 = t304 * t25 * t15; + t401 = t361 * t25; + t405 = t84 * t65; + t410 = t148 * t18; + t414 = t25 * t16 * t9; + t417 = t84 * t74; + t422 = t177 * t86; + t428 = ZB * t38; + t429 = t47 * t428; + t432 = t148 * t39; + t439 = 0.16e2 * t386 * t389 - 0.16e2 * t386 * t174 + 0.8e1 * t46 * t394 + 0.2e1 * t237 * t398 - + t147 * t401 + 0.4e1 * t7 * t374 + 0.2e1 * t83 * t405 - 0.4e1 * t46 * t241 - 0.4e1 * t226 * t410 + + 0.2e1 * t131 * t414 + 0.8e1 * t35 * t417 - 0.8e1 * t142 * t365 + 0.2e1 * t70 * t422 - + 0.4e1 * t181 * t182 * t60 + 0.12e2 * t102 * t429 - 0.4e1 * t226 * t432 + 0.32e2 * t35 * t374 - + 0.4e1 * t7 * t106; + t442 = t36 * t9 * t118; + t444 = t123 * t9; + t445 = t8 * t444; + t448 = t361 * t36; + t451 = t47 * t372 * t17; + t454 = t94 * t60; + t457 = t25 * t103; + t465 = t47 * t372 * t15; + t468 = t36 * t85; + t469 = t468 * t16; + t474 = t43 * t85; + t478 = t8 * t74; + t484 = t256 * t74; + t489 = t198 * ZA * t10 * t15; + t501 = -t111 * t442 + 0.4e1 * t131 * t445 - t147 * t448 + 0.4e1 * t7 * t451 + 0.8e1 * t92 * t454 - + 0.2e1 * t24 * t457 * t13 - 0.2e1 * t286 * t211 * t65 + 0.4e1 * t7 * t465 + t111 * t469 - + 0.2e1 * t216 * t250 * t17 - 0.2e1 * t216 * t474 * t25 - 0.4e1 * t24 * t478 + 0.4e1 * t24 * t8 * t38 + + 0.4e1 * t226 * t484 - 0.16e2 * t142 * t489 - 0.2e1 * t24 * t212 * t103 - + 0.2e1 * t216 * t22 * t17 * t25 + 0.2e1 * t70 * t120; + t504 = t33 * t36 * t55 * t38; + t507 = t37 * t18; + t512 = t47 * ZB * t13 * t10; + t518 = t59 * t95; + t530 = t84 * t351; + t534 = t37 * t227; + t549 = -0.8e1 * t210 * t504 + 0.2e1 * t102 * t507 + 0.4e1 * t7 * t512 + t111 * t133 - 0.16e2 * t35 * t489 + + 0.8e1 * t170 * t518 + 0.2e1 * t24 * t36 * t13 * t10 + 0.4e1 * t131 * t387 * ZB + + 0.12e2 * t102 * t465 - 0.8e1 * t142 * t530 + t111 * t291 - 0.2e1 * t102 * t534 - 0.4e1 * t70 * t394 - + 0.10e2 * t102 * t128 + 0.4e1 * t237 * t305 + 0.8e1 * t102 * t19 + 0.2e1 * t83 * t346 - + 0.16e2 * t35 * t128; + t557 = t468 * t118; + t562 = t93 * t58; + t563 = t562 * t60; + t567 = t44 * t90 * t93; + t575 = ZA * t55; + t576 = t575 * t428; + t583 = t37 * t60; + t590 = t140 * t3; + t601 = -0.2e1 * t226 * t398 - 0.2e1 * t70 * t340 - 0.2e1 * t131 * t557 - 0.4e1 * t24 * t115 + + 0.8e1 * t324 * t563 + 0.16e2 * t567 * t389 + 0.16e2 * t70 * t84 * t95 + 0.2e1 * t70 * t178 - + 0.16e2 * t142 * t576 - 0.4e1 * t237 * t257 - 0.4e1 * t226 * t312 + 0.8e1 * t46 * t583 + + 0.2e1 * t24 * t36 * t38 * t103 + 0.8e1 * t590 * t213 + 0.2e1 * t102 * t143 - 0.16e2 * t35 * t143 + + 0.2e1 * t131 * t248 + 0.4e1 * t46 * t346; + t604 = n * t36; + t606 = t154 * t95; + t625 = t36 * t103; + t640 = t30 * t36; + t641 = t54 * t640; + t642 = t325 * t95; + t647 = -0.4e1 * t131 * t315 - 0.4e1 * t54 * t604 * t606 - t147 * t148 * t60 + 0.16e2 * t35 * t576 - + 0.8e1 * t102 * t478 + 0.32e2 * t142 * t465 - 0.4e1 * t237 * t484 - 0.2e1 * t70 * t355 + + 0.2e1 * t70 * t273 + 0.2e1 * t102 * t233 - 0.2e1 * t24 * t625 * t13 - 0.8e1 * t7 * t358 - + 0.2e1 * t111 * t445 - 0.4e1 * t7 * t429 + 0.16e2 * t46 * t47 * t222 + 0.2e1 * t131 * t113 + + 0.8e1 * t641 * t642 - 0.2e1 * t7 * t534; + t652 = t36 * t16; + t653 = t652 * t9; + t655 = t64 * t227; + t658 = t182 * t95; + t663 = t562 * t95; + t684 = t64 * t351; + t689 = t36 * t10; + t695 = t154 * t222; + t698 = -0.4e1 * t216 * t217 * t38 - t111 * t653 - 0.2e1 * t7 * t655 - 0.4e1 * t181 * t658 + + 0.2e1 * t131 * t469 - 0.8e1 * t641 * t663 - 0.4e1 * t83 * t583 - 0.2e1 * t83 * t177 * t65 - + 0.4e1 * t24 * t457 * t15 + 0.16e2 * t70 * t84 * t60 + 0.8e1 * t57 * t518 - 0.32e2 * t142 * t374 + + 0.4e1 * t24 * t8 * t351 + 0.4e1 * t102 * t684 - t147 * t256 * t86 - 0.2e1 * t24 * t689 * t15 - + 0.2e1 * t70 * t241 + 0.8e1 * t153 * t695; + t711 = t575 * t373; + t717 = t304 * t17 * t25; + t736 = t177 * t74; + t739 = 0.2e1 * t226 * t245 - 0.8e1 * t102 * t358 - 0.16e2 * t57 * t389 - 0.2e1 * t102 * t655 + + 0.8e1 * t590 * t504 - 0.8e1 * t641 * t326 - 0.16e2 * t35 * t711 - t111 * t557 + t111 * t137 - + 0.2e1 * t226 * t717 + 0.8e1 * t102 * t37 * t351 + 0.2e1 * t131 * t335 - 0.4e1 * t131 * t332 - + 0.2e1 * t216 * t474 * t36 - 0.2e1 * t111 * t332 + 0.16e2 * t142 * t711 - t147 * t256 * t60 + + 0.8e1 * t142 * t736; + t750 = t64 * t262; + t763 = t44 * t640; + t770 = t84 * t119; + t782 = 0.4e1 * t102 * t512 + 0.8e1 * t142 * t417 + 0.8e1 * t641 * t563 - 0.2e1 * t7 * t507 + + 0.2e1 * t7 * t750 - 0.8e1 * t35 * t352 + 0.4e1 * t237 * t410 + 0.4e1 * t7 * t684 - + 0.2e1 * t46 * t445 + t147 * t148 * t65 + 0.4e1 * t763 * t304 * t119 + 0.16e2 * t70 * t177 * t60 + + 0.2e1 * t70 * t770 - t111 * t414 - 0.16e2 * t567 * t174 - 0.4e1 * t46 * t71 - 0.4e1 * t46 * t355 - + 0.4e1 * t7 * t277; + t797 = t64 * t149; + t821 = -t54 * t448 + 0.2e1 * t131 * t442 + 0.8e1 * t7 * t478 + 0.8e1 * t35 * t379 - + 0.2e1 * t181 * t182 * t149 + 0.2e1 * t70 * t405 + 0.2e1 * t83 * t770 - 0.2e1 * t70 * t797 - + 0.6e1 * t7 * t75 - 0.4e1 * t286 * t606 - 0.4e1 * t237 * t432 + t147 * t256 * t149 - + 0.4e1 * t763 * t304 * t149 - 0.2e1 * t102 * t75 + 0.2e1 * t237 * t717 + 0.8e1 * t324 * t642 - + 0.16e2 * t170 * t389 + 0.2e1 * t83 * t422; + t827 = t84 * t149; + t846 = t54 * n * ZA; + t854 = t64 * t18; + t867 = -0.16e2 * t142 * t128 + 0.32e2 * t35 * t465 - 0.2e1 * t83 * t827 + 0.2e1 * t46 * t315 + + t147 * t148 * t86 - 0.4e1 * t102 * t451 - 0.8e1 * t226 * t148 * xc * t38 - 0.2e1 * t24 * t689 * t38 + + 0.2e1 * t131 * t187 + 0.8e1 * t846 * t155 + 0.8e1 * t35 * t736 + 0.2e1 * t24 * t689 * t17 - + 0.2e1 * t7 * t854 + t147 * t256 * t119 + 0.2e1 * t102 * t854 - 0.8e1 * t35 * t530 + + 0.4e1 * t46 * t797 + 0.2e1 * t102 * t750; + t909 = -0.8e1 * t324 * t663 + t147 * t256 * t444 - t147 * t256 * t65 + 0.4e1 * t226 * t238 + + 0.2e1 * t7 * t40 - t54 * t401 + 0.16e2 * t57 * t174 + 0.4e1 * t226 * t337 + 0.4e1 * t24 * t8 * t163 + + 0.8e1 * t846 * t695 + 0.8e1 * t319 * t454 + 0.2e1 * t131 * t653 - 0.8e1 * t46 * t64 * t95 + + 0.6e1 * t24 * t78 * t15 - 0.4e1 * t44 * t31 * xc * t658 - 0.32e2 * t153 * t211 * t49 - + 0.2e1 * t70 * t827 + t147 * t148 * t444; + t914 = t25 * ZB; + t915 = t33 * t914; + t919 = t4 * t4; + t920 = t16 * t919; + t929 = t123 * t90; + t932 = t919 * t103; + t935 = t33 * ZB; + t939 = t652 * t919; + t942 = t16 * t30; + t943 = t942 * t4; + t949 = t103 * t16; + t950 = t949 * t90; + t953 = -0.2e1 * t915 * t103 * t90 + 0.2e1 * t915 * t920 - 0.2e1 * t915 * t123 * t919 + + 0.2e1 * t915 * t16 * t90 - 0.2e1 * t915 * t929 - 0.2e1 * t915 * t932 - 0.2e1 * t935 * t323 * t123 + + 0.2e1 * t935 * t939 + 0.4e1 * t915 * t943 + 0.4e1 * t182 * t172 * t90 + 0.2e1 * t915 * t950; + t954 = t171 * t36; + t955 = t90 * n; + t956 = xc * t955; + t957 = t118 * t10; + t964 = t33 * t33; + t965 = t964 * ZB; + t966 = t965 * t640; + t967 = t10 * t919; + t968 = t55 * t16; + t969 = t967 * t968; + t972 = t935 * t36; + t974 = t103 * t30 * t4; + t977 = xc * t16; + t978 = t967 * t977; + t981 = t90 * t30; + t983 = t16 * t10; + t987 = t182 * ZA; + t988 = t4 * t10; + t992 = t171 * t604; + t993 = xc * t14; + t994 = t932 * t993; + t997 = t182 * t30; + t1005 = t171 * t285; + t1006 = t988 * t993; + t1009 = t58 * t914; + t1010 = t1009 * t31; + t1013 = 0.8e1 * t954 * t956 * t957 + 0.2e1 * t915 * t932 * t16 + 0.32e2 * t966 * t969 - + 0.4e1 * t972 * t974 - 0.32e2 * t966 * t978 + 0.32e2 * t965 * t981 * t177 * t983 - + 0.32e2 * t987 * t942 * t988 + 0.8e1 * t992 * t994 + 0.8e1 * t997 * t949 * ZA * t4 - + 0.2e1 * t935 * t124 * t919 - 0.16e2 * t1005 * t1006 + 0.16e2 * t1010 * t1006; + t1015 = t964 * t25; + t1016 = ZA * t30; + t1017 = t1015 * t1016; + t1020 = t967 * t993; + t1031 = t1009 * t118; + t1032 = t31 * t10; + t1040 = t964 * t914; + t1041 = t1040 * t90; + t1044 = t55 * t10 * t4 * t16; + t1047 = t1040 * t30; + t1050 = t123 * ZA; + t1054 = t977 * t988; + t1057 = 0.64e2 * t1017 * t978 - 0.8e1 * t992 * t1020 + 0.2e1 * t972 * t950 + 0.4e1 * t182 * t929 * ZA + + 0.4e1 * t182 * t199 * t90 - 0.16e2 * t1031 * t1032 * t4 * xc + 0.4e1 * t182 * t172 * t919 + + 0.64e2 * t1041 * t1044 + 0.32e2 * t1047 * t969 + 0.4e1 * t182 * t1050 * t919 - + 0.64e2 * t1041 * t1054; + t1058 = t1009 * n; + t1063 = t932 * ZA; + t1069 = t123 * t30 * t4; + t1080 = t993 * t103 * t4; + t1088 = t935 * t103; + t1094 = -0.8e1 * t1058 * t994 - 0.32e2 * t1047 * t978 + 0.4e1 * t182 * t1063 - 0.4e1 * t915 * t974 - + 0.4e1 * t915 * t1069 - 0.2e1 * t935 * t625 * t90 - 0.8e1 * t1009 * t10 * t14 * t955 - + 0.16e2 * t1010 * t1080 - 0.2e1 * t935 * t625 * t919 - 0.64e2 * t1017 * t969 + 0.2e1 * t1088 * t939 + + 0.8e1 * t1009 * t957 * t955; + t1113 = t955 * t118 * xc; + t1120 = t4 * t118; + t1125 = t981 * xc; + t1133 = n * t10; + t1140 = -0.8e1 * t954 * t955 * t10 * t993 + 0.2e1 * t935 * t652 * t90 - + 0.64e2 * t1015 * t981 * t575 * t983 + 0.8e1 * t182 * t103 * t1016 * t4 + 0.8e1 * t1009 * t1113 + + 0.16e2 * t954 * t1032 * t4 * t14 - 0.16e2 * t954 * t1032 * t1120 + + 0.64e2 * t1015 * t10 * t172 * t1125 + 0.8e1 * t171 * t103 * t136 * t956 - + 0.8e1 * t1031 * t1133 * t919 * xc + 0.8e1 * t1058 * t1020; + t1153 = xc * t118; + t1165 = t182 * t16; + t1170 = t171 * t10; + t1178 = ZA * t90; + t1182 = 0.4e1 * t1088 * t652 * t140 + 0.8e1 * t954 * t1133 * t919 * t14 + 0.4e1 * t972 * t943 - + 0.4e1 * t972 * t1069 - 0.16e2 * t954 * t31 * t4 * t1153 - 0.8e1 * t954 * n * t919 * t1153 - + 0.8e1 * t954 * t1133 * t919 * t118 + 0.4e1 * t1165 * t1063 + 0.16e2 * t1005 * t1080 - + 0.8e1 * t1170 * t118 * t36 * t955 - 0.16e2 * t987 * t920 * t10 - 0.16e2 * t1165 * t1178 * t10; + t1195 = t1040 * t981; + t1199 = t1009 * t955; + t1203 = t1009 * t10; + t1211 = t965 * t323; + t1225 = -0.32e2 * t965 * t10 * t652 * t1125 + 0.4e1 * t915 * t16 * t974 + 0.4e1 * t182 * t90 * t949 * ZA + + 0.32e2 * t1195 * t968 * t10 - 0.8e1 * t1199 * t993 * t103 + 0.8e1 * t1203 * t118 * n * t919 + + 0.8e1 * t1170 * t136 * t955 + 0.64e2 * t1211 * t1044 + 0.16e2 * t1031 * t1032 * t4 + + 0.8e1 * t987 * t943 + 0.8e1 * t1199 * t993 * t10 + 0.8e1 * t997 * t1050 * t4; + t1263 = -0.128e3 * t1015 * t1178 * t1044 + 0.16e2 * t1005 * t988 * t1153 + 0.8e1 * t1058 * t1153 * t919 + + 0.16e2 * t1010 * t1120 * xc - 0.8e1 * t954 * t1113 - 0.8e1 * t1203 * t14 * n * t919 - + 0.16e2 * t1203 * t14 * t31 * t4 - 0.8e1 * t1203 * t1113 - 0.32e2 * t1195 * t977 * t10 - + 0.64e2 * t1211 * t1054 + 0.8e1 * t992 * t967 * t1153 + 0.128e3 * t1015 * t983 * t90 * t4 * t47; + + _C1B = (t127 + t204 + t270 + t329 + t384 + t439 + t501 + t549 + t601 + t647 + t698 + t739 + t782 + t821 + + t867 + t909) / (t953 + t1013 + t1057 + t1094 + t1140 + t1182 + t1225 + t1263); + /****************************************************************************************/ + t1 = n * n; + t2 = t1 * n; + t3 = nx * t2; + t4 = 0.3141592654e1 * ZA; + t5 = t3 * t4; + t6 = nx * 0.3141592654e1; + t7 = t6 * xc; + t8 = sin(t7); + t9 = t8 * ZB; + t10 = n * 0.3141592654e1; + t11 = exp(t10); + t12 = t11 * t11; + t15 = exp(xc * n * 0.3141592654e1); + t16 = t15 * t15; + t17 = t16 * t16; + t18 = t17 * t15; + t19 = t12 * t18; + t23 = t1 * t1; + t24 = nx * t23; + t25 = ZB * ZB; + t27 = t18 * t8; + t28 = 0.3141592654e1 * 0.3141592654e1; + t29 = xc * xc; + t30 = t28 * t29; + t34 = t1 * xc; + t35 = 0.3141592654e1 * ZB; + t36 = t34 * t35; + t37 = cos(t7); + t38 = ZA * t37; + t39 = nx * nx; + t40 = t39 * t12; + t41 = t16 * t15; + t43 = t38 * t40 * t41; + t46 = t25 * n; + t47 = t46 * 0.3141592654e1; + t48 = t39 * nx; + t49 = sin(t6); + t50 = t48 * t49; + t51 = t12 * t11; + t52 = t51 * t17; + t53 = t50 * t52; + t56 = t34 * 0.3141592654e1 * t25; + t57 = t37 * t39; + t58 = t17 * t41; + t59 = t12 * t58; + t60 = t57 * t59; + t63 = t25 * t18; + t64 = t57 * n; + t67 = ZA * ZA; + t68 = t67 * n; + t69 = 0.3141592654e1 * t48; + t70 = t68 * t69; + t71 = t49 * xc; + t72 = t17 * t16; + t73 = t11 * t72; + t74 = t71 * t73; + t77 = t1 * t67; + t78 = t77 * 0.3141592654e1; + t81 = nx * t25; + t82 = t81 * t49; + t83 = t17 * t17; + t85 = t1 * t83 * t11; + t87 = nx * ZB; + t88 = t8 * t2; + t89 = t87 * t88; + t90 = 0.3141592654e1 * xc; + t91 = t12 * t12; + t92 = ZA * t91; + t97 = ZB * ZA; + t98 = t97 * t37; + t99 = t39 * n; + t100 = t12 * t41; + t104 = 0.8e1 * t5 * t9 * t19 + 0.8e1 * t24 * t25 * t27 * t30 + 0.12e2 * t36 * t43 - t47 * t53 - + 0.2e1 * t56 * t60 - 0.4e1 * t63 * t64 + 0.6e1 * t70 * t74 + 0.4e1 * t78 * t60 - t82 * t85 + + 0.4e1 * t89 * t90 * t92 * t41 + 0.4e1 * t98 * t99 * t100; + t105 = t67 * t48; + t106 = t49 * t51; + t107 = t106 * t72; + t109 = t1 * 0.3141592654e1; + t110 = t109 * xc; + t115 = nx * t67; + t116 = t115 * t49; + t117 = t1 * t16; + t118 = t117 * t11; + t120 = t2 * t25; + t121 = t28 * 0.3141592654e1; + t122 = t121 * t29; + t123 = t120 * t122; + t129 = t1 * ZB; + t130 = t129 * t4; + t131 = t57 * t100; + t134 = t12 * t16; + t136 = t109 * t39; + t139 = ZB * t18; + t141 = t39 * t1; + t142 = t141 * t90; + t145 = t77 * t90; + t146 = t91 * t41; + t147 = t57 * t146; + t151 = t25 * t39 * t1; + t152 = t72 * t12; + t156 = t49 * t2; + t158 = t83 * t11; + t162 = -t105 * t107 + 0.8e1 * t110 * t72 * t25 * t39 - t116 * t118 + 0.8e1 * t123 * t53 + + 0.8e1 * t5 * t9 * t59 - 0.8e1 * t130 * t131 - 0.8e1 * t134 * t25 * t136 - + 0.12e2 * t139 * t38 * t142 - 0.8e1 * t145 * t147 - 0.8e1 * t151 * t90 * t152 - + 0.2e1 * t87 * t156 * t4 * t158; + t164 = t115 * t88; + t165 = t90 * t19; + t168 = t25 * t48; + t169 = t49 * t16; + t170 = t169 * t11; + t174 = ZA * n * t69; + t175 = ZB * t51; + t176 = t175 * t17; + t177 = t71 * t176; + t180 = t1 * t29; + t181 = t28 * t25; + t182 = t180 * t181; + t183 = t50 * t73; + t186 = ZA * t1; + t187 = t28 * t48; + t188 = t186 * t187; + t189 = ZB * t17; + t190 = t189 * t11; + t191 = t71 * t190; + t194 = t50 * t158; + t196 = t115 * t156; + t197 = t90 * t73; + t201 = t49 * t17 * t11; + t204 = t88 * t90; + t207 = t68 * 0.3141592654e1; + t208 = t17 * t11; + t209 = t50 * t208; + t211 = -0.2e1 * t164 * t165 - t168 * t170 + t168 * t107 + 0.8e1 * t174 * t177 + 0.2e1 * t182 * t183 + + 0.8e1 * t188 * t191 + t47 * t194 - 0.6e1 * t196 * t197 - t168 * t201 - 0.4e1 * t81 * t18 * t204 - + t207 * t209; + t212 = t2 * 0.3141592654e1; + t213 = t212 * t52; + t215 = t81 * t8; + t216 = t212 * t59; + t219 = t3 * t90; + t220 = t25 * t8; + t221 = t18 * t91; + t225 = t71 * t52; + t231 = t16 * t51; + t232 = t50 * t231; + t237 = ZA * t12; + t243 = t67 * t28; + t244 = t24 * t243; + t245 = t71 * t231; + t249 = -t116 * t213 - 0.4e1 * t215 * t216 + 0.2e1 * t219 * t220 * t221 - 0.4e1 * t70 * t225 + + 0.4e1 * t98 * t99 * t146 + t47 * t232 - 0.2e1 * t145 * t57 * t221 + 0.4e1 * t89 * t90 * t237 * t41 - + t105 * t201 - 0.6e1 * t244 * t245 + t105 * t170; + t252 = t25 * t37; + t253 = t252 * t39; + t255 = n * t15 * t12; + t258 = t2 * t29; + t259 = ZB * t28; + t260 = t258 * t259; + t263 = t106 * t17; + t265 = xc * t25; + t269 = t25 * t49; + t270 = t269 * t52; + t273 = t1 * t25; + t274 = t273 * 0.3141592654e1; + t275 = t57 * t19; + t278 = t24 * t30; + t288 = t1 * t11 * t72; + t290 = t212 * t208; + t292 = t2 * xc; + t296 = 0.2e1 * t253 * t255 + 0.16e2 * t260 * t43 + t105 * t263 - 0.4e1 * t10 * t265 * t53 + + 0.4e1 * t219 * t270 - 0.12e2 * t274 * t275 + 0.8e1 * t278 * t270 - + 0.2e1 * ZB * n * t69 * t49 * ZA * t158 - t82 * t288 - t116 * t290 + 0.16e2 * t292 * t243 * t275; + t301 = t50 * t176; + t304 = t51 * t72; + t305 = t71 * t304; + t308 = t25 * t41; + t311 = ZA * t48; + t312 = t311 * t49; + t317 = t91 * t15; + t318 = t57 * t317; + t321 = t81 * t88; + t322 = t90 * t59; + t325 = t212 * t231; + t327 = t15 * t12; + t328 = t57 * t327; + t331 = t77 * t187; + t334 = t2 * ZA; + t335 = t334 * t122; + t336 = t50 * t190; + t339 = 0.8e1 * t151 * t90 * t134 + 0.16e2 * t186 * t30 * t301 - 0.2e1 * t70 * t305 + 0.2e1 * t308 * t64 - + 0.2e1 * t312 * ZB * t83 * t11 + 0.2e1 * t56 * t318 + 0.2e1 * t321 * t322 - t116 * t325 - + 0.4e1 * t274 * t328 + 0.2e1 * t331 * t305 - 0.16e2 * t335 * t336; + t341 = t169 * t51; + t344 = t49 * t11 * t72; + t346 = t77 * t30; + t347 = t50 * t304; + t350 = t25 * t51; + t352 = nx * ZA; + t353 = t49 * t23; + t354 = t352 * t353; + t355 = t28 * xc; + t362 = t25 * t91; + t365 = t23 * n; + t366 = nx * t365; + t367 = t366 * t122; + t368 = ZB * t49; + t369 = ZA * t51; + t370 = t369 * t17; + t371 = t368 * t370; + t374 = t115 * t353; + t375 = t355 * t73; + t381 = t105 * t341 - t105 * t344 - 0.2e1 * t346 * t347 - t350 * t50 - 0.8e1 * t354 * t355 * t176 - + 0.4e1 * t98 * t99 * t317 - 0.2e1 * t362 * t99 - 0.16e2 * t367 * t371 + 0.6e1 * t374 * t375 - + 0.8e1 * t182 * t53 - t82 * t290; + t382 = t71 * t208; + t394 = t2 * t67; + t395 = t394 * t122; + t398 = t352 * t156; + t402 = t17 * t12; + t403 = t39 * ZA; + t404 = t402 * t403; + t407 = t269 * t208; + t411 = t49 * t83 * t11; + t413 = t46 * t69; + t419 = -0.4e1 * t331 * t382 + 0.2e1 * t115 * t58 * t204 - 0.2e1 * t145 * t60 + 0.12e2 * t274 * t131 + + 0.2e1 * t346 * t232 + 0.8e1 * t395 * t53 - 0.8e1 * t398 * t90 * t176 - 0.64e2 * t260 * t404 + + 0.4e1 * t219 * t407 + t168 * t411 - 0.6e1 * t413 * t74 - 0.2e1 * t110 * t308 * t57; + t424 = t16 * t11; + t425 = t212 * t424; + t427 = t258 * t181; + t430 = t67 * t29; + t431 = t366 * t430; + t432 = t121 * t49; + t433 = t432 * t52; + t436 = n * t12; + t437 = t436 * t18; + t440 = t29 * xc; + t441 = t440 * t121; + t442 = t394 * t441; + t445 = t67 * t37; + t446 = t445 * t39; + t448 = n * t18 * t91; + t453 = t352 * t49; + t458 = t8 * t23; + t462 = t81 * t458; + t463 = t30 * t19; + t466 = -t47 * t209 + t116 * t425 - 0.8e1 * t427 * t275 + 0.8e1 * t431 * t433 - 0.2e1 * t253 * t437 - + 0.8e1 * t442 * t53 - 0.2e1 * t446 * t448 + 0.2e1 * t175 * t312 + 0.6e1 * t453 * t129 * t208 + + 0.8e1 * t115 * t18 * t458 * t30 + 0.8e1 * t462 * t463; + t470 = t436 * t58; + t475 = t2 * t121 * t440 * t25; + t485 = t212 * t73; + t488 = t67 * t72 * t1; + t490 = t39 * xc; + t501 = 0.4e1 * t374 * t355 * t52 + 0.2e1 * t446 * t470 - 0.8e1 * t475 * t53 - 0.2e1 * t446 * t437 - + 0.4e1 * t36 * t38 * t39 * t15 * t12 - t116 * t485 + 0.8e1 * t488 * 0.3141592654e1 * t12 * t490 - + t207 * t183 - 0.2e1 * t182 * t232 - 0.6e1 * t413 * t245 - 0.4e1 * t413 * t382; + t503 = t115 * t8; + t510 = t355 * t19; + t513 = t432 * t208; + t525 = t38 * t40 * t18; + t533 = -0.4e1 * t503 * t216 - 0.4e1 * t89 * t90 * t92 * t15 - 0.16e2 * t462 * t510 + 0.8e1 * t431 * t513 - + 0.4e1 * t78 * t131 + t47 * t183 - 0.2e1 * t67 * t83 * t99 + 0.4e1 * t331 * t225 + + 0.16e2 * t260 * t525 - 0.4e1 * t89 * t90 * t237 * t58 - t207 * t53; + t536 = t28 * t37; + t538 = t490 * t100; + t541 = t334 * t441; + t547 = t394 * t30; + t550 = t212 * t19; + t553 = t366 * t441; + t556 = n * t17; + t571 = -0.8e1 * t427 * t131 + 0.16e2 * t394 * t536 * t538 + 0.16e2 * t541 * t336 + + 0.2e1 * t453 * t129 * t158 - 0.8e1 * t547 * t147 + 0.4e1 * t503 * t550 - 0.8e1 * t553 * t270 + + 0.4e1 * t556 * ZB * t92 * t39 - 0.2e1 * t67 * t91 * t99 - t82 * t425 + 0.4e1 * t78 * t275 + + 0.2e1 * t78 * xc * t41 * t57; + t583 = t90 * t317; + t594 = t212 * t158; + t596 = t152 * t67; + t602 = t67 * t17; + t607 = 0.8e1 * t367 * t407 - 0.4e1 * t98 * t99 * t59 + 0.16e2 * t260 * t18 * ZA * t57 + + 0.2e1 * t321 * t583 - 0.6e1 * t174 * t368 * t52 - 0.4e1 * t89 * t90 * ZA * t15 * t12 + t116 * t594 - + 0.8e1 * t596 * t136 - 0.4e1 * t98 * t99 * t327 + 0.2e1 * t602 * t99 + 0.2e1 * t164 * t583; + t613 = t83 * t25; + t616 = t81 * t156; + t627 = t90 * t231; + t630 = t91 * t16; + t638 = 0.4e1 * t196 * t90 * t208 - 0.8e1 * t130 * t60 - 0.2e1 * t613 * t99 + 0.6e1 * t616 * t197 - + 0.8e1 * t547 * t131 + 0.8e1 * t67 * t18 * t37 * t142 + 0.2e1 * t145 * t328 - 0.6e1 * t196 * t627 + + 0.8e1 * t630 * t67 * t142 - 0.8e1 * t547 * t275 + 0.8e1 * t395 * t209; + t643 = t77 * t355; + t648 = t115 * t458; + t651 = t134 * t67; + t657 = t30 * t304; + t660 = t30 * t146; + t665 = t25 * t17; + t668 = t50 * t424; + t671 = -0.4e1 * t321 * t90 * t146 - 0.6e1 * t643 * t232 + 0.8e1 * t182 * t209 - 0.16e2 * t648 * t510 + + 0.8e1 * t651 * t136 + 0.8e1 * t89 * t4 * t100 - 0.2e1 * t374 * t657 - 0.8e1 * t648 * t660 + + 0.8e1 * t130 * t328 + 0.2e1 * t665 * t99 + 0.2e1 * t346 * t668; + t672 = t90 * t424; + t676 = t120 * t536; + t680 = t436 * t41; + t688 = t366 * t67 * t440; + t696 = xc * t12; + t697 = t696 * t18; + t701 = t252 * t141; + t702 = t90 * t221; + t705 = 0.2e1 * t196 * t672 - t47 * t347 + 0.16e2 * t676 * t538 - t116 * t85 - 0.2e1 * t253 * t680 + + t207 * t194 + 0.4e1 * t98 * t99 * t19 - 0.8e1 * t688 * t433 + 0.16e2 * t541 * t301 - + 0.6e1 * t312 * t190 + 0.4e1 * t352 * t88 * t35 * t697 + 0.2e1 * t701 * t702; + t712 = t24 * t430; + t713 = t28 * t49; + t721 = t1 * t17 * t11; + t726 = ZB * xc; + t737 = n * t91; + t741 = 0.8e1 * t346 * t209 + 0.2e1 * t712 * t713 * t424 + 0.8e1 * t130 * t275 - t47 * t668 + t116 * t721 - + 0.8e1 * t688 * t513 + 0.4e1 * t352 * t27 * t212 * t726 + 0.8e1 * t648 * t463 + 0.4e1 * t274 * t60 - + 0.4e1 * t374 * t355 * t208 - 0.4e1 * t253 * t737 * t41; + t745 = t269 * t231; + t749 = t1 * t28 * t265; + t757 = t16 * t39; + t758 = t696 * t757; + t762 = t69 * t49; + t772 = t355 * t100; + t775 = t81 * t353; + t778 = -0.8e1 * t398 * t90 * t190 - 0.2e1 * t278 * t745 + 0.4e1 * t749 * t53 + + 0.32e2 * t394 * t29 * t28 * t17 * t40 - 0.8e1 * t78 * t758 + t350 * n * t762 - + 0.6e1 * t87 * t49 * t186 * t52 - 0.8e1 * t553 * t407 - 0.4e1 * t749 * t209 + 0.16e2 * t648 * t772 - + 0.6e1 * t775 * t375; + t790 = t212 * t304; + t793 = t156 * 0.3141592654e1; + t795 = t355 * t304; + t800 = t91 * t39; + t801 = t800 * n; + t807 = t2 * t28; + t808 = t807 * t726; + t811 = -0.2e1 * t616 * t672 - 0.2e1 * t446 * t680 - 0.2e1 * t78 * xc * t58 * t57 + 0.8e1 * t367 * t270 - + t82 * t790 + t115 * t51 * t793 - 0.2e1 * t775 * t795 + 0.8e1 * t123 * t209 + 0.2e1 * t665 * t801 - + 0.2e1 * t67 * t41 * t64 - 0.32e2 * t808 * t43; + t812 = t117 * t51; + t821 = t24 * t355; + t827 = t90 * t304; + t840 = t800 * t41; + t844 = -t116 * t812 - 0.2e1 * t110 * t25 * t58 * t57 - 0.4e1 * t78 * t328 + t82 * t485 - + 0.4e1 * t821 * t407 + 0.4e1 * t196 * t90 * t52 + 0.2e1 * t196 * t827 + t82 * t325 + + 0.2e1 * t253 * t448 - 0.32e2 * t402 * t67 * t807 * t490 - t207 * t232 + + 0.12e2 * t186 * t90 * ZB * t37 * t840; + t849 = t1 * t51; + t850 = t849 * t17; + t860 = t269 * t424; + t863 = t273 * t187; + t874 = 0.16e2 * t462 * t772 - t116 * t850 + 0.16e2 * t553 * t371 + t116 * t288 - + 0.12e2 * t97 * t57 * t109 * t697 + t82 * t594 - 0.2e1 * t278 * t860 - 0.2e1 * t863 * t305 - + 0.16e2 * t180 * t259 * t311 * t201 - 0.6e1 * t863 * t74 + 0.8e1 * t174 * t191; + t879 = xc * ZA; + t888 = t67 * t51; + t901 = ZA * t17; + t903 = t368 * t901 * t11; + t908 = -0.2e1 * t352 * t51 * t156 * t35 + 0.64e2 * t879 * t189 * t807 * t40 + + 0.2e1 * t46 * t58 * t37 * t39 - t888 * t50 + t105 * t411 - 0.16e2 * t335 * t301 + + 0.8e1 * t152 * t25 * t136 - 0.8e1 * t278 * t407 + 0.2e1 * t712 * t713 * t231 - 0.16e2 * t367 * t903 + + 0.2e1 * t145 * t318; + t923 = t71 * t424; + t926 = t87 * t458; + t927 = t28 * ZA; + t944 = 0.8e1 * t354 * t355 * t190 - 0.8e1 * t110 * t16 * t25 * t800 - 0.2e1 * t374 * t30 * t73 - + 0.16e2 * t354 * t30 * t176 - 0.2e1 * t244 * t923 - 0.32e2 * t926 * t927 * t696 * t41 - + 0.32e2 * t808 * t525 + 0.6e1 * t749 * t232 - 0.8e1 * t188 * t177 + 0.4e1 * t36 * t58 * ZA * t57 + + 0.4e1 * t821 * t270; + t948 = t90 * t327; + t961 = t30 * t100; + t964 = t29 * t49; + t981 = t106 * t1; + t983 = -0.2e1 * t219 * t220 * t100 + 0.2e1 * t321 * t948 - 0.16e2 * t189 * ZA * t99 * t12 - + 0.2e1 * t369 * n * t69 * t368 + 0.2e1 * t374 * t795 - 0.8e1 * t462 * t961 - + 0.8e1 * t244 * t964 * t208 + 0.2e1 * t413 * t923 + 0.4e1 * t36 * t38 * t40 * t58 - + 0.2e1 * t87 * t51 * t49 * t1 * ZA + t888 * n * t762 + t115 * t981; + t1012 = 0.6e1 * t616 * t627 - t82 * t213 + 0.2e1 * t775 * t657 - 0.12e2 * t215 * t550 - + 0.6e1 * t145 * t131 + 0.2e1 * t81 * t41 * t204 + 0.6e1 * ZB * t48 * t49 * t370 - + 0.4e1 * t70 * t382 + 0.2e1 * t446 * t255 + 0.8e1 * t89 * t4 * t327 - 0.4e1 * t56 * t147; + t1018 = t212 * t100; + t1029 = t212 * t327; + t1040 = 0.6e1 * t70 * t245 + 0.2e1 * t56 * t328 + t207 * t668 + 0.4e1 * t503 * t1018 + 0.2e1 * t253 * t470 - + 0.6e1 * t398 * t35 * t208 - 0.8e1 * t331 * t964 * t52 - 0.4e1 * t503 * t1029 + 0.6e1 * t821 * t745 + + 0.4e1 * t63 * t37 * t142 + 0.16e2 * t260 * t38 * t840; + t1068 = t207 * t347 - 0.2e1 * t164 * t702 - 0.2e1 * t331 * t964 * t73 + 0.8e1 * t374 * t30 * t52 + + 0.16e2 * t278 * t903 + 0.2e1 * t863 * t923 + 0.6e1 * t445 * t141 * t165 - + 0.2e1 * t164 * t90 * t100 + 0.6e1 * t331 * t74 - 0.2e1 * t182 * t668 - 0.2e1 * t115 * t41 * t204; + t1079 = t58 * t8; + t1091 = t807 * t29; + t1092 = t665 * t40; + t1101 = ZB * t91; + t1102 = t403 * n; + t1105 = -0.4e1 * t58 * ZB * ZA * t64 - t82 * t850 + 0.2e1 * t821 * t860 + t81 * t51 * t793 + + 0.2e1 * t3 * t25 * t1079 * t90 + t82 * t721 - 0.2e1 * t643 * t668 + + 0.16e2 * t926 * t927 * t29 * t91 * t41 + 0.32e2 * t1091 * t1092 - 0.2e1 * t219 * t220 * t19 + + 0.4e1 * t139 * ZA * t64 + 0.4e1 * t1101 * t1102; + t1108 = t849 * t72; + t1121 = t737 * t15; + t1124 = t29 * t12; + t1133 = t116 * t1108 - 0.8e1 * t475 * t209 - 0.32e2 * t807 * xc * t1092 + 0.2e1 * t278 * t269 * t73 + + t82 * t812 - 0.6e1 * t56 * t131 + 0.2e1 * t253 * t1121 + 0.16e2 * t926 * t927 * t1124 * t41 + + t168 * t263 - 0.2e1 * t616 * t827 + t81 * t981; + t1134 = t394 * t28; + t1159 = -0.8e1 * t1134 * t29 * t18 * t57 + t82 * t118 - 0.12e2 * t215 * t1018 + 0.2e1 * t602 * t801 - + t168 * t341 + 0.2e1 * t67 * t58 * t64 + t168 * t344 - 0.6e1 * t174 * t368 * t208 + + 0.16e2 * t553 * t903 + t116 * t790 - 0.4e1 * t36 * t38 * t800 * t15; + t1161 = n * t83; + t1173 = ZB * t12; + t1196 = 0.4e1 * t1161 * ZB * t39 * ZA - 0.4e1 * t215 * t1029 - 0.8e1 * t488 * 0.3141592654e1 * t39 * xc + + 0.32e2 * t821 * ZA * t8 * t1173 * t18 - 0.8e1 * t427 * t147 + 0.6e1 * t701 * t165 - + 0.16e2 * t926 * t927 * t1124 * t18 - 0.8e1 * t1091 * t63 * t57 - 0.8e1 * t442 * t209 - + 0.8e1 * t462 * t660 - 0.6e1 * t398 * t35 * t52; + t1228 = 0.2e1 * t413 * t305 - 0.8e1 * t648 * t961 - 0.16e2 * t87 * t27 * t23 * t28 * ZA * t29 + + 0.4e1 * t189 * t1102 - 0.4e1 * t87 * t1079 * t212 * t879 + 0.2e1 * t164 * t948 - + 0.2e1 * t70 * t923 + 0.2e1 * t164 * t322 + 0.2e1 * t446 * t1121 + 0.2e1 * t863 * t964 * t304 - + t82 * t1108 + 0.16e2 * t676 * t490 * t19; + t1234 = t25 * ZB; + t1235 = t1234 * t28; + t1236 = t365 * t91; + t1240 = ZB * t121; + t1241 = t1240 * t77; + t1242 = t39 * t39; + t1243 = t12 * t1242; + t1244 = xc * t72; + t1245 = t1243 * t1244; + t1248 = t365 * t25; + t1252 = t243 * n; + t1257 = t23 * t1; + t1258 = t1240 * t1257; + t1259 = t67 * t12; + t1260 = xc * t16; + t1268 = t1234 * t121; + t1269 = t1268 * t23; + t1272 = t1242 * t91; + t1280 = t67 * xc; + t1284 = t28 * t28; + t1285 = t67 * t1284; + t1287 = t1285 * t2 * ZB; + t1288 = t17 * xc; + t1289 = t1243 * t1288; + t1292 = 0.2e1 * t1235 * t1236 * t17 + 0.8e1 * t1241 * t1245 + 0.4e1 * t927 * t1248 * t91 - + 0.2e1 * t1252 * ZB * t1242 * t91 - 0.8e1 * t1258 * t1259 * t1260 - 0.4e1 * t1235 * t2 * t83 * t39 + + 0.16e2 * t1269 * t758 + 0.2e1 * t1252 * t189 * t1272 - 0.2e1 * t1252 * t83 * t1242 * ZB + + 0.8e1 * t1258 * t630 * t1280 - 0.32e2 * t1287 * t1289; + t1293 = t365 * t83; + t1300 = ZA * t1284; + t1304 = t17 * t1242 * t25 * t12; + t1307 = t927 * t2; + t1311 = t23 * t2; + t1312 = t1300 * t1311; + t1316 = t1234 * t1284; + t1317 = t1316 * t1311; + t1321 = t1240 * t23; + t1331 = t1240 * t23 * t67; + t1332 = t40 * t1244; + t1338 = t1243 * t1260; + t1344 = -0.2e1 * t1235 * t1293 - 0.16e2 * t181 * t365 * t901 * t12 - 0.64e2 * t1300 * t258 * t1304 + + 0.8e1 * t1307 * t613 * t39 + 0.64e2 * t1312 * t265 * t402 - 0.32e2 * t1317 * t1288 * t12 - + 0.16e2 * t1321 * t67 * t39 * t1244 + 0.2e1 * t1235 * n * t1272 * t17 + 0.16e2 * t1331 * t1332 + + 0.64e2 * t1300 * t292 * t1304 - 0.8e1 * t1241 * t1338 - 0.2e1 * t243 * t1293 * ZB; + t1346 = t1316 * t2; + t1349 = t927 * n; + t1350 = t25 * t1242; + t1354 = t1268 * t1257; + t1366 = t1268 * t1; + t1370 = t29 * t17; + t1371 = t1243 * t1370; + t1386 = -0.32e2 * t1346 * t1289 + 0.4e1 * t1349 * t1350 * t91 + 0.8e1 * t1354 * t1260 * t12 - + 0.16e2 * t181 * n * t901 * t1243 - 0.4e1 * t1235 * t2 * t91 * t39 + 0.8e1 * t1366 * t152 * t1242 + + 0.32e2 * t1287 * t1371 + 0.8e1 * t1258 * t1280 * t152 - 0.8e1 * t1354 * t1260 * t91 + + 0.128e3 * t1300 * t365 * xc * t1092 + 0.8e1 * t1366 * t1338; + t1387 = t1257 * t12; + t1391 = t1240 * t1; + t1399 = t1272 * t1260; + t1412 = t1285 * t1311; + t1427 = -0.8e1 * t1268 * t1387 * t16 - 0.8e1 * t1391 * t67 * t1242 * t1244 - 0.4e1 * t1134 * t1101 * t39 + + 0.8e1 * t1241 * t1399 - 0.8e1 * t1258 * t596 + 0.4e1 * t927 * t1293 * t25 - 0.16e2 * t1331 * t758 + + 0.8e1 * t1307 * t665 * t39 + 0.32e2 * t1412 * t1370 * t1173 + 0.8e1 * t1307 * t665 * t800 + + 0.8e1 * t1391 * t1259 * t1242 * t16 - 0.8e1 * t1391 * t1259 * t1242 * t72; + t1456 = t365 * ZB; + t1468 = 0.4e1 * t927 * t1248 * t17 - 0.2e1 * t1235 * n * t1242 * t91 + 0.8e1 * t1366 * t1244 * t1242 - + 0.16e2 * t1269 * t134 * t39 + 0.8e1 * t1268 * t1257 * t72 * xc + 0.16e2 * t1321 * t1259 * t757 + + 0.32e2 * t1317 * t1370 * t12 + 0.4e1 * t1349 * t613 * t1242 + 0.2e1 * t243 * t1456 * t17 - + 0.64e2 * t1285 * t365 * t12 * t189 * t490 - 0.8e1 * t1354 * t152 * xc; + t1472 = t1316 * t365; + t1474 = t1124 * t39 * t17; + t1478 = t17 * t91; + t1504 = t72 * t39; + t1511 = 0.4e1 * t1134 * t189 * t800 + 0.64e2 * t1472 * t1474 + 0.4e1 * t1235 * t2 * t1478 * t39 + + 0.4e1 * t1349 * t665 * t1242 - 0.8e1 * t1258 * t1280 * t72 + 0.2e1 * t1252 * t189 * t1242 + + 0.2e1 * t243 * t365 * t189 * t91 + 0.4e1 * t927 * t365 * t1478 * t25 - + 0.128e3 * t1300 * t1248 * t1474 - 0.2e1 * t1235 * t1236 + 0.16e2 * t1269 * t1504 * xc + + 0.2e1 * t1235 * t365 * t17; + t1545 = -0.2e1 * t1235 * t1161 * t1242 + 0.4e1 * t1349 * t1350 * t1478 - 0.8e1 * t1366 * t1245 + + 0.2e1 * t1235 * t556 * t1242 - 0.32e2 * t1412 * t402 * t726 - 0.8e1 * t1366 * t1399 + + 0.8e1 * t1258 * t651 - 0.2e1 * t243 * t1456 * t91 + 0.8e1 * t1268 * t1387 * t72 - + 0.16e2 * t1269 * t1332 + 0.4e1 * t1134 * t189 * t39 + 0.16e2 * t1269 * t152 * t39; + t1564 = t1260 * t800; + t1583 = 0.64e2 * t1285 * t1456 * t1474 - 0.64e2 * t1472 * t1288 * t40 - 0.8e1 * t1366 * t134 * t1242 + + 0.8e1 * t1307 * t362 * t39 + 0.4e1 * t1235 * t2 * t17 * t39 + 0.32e2 * t1346 * t1371 - + 0.16e2 * t1269 * t1564 - 0.16e2 * t1321 * t1259 * t1504 + 0.16e2 * t1331 * t1564 - + 0.64e2 * t1312 * t29 * t25 * t402 - 0.4e1 * t1134 * t83 * t39 * ZB - 0.32e2 * t181 * t2 * t404; + + _C2B = (t1133 + t1196 + t1068 + t811 + t466 + t1012 + t381 + t162 + t249 + t533 + t844 + t104 + t1159 + + t571 + t211 + t874 + t607 + t339 + t296 + t638 + t908 + t671 + t419 + t983 + t705 + t1105 + t501 + + t778 + t1040 + t1228 + t741 + t944) / + (t1292 + t1344 + t1386 + t1427 + t1468 + t1511 + t1545 + t1583); + /****************************************************************************************/ + t1 = n * n; + t2 = t1 * n; + t3 = t2 * nx; + t4 = nx * 0.3141592654e1; + t5 = t4 * xc; + t6 = sin(t5); + t7 = 0.3141592654e1 * 0.3141592654e1; + t9 = t3 * t6 * t7; + t10 = xc * xc; + t11 = ZA * ZA; + t12 = t10 * t11; + t13 = n * 0.3141592654e1; + t14 = exp(t13); + t15 = t14 * t14; + t16 = xc * n; + t18 = exp(t16 * 0.3141592654e1); + t19 = t18 * t18; + t20 = t19 * t18; + t21 = t15 * t20; + t22 = t12 * t21; + t25 = nx * t6; + t26 = t1 * 0.3141592654e1; + t27 = t25 * t26; + t28 = ZA * ZB; + t29 = t18 * t15; + t30 = t28 * t29; + t33 = t25 * n; + t34 = t11 * t15; + t35 = t19 * t19; + t36 = t35 * t18; + t40 = t25 * t1; + t41 = 0.3141592654e1 * t11; + t42 = t15 * t36; + t43 = t41 * t42; + t46 = nx * nx; + t47 = t1 * t46; + t48 = t47 * t11; + t49 = t7 * xc; + t50 = t35 * t15; + t51 = t49 * t50; + t55 = sin(t4); + t56 = t46 * nx * t55; + t58 = t56 * n * t7; + t59 = ZB * ZB; + t60 = t10 * t59; + t61 = t15 * t14; + t62 = t19 * t61; + t63 = t60 * t62; + t66 = t19 * t14; + t67 = t60 * t66; + t70 = t28 * t42; + t73 = cos(t5); + t74 = t47 * t73; + t75 = t7 * t11; + t77 = t75 * t10 * t36; + t80 = t73 * t46; + t81 = t80 * n; + t82 = 0.3141592654e1 * t59; + t83 = t82 * t42; + t87 = xc * t11; + t88 = t87 * t62; + t91 = n * nx; + t92 = t55 * t61; + t96 = nx * t55; + t98 = t96 * t2 * t7; + t101 = xc * t59; + t102 = t101 * t62; + t108 = t1 * t1; + t109 = t108 * t7; + t111 = t59 * t35; + t112 = t111 * t15; + t115 = t35 * t20; + t123 = t1 * nx * t55; + t124 = t61 * t35; + t127 = t35 * t19; + t128 = t61 * t127; + t129 = t60 * t128; + t132 = t56 * t16; + t133 = t7 * t59; + t134 = t133 * t124; + t137 = 0.6e1 * t58 * t88 - 0.2e1 * t91 * t92 * t11 + 0.2e1 * t98 * t63 - 0.6e1 * t58 * t102 - + 0.2e1 * t91 * t92 * t59 - 0.16e2 * t109 * xc * t112 - 0.2e1 * t91 * t6 * t115 * t59 + + 0.12e2 * t40 * t83 + t123 * t41 * t124 - 0.2e1 * t58 * t129 + 0.4e1 * t132 * t134; + t139 = t56 * 0.3141592654e1; + t140 = t111 * t14; + t144 = t49 * t124; + t147 = t91 * t55; + t148 = t61 * ZA; + t154 = ZA * t115 * xc * ZB; + t157 = t7 * 0.3141592654e1; + t159 = t96 * t108 * t157; + t160 = t10 * xc; + t161 = t160 * t59; + t162 = t35 * t14; + t163 = t161 * t162; + t166 = t28 * t162; + t169 = t80 * t13; + t170 = t101 * t42; + t173 = t2 * t11; + t174 = t96 * t173; + t175 = t7 * t10; + t179 = t59 * t15; + t184 = t15 * t15; + t193 = t139 * t140 + 0.4e1 * t56 * n * t11 * t144 + 0.4e1 * t147 * t148 * ZB + 0.4e1 * t27 * t154 + + 0.8e1 * t159 * t163 - 0.12e2 * t147 * t166 + 0.2e1 * t169 * t170 - 0.16e2 * t174 * t175 * t124 + + 0.2e1 * t33 * t179 * t20 - 0.2e1 * t33 * t11 * t36 * t184 + + 0.2e1 * t56 * t61 * 0.3141592654e1 * ZA * ZB; + t194 = t173 * 0.3141592654e1; + t195 = xc * t15; + t196 = t195 * t19; + t202 = t15 * t115; + t203 = t28 * t202; + t206 = t96 * t26; + t207 = t14 * t127; + t208 = t101 * t207; + t211 = t12 * t128; + t218 = t11 * t61; + t219 = t218 * t35; + t221 = t108 * ZA; + t223 = t7 * ZB; + t224 = t223 * t50; + t227 = ZA * xc; + t228 = ZB * t15; + t229 = t228 * t36; + t230 = t227 * t229; + t233 = t87 * t207; + t236 = t6 * t11; + t240 = -0.4e1 * t194 * t196 + 0.4e1 * t194 * t195 * t127 + 0.4e1 * t33 * t203 - 0.12e2 * t206 * t208 + + 0.2e1 * t58 * t211 - 0.16e2 * t47 * t10 * t133 * t50 + t139 * t219 - 0.32e2 * t221 * t10 * t224 - + 0.4e1 * t169 * t230 - 0.6e1 * t98 * t233 + 0.2e1 * t91 * t236 * t20; + t244 = t227 * t228 * t20; + t252 = t184 * t18; + t253 = t101 * t252; + t256 = t35 * t35; + t257 = t256 * t14; + t258 = t28 * t257; + t261 = t108 * t11; + t263 = t7 * t35; + t268 = ZB * t61 * t35; + t273 = t96 * t108 * t160; + t274 = t157 * ZB; + t276 = t274 * t148 * t35; + t279 = t101 * t21; + t282 = 0.3141592654e1 * xc; + t283 = t59 * t36; + t284 = t282 * t283; + t289 = 0.4e1 * t169 * t244 - 0.4e1 * t132 * t133 * t162 - 0.2e1 * t147 * t140 - 0.2e1 * t27 * t253 + + 0.2e1 * t139 * t258 + 0.16e2 * t261 * t10 * t263 * t15 - 0.16e2 * t206 * t227 * t268 - + 0.16e2 * t273 * t276 - 0.6e1 * t27 * t279 - 0.4e1 * t40 * t284 - 0.32e2 * t9 * t230; + t290 = t1 * t11; + t291 = t96 * t290; + t297 = t59 * t61; + t298 = t297 * t127; + t300 = ZB * t36; + t301 = t227 * t300; + t304 = t1 * t59; + t305 = t184 * t35; + t310 = t46 * ZB; + t311 = t184 * ZA; + t312 = t310 * t311; + t314 = t60 * t21; + t317 = t1 * ZA; + t318 = ZB * t35; + t321 = t1 * t256; + t324 = t96 * t261; + t325 = t10 * t157; + t326 = t325 * t124; + t329 = -0.4e1 * t291 * t282 * t128 + t123 * t82 * t62 - t139 * t298 + 0.12e2 * t27 * t301 + t304 * t305 - + 0.2e1 * t58 * t12 * t66 - 0.2e1 * t312 + 0.8e1 * t9 * t314 + 0.2e1 * t317 * t318 + + 0.2e1 * t321 * t28 - 0.8e1 * t324 * t326; + t331 = t28 * t124; + t334 = 0.3141592654e1 * t15; + t335 = t334 * t127; + t338 = t35 * ZA; + t341 = t46 * t256; + t344 = t46 * t11; + t346 = t46 * t59; + t348 = t297 * t35; + t351 = ZA * t10; + t352 = t351 * t300; + t355 = t1 * ZB; + t362 = 0.12e2 * t147 * t331 - 0.4e1 * t173 * t335 - 0.2e1 * t310 * t338 - 0.2e1 * t341 * t28 - t344 * t305 - + t346 * t305 + 0.2e1 * t147 * t348 + 0.16e2 * t9 * t352 + 0.2e1 * t355 * t311 + t290 * t305 + + 0.2e1 * t33 * t34 * t20; + t363 = t36 * t184; + t364 = t87 * t363; + t368 = t47 * t73 * t7; + t373 = t160 * t157; + t374 = t373 * t124; + t377 = t311 * t35; + t380 = t12 * t62; + t386 = ZB * t10 * ZA * t15 * t20; + t389 = t87 * t66; + t393 = t56 * t1 * t10; + t401 = 0.2e1 * t27 * t364 - 0.16e2 * t368 * t279 - t123 * t41 * t257 + 0.8e1 * t324 * t374 + + 0.2e1 * t355 * t377 - 0.2e1 * t98 * t380 - 0.16e2 * t9 * t386 + 0.2e1 * t58 * t389 + + 0.16e2 * t393 * t276 + t123 * t82 * t162 - 0.2e1 * t33 * t179 * t36; + t412 = t11 * t14 * t127; + t416 = t11 * t19; + t417 = t416 * t61; + t421 = t96 * t2 * ZA; + t426 = t56 * n * ZA; + t427 = t318 * t14; + t428 = t49 * t427; + t431 = t82 * t29; + t434 = t87 * t21; + t442 = 0.2e1 * t33 * t11 * t184 * t18 + 0.4e1 * t81 * t284 - t139 * t412 + 0.2e1 * t147 * t219 - + 0.2e1 * t147 * t417 + 0.32e2 * t421 * t175 * t268 + 0.8e1 * t426 * t428 + 0.4e1 * t81 * t431 - + 0.2e1 * t169 * t434 - 0.2e1 * t98 * t129 - 0.32e2 * t47 * t28 * t51; + t443 = t184 * t20; + t447 = t61 * 0.3141592654e1; + t448 = t447 * t11; + t450 = t49 * t268; + t453 = t60 * t42; + t456 = t41 * t202; + t463 = t101 * t443; + t469 = t41 * xc * t20; + t474 = -0.8e1 * t27 * t87 * t443 - t56 * t448 - 0.8e1 * t426 * t450 + 0.8e1 * t368 * t453 + + 0.4e1 * t40 * t456 + 0.4e1 * t40 * t431 - 0.4e1 * t81 * t456 - 0.4e1 * t27 * t463 + + 0.6e1 * t139 * t331 + 0.2e1 * t40 * t469 - 0.16e2 * t9 * t434; + t482 = t108 * t10; + t492 = n * t46; + t493 = t492 * t11; + t495 = t282 * t19 * t184; + t498 = t56 * t290; + t499 = t325 * t162; + t502 = t416 * t14; + t504 = t60 * t207; + t507 = -t123 * t82 * t257 - 0.4e1 * t169 * t301 + t123 * t41 * t162 + 0.16e2 * t482 * t7 * t112 - + 0.12e2 * t206 * t102 - t123 * t82 * t66 - 0.4e1 * t147 * t258 - 0.4e1 * t493 * t495 - + 0.8e1 * t498 * t499 + t139 * t502 - 0.2e1 * t98 * t504; + t508 = t101 * t162; + t512 = t41 * t115 * xc; + t515 = t87 * t42; + t520 = ZB * t184; + t522 = t227 * t520 * t18; + t525 = t492 * t59; + t528 = t6 * t59; + t532 = t520 * t20; + t533 = t351 * t532; + t539 = t447 * t59; + t544 = 0.8e1 * t206 * t508 - 0.2e1 * t40 * t512 - 0.16e2 * t368 * t515 + 0.12e2 * t206 * t88 + + 0.4e1 * t27 * t522 + 0.4e1 * t525 * t495 - 0.4e1 * t91 * t528 * t36 - 0.16e2 * t368 * t533 - + 0.16e2 * t206 * t227 * t427 - t56 * t539 - 0.2e1 * t132 * t133 * t66; + t551 = t87 * t162; + t554 = t351 * t229; + t560 = t59 * t19; + t561 = t560 * t14; + t564 = t101 * t202; + t567 = t87 * t252; + t573 = t227 * t228 * t115; + t578 = 0.4e1 * t33 * t70 + 0.4e1 * t493 * t335 - 0.4e1 * t58 * t551 + 0.16e2 * t9 * t554 - + 0.4e1 * t33 * t28 * t252 + 0.2e1 * t147 * t561 + 0.2e1 * t169 * t564 - 0.2e1 * t27 * t567 - + 0.8e1 * t324 * t499 - 0.4e1 * t169 * t573 + 0.12e2 * t27 * t244; + t579 = t82 * t202; + t591 = t282 * t115 * t59; + t598 = t101 * t66; + t606 = -0.4e1 * t81 * t579 - 0.2e1 * t169 * t567 - 0.6e1 * t27 * t170 + 0.8e1 * t169 * t203 + + 0.2e1 * t98 * t67 + 0.2e1 * t81 * t591 + 0.32e2 * t368 * t244 - 0.2e1 * t27 * t564 + + 0.4e1 * t206 * t598 + 0.16e2 * t9 * t170 + 0.2e1 * t33 * t283 * t184; + t608 = t373 * t162; + t611 = t59 * t184; + t617 = t101 * t29; + t624 = t227 * ZB * t18 * t15; + t629 = t157 * t59; + t630 = t629 * t124; + t633 = t3 * t6; + t634 = t175 * t283; + t644 = 0.8e1 * t498 * t608 + 0.2e1 * t33 * t611 * t18 - 0.4e1 * t206 * t389 - 0.2e1 * t27 * t617 - + 0.4e1 * t169 * t154 + 0.4e1 * t27 * t624 + 0.12e2 * t27 * t230 - 0.8e1 * t393 * t630 - + 0.8e1 * t633 * t634 + 0.16e2 * t47 * t7 * t101 * t50 + 0.2e1 * t123 * t447 * t28; + t645 = t41 * t29; + t648 = t2 * 0.3141592654e1; + t649 = t648 * xc; + t650 = t560 * t184; + t656 = t56 * t1 * t157; + t659 = t87 * t128; + t662 = t96 * t482; + t663 = t629 * t162; + t671 = t161 * t124; + t674 = t218 * t127; + t679 = 0.4e1 * t81 * t645 - 0.4e1 * t649 * t650 - 0.8e1 * t169 * t70 + 0.8e1 * t656 * t163 - + 0.2e1 * t98 * t659 - 0.8e1 * t662 * t663 - 0.32e2 * t421 * t175 * t427 - 0.2e1 * t147 * t502 + + 0.8e1 * t656 * t671 + 0.2e1 * t147 * t674 - 0.16e2 * t368 * t386; + t714 = t334 * t19; + t719 = t12 * t42; + t722 = t304 * t35 - t346 * t35 + t341 * t59 - t344 * t35 + t344 * t256 + t346 * t184 - + 0.16e2 * t368 * t554 - 0.16e2 * t48 * t175 * t50 + 0.4e1 * t525 * t714 - 0.2e1 * t58 * t659 + + 0.8e1 * t368 * t719; + t730 = xc * t19; + t735 = t59 * t256 * t14; + t752 = 0.4e1 * t173 * t714 - 0.6e1 * t27 * t515 - 0.16e2 * t9 * t279 + 0.4e1 * t194 * t730 * t184 - + t139 * t735 - 0.4e1 * t492 * t127 * t82 * xc - 0.4e1 * t98 * t508 - t123 * t41 * t207 - + 0.2e1 * t147 * t298 + 0.8e1 * t368 * t314 + 0.6e1 * t132 * t133 * t207; + t755 = t28 * t21; + t759 = t274 * t338 * t14; + t767 = t11 * t35; + t768 = t767 * t14; + t778 = t560 * t61; + t781 = -0.2e1 * t58 * t504 - 0.8e1 * t27 * t755 + 0.16e2 * t662 * t759 + 0.12e2 * t291 * t282 * t207 - + 0.6e1 * t27 * t434 + t139 * t768 - 0.8e1 * t498 * t326 + 0.4e1 * t33 * t611 * t20 + + 0.2e1 * t81 * t512 - t139 * t561 + 0.2e1 * t147 * t778; + t786 = t12 * t443; + t790 = t282 * t59 * t20; + t796 = t59 * t14 * t127; + t806 = t41 * t21; + t811 = -0.8e1 * t393 * t663 + 0.8e1 * t368 * t786 + 0.2e1 * t81 * t790 + 0.4e1 * t169 * t624 + t139 * t796 + + 0.2e1 * t206 * t258 - 0.2e1 * t40 * t591 - 0.8e1 * t662 * t630 - 0.4e1 * t33 * t30 - + 0.4e1 * t40 * t806 + 0.8e1 * t9 * t786; + t819 = t282 * t15 * t127; + t822 = t101 * t363; + t830 = t11 * t256 * t14; + t835 = t227 * t532; + t842 = 0.2e1 * t33 * t11 * t18 * t15 + t123 * t41 * t66 - 0.4e1 * t493 * t819 - 0.2e1 * t27 * t822 - + 0.16e2 * t368 * t170 - 0.4e1 * t169 * t463 - t139 * t830 - 0.4e1 * t649 * t179 * t127 + + 0.12e2 * t27 * t835 - 0.16e2 * t368 * t434 - 0.2e1 * t40 * t790; + t845 = t87 * t202; + t854 = t338 * t15; + t859 = t12 * t207; + t868 = t139 * t348 - 0.2e1 * t27 * t845 + 0.8e1 * t169 * t755 - 0.2e1 * t58 * t380 + 0.6e1 * t206 * t331 + + 0.8e1 * t310 * t854 - 0.2e1 * t169 * t822 + 0.2e1 * t98 * t859 + 0.8e1 * t159 * t671 + + 0.8e1 * t74 * t634 - 0.2e1 * t169 * t253; + t880 = t60 * t443; + t891 = t101 * t128; + t894 = -t123 * t539 - 0.2e1 * t147 * t796 + 0.32e2 * t368 * t230 + t139 * t674 - 0.16e2 * t98 * t60 * t124 + + 0.32e2 * t9 * t244 + 0.8e1 * t368 * t880 - 0.8e1 * t40 * t41 * xc * t36 - t123 * t82 * t128 - + 0.6e1 * t58 * t233 + 0.2e1 * t58 * t891; + t903 = t179 * t19; + t920 = t56 * t1 * t160; + t925 = -0.2e1 * t174 * t175 * t66 - 0.4e1 * t493 * t714 + 0.4e1 * t649 * t903 - 0.4e1 * t81 * t43 + + t123 * t82 * t207 + 0.4e1 * t206 * t891 - 0.16e2 * t273 * t759 - 0.8e1 * t27 * t203 + + 0.32e2 * t221 * ZB * t51 - 0.16e2 * t920 * t759 - 0.8e1 * t9 * t453; + t932 = t87 * t29; + t945 = t82 * t21; + t953 = -0.16e2 * t920 * t276 - 0.8e1 * t169 * t30 - 0.8e1 * t633 * t77 - 0.2e1 * t27 * t932 - + 0.4e1 * t174 * t49 * t162 + 0.8e1 * t206 * t87 * t124 - 0.2e1 * t147 * t768 + 0.4e1 * t169 * t522 - + 0.12e2 * t81 * t945 + 0.4e1 * t33 * t28 * t115 + 0.4e1 * t525 * t819; + t971 = t282 * t127; + t978 = -0.6e1 * t98 * t102 + 0.2e1 * t169 * t515 - 0.2e1 * t310 * t377 + 0.2e1 * t147 * t830 + + 0.8e1 * t368 * t22 - 0.2e1 * t169 * t617 + 0.16e2 * t662 * t276 - 0.8e1 * t355 * t854 + + 0.4e1 * t493 * t971 - 0.16e2 * t9 * t533 - 0.2e1 * t169 * t279; + t997 = xc * t127; + t998 = t997 * t59; + t1003 = 0.4e1 * t40 * t579 + 0.2e1 * t169 * t845 + 0.16e2 * t9 * t515 + 0.8e1 * t206 * t551 + + t123 * t41 * t128 + 0.16e2 * t98 * t60 * t162 + 0.2e1 * t169 * t364 - 0.2e1 * t169 * t932 + + t139 * t778 + 0.4e1 * t648 * t998 + 0.2e1 * t147 * t412; + t1006 = t2 * t59; + t1017 = xc * t35; + t1033 = 0.4e1 * t1006 * t335 + 0.4e1 * t81 * t806 - 0.2e1 * t33 * t34 * t115 + 0.8e1 * t498 * t374 - + 0.16e2 * t261 * t7 * t1017 * t15 + 0.8e1 * t206 * t101 * t124 - t123 * t448 + 0.2e1 * t147 * t735 + + 0.6e1 * t98 * t208 + 0.6e1 * t98 * t88 - 0.4e1 * t33 * t755; + t1055 = -0.4e1 * t173 * t971 + 0.2e1 * t98 * t891 + 0.8e1 * t9 * t880 + 0.4e1 * t169 * t835 - t304 * t184 + + t344 * t184 - t123 * t41 * t62 - 0.2e1 * t98 * t598 + 0.2e1 * t58 * t859 + + 0.32e2 * t47 * t351 * t224 + 0.2e1 * t98 * t389; + t1070 = t15 * t19; + t1089 = -0.16e2 * t368 * t352 - 0.8e1 * t9 * t719 + 0.4e1 * t96 * t2 * xc * t134 - + 0.2e1 * t91 * t236 * t115 + 0.4e1 * t27 * t573 + 0.4e1 * t493 * t282 * t1070 + + 0.2e1 * t33 * t59 * t18 * t15 + 0.12e2 * t40 * t945 - 0.4e1 * t492 * xc * t82 * t1070 - + 0.2e1 * t91 * t528 * t20 + 0.8e1 * t324 * t608; + t1113 = t123 * t82 * t124 + 0.8e1 * t421 * t428 - t139 * t417 + 0.4e1 * t40 * t645 + 0.16e2 * t393 * t759 - + 0.2e1 * t33 * t179 * t115 - 0.4e1 * t525 * t335 + 0.4e1 * t33 * t28 * t36 - 0.4e1 * t1006 * t714 + + 0.6e1 * t206 * t166 - 0.8e1 * t421 * t450; + t1119 = t321 * t46; + t1122 = t157 * t11; + t1123 = t1122 * t2; + t1124 = t184 * t46; + t1128 = t108 * n; + t1132 = t7 * t7; + t1133 = t1132 * t11; + t1134 = t1133 * t108; + t1135 = t15 * t46; + t1139 = t7 * ZA; + t1140 = t1139 * ZB; + t1141 = t1 * t35; + t1145 = t629 * t2; + t1146 = t1135 * t730; + t1149 = t157 * t1128; + t1150 = t1149 * xc; + t1153 = t46 * xc; + t1154 = t1153 * t127; + t1158 = t184 * t1 * t46; + t1161 = t46 * t46; + t1162 = t35 * t1161; + t1166 = t7 * t1; + t1170 = -0.4e1 * t133 * t1119 + 0.16e2 * t1123 * t1124 * t730 - 0.8e1 * t1122 * t1128 * t196 - + 0.64e2 * t1134 * t1135 * t1017 - 0.32e2 * t1140 * t1141 * t1135 + 0.16e2 * t1145 * t1146 - + 0.8e1 * t1150 * t650 - 0.16e2 * t1123 * t1154 - 0.4e1 * t133 * t1158 - + 0.16e2 * t1140 * t1162 * t15 + 0.8e1 * t1166 * t35 * t312; + t1171 = t1161 * t184; + t1175 = t1122 * n; + t1176 = t15 * t1161; + t1180 = t1132 * ZA; + t1181 = t1180 * t355; + t1182 = t1176 * t1017; + t1185 = t1161 * xc; + t1189 = t1133 * t1; + t1192 = t108 * t1; + t1193 = t1132 * t1192; + t1195 = t10 * t35; + t1199 = t157 * t15; + t1203 = t1141 * t46; + t1211 = t184 * t108; + t1218 = 0.2e1 * t133 * t1171 * t35 + 0.8e1 * t1175 * t1176 * t997 + 0.64e2 * t1181 * t1182 - + 0.8e1 * t1175 * t1185 * t127 - 0.32e2 * t1189 * t1182 - 0.64e2 * t1193 * ZA * t1195 * t228 + + 0.8e1 * t1199 * t416 * t1128 + 0.8e1 * t1140 * t1203 - 0.4e1 * t75 * t1158 - + 0.8e1 * t1199 * t560 * t1128 - 0.2e1 * t133 * t1211 - 0.8e1 * t1199 * t127 * t11 * t1128; + t1221 = t256 * t1161; + t1224 = t35 * t108; + t1233 = t7 * t256; + t1236 = -t75 * t1211 - t75 * t1221 - t133 * t1221 + t75 * t1224 - t75 * t1171 - t133 * t1171 + + t133 * t1224 + t75 * t1162 - t75 * t108 * t256 + t133 * t1162 - t1233 * t59 * t108; + t1240 = t1135 * t1195; + t1252 = t629 * t127; + t1263 = t1171 * ZA; + t1280 = -0.128e3 * t1180 * ZB * t108 * t1240 + 0.32e2 * t1193 * t10 * t112 + 0.4e1 * t133 * t1203 + + 0.4e1 * t109 * t256 * ZA * ZB - 0.8e1 * t1252 * n * t15 * t1185 + 0.8e1 * t1175 * t1171 * t730 - + 0.8e1 * t1175 * t1176 * t127 + 0.4e1 * t223 * t1263 - 0.8e1 * t1175 * t1176 * t730 + + 0.8e1 * t1166 * ZA * t341 * ZB + 0.64e2 * t1134 * t1240 + 0.8e1 * t1122 * xc * t1128 * t127 * t15; + t1283 = t1199 * t19; + t1287 = t1199 * t127; + t1289 = t59 * n * t1161; + t1293 = t157 * n * xc; + t1304 = t1132 * t108; + t1310 = t263 * ZB; + t1316 = t2 * t15; + t1323 = -0.16e2 * t1283 * t1006 * t46 + 0.8e1 * t1287 * t1289 + 0.8e1 * t1293 * t127 * t1161 * t59 + + 0.16e2 * t1123 * t1135 * t19 + 0.8e1 * t1293 * t560 * t1176 + 0.64e2 * t1304 * t59 * t1240 + + 0.4e1 * t75 * t1203 + 0.4e1 * t1310 * t1263 + 0.4e1 * t223 * t338 * t108 - + 0.16e2 * t1252 * t1316 * t1153 - 0.16e2 * t1310 * t221 * t15; + t1330 = t1132 * t15; + t1336 = t1132 * t1; + t1338 = t1162 * t179; + t1370 = 0.8e1 * t1175 * t1176 * t19 + 0.4e1 * t1139 * t318 * t1161 + + 0.128e3 * t1330 * t318 * t108 * t46 * t227 - 0.32e2 * t1336 * xc * t1338 + + 0.4e1 * t1233 * ZA * t1161 * ZB - 0.8e1 * t1287 * t59 * t1128 * xc + 0.2e1 * t75 * t305 * t108 + + 0.8e1 * t1199 * t127 * t59 * t1128 - 0.8e1 * t1283 * t1289 - 0.8e1 * t1293 * t560 * t1171 + + 0.4e1 * t133 * t35 * t1158 + 0.8e1 * t157 * t184 * t19 * t11 * t1128 * xc; + t1376 = t7 * t184; + t1380 = t1176 * t1195; + t1393 = t1330 * t35; + t1411 = 0.16e2 * t1145 * t1154 + 0.8e1 * t1149 * t998 + 0.4e1 * t1376 * t35 * t48 + 0.32e2 * t1189 * t1380 + + 0.32e2 * t1193 * t11 * t1195 * t15 - 0.64e2 * t1304 * xc * t111 * t1135 - 0.16e2 * t1123 * t1146 + + 0.64e2 * t1393 * t28 * t1192 * xc - 0.16e2 * t1123 * t1135 * t127 - + 0.8e1 * t1122 * xc * t1128 * t127 - 0.32e2 * t1193 * xc * t112 + 0.16e2 * t1252 * t1316 * t46; + t1450 = 0.2e1 * t1376 * t767 * t1161 + 0.2e1 * t1376 * t111 * t108 + 0.4e1 * t223 * t311 * t108 + + 0.4e1 * t109 * t35 * t520 * ZA + 0.16e2 * t1123 * t1135 * t997 - 0.64e2 * t1181 * t1380 + + 0.8e1 * t1150 * t903 - 0.32e2 * t1393 * t11 * t1192 * xc - 0.16e2 * t157 * t2 * xc * t560 * t1124 + + 0.8e1 * t223 * t184 * t317 * t46 + 0.32e2 * t1336 * t10 * t1338 - 0.4e1 * t75 * t1119; + _C3B = (t606 + t722 + t1089 + t781 + 0.16e2 * t48 * t51 + t978 + t868 + t507 - t304 * t256 + + 0.8e1 * t9 * t22 + t752 + 0.4e1 * t174 * t144 - 0.2e1 * t81 * t469 + 0.6e1 * t139 * t166 + t362 + + 0.2e1 * t98 * t211 + t925 + t137 - t290 * t184 + 0.12e2 * t81 * t83 + t842 + 0.8e1 * t74 * t77 + + 0.16e2 * t98 * t12 * t162 - 0.4e1 * t33 * t28 * t443 - 0.8e1 * t27 * t70 - 0.2e1 * t33 * t34 * t36 - + 0.8e1 * t27 * t30 + 0.2e1 * t58 * t67 - 0.4e1 * t40 * t43 + 0.2e1 * t58 * t63 + t1033 - + t290 * t256 + t290 * t35 + t193 + t1113 + t578 + t442 + t474 + t544 + t329 + t679 + t401 + t953 + + t811 + t644 + t894 + t289 + t240 + t1055 + t1003) / + (t1170 + t1218 + 0.2e1 * t1236 + t1280 + t1323 + t1370 + t1411 + t1450); + /****************************************************************************************/ + t1 = n * n; + t2 = t1 * xc; + t3 = ZB * ZB; + t5 = t2 * 0.3141592654e1 * t3; + t6 = nx * 0.3141592654e1; + t7 = t6 * xc; + t8 = cos(t7); + t9 = nx * nx; + t10 = t8 * t9; + t11 = n * 0.3141592654e1; + t12 = exp(t11); + t13 = t12 * t12; + t16 = exp(xc * n * 0.3141592654e1); + t17 = t16 * t16; + t18 = t17 * t16; + t19 = t17 * t17; + t20 = t19 * t18; + t21 = t13 * t20; + t22 = t10 * t21; + t25 = ZA * ZA; + t26 = t1 * t25; + t27 = xc * 0.3141592654e1; + t28 = t26 * t27; + t29 = t19 * t16; + t30 = t13 * t13; + t31 = t29 * t30; + t35 = t9 * nx; + t36 = t3 * t35; + t37 = sin(t6); + t38 = t13 * t12; + t39 = t37 * t38; + t40 = t39 * t19; + t42 = t1 * t1; + t43 = nx * t42; + t44 = xc * xc; + t45 = t25 * t44; + t46 = t43 * t45; + t47 = 0.3141592654e1 * 0.3141592654e1; + t48 = t47 * t37; + t49 = t17 * t38; + t54 = 0.3141592654e1 * t35; + t55 = ZA * n * t54; + t56 = t37 * ZB; + t57 = t19 * t12; + t61 = t25 * t8; + t62 = t61 * t9; + t63 = n * t30; + t64 = t63 * t16; + t67 = t1 * n; + t69 = t47 * ZB; + t70 = t67 * t44 * t69; + t75 = nx * t3; + t76 = t75 * t37; + t77 = t67 * 0.3141592654e1; + t78 = t19 * t19; + t79 = t78 * t12; + t80 = t77 * t79; + t82 = t3 * t38; + t84 = t54 * t37; + t87 = sin(t7); + t88 = t29 * t87; + t89 = t47 * t44; + t93 = nx * t25; + t94 = t87 * t42; + t95 = t93 * t94; + t96 = t47 * xc; + t97 = t13 * t29; + t98 = t96 * t97; + t101 = t87 * t67; + t102 = t93 * t101; + t103 = t13 * t18; + t107 = t47 * t35; + t108 = t26 * t107; + t109 = t37 * t44; + t110 = t19 * t17; + t111 = t12 * t110; + t116 = t37 * t19 * t12; + t118 = t37 * xc; + t119 = ZB * t19; + t120 = t119 * t12; + t121 = t118 * t120; + t125 = xc * t3; + t126 = t1 * t47 * t125; + t127 = t35 * t37; + t128 = t38 * t19; + t129 = t127 * t128; + t132 = t26 * 0.3141592654e1; + t133 = t16 * t13; + t134 = t10 * t133; + t137 = 0.3141592654e1 * ZB; + t138 = t2 * t137; + t139 = ZA * t8; + t140 = t9 * t13; + t145 = t30 * t18; + t146 = t10 * t145; + t149 = t3 * t8; + t150 = t149 * t9; + t153 = 0.2e1 * t5 * t22 + 0.2e1 * t28 * t10 * t31 + t36 * t40 - 0.2e1 * t46 * t48 * t49 - + 0.2e1 * t55 * t56 * t57 - 0.2e1 * t62 * t64 + 0.16e2 * t70 * t29 * ZA * t10 - t76 * t80 + + t82 * n * t84 + 0.8e1 * t43 * t3 * t88 * t89 + 0.16e2 * t95 * t98 + 0.2e1 * t102 * t27 * t103 - + 0.2e1 * t108 * t109 * t111 + t36 * t116 + 0.8e1 * t55 * t121 - 0.4e1 * t126 * t129 - + 0.4e1 * t132 * t134 - 0.4e1 * t138 * t139 * t140 * t20 + 0.8e1 * t28 * t146 - 0.2e1 * t150 * t64; + t154 = t42 * n; + t155 = nx * t154; + t156 = t44 * xc; + t157 = t47 * 0.3141592654e1; + t158 = t156 * t157; + t159 = t155 * t158; + t162 = t56 * ZA * t19 * t12; + t165 = t77 * t49; + t167 = t1 * t3; + t168 = t167 * t89; + t169 = t127 * t49; + t172 = t37 * t67; + t173 = t75 * t172; + t174 = t38 * t110; + t175 = t27 * t174; + t179 = t47 * t25; + t181 = t10 * t97; + t184 = t27 * t31; + t187 = t67 * t47; + t188 = t44 * t3; + t189 = t187 * t188; + t192 = t25 * t35; + t193 = t37 * t17; + t194 = t193 * t12; + t196 = nx * ZA; + t197 = t196 * t172; + t198 = ZB * t38; + t199 = t198 * t19; + t204 = t1 * t12 * t110; + t207 = nx * ZB; + t209 = t1 * ZA; + t215 = t67 * t3; + t216 = t47 * t8; + t217 = t215 * t216; + t218 = t9 * xc; + t222 = nx * t67; + t223 = t222 * t27; + t224 = t3 * t87; + t228 = t167 * t107; + t232 = t26 * t96; + t235 = t207 * t94; + t236 = t47 * ZA; + t243 = xc * t13; + t244 = t243 * t29; + t248 = t25 * n; + t249 = t248 * 0.3141592654e1; + t253 = ZB * ZA; + t254 = t253 * t8; + t255 = t9 * n; + t256 = t30 * t16; + t260 = 0.2e1 * t207 * t37 * t209 * t128 + 0.2e1 * t5 * t134 - 0.16e2 * t217 * t218 * t97 - + 0.2e1 * t223 * t224 * t31 - 0.2e1 * t228 * t109 * t174 - 0.2e1 * t232 * t169 - + 0.16e2 * t235 * t236 * t44 * t30 * t18 - 0.4e1 * t196 * t101 * t137 * t244 + t249 * t169 + + 0.8e1 * t168 * t129 + 0.4e1 * t254 * t255 * t256; + t263 = t43 * t179; + t267 = t3 * n; + t268 = t267 * t54; + t269 = t118 * t57; + t272 = t39 * t1; + t274 = t67 * t25; + t275 = t274 * t158; + t278 = t75 * t87; + t279 = t77 * t103; + t282 = t25 * t38; + t285 = ZA * t38; + t290 = t267 * 0.3141592654e1; + t296 = t77 * t111; + t298 = t196 * t37; + t299 = t1 * ZB; + t303 = t37 * t42; + t304 = t196 * t303; + t308 = t77 * t57; + t310 = t26 * t89; + t313 = t77 * t128; + t316 = t101 * t27; + t319 = t93 * t87; + t320 = t77 * t97; + t323 = t127 * t57; + t326 = t10 * n; + t329 = t118 * t174; + t332 = -0.8e1 * t263 * t109 * t57 - 0.4e1 * t268 * t269 + t93 * t272 + 0.8e1 * t275 * t129 - + 0.4e1 * t278 * t279 + t282 * n * t84 - 0.2e1 * t285 * n * t54 * t56 - t290 * t169 - + 0.2e1 * t196 * t38 * t172 * t137 + t76 * t296 - 0.2e1 * t298 * t299 * t79 + + 0.8e1 * t304 * t96 * t120 + t76 * t308 - 0.2e1 * t310 * t169 - t76 * t313 + + 0.2e1 * t75 * t18 * t316 + 0.4e1 * t319 * t320 + t249 * t323 - 0.2e1 * t25 * t18 * t326 + + 0.2e1 * t228 * t329; + t335 = t75 * t101; + t336 = t27 * t21; + t342 = t77 * t133; + t347 = t209 * t137; + t350 = t9 * t1; + t351 = t149 * t350; + t355 = t37 * t78 * t12; + t359 = t93 * t303; + t367 = t172 * 0.3141592654e1; + t369 = t96 * t103; + t376 = t209 * t107; + t379 = t10 * t103; + t383 = t207 * t101; + t389 = 0.3141592654e1 * ZA; + t390 = t222 * t389; + t391 = t87 * ZB; + t398 = -0.2e1 * t102 * t336 + t93 * t38 * t367 + 0.16e2 * t95 * t369 - t82 * t127 - + 0.8e1 * t197 * t27 * t120 + 0.8e1 * t376 * t121 - 0.8e1 * t189 * t379 - t249 * t129 - + 0.4e1 * t383 * t27 * ZA * t16 * t13 - 0.8e1 * t390 * t391 * t21 - 0.2e1 * t197 * t137 * t57; + t402 = t39 * t110; + t404 = t193 * t38; + t406 = t127 * t174; + t408 = t167 * 0.3141592654e1; + t411 = t44 * t157; + t412 = t155 * t411; + t413 = t285 * t19; + t414 = t56 * t413; + t417 = ZA * t30; + t424 = t93 * t37; + t426 = t248 * t54; + t427 = t17 * t12; + t428 = t118 * t427; + t431 = t77 * t21; + t438 = ZA * t13; + t443 = t93 * t172; + t444 = t27 * t427; + t448 = t1 * t78 * t12; + t455 = t274 * t89; + t461 = t118 * t111; + t464 = -t36 * t402 + t36 * t404 - t249 * t406 - 0.4e1 * t408 * t134 + 0.16e2 * t412 * t414 - + 0.4e1 * t383 * t27 * t417 * t18 + 0.2e1 * t28 * t22 - t424 * t80 - 0.2e1 * t426 * t428 + + 0.4e1 * t278 * t431 + 0.4e1 * t254 * t255 * t103 + t290 * t323 + 0.4e1 * t383 * t27 * t438 * t20 + + 0.2e1 * t443 * t444 + t424 * t448 - t36 * t194 - 0.32e2 * t235 * t236 * t243 * t18 + + 0.8e1 * t455 * t181 - 0.4e1 * t359 * t96 * t128 - 0.2e1 * t426 * t461; + t469 = n * t16 * t13; + t474 = t1 * t38; + t475 = t474 * t19; + t480 = t89 * t103; + t483 = t67 * ZA; + t484 = t483 * t411; + t485 = t127 * t120; + t488 = t127 * t111; + t497 = t77 * t427; + t502 = t27 * t97; + t508 = t1 * t19 * t12; + t511 = t155 * t25 * t156; + t512 = t157 * t37; + t513 = t512 * t128; + t527 = t1 * t17; + t528 = t527 * t38; + t530 = -t76 * t497 - 0.4e1 * t254 * t255 * t97 - 0.2e1 * t102 * t502 - 0.4e1 * t108 * t269 - t76 * t508 + + 0.8e1 * t511 * t513 + 0.4e1 * t150 * t63 * t18 + 0.4e1 * t383 * t27 * t438 * t18 + + 0.4e1 * t132 * t379 + 0.2e1 * t168 * t488 - t76 * t528; + t535 = t44 * t13; + t542 = t527 * t12; + t544 = n * t13; + t545 = t544 * t20; + t548 = t75 * t303; + t549 = t96 * t111; + t552 = ZA * t35; + t553 = t552 * t37; + t562 = t43 * t96; + t563 = t3 * t37; + t564 = t563 * t128; + t579 = t474 * t110; + t590 = t9 * t30; + t591 = t590 * t18; + t595 = t127 * t427; + t598 = t77 * t174; + t600 = 0.4e1 * t5 * t146 + 0.16e2 * t235 * t236 * t535 * t18 + 0.8e1 * t455 * t146 + t76 * t542 - + 0.2e1 * t150 * t545 + 0.2e1 * t548 * t549 - 0.2e1 * t553 * t120 + t290 * t488 - + 0.8e1 * t274 * t47 * t44 * t29 * t10 - 0.4e1 * t562 * t564 - 0.2e1 * t132 * xc * t20 * t10 - + 0.32e2 * t562 * ZA * t87 * ZB * t13 * t29 - 0.8e1 * t347 * t379 + t76 * t579 - + 0.4e1 * t359 * t96 * t57 + 0.4e1 * t408 * t181 - 0.4e1 * t223 * t564 - + 0.12e2 * t209 * t27 * ZB * t8 * t591 + 0.2e1 * t310 * t595 + t76 * t598; + t601 = t27 * t49; + t604 = t127 * t79; + t606 = ZB * t29; + t616 = t139 * t140 * t18; + t638 = t10 * t256; + t643 = t118 * t199; + t653 = t544 * t29; + t658 = t3 * t29; + t660 = t350 * t27; + t663 = -0.4e1 * t254 * t255 * t145 + 0.2e1 * t267 * t20 * t8 * t9 - 0.4e1 * t138 * t139 * t9 * t16 * t13 - + 0.2e1 * t5 * t638 + 0.2e1 * t126 * t169 + 0.8e1 * t376 * t643 + 0.4e1 * t335 * t27 * t145 + + 0.16e2 * t235 * t236 * t535 * t29 + 0.6e1 * t150 * t653 - 0.4e1 * t426 * t269 + + 0.4e1 * t658 * t8 * t660; + t670 = t274 * t411; + t673 = t118 * t49; + t694 = t155 * t45; + t713 = n * t29 * t30; + t717 = t20 * t87; + t723 = t512 * t57; + t728 = -0.2e1 * t443 * t175 - 0.8e1 * t670 * t129 + 0.2e1 * t426 * t673 - + 0.16e2 * t207 * t88 * t42 * t47 * ZA * t44 + 0.4e1 * t254 * t255 * t21 + t249 * t595 + + 0.8e1 * t25 * t29 * t8 * t660 + 0.2e1 * t268 * t461 + 0.8e1 * t189 * t181 - 0.8e1 * t694 * t513 + + 0.2e1 * t198 * t553 - 0.12e2 * t606 * t139 * t660 - 0.2e1 * t359 * t549 + + 0.4e1 * t138 * t139 * t590 * t16 + 0.8e1 * t93 * t29 * t94 * t89 - 0.2e1 * t150 * t713 + + 0.2e1 * t222 * t3 * t717 * t27 + 0.8e1 * t670 * t323 + 0.8e1 * t694 * t723 - 0.2e1 * t62 * t653; + t734 = t43 * t89; + t735 = t563 * t427; + t740 = t75 * t94; + t744 = ZB * xc; + t750 = t563 * t57; + t754 = t218 * t103; + t771 = t127 * t199; + t776 = t89 * t174; + t791 = -0.4e1 * t207 * t717 * t77 * xc * ZA + 0.4e1 * t443 * t27 * t57 + t192 * t40 - 0.8e1 * t55 * t643 - + 0.16e2 * t209 * t89 * t771 - 0.8e1 * t275 * t323 + 0.2e1 * t359 * t776 + 0.16e2 * t304 * t89 * t199 + + 0.4e1 * t278 * t320 + 0.2e1 * t207 * t172 * t389 * t79 - 0.8e1 * t390 * t391 * t97; + t794 = t483 * t158; + t801 = t2 * 0.3141592654e1; + t818 = t215 * t411; + t827 = t96 * t174; + t837 = t37 * t12 * t110; + t845 = 0.16e2 * t794 * t485 + 0.8e1 * t159 * t564 - 0.8e1 * t455 * t379 - 0.2e1 * t801 * t3 * t20 * t10 - + 0.4e1 * t132 * t22 - 0.8e1 * t734 * t564 - 0.8e1 * t187 * t44 * t658 * t10 - 0.8e1 * t412 * t564 + + 0.4e1 * t132 * t181 - 0.8e1 * t818 * t129 + 0.2e1 * t46 * t48 * t427 - 0.4e1 * t75 * t29 * t316 - + 0.2e1 * t359 * t827 - t290 * t595 + 0.16e2 * t217 * t754 - t424 * t542 - 0.8e1 * t734 * t750 - + t192 * t837 - 0.4e1 * t254 * t255 * t133 + 0.8e1 * t304 * t96 * t199; + t864 = t544 * t18; + t867 = t3 * t18; + t884 = t27 * t256; + t891 = t187 * t744; + t894 = t563 * t49; + t900 = -0.2e1 * t263 * t428 + 0.2e1 * t228 * t428 - 0.6e1 * t223 * t224 * t103 - t192 * t404 + + 0.2e1 * t268 * t428 - 0.2e1 * t335 * t884 - t424 * t296 + 0.2e1 * t93 * t20 * t316 - + 0.32e2 * t891 * t616 + 0.2e1 * t562 * t894 - 0.2e1 * t801 * t867 * t10; + t904 = t27 * t111; + t907 = t118 * t128; + t915 = t89 * t145; + t947 = t139 * t140 * t29; + t952 = -0.2e1 * t173 * t904 + 0.4e1 * t426 * t907 + 0.12e2 * t253 * t10 * t1 * 0.3141592654e1 * t244 + + 0.8e1 * t95 * t915 - t36 * t355 - 0.16e2 * t794 * t771 - 0.8e1 * t511 * t723 + 0.16e2 * t734 * t162 + + t36 * t837 + 0.2e1 * t298 * t299 * t57 - 0.2e1 * t28 * t638 - 0.2e1 * t62 * t545 + + 0.2e1 * t310 * t406 + 0.12e2 * t138 * t616 + 0.4e1 * t223 * t750 + t424 * t497 + + 0.2e1 * t734 * t894 + 0.2e1 * t132 * xc * t18 * t10 - 0.16e2 * t70 * t947 + 0.32e2 * t891 * t947; + t969 = t67 * t157 * t156 * t3; + t974 = t27 * t133; + t1001 = -0.8e1 * t159 * t750 - 0.16e2 * t412 * t162 - t290 * t129 + 0.8e1 * t310 * t323 - + 0.4e1 * t319 * t342 + t75 * t272 + t192 * t402 - 0.8e1 * t359 * t89 * t128 - + 0.10e2 * t61 * t350 * t502 + 0.8e1 * t818 * t323 - 0.4e1 * t108 * t907; + t1042 = t89 * t97; + t1055 = -0.2e1 * t168 * t595 + 0.16e2 * t484 * t771 + 0.4e1 * t11 * t125 * t129 - 0.2e1 * t173 * t444 + + 0.2e1 * ZB * n * t54 * t37 * ZA * t79 - t424 * t475 + 0.2e1 * t562 * t735 - 0.2e1 * t548 * t776 + + t424 * t204 + 0.2e1 * t25 * t20 * t326 + 0.8e1 * t383 * t389 * t133 + t75 * t38 * t367 + + 0.2e1 * t62 * t469 + 0.2e1 * t197 * t137 * t128 - 0.2e1 * t102 * t884 - 0.2e1 * t5 * t379 - + 0.8e1 * t740 * t1042 - 0.16e2 * t159 * t414 - 0.2e1 * ZB * t35 * t37 * t413 + + 0.2e1 * t553 * ZB * t78 * t12; + t1096 = 0.2e1 * t443 * t904 - 0.2e1 * t268 * t329 - 0.2e1 * t443 * t601 + 0.2e1 * t102 * t974 - + 0.2e1 * t263 * t673 + t424 * t165 + 0.2e1 * t62 * t713 + t424 * t308 - t424 * t313 + + 0.8e1 * t347 * t22 - t424 * t598; + t1103 = t42 * t1 * t157; + t1104 = t1103 * t25; + t1108 = t3 * t19; + t1112 = n * t47; + t1113 = t9 * t9; + t1118 = t42 * t157; + t1119 = t1118 * t9; + t1120 = t25 * xc; + t1121 = t13 * t110; + t1122 = t1120 * t1121; + t1125 = t47 * t47; + t1126 = t67 * t1125; + t1127 = t1113 * ZA; + t1128 = t1126 * t1127; + t1129 = t19 * t13; + t1130 = t744 * t1129; + t1133 = t154 * t1125; + t1134 = t1133 * t9; + t1135 = t45 * t1129; + t1138 = t154 * t47; + t1139 = t25 * t30; + t1142 = t1126 * t1113; + t1145 = t125 * t1129; + t1148 = t1103 * xc; + t1149 = t3 * t13; + t1150 = t1149 * t17; + t1153 = t25 * t78; + t1156 = -0.8e1 * t1104 * t243 * t17 + 0.4e1 * t187 * t1108 * t9 - 0.2e1 * t1112 * t3 * t1113 * t30 + + 0.16e2 * t1119 * t1122 + 0.64e2 * t1128 * t1130 + 0.64e2 * t1134 * t1135 - 0.2e1 * t1138 * t1139 + + 0.32e2 * t1142 * t1135 - 0.32e2 * t1142 * t1145 + 0.8e1 * t1148 * t1150 - 0.2e1 * t1138 * t1153; + t1157 = t25 * t13; + t1158 = t1157 * t17; + t1161 = t13 * t17; + t1162 = t1120 * t1161; + t1165 = t3 * t78; + t1170 = t42 * t67 * t1125; + t1172 = t1108 * t13; + t1175 = t1 * t157; + t1176 = t1175 * t1113; + t1182 = t1120 * t1129; + t1189 = t110 * t9 * xc; + t1192 = t1149 * t110; + t1201 = 0.8e1 * t1103 * t1158 - 0.16e2 * t1119 * t1162 - 0.2e1 * t1112 * t1165 * t1113 + + 0.32e2 * t1170 * t44 * t1172 - 0.8e1 * t1176 * t1162 + 0.8e1 * t1104 * t243 * t110 - + 0.64e2 * t1134 * t1182 - 0.64e2 * t1134 * t1145 + 0.16e2 * t1118 * t3 * t1189 + + 0.16e2 * t1119 * t1192 - 0.4e1 * t187 * t1165 * t9 - 0.4e1 * t187 * t1139 * t9; + t1209 = t17 * t30; + t1210 = t125 * t1209; + t1213 = t1138 * ZA; + t1214 = ZB * t30; + t1218 = t1157 * t110; + t1226 = t3 * t30; + t1237 = t1170 * t25; + t1242 = 0.4e1 * t1112 * ZA * t119 * t1113 - 0.16e2 * t1119 * t1150 - 0.8e1 * t1176 * t1210 + + 0.4e1 * t1213 * t1214 * t19 - 0.16e2 * t1119 * t1218 - 0.32e2 * t1142 * t1182 - + 0.8e1 * t1103 * t1120 * t110 - 0.4e1 * t187 * t1226 * t9 + 0.8e1 * t1103 * t1192 + + 0.4e1 * t1112 * ZB * t1113 * t30 * ZA - 0.32e2 * t1237 * xc * t19 * t13; + t1251 = t125 * t1121; + t1260 = t1120 * t1209; + t1263 = t1139 * t19; + t1282 = 0.8e1 * t1103 * t110 * t3 * xc + 0.8e1 * t1104 * xc * t17 * t30 - 0.8e1 * t1176 * t1251 + + 0.16e2 * t1119 * t1158 + 0.4e1 * t1112 * t78 * t1127 * ZB + 0.16e2 * t1119 * t1260 + + 0.2e1 * t1138 * t1263 - 0.32e2 * t1170 * xc * t1172 - 0.16e2 * t1213 * t119 * t13 + + 0.4e1 * t1138 * t1214 * ZA + 0.32e2 * t1237 * t44 * t19 * t13 - 0.16e2 * t1118 * t25 * t1189; + t1287 = t188 * t1129; + t1292 = t25 * t19; + t1296 = t187 * t9; + t1297 = t1226 * t19; + t1311 = t1112 * t1113; + t1317 = -0.8e1 * t1176 * t1150 + 0.32e2 * t1142 * t1287 - 0.8e1 * t1103 * t1150 + + 0.2e1 * t1112 * t1292 * t1113 + 0.4e1 * t1296 * t1297 + 0.8e1 * t1176 * t1192 + + 0.4e1 * t1296 * t1263 + 0.8e1 * t1176 * t1158 - 0.8e1 * t1175 * t25 * t1113 * xc * t110 + + 0.2e1 * t1311 * t1297 + 0.2e1 * t1112 * t1108 * t1113; + t1320 = t253 * t1129; + t1328 = t253 * t30 * t19; + t1333 = t125 * t1161; + t1343 = ZB * t44 * t1129; + t1350 = -0.8e1 * t1176 * t1218 - 0.16e2 * t1311 * t1320 + 0.8e1 * t1176 * t1260 - 0.16e2 * t1119 * t1210 + + 0.4e1 * t1311 * t1328 + 0.2e1 * t1311 * t1263 + 0.8e1 * t1176 * t1333 + + 0.8e1 * t187 * ZB * t417 * t9 - 0.2e1 * t1138 * t1165 - 0.64e2 * t1128 * t1343 + + 0.64e2 * t1134 * t1287 + 0.2e1 * t1138 * t1108; + t1369 = t1133 * t9 * ZA; + t1378 = t187 * ZA; + t1383 = t1170 * ZA; + t1388 = 0.2e1 * t1138 * t1297 - 0.8e1 * t1148 * t1192 + 0.2e1 * t1138 * t1292 - 0.16e2 * t1119 * t1251 + + 0.8e1 * t1175 * xc * t110 * t1113 * t3 - 0.2e1 * t1112 * t1153 * t1113 + 0.128e3 * t1369 * t1130 + + 0.16e2 * t1119 * t1333 + 0.4e1 * t1138 * t78 * ZA * ZB + 0.8e1 * t1378 * t78 * t9 * ZB - + 0.64e2 * t1383 * t1343 + 0.64e2 * t1383 * t1130; + t1420 = 0.4e1 * t1138 * t119 * ZA - 0.128e3 * t1369 * t1343 - 0.4e1 * t187 * t1153 * t9 - + 0.2e1 * t1138 * t1226 + 0.8e1 * t1296 * t1328 - 0.2e1 * t1112 * t1139 * t1113 - + 0.8e1 * t1148 * t3 * t17 * t30 - 0.32e2 * t1296 * t1320 + 0.8e1 * t1176 * t1122 + + 0.4e1 * t187 * t1292 * t9 + 0.8e1 * t1378 * t119 * t9 - 0.8e1 * t1103 * t1218; + + _C4B = (-t424 * t508 + 0.8e1 * t412 * t750 - 0.2e1 * t232 * t595 - 0.4e1 * t126 * t323 + t1096 - + t76 * t204 + t728 + 0.2e1 * t548 * t827 + 0.2e1 * t150 * t469 + t398 + 0.8e1 * t189 * t146 + t260 - + 0.2e1 * t351 * t184 - 0.2e1 * t268 * t673 - 0.4e1 * t319 * t279 + t464 - 0.2e1 * t108 * t461 + + 0.16e2 * t740 * t369 + 0.16e2 * t274 * t216 * t754 - 0.16e2 * t70 * t139 * t591 + + 0.2e1 * t55 * t56 * t128 - 0.2e1 * t359 * t89 * t111 + 0.2e1 * t734 * t563 * t111 + + 0.6e1 * t223 * t224 * t97 + 0.8e1 * t383 * t389 * t103 + 0.4e1 * t606 * ZA * t326 - + 0.2e1 * t93 * t18 * t316 - 0.4e1 * t443 * t27 * t128 + 0.8e1 * t197 * t27 * t199 + + 0.8e1 * t108 * t109 * t128 - t249 * t604 + 0.16e2 * t70 * t616 - 0.8e1 * t969 * t323 + t845 - + t424 * t579 + 0.16e2 * t159 * t162 + t290 * t406 - 0.6e1 * t150 * t864 + t192 * t116 + + 0.2e1 * t867 * t326 - 0.4e1 * t658 * t326 - 0.2e1 * t351 * t502 - t76 * t165 + t900 + + 0.8e1 * t168 * t323 + t791 + 0.8e1 * t740 * t915 - 0.4e1 * t562 * t750 - 0.4e1 * t278 * t342 + + 0.4e1 * t319 * t431 + 0.2e1 * t173 * t175 + t424 * t528 + 0.8e1 * t969 * t129 - + 0.8e1 * t347 * t181 + t332 + t530 - 0.2e1 * t108 * t329 - 0.2e1 * t207 * t38 * t37 * t1 * ZA + + t1001 + 0.4e1 * t408 * t379 + t76 * t448 + 0.2e1 * t102 * t184 + 0.2e1 * t426 * t329 + + 0.16e2 * t740 * t98 - t282 * t127 - 0.16e2 * t1 * t44 * t69 * t552 * t116 + 0.2e1 * t168 * t169 + + 0.2e1 * t28 * t134 - t290 * t604 - 0.16e2 * t484 * t485 - 0.8e1 * t740 * t480 + + 0.2e1 * t173 * t601 - 0.2e1 * t335 * t336 + t600 + 0.2e1 * t62 * t864 + t952 + 0.8e1 * t347 * t134 - + t192 * t355 + t192 * t194 + 0.2e1 * t228 * t461 + t663 + 0.4e1 * t383 * t27 * t417 * t16 + + 0.4e1 * t138 * t20 * ZA * t10 - 0.4e1 * t20 * ZB * ZA * t326 + 0.4e1 * t196 * t88 * t77 * t744 - + 0.16e2 * t67 * xc * t179 * t181 - 0.8e1 * t95 * t480 - t249 * t488 - t76 * t475 + t1055 - + 0.4e1 * t408 * t22 - 0.10e2 * t28 * t379 + 0.2e1 * t335 * t974 + t153 - 0.8e1 * t95 * t1042 - + 0.2e1 * t734 * t735) / (t1156 + t1201 + t1242 + t1282 + t1317 + t1350 + t1388 + t1420); + /****************************************************************************************/ + /****************************************************************************************/ + + if (x > xc) + { + _C1 = _C1B; + _C2 = _C2B; + _C3 = _C3B; + _C4 = _C4B; + Z = ZB; + } + else + { + _C1 = _C1A; + _C2 = _C2A; + _C3 = _C3A; + _C4 = _C4A; + Z = ZA; + } + /****************************************************************************************/ + /****************************************************************************************/ + t1 = n * n; + t2 = t1 * t1; + t3 = t2 * n; + t4 = x * t3; + t5 = 0.3141592654e1 * 0.3141592654e1; + t6 = t5 * 0.3141592654e1; + t11 = _C3 * t6; + t12 = x * n; + t13 = nx * nx; + t14 = t13 * t13; + t15 = t12 * t14; + t19 = exp(t12 * 0.3141592654e1); + t20 = t19 * t19; + t21 = t4 * t20; + t24 = _C1 * t5; + t25 = Z * t20; + t29 = _C1 * t6; + t30 = t29 * Z; + t31 = t1 * n; + t32 = x * t31; + t33 = t32 * t13; + t36 = t11 * x; + t41 = n * t20; + t45 = t6 * _C4; + t49 = t20 * t1; + t51 = _C2 * Z; + t55 = -0.2e1 * t4 * t6 * _C2 * Z - 0.2e1 * t11 * t15 - 0.2e1 * t11 * t21 + 0.2e1 * t24 * t25 * t14 - t13 + + 0.4e1 * t30 * t33 - 0.4e1 * t36 * t31 * t20 * t13 - 0.2e1 * t36 * t41 * t14 - 0.2e1 * t4 * t45 * t20 - + t49 - 0.2e1 * t4 * t6 * t51 * t20; + t58 = t32 * t6; + t59 = _C4 * t20; + t63 = t20 * t13; + t67 = t12 * t6; + t68 = t20 * t14; + t87 = t49 * t13; + t90 = -0.4e1 * t11 * t33 - 0.4e1 * t58 * t59 * t13 - 0.4e1 * t58 * t51 * t63 - 0.2e1 * t67 * t51 * t68 + + 0.4e1 * t32 * t45 * t13 - 0.2e1 * t67 * t59 * t14 - 0.2e1 * t30 * t21 + t1 + 0.2e1 * t24 * t25 * t2 + + 0.2e1 * t12 * t45 * t14 + 0.4e1 * t24 * Z * t87; + t106 = _C3 * t5; + t120 = -0.4e1 * t30 * t32 * t63 + t63 + 0.4e1 * t24 * Z * t1 * t13 + 0.2e1 * t29 * Z * x * t3 - + 0.4e1 * t58 * t51 * t13 - 0.2e1 * t106 * t2 + t32 * 0.3141592654e1 - 0.2e1 * t106 * t14 - + 0.2e1 * t30 * t12 * t68 - 0.2e1 * t67 * t51 * t14 + 0.4e1 * t106 * t87; + t129 = sin(nx * 0.3141592654e1 * x); + t155 = 0.2e1 * t30 * t15 + x * 0.3141592654e1 * t41 * t13 - 0.4e1 * t19 * nx * t129 * n + + t32 * 0.3141592654e1 * t20 + 0.2e1 * t106 * t68 + 0.2e1 * t106 * t20 * t2 - 0.4e1 * t106 * t1 * t13 - + 0.2e1 * t11 * t4 + 0.2e1 * t4 * t45 + 0.2e1 * t24 * Z * t2 + 0.2e1 * t24 * Z * t14 + + t12 * 0.3141592654e1 * t13; + t158 = t5 * Z; + + u1 = (t55 + t90 + t120 + t155) / + (0.4e1 * t158 * t19 * t2 + 0.8e1 * t158 * t19 * t1 * t13 + 0.4e1 * t158 * t19 * t14); + /****************************************************************************************/ + /****************************************************************************************/ + t1 = n * n; + t2 = t1 * n; + t3 = x * t2; + t4 = 0.3141592654e1 * 0.3141592654e1; + t5 = t4 * 0.3141592654e1; + t6 = t3 * t5; + t7 = _C2 * Z; + t8 = nx * nx; + t12 = t1 * t1; + t13 = t12 * n; + t14 = x * t13; + t15 = t5 * _C4; + t16 = x * n; + t18 = exp(t16 * 0.3141592654e1); + t19 = t18 * t18; + t23 = t16 * t5; + t24 = t8 * t8; + t28 = _C3 * t5; + t29 = t14 * t19; + t32 = _C1 * t5; + t33 = t32 * Z; + t34 = t16 * t24; + t37 = _C4 * t19; + t45 = _C2 * t4; + t53 = t19 * t8; + t58 = _C4 * t4; + t60 = t1 * t19 * t8; + t63 = t19 * t24; + t67 = t3 * t8; + t73 = n * t19; + t86 = t28 * x; + t91 = 0.4e1 * t58 * t60 + 0.2e1 * t33 * t16 * t63 + 0.4e1 * t33 * t67 + 0.2e1 * t33 * t29 - + x * 0.3141592654e1 * t73 * t8 - 0.2e1 * t53 + 0.2e1 * t32 * Z * x * t13 - 0.2e1 * t58 * t12 - + 0.2e1 * t58 * t24 + t3 * 0.3141592654e1 + 0.4e1 * t86 * t2 * t19 * t8; + t94 = Z * t12; + t121 = -0.2e1 * t8 + 0.2e1 * t45 * t94 * t19 + 0.2e1 * t14 * t5 * t7 * t19 + 0.4e1 * t6 * t7 * t53 + + 0.2e1 * t23 * t7 * t63 - 0.4e1 * t28 * t67 + 0.2e1 * t45 * t94 + 0.2e1 * t58 * t12 * t19 + + t16 * 0.3141592654e1 * t8 + 0.2e1 * t14 * t15 - 0.2e1 * t28 * t14; + t146 = cos(nx * 0.3141592654e1 * x); + t156 = -t3 * 0.3141592654e1 * t19 + 0.2e1 * t58 * t63 - 0.4e1 * t58 * t1 * t8 + 0.4e1 * t45 * Z * t1 * t8 - + 0.2e1 * t28 * t34 + 0.2e1 * t86 * t73 * t24 + 0.4e1 * t3 * t15 * t8 + 0.4e1 * t45 * Z * t60 + + 0.4e1 * t18 * t146 * t8 + 0.2e1 * t45 * Z * t24 + 0.2e1 * t16 * t15 * t24; + t159 = t4 * Z; + + u2 = (-0.4e1 * t6 * t7 * t8 + 0.2e1 * t14 * t15 * t19 - 0.2e1 * t23 * t7 * t24 + 0.2e1 * t28 * t29 + + 0.2e1 * t33 * t34 + 0.4e1 * t6 * t37 * t8 - 0.2e1 * t14 * t5 * _C2 * Z + 0.2e1 * t45 * Z * t19 * t24 + + 0.2e1 * t23 * t37 * t24 + 0.4e1 * t33 * t3 * t53 + t91 + t121 + t156) / + (0.4e1 * t159 * t18 * t12 + 0.8e1 * t159 * t18 * t1 * t8 + 0.4e1 * t159 * t18 * t24); + /****************************************************************************************/ + /****************************************************************************************/ + t1 = 0.3141592654e1 * 0.3141592654e1; + t2 = t1 * 0.3141592654e1; + t3 = _C1 * t2; + t4 = t3 * Z; + t5 = n * n; + t6 = t5 * t5; + t7 = t6 * n; + t8 = x * t7; + t9 = x * n; + t11 = exp(t9 * 0.3141592654e1); + t12 = t11 * t11; + t13 = t8 * t12; + t16 = t5 * n; + t17 = x * t16; + t18 = t17 * t2; + t19 = _C4 * t12; + t20 = nx * nx; + t24 = t2 * _C4; + t28 = _C3 * t2; + t29 = t28 * x; + t30 = t12 * n; + t31 = t20 * t20; + t40 = _C2 * Z; + t44 = t9 * t2; + t48 = t12 * t20; + t52 = t17 * t20; + t57 = -0.2e1 * t4 * t13 - 0.4e1 * t18 * t19 * t20 - 0.2e1 * t8 * t24 * t12 - 0.2e1 * t29 * t30 * t31 + + 0.2e1 * t8 * t2 * _C2 * Z - 0.2e1 * t8 * t2 * t40 * t12 - 0.2e1 * t44 * t19 * t31 - + 0.4e1 * t18 * t40 * t48 + t20 + 0.4e1 * t28 * t52 + t17 * 0.3141592654e1 * t12; + t58 = t9 * t31; + t61 = _C3 * t1; + t62 = t12 * t31; + t73 = t5 * t20; + t78 = _C1 * t1; + t90 = Z * t12; + t94 = 0.2e1 * t28 * t58 + 0.2e1 * t61 * t62 + 0.2e1 * t61 * t12 * t6 - 0.4e1 * t4 * t17 * t48 + + 0.2e1 * t28 * t8 + 0.4e1 * t61 * t73 - 0.2e1 * t8 * t24 - 0.2e1 * t78 * Z * t6 - + 0.2e1 * t44 * t40 * t62 - 0.2e1 * t78 * Z * t31 - t9 * 0.3141592654e1 * t20 + 0.2e1 * t78 * t90 * t6; + t101 = cos(nx * 0.3141592654e1 * x); + t102 = t11 * t101; + t109 = t12 * t5; + t110 = t109 * t20; + t128 = 0.2e1 * t61 * t6 - t17 * 0.3141592654e1 + 0.2e1 * t102 * t5 - 0.4e1 * t17 * t24 * t20 + + 0.4e1 * t78 * Z * t110 - 0.2e1 * t9 * t24 * t31 - 0.4e1 * t4 * t52 - 0.2e1 * t4 * t9 * t62 + + x * 0.3141592654e1 * t30 * t20 - t5 - 0.4e1 * t78 * Z * t5 * t20; + t156 = 0.2e1 * t78 * t90 * t31 - 0.2e1 * t3 * Z * x * t7 + t48 + 0.4e1 * t61 * t110 + + 0.4e1 * t18 * t40 * t20 - 0.2e1 * t102 * t20 + 0.2e1 * t61 * t31 + 0.2e1 * t44 * t40 * t31 - t109 - + 0.2e1 * t4 * t58 - 0.2e1 * t28 * t13 - 0.4e1 * t29 * t16 * t12 * t20; + t159 = t1 * t11; + + u3 = (t57 + t94 + t128 + t156) / (0.4e1 * t159 * t6 + 0.8e1 * t159 * t73 + 0.4e1 * t159 * t31); + /****************************************************************************************/ + /****************************************************************************************/ + t1 = _C2 * Z; + t2 = 0.3141592654e1 * 0.3141592654e1; + t3 = t2 * 0.3141592654e1; + t4 = n * n; + t5 = t4 * t4; + t6 = t5 * t4; + t8 = t3 * t6 * x; + t11 = x * t4; + t12 = t11 * t3; + t15 = exp(x * n * 0.3141592654e1); + t16 = t15 * t15; + t17 = _C3 * t16; + t18 = nx * nx; + t19 = t18 * t18; + t23 = t5 * n; + t24 = t2 * t23; + t28 = t1 * t3; + t29 = t6 * x; + t30 = t29 * t16; + t33 = _C4 * t3; + t34 = t5 * x; + t35 = t34 * t18; + t41 = sin(nx * 0.3141592654e1 * x); + t47 = t11 * t19; + t54 = t3 * _C3; + t57 = 0.2e1 * t1 * t8 + 0.2e1 * t12 * t17 * t19 + 0.2e1 * t1 * t24 * t16 + 0.2e1 * t28 * t30 - + 0.4e1 * t33 * t35 + 0.2e1 * t15 * nx * t41 * t4 + 0.4e1 * t28 * t35 - 0.2e1 * t33 * t47 - + 0.2e1 * t1 * t24 - 0.2e1 * t33 * t29 + 0.2e1 * t29 * t54; + t58 = 0.3141592654e1 * t16; + t60 = t2 * _C4; + t69 = t4 * n; + t73 = t1 * t2; + t75 = t69 * t16 * t18; + t79 = x * t16; + t83 = n * t16; + t84 = t83 * t19; + t95 = -t34 * t58 + 0.2e1 * t60 * t23 * t16 + 0.2e1 * t60 * n * t19 - t11 * 0.3141592654e1 * t18 + + 0.4e1 * t60 * t69 * t18 + 0.4e1 * t73 * t75 + 0.4e1 * t33 * t5 * t79 * t18 + 0.2e1 * t73 * t84 + + 0.2e1 * t60 * t84 + 0.2e1 * t33 * t4 * t79 * t19 + 0.4e1 * t60 * t75; + t97 = t34 * t3; + t101 = Z * _C1; + t102 = t16 * t19; + t106 = t16 * t18; + t127 = t2 * t69; + t131 = t2 * n; + t135 = 0.4e1 * t97 * t17 * t18 + 0.2e1 * t12 * t101 * t102 + 0.4e1 * t28 * t34 * t106 + + 0.2e1 * t28 * t11 * t102 - 0.2e1 * t29 * t3 * Z * _C1 - 0.4e1 * t97 * t101 * t18 - + 0.2e1 * t12 * t101 * t19 + 0.2e1 * t60 * t23 - 0.2e1 * t83 * t18 - 0.4e1 * t1 * t127 * t18 - + 0.2e1 * t1 * t131 * t19; + t164 = 0.2e1 * t28 * t47 + 0.2e1 * t11 * t54 * t19 + 0.2e1 * t8 * t101 * t16 + 0.2e1 * t33 * t30 - + t11 * t58 * t18 + 0.2e1 * t29 * t54 * t16 + 0.4e1 * t34 * t54 * t18 + 0.4e1 * t97 * t101 * t106 - + 0.2e1 * t15 * t18 * nx * t41 - t34 * 0.3141592654e1 + 0.2e1 * n * t18; + + u4 = (t57 + t95 + t135 + t164) / (0.4e1 * t24 * t15 + 0.8e1 * t127 * t15 * t18 + 0.4e1 * t131 * t15 * t19); + + + /****************************************************************************************/ + /****************************************************************************************/ + + + u5 = (double) (-2 * Z * n * PI * u2 - u3 * 2 * n * PI) * cos(n * PI * z); /* pressure */ + + u6 = (double) (u3 * 2 * n * PI + 4 * Z * n * PI * u2) * cos(n * PI * z); /* zz stress */ + sum5 += u5; + sum6 += u6; + + u1 *= cos(n * PI * z); /* x velocity */ + sum1 += u1; + u2 *= sin(n * PI * z); /* z velocity */ + sum2 += u2; + u3 *= 2 * n * PI * cos(n * PI * z); /* xx stress */ + sum3 += u3; + u4 *= 2 * n * PI * sin(n * PI * z); /* zx stress */ + sum4 += u4; + + /*printf("%0.7f %0.7f %0.7f %0.7f %0.7f %0.7f %0.7f %0.7f\n",x,z,sum1,sum2,sum3,sum4,sum5,sum6);*/ + + /* Output */ + if (vel != nullptr) + { + vel[0] = sum1; + vel[1] = sum2; + } + if (presssure != nullptr) + { + (*presssure) = sum5; + } + if (total_stress != nullptr) + { + total_stress[0] = sum3; + total_stress[1] = sum6; + total_stress[2] = sum4; + } + if (strain_rate != nullptr) + { + if (x > xc) + { + Z = ZB; + } + else + { + Z = ZA; + } + strain_rate[0] = (sum3 + sum5) / (2.0 * Z); + strain_rate[1] = (sum6 + sum5) / (2.0 * Z); + strain_rate[2] = (sum4) / (2.0 * Z); + } + /* Value checks, could be cleaned up if needed. Julian Giordani 2-Oct-2006*/ + if (fabs(sum5 - (-0.5 * (sum6 + sum3))) > 1e-5) + { + assert(0); + } + } + + + + /** + * The exact solution for the SolCx benchmark, given the value of the + * jump in viscosity $\eta_B$. + */ + template + class FunctionSolCx : public Function + { + public: + FunctionSolCx(const double eta_B, + const double background_density, + const unsigned int n_compositional_fields) + : + Function(dim+2+n_compositional_fields), + eta_B_(eta_B), + background_density(background_density), + n_compositional_fields(n_compositional_fields) {} + + + void vector_value(const Point &p, + Vector &values) const override + { + AssertDimension(values.size(), 4 + n_compositional_fields); + + double pos[2] = {p(0), p(1)}; + double total_stress[3], strain_rate[3]; + double eta_A = 1.0; + double eta_B = eta_B_; + + // call the analytic function for the solution with a zero + // background density + AnalyticSolutions::_Velic_solCx + (pos, + eta_A, eta_B, + 0.5, 1, + &values[0], &values[2], total_stress, strain_rate); + + // then add the background pressure to the value we just got + values[2] += (0.5 - p[1]) * background_density; + } + + private: + double eta_B_, background_density; + unsigned int n_compositional_fields; + }; + } + + + + /** + * A material model that describes the SolCx benchmark of the paper + * cited in the documentation of the DuretzEtAl namespace. + * + * @note The SolCx benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @note The analytic solution of this benchmark is implemented in the + * "SolCx error" postprocessor in aspect::Postprocessor::DuretzEtAl::SolCx + * class and can be used to assess the accuracy of the computed solution. + * + * @ingroup MaterialModels + */ + template + class SolCxMaterial : public MaterialModel::Interface + { + public: + /** + * @name Physical parameters used in the basic equations + * @{ + */ + + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + + const Point &pos = in.position[i]; + out.viscosities[i] = (pos[0] < 0.5 ? 1 : eta_B); + out.densities[i] = background_density-std::sin(numbers::PI*pos[1])*std::cos(numbers::PI*pos[0]); + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + + } + } + + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + + /** + * Return whether the model is compressible or not. + * Incompressibility does not necessarily imply that the density is + * constant; rather, it may still depend on temperature or pressure. + * In the current context, compressibility means whether we should + * solve the continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + bool is_compressible () const override + { + return false; + } + /** + * @} + */ + + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("SolCx"); + { + prm.declare_entry ("Viscosity jump", "1e6", + Patterns::Double (0.), + "Viscosity in the right half of the domain."); + prm.declare_entry ("Background density", "0.", + Patterns::Double (0.), + "Density value upon which the variation of this testcase " + "is overlaid. Since this background density is constant " + "it does not affect the flow pattern but it adds to the " + "total pressure since it produces a nonzero adiabatic " + "pressure if set to a nonzero value."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("SolCx"); + { + eta_B = prm.get_double ("Viscosity jump"); + background_density = prm.get_double("Background density"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + + /** + * Returns the viscosity value on the right half of the domain, + * typically 1 or 1e6 + */ + double get_eta_B() const + { + return eta_B; + } + + /** + * Returns the background density of this model. See the + * corresponding member variable of this class for more information. + */ + double get_background_density() const + { + return background_density; + } + + private: + /** + * Viscosity value on the right half of the domain, typically 1 or + * 1e6 + */ + double eta_B; + + /** + * A constant background density over which the density variations + * are overlaid. This constant density has no effect on the dynamic + * pressure and consequently on the flow field, but it contributes + * to the total pressure via the adiabatic pressure. We use this + * field to support our claim in the first ASPECT paper that the + * accuracy of the solutions is guaranteed even if we don't subtract + * the adiabatic pressure in our computations. + */ + double background_density; + }; + + + + + /** + * A postprocessor that evaluates the accuracy of the solution. + * + * The implementation of error evaluators that correspond to the + * benchmarks defined in the paper Duretz et al. reference above. + */ + template + class SolCxPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &/*statistics*/) override + { + + AssertThrow(Plugins::plugin_type_matches>(this->get_material_model()), + ExcMessage("Postprocessor DuretzEtAl only works with the material model SolCx, SolKz, and Inclusion.")); + + const SolCxMaterial & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + std::unique_ptr> ref_func + = std::make_unique>(material_model.get_eta_B(), + material_model.get_background_density(), + this->n_compositional_fields()); + + const QGauss quadrature_formula (this->introspection().polynomial_degree.velocities + 2); + + Vector cellwise_errors_u (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_p (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_ul2 (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_pl2 (this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_u(std::pair(0,dim), + this->get_fe().n_components()); + ComponentSelectFunction comp_p(dim, + this->get_fe().n_components()); + + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_u, + quadrature_formula, + VectorTools::L1_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_p, + quadrature_formula, + VectorTools::L1_norm, + &comp_p); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_ul2, + quadrature_formula, + VectorTools::L2_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_pl2, + quadrature_formula, + VectorTools::L2_norm, + &comp_p); + + const double u_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_u, VectorTools::L1_norm); + const double p_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_p, VectorTools::L1_norm); + const double u_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_ul2, VectorTools::L2_norm); + const double p_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_pl2, VectorTools::L2_norm); + + std::ostringstream os; + os << std::scientific << u_l1 + << ", " << p_l1 + << ", " << u_l2 + << ", " << p_l2; + + return std::make_pair("Errors u_L1, p_L1, u_L2, p_L2:", os.str()); + } + }; + + } +} +#endif diff --git a/benchmarks/solcx/solcx.prm.bak b/benchmarks/solcx/solcx.prm.bak new file mode 100644 index 00000000000..b21e251c484 --- /dev/null +++ b/benchmarks/solcx/solcx.prm.bak @@ -0,0 +1,66 @@ +# A description of the SolCX benchmark for which a known solution +# is available. See the manual for more information. + +set Additional shared libraries = ./libsolcx.so + +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output +set Pressure normalization = volume +set Nonlinear solver scheme = no Advection, iterated Stokes +set Use years in output instead of seconds = false + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Material model + set Model name = SolCxMaterial + + subsection SolCx + set Viscosity jump = 1e6 + end +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + + +subsection Initial temperature model + set Model name = perturbed box +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = false +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 4 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = SolCxPostprocessor, visualization +end diff --git a/benchmarks/solitary_wave/doc/solitary_wave.prm.bak b/benchmarks/solitary_wave/doc/solitary_wave.prm.bak new file mode 100644 index 00000000000..faf3e731475 --- /dev/null +++ b/benchmarks/solitary_wave/doc/solitary_wave.prm.bak @@ -0,0 +1,103 @@ +# Listing of Parameters +# --------------------- +# Set up the solitary wave benchmark +# (Barcilon & Richter, 1986; Simpson & Spiegelman, 2011; +# Keller et al., 2013; Schmeling, 200 + +set Additional shared libraries = ./libsolitary_wave.so + +# A non-linear solver has to be used for models with melt migration +set Nonlinear solver scheme = iterated Advection and Stokes +set Max nonlinear iterations = 10 +set Nonlinear solver tolerance = 1e-5 + +# The end time is chosen in such a way that the solitary wave travels +# approximately 5 times its wavelength during the model time. +set End time = 6e6 + +# To model melt migration, there has to be a compositional field with +# the name 'porosity'. +subsection Compositional fields + set Number of fields = 1 + set Names of fields = porosity +end + +# Enable modeling of melt migration in addition to the advection of +# solid material. +subsection Melt settings + set Include melt transport = true +end + +######### Parameters for the porosity field ######################## + +# We use the initial conditions and material model from the +# solitary wave plugin and choose a wave with an amplitude of +# 0.01 and a background porosity of 0.001. +subsection Initial composition model + set Model name = Solitary wave initial condition + + subsection Solitary wave initial condition + set Offset = 200 + set Read solution from file = true + set Amplitude = 0.01 + set Background porosity = 0.001 + end +end + +subsection Material model + set Model name = Solitary Wave +end + +# As material is flowing in, we prescribe the porosity at the +# upper and lower boundary. +subsection Boundary composition model + set List of model names = initial composition + set Fixed composition boundary indicators = 2,3 +end + +# As we know that our solution does not have any steep gradients +# we can use a low stabilization to avoid too much diffusion. +subsection Discretization + subsection Stabilization parameters + set beta = 0.001 + end +end + +######### Model geometry ############################################## + +# Our domain is a pseudo-1D-profile 400 m in height, but only a few elements wide +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 10 + set Y extent = 400 + set Y repetitions = 40 + end +end + +######### Velocity boundary conditions ################################ + +# We apply the phase speed of the wave here, so that it always stays in the +# same place in our model. The phase speed is c = 5.25e-11 m/s, but we have +# to convert it to m/years using the same conversion that is used internally +# in ASPECT: year_in_seconds = 60*60*24*365.2425. +subsection Boundary velocity model + set Tangential velocity boundary indicators = 0,1 + set Prescribed velocity boundary indicators = 2:function, 3:function + + subsection Function + set Function expression = 0;-1.65673998e-4 + end +end + +# Postprocessor for the error calculation +subsection Postprocess + set List of postprocessors = solitary wave statistics +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-10 + end +end diff --git a/benchmarks/solitary_wave/solitary_wave.cc.bak b/benchmarks/solitary_wave/solitary_wave.cc.bak new file mode 100644 index 00000000000..715f6dd3301 --- /dev/null +++ b/benchmarks/solitary_wave/solitary_wave.cc.bak @@ -0,0 +1,1025 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +/** + * MPI operator used by MPI_max_and_data + */ +void myop_func(void *invec, + void *inoutvec, + int *len, + MPI_Datatype *datatype) +{ + AssertThrow(*len > 1, dealii::ExcNotImplemented()); + AssertThrow(*datatype == MPI_DOUBLE, dealii::ExcNotImplemented()); + + double *indata = static_cast(invec); + double *inoutdata = static_cast(inoutvec); + + if (indata[0]>inoutdata[0]) + { + for (int i=0; i<*len; ++i) + inoutdata[i] = indata[i]; + } +} + + +/** + * Computes MPI_MAX of @p local_max like Allreduce, but also transmits the + * @p local_data from the rank with the largest @local_max to every rank + * (returned in @p global_data). + */ +void MPI_max_and_data(const double &local_max, + const double &local_data, + double &global_max, + double &global_data) +{ + MPI_Op myop; + MPI_Op_create(&myop_func, /* commutes? */ 1 ,&myop); + + double local[] = {local_max, local_data}; + double global[2]; + + MPI_Allreduce(local, global, 2, MPI_DOUBLE, myop, MPI_COMM_WORLD); + global_max = global[0]; + global_data = global[1]; + MPI_Op_free(&myop); +} + + +namespace aspect +{ + /** + * This is the "Solitary wave" benchmark defined in the following paper: + * @code + * @Article{DMGT11, + * author = {T. Keller and D. A. May and B. J. P. Kaus}, + * title = {Numerical modelling of magma dynamics coupled + * to tectonic deformation of lithosphere and crust}, + * journal = {Geophysical Journal International}, + * year = 2013, + * volume = 195(3), + * pages = {1406-1442} + * @endcode + * + * To calculate the initial condition, which is a solitary wave solution of + * the magma dynamics equations, we use the equation for the one-dinemsional + * case and the non-dimensionalization as it is described in + * @code + * @Article{SS11, + * author = {G. Simpson and M. Spiegelman}, + * title = {Solitary Wave Benchmarks in Magma Dynamics}, + * journal = {Journal of Scientific Computing}, + * year = 2011, + * volume = 49(3), + * pages = {268-290} + * @endcode + * + * Specifically, this means that we scale the porosity with the background + * porosity, and the coordinates with the compaction length $\delta_0$, which is + * defined as $\sqrt \frac{k(\phi_0) \xi^{*}+4/3 \eta^{*}}{\eta_f}$. $k(\phi_0)$ is the + * permeability at background porosity, $\xi^{*}$ is the compaction viscosity, + * $\eta^{*}$ is the shear viscosity of the fluid and $\eta_f$ is the shear viscosity + * of the melt. + */ + namespace SolitaryWaveBenchmark + { + using namespace dealii; + + namespace AnalyticSolutions + { + // vectors to store the porosity field and the corresponding coordinate in + const unsigned int max_points = 2e8; + std::vector porosity, coordinate; + + /** + * @note The solitary wave solution only exists as a function x = func(phi) + * and not phi = func(x), which is what we would like to have for describing + * the shape of the wave. Thus, we calculate x = func(phi) for a range of phis + * between the background porosity and the amplitude of the wave. In a next + * step, we interpolate these values to the grid. + * + * @param phi The characteristic shape of the wave, with phi --> 1 + * for x --> +- infinity + * + * @param amplitude The amplitude of the solitary wave, which is always + * greater than 1. + */ + double solitary_wave_solution (const double phi, const double amplitude) + { + AssertThrow(phi > 1.0 && phi <= amplitude, + ExcMessage("The solitary wave solution can only be computed " + "for porosities larger than the background porosity of 1 " + "and smaller than or equal to the amplitude of the wave.")); + AssertThrow(amplitude > 1, + ExcMessage("Amplitude of the solitary wave must be larger than 1!")); + const double A_1 = std::sqrt(amplitude - 1.0); + const double A_phi = std::sqrt(amplitude - phi); + return std::sqrt(amplitude + 0.5) + * (2 * A_phi - 1.0/A_1 * std::log((A_1 - A_phi)/(A_1 + A_phi))); + } + + + /** + * This function reads the coordinate and the porosity of the solitary wave + * from an input file. + * + * @param filename Name of the input file. + */ + void read_solitary_wave_solution (const std::string &filename, + const MPI_Comm comm) + { + std::string temp; + std::stringstream in(Utilities::read_and_distribute_file_content(filename, comm)); + + while (!in.eof()) + { + double x, f; + in >> x >> f; + if (in.eof()) + break; + getline(in, temp); + + coordinate.insert(coordinate.begin(),x); + porosity.insert(porosity.begin(),f); + } + } + + + /** + * This function gets the coordinate as an input parameters and gives + * back the porosity of the solitary wave. As this function is only defined + * implicitly, we have to interpolate from the coordinates where we have the + * porosity to our mesh. + * + * @param amplitude The amplitude of the solitary wave, which is always + * greater than 1. + * @param offset The offset of the center of the solitary wave from the + * boundary of the domain. + */ + void compute_porosity (const double amplitude, + const double background_porosity, + const double /*offset*/, + const double compaction_length, + const bool read_solution, + const std::string file_name, + const MPI_Comm comm) + { + // non-dimensionalize the amplitude + const double non_dim_amplitude = amplitude / background_porosity; + + if (read_solution) + read_solitary_wave_solution(file_name, comm); + else + { + porosity.resize(max_points); + coordinate.resize(max_points); + + // get the coordinates where we have the solution + for (unsigned int i=0; i offset + ? + position - offset + : + offset - position); + + if (x > coordinate[0]) + return porosity[0]; + + unsigned int j= coordinate.size()-2; + unsigned int i = j/2; + while (!(x < coordinate[j] && x >= coordinate[j+1])) + { + if (x < coordinate[j]) + j += i; + else + j -= i; + if (i>1) + i /= 2; + } + + const double distance = (x - coordinate[j+1]) + /(coordinate[j] - coordinate[j+1]); + return porosity[j+1] + distance * (porosity[j] - porosity[j+1]); + } + + /** + * The exact solution for the Solitary wave benchmark. + */ + template + class FunctionSolitaryWave : public Function + { + public: + FunctionSolitaryWave (const double offset, const double delta, const std::vector &initial_pressure, const double max_z, const unsigned int n_components) + : + Function(n_components), + offset_(offset), + delta_(delta), + initial_pressure_(initial_pressure), + max_z_(max_z) + {} + + void set_delta(const double delta) + { + delta_ = delta; + } + + void vector_value (const Point &p, + Vector &values) const override + { + unsigned int index = static_cast((p[dim-1]-delta_)/max_z_ * (initial_pressure_.size()-1)); + if (p[dim-1]-delta_ < 0) + index = 0; + else if (p[dim-1]-delta_ > max_z_) + index = initial_pressure_.size()-1; + AssertThrow(index < initial_pressure_.size(), ExcMessage("not in range")); + const double z_coordinate1 = static_cast(index)/static_cast(initial_pressure_.size()-1) * max_z_; + const double z_coordinate2 = static_cast(index+1)/static_cast(initial_pressure_.size()-1) * max_z_; + const double interpolated_pressure = (index == initial_pressure_.size()-1) + ? + initial_pressure_[index] + : + initial_pressure_[index] + (initial_pressure_[index+1] - initial_pressure_[index]) + * (p[dim-1]-delta_ - z_coordinate1) / (z_coordinate2 - z_coordinate1); + + values[dim+2+dim+2] = AnalyticSolutions::interpolate(p[dim-1]-delta_,offset_); //porosity + values[dim+1] = interpolated_pressure; //compaction pressure + } + + private: + const double offset_; + double delta_; + const std::vector initial_pressure_; + const double max_z_; + }; + } + + + /** + * An initial conditions model for the solitary waves benchmark. + */ + template + class SolitaryWaveInitialCondition : public InitialComposition::Interface, + public ::aspect::SimulatorAccess + { + public: + + /** + * Initialization function. Take references to the material model and + * get the compaction length, so that it can be used subsequently to + * compute the analytical solution for the shape of the solitary wave. + */ + void + initialize () override; + + /** + * Return the boundary velocity as a function of position. + */ + double + initial_composition (const Point &position, const unsigned int n_comp) const override; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + double + get_amplitude () const; + + double + get_background_porosity () const; + + double + get_offset () const; + + private: + double amplitude; + double background_porosity; + double offset; + double compaction_length; + bool read_solution; + std::string file_name; + }; + + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @ingroup MaterialModels + */ + template + class SolitaryWaveMaterial : public MaterialModel::MeltInterface, public ::aspect::SimulatorAccess + { + public: + bool is_compressible () const override + { + return false; + } + + double reference_darcy_coefficient () const override + { + // Make sure we keep track of the initial composition manager and + // that it continues to live beyond the time when the simulator + // class releases its pointer to it. + if (initial_composition_manager == nullptr) + const_cast>&>(initial_composition_manager) + = this->get_initial_composition_manager_pointer(); + + // Note that this number is based on the background porosity in the + // solitary wave initial condition. + const SolitaryWaveInitialCondition &initial_composition = + initial_composition_manager->template + get_matching_initial_composition_model>(); + + return reference_permeability * pow(initial_composition.get_background_porosity(), 3.0) / eta_f; + + } + + double length_scaling (const double porosity) const + { + return std::sqrt(reference_permeability * std::pow(porosity,3) * (xi_0 + 4.0/3.0 * eta_0) / eta_f); + } + + double velocity_scaling (const double porosity) const + { + const Point surface_point = this->get_geometry_model().representative_point(0.0); + return reference_permeability * std::pow(porosity,2) * (reference_rho_s - reference_rho_f) + * this->get_gravity_model().gravity_vector(surface_point).norm() / eta_f; + } + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + void evaluate(const typename MaterialModel::Interface::MaterialModelInputs &in, + typename MaterialModel::Interface::MaterialModelOutputs &out) const override + { + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + + for (unsigned int i=0; i *melt_out = out.template get_additional_output>(); + + if (melt_out != nullptr) + for (unsigned int i=0; icompaction_viscosities[i] = xi_0 * (1.0 - porosity); + melt_out->fluid_viscosities[i]= eta_f; + melt_out->permeabilities[i]= reference_permeability * std::pow(porosity,3); + melt_out->fluid_densities[i]= reference_rho_f; + melt_out->fluid_density_gradients[i] = 0.0; + } + + } + + private: + double reference_rho_s; + double reference_rho_f; + double eta_0; + double xi_0; + double eta_f; + double reference_permeability; + + /** + * A shared pointer to the initial composition object + * that ensures that the current object can continue + * to access the initial composition object beyond the + * first time step. + */ + std::shared_ptr> initial_composition_manager; + }; + + template + void + SolitaryWaveMaterial::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Solitary wave"); + { + prm.declare_entry ("Reference solid density", "3000", + Patterns::Double (0), + "Reference density of the solid $\\rho_{s,0}$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference melt density", "2500", + Patterns::Double (0), + "Reference density of the melt/fluid$\\rho_{f,0}$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference shear viscosity", "1e20", + Patterns::Double (0), + "The value of the constant viscosity $\\eta_0$ of the solid matrix. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Reference compaction viscosity", "1e20", + Patterns::Double (0), + "The value of the constant volumetric viscosity $\\xi_0$ of the solid matrix. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Reference melt viscosity", "100.0", + Patterns::Double (0), + "The value of the constant melt viscosity $\\eta_f$. " + "Units: \\si{\\pascal\\second}."); + + prm.declare_entry ("Reference permeability", "5e-9", + Patterns::Double(), + "Reference permeability of the solid host rock." + "Units: \\si{\\meter\\squared}."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + SolitaryWaveMaterial::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Solitary wave"); + { + reference_rho_s = prm.get_double ("Reference solid density"); + reference_rho_f = prm.get_double ("Reference melt density"); + eta_0 = prm.get_double ("Reference shear viscosity"); + xi_0 = prm.get_double ("Reference compaction viscosity"); + eta_f = prm.get_double ("Reference melt viscosity"); + reference_permeability = prm.get_double ("Reference permeability"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + double + SolitaryWaveInitialCondition::get_amplitude () const + { + return amplitude; + } + + template + double + SolitaryWaveInitialCondition::get_background_porosity () const + { + return background_porosity; + } + + template + double + SolitaryWaveInitialCondition::get_offset () const + { + return offset; + } + + template + void + SolitaryWaveInitialCondition::initialize () + { + std::cout << "Initialize solitary wave solution" + << std::endl; + + AssertThrow(Plugins::plugin_type_matches>(this->get_material_model()), + ExcMessage("Initial condition Solitary Wave only works with the material model Solitary wave.")); + + const SolitaryWaveMaterial & + material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + compaction_length = material_model.length_scaling(background_porosity); + + AnalyticSolutions::compute_porosity(amplitude, + background_porosity, + offset, + compaction_length, + read_solution, + file_name, + this->get_mpi_communicator()); + } + + + template + double + SolitaryWaveInitialCondition:: + initial_composition (const Point &position, const unsigned int /*n_comp*/) const + { + return AnalyticSolutions::interpolate(position[dim-1], + offset); + } + + + template + void + SolitaryWaveInitialCondition::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + prm.enter_subsection("Solitary wave initial condition"); + { + prm.declare_entry ("Amplitude", "0.01", + Patterns::Double (0), + "Amplitude of the solitary wave. Units: none."); + prm.declare_entry ("Background porosity", "0.001", + Patterns::Double (0), + "Background porosity of the solitary wave. Units: none."); + prm.declare_entry ("Offset", "150", + Patterns::Double (0), + "Offset of the center of the solitary wave from the boundary" + "of the domain. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Read solution from file", "false", + Patterns::Bool (), + "Whether to read the porosity initial condition from " + "a file or to compute it."); + prm.declare_entry ("File name", "solitary_wave.txt", + Patterns::Anything (), + "The file name of the porosity initial condition data. "); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + SolitaryWaveInitialCondition::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + prm.enter_subsection("Solitary wave initial condition"); + { + amplitude = prm.get_double ("Amplitude"); + background_porosity = prm.get_double ("Background porosity"); + offset = prm.get_double ("Offset"); + read_solution = prm.get_bool ("Read solution from file"); + file_name = prm.get ("File name"); + + AssertThrow(amplitude > background_porosity, + ExcMessage("Amplitude of the solitary wave must be larger " + "than the background porosity.")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + /** + * A postprocessor that evaluates the accuracy of the solution. + * + * The implementation of error evaluators that correspond to the + * benchmarks defined in the paper Keller et al. reference above. + */ + template + class SolitaryWavePostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Initialization function. Take references to the material model and + * initial conditions model to get the parameters necessary for computing + * the analytical solution for the shape of the solitary wave and store them. + */ + void + initialize () override; + + void + store_initial_pressure (); + + double + compute_phase_shift (); + + private: + double amplitude; + double background_porosity; + double offset; + double compaction_length; + double velocity_scaling; + double boundary_velocity; + unsigned int max_points; + std::vector initial_pressure; + double maximum_pressure; + std::shared_ptr> ref_func; + + }; + + template + void + SolitaryWavePostprocessor::initialize () + { + // verify that we are using the "Solitary wave" initial conditions and material model, + // then get the parameters we need + + const SolitaryWaveInitialCondition &initial_composition + = this->get_initial_composition_manager().template get_matching_initial_composition_model> (); + + amplitude = initial_composition.get_amplitude(); + background_porosity = initial_composition.get_background_porosity(); + offset = initial_composition.get_offset(); + + AssertThrow(Plugins::plugin_type_matches>(this->get_material_model()), + ExcMessage("Postprocessor Solitary Wave only works with the material model Solitary wave.")); + + const SolitaryWaveMaterial &material_model + = Plugins::get_plugin_as_type>(this->get_material_model()); + + compaction_length = material_model.length_scaling(background_porosity); + velocity_scaling = material_model.velocity_scaling(background_porosity); + + + // we also need the boundary velocity, but we can not get it from simulator access + // TODO: write solitary wave boundary condition where the phase speed is calculated! + + max_points = 1e6; + initial_pressure.resize(max_points); + maximum_pressure = 0.0; + } + + template + void + SolitaryWavePostprocessor::store_initial_pressure () + { + const QGauss quadrature_formula (this->get_fe().base_element(this->introspection().base_elements.pressure).degree); + const unsigned int n_q_points = quadrature_formula.size(); + const double max_depth = this->get_geometry_model().maximal_depth(); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_quadrature_points | + update_JxW_values); + + // do the same stuff we do in depth average + std::vector volume(max_points,0.0); + std::vector pressure(max_points,0.0); + std::vector p_c(n_q_points); + double local_max_pressure = 0.0; + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + fe_values[this->introspection().variable("compaction pressure").extractor_scalar()] + .get_function_values (this->get_solution(), + p_c); + + for (unsigned int q=0; q((z*(max_points-1))/max_depth); + AssertThrow(idx < max_points, ExcInternalError()); + + pressure[idx] += p_c[q] * fe_values.JxW(q); + volume[idx] += fe_values.JxW(q); + + local_max_pressure = std::max (local_max_pressure, std::abs(p_c[q])); + } + } + + std::vector volume_all(max_points, 0.0); + Utilities::MPI::sum(volume, this->get_mpi_communicator(), volume_all); + Utilities::MPI::sum(pressure, this->get_mpi_communicator(), initial_pressure); + maximum_pressure = Utilities::MPI::max (local_max_pressure, this->get_mpi_communicator()); + + for (unsigned int i=0; i(volume_all[i])+1e-20); + } + + // fill the first and last element of the initial_pressure vector if they are empty + // this makes sure they can be used for the interpolation later on + if (initial_pressure[0] == 0.0) + { + unsigned int j = 1; + while (initial_pressure[j] == 0.0) + j++; + initial_pressure[0] = initial_pressure[j]; + } + + if (initial_pressure[max_points-1] == 0.0) + { + unsigned int k = max_points-2; + while (initial_pressure[k] == 0.0) + k--; + initial_pressure[max_points-1] = initial_pressure[k]; + } + + // interpolate between the non-zero elements to fill the elements that are 0 + for (unsigned int i=1; i 0, ExcInternalError()); + k--; + } + + unsigned int j = i+1; + while (initial_pressure[j] == 0.0) + j++; + Assert(j < max_points, ExcInternalError()); + initial_pressure[i] = initial_pressure[k] + (initial_pressure[j]-initial_pressure[k]) * static_cast(i-k)/static_cast(j-k); + } + } + } + + template + double + SolitaryWavePostprocessor::compute_phase_shift () + { + AssertThrow(this->introspection().compositional_name_exists("porosity"), + ExcMessage("Postprocessor Solitary Wave only works if there is a compositional field called porosity.")); + const unsigned int porosity_index = this->introspection().compositional_index_for_name("porosity"); + const typename Simulator::AdvectionField porosity = Simulator::AdvectionField::composition(porosity_index); + + // create a quadrature formula based on the compositional element alone. + AssertThrow (this->introspection().n_compositional_fields > 0, + ExcMessage("This postprocessor cannot be used without compositional fields.")); + + const QGauss quadrature_formula (this->get_fe().base_element(porosity.base_element(this->introspection())).degree+1); + const unsigned int n_q_points = quadrature_formula.size(); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_quadrature_points | + update_JxW_values); + + std::vector compositional_values(n_q_points); + + // The idea here is to first find the maximum, and then use the analytical solution of the + // solitary wave to calculate a phase shift for every point. + // This has to be done separately for points left and right of the maximum, as the analytical + // solution is only defined for coordinates > 0. + // In the end, these values for the phase shift are averaged. + + // compute the maximum composition by quadrature (because we also need the coordinate) + double z_max_porosity = std::numeric_limits::quiet_NaN(); + { + double local_max_porosity = -std::numeric_limits::max(); + double local_max_z_location = std::numeric_limits::quiet_NaN(); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + fe_values[this->introspection().extractors.compositional_fields[porosity_index]].get_function_values (this->get_solution(), + compositional_values); + for (unsigned int q=0; q local_max_porosity) + { + local_max_porosity = composition; + local_max_z_location = fe_values.quadrature_point(q)[dim-1]; + } + } + } + + double max_porosity = 0.0; + MPI_max_and_data(local_max_porosity, local_max_z_location, max_porosity, z_max_porosity); + } + + + // iterate over all points and calculate the phase shift + double phase_shift_integral = 0.0; + unsigned int number_of_points = 0; + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + fe_values[this->introspection().extractors.compositional_fields[porosity_index]].get_function_values (this->get_solution(), + compositional_values); + + for (unsigned int q=0; q background_porosity + (amplitude - background_porosity)*0.05 && composition <= amplitude*0.9) + { + double z_analytical = compaction_length + * AnalyticSolutions::solitary_wave_solution(composition/background_porosity, + amplitude/background_porosity); + double z = fe_values.quadrature_point(q)[dim-1]; + + if (z > z_max_porosity) + { + z -= offset; + phase_shift_integral += (z - z_analytical); + } + else + { + z = offset - z; + phase_shift_integral -= (z - z_analytical); + } + + number_of_points += 1; + } + } + } + + double integral = Utilities::MPI::sum (phase_shift_integral, this->get_mpi_communicator()) + / Utilities::MPI::sum (static_cast(number_of_points), this->get_mpi_communicator()); + + // TODO: different case for moving wave (with zero boundary velocity) + // const double phase_speed = velocity_scaling * (2.0 * amplitude / background_porosity + 1); + return integral; // + phase_speed * this->get_time(); + } + + template + std::pair + SolitaryWavePostprocessor::execute (TableHandler & /*statistics*/) + { + // as we do not have an analytical solution for the pressure, we store the initial solution + if (this->get_timestep_number()==0) + { + store_initial_pressure(); + ref_func = std::make_unique>(offset,0.0,initial_pressure, + this->get_geometry_model().maximal_depth(), this->introspection().n_components); + } + + double delta=0; + + delta = compute_phase_shift(); + // reset the phase shift of the analytical solution so we can compare the shape of the wave + ref_func->set_delta(delta); + + // what we want to compare: + // (1) error of the numerical phase speed c: + // c_numerical = c_analytical - Delta / time; + const double c_analytical = velocity_scaling * (2.0 * amplitude / background_porosity + 1); + const double c_numerical = c_analytical + (this->get_time() > 0 ? delta / this->get_time() : 0.0); + const double error_c = std::abs (c_numerical / c_analytical - 1); + + // (3) preservation of shape of melt fraction + // (4) preservation of the shape of compaction pressure + + Vector cellwise_errors_f (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_p (this->get_triangulation().n_active_cells()); + + // get correct components for porosity and compaction pressure + const unsigned int n_total_comp = this->introspection().n_components; + ComponentSelectFunction comp_f(dim+2+dim+2, n_total_comp); + ComponentSelectFunction comp_p(dim+1, n_total_comp); + + const QGauss quadrature_formula (this->get_fe().base_element(this->introspection().base_elements.pressure).degree+1); + + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_f, + quadrature_formula, + VectorTools::L2_norm, + &comp_f); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_p, + quadrature_formula, + VectorTools::L2_norm, + &comp_p); + + const double e_f = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_f, VectorTools::L2_norm); + const double e_p = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_p, VectorTools::L2_norm); + + std::ostringstream os; + os << std::scientific << e_f / amplitude + << ", " << e_p / maximum_pressure + << ", " << error_c + << ", " << std::abs(delta); + + + return std::make_pair("Errors e_f, e_p_c_bar, e_c, delta:", os.str()); + } + + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace SolitaryWaveBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(SolitaryWaveMaterial, + "Solitary Wave", + "A material model that corresponds to the 'SolitaryWave' benchmark " + "defined in Keller et al., JGI, 2013.") + + ASPECT_REGISTER_POSTPROCESSOR(SolitaryWavePostprocessor, + "solitary wave statistics", + "A postprocessor that compares the solution of the benchmarks from " + "the Keller et al., JGI, 2013, paper with the one computed by ASPECT " + "and reports the error.") + + ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(SolitaryWaveInitialCondition, + "Solitary wave initial condition", + "Composition is set to a solitary wave function.") + } +} diff --git a/benchmarks/solitary_wave/solitary_wave.prm.bak b/benchmarks/solitary_wave/solitary_wave.prm.bak new file mode 100644 index 00000000000..6d3059ca04f --- /dev/null +++ b/benchmarks/solitary_wave/solitary_wave.prm.bak @@ -0,0 +1,170 @@ +# Listing of Parameters +# --------------------- +# Set up the solitary wave benchmark +# (Barcilon & Richter, 1986; Simpson & Spiegelman, 2011; +# Keller et al., 2013; Schmeling, 200 + +set Additional shared libraries = ./libsolitary_wave.so +set Adiabatic surface temperature = 1623 +set CFL number = 1.0 +set Nonlinear solver scheme = iterated Advection and Stokes +set Output directory = output +set Max nonlinear iterations = 10 +set Nonlinear solver tolerance = 1e-5 + +# The number of space dimensions you want to run this program in. +set Dimension = 2 + +# The end time of the simulation. Units: years if the 'Use years in output +# instead of seconds' parameter is set; seconds otherwise. +# This end time is chosen in such a way that the solitary wave travels +# approximately 5 times its wavelength during the model time. +set End time = 6e6 +set Pressure normalization = surface +set Surface pressure = 0 +set Resume computation = false +set Start time = 0 +set Use years in output instead of seconds = true + +subsection Discretization + subsection Stabilization parameters + set beta = 0.001 + end +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = porosity +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = initial temperature + + subsection Initial temperature + # Temperature at the inner boundary (core mantle boundary). Units: K. + set Maximal temperature = 3773 + + # Temperature at the outer boundary (lithosphere water/air). Units: K. + set Minimal temperature = 273 + end +end + +subsection Boundary composition model + set Fixed composition boundary indicators = top, bottom + set List of model names = initial composition +end + +# we apply the phase speed of the wave here, so that it always stays in the same place in our model +# the phase speed is c = 5.25e-11 m/s, but we have to convert it to m/years using the same conversion +# that is used internally in ASPECT: year_in_seconds = 60*60*24*365.2425 +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right + set Prescribed velocity boundary indicators = top:function, bottom:function + + subsection Function + # set Function expression = 0;-8.2836999e-5 + set Function expression = 0;-1.65673998e-4 + + # set Function expression = 0;-3.31347996e-4 + # set Function expression = 0;-6.62695992e-4 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 10 + set Y extent = 400 + set Y repetitions = 40 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + # Magnitude of the gravity vector in $m/s^2$. The direction is always + # radially outward from the center of the earth. + set Magnitude = 10.0 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +subsection Initial composition model + set Model name = Solitary wave initial condition + + subsection Solitary wave initial condition + set Offset = 200 + set Read solution from file = true + set Amplitude = 0.01 + set Background porosity = 0.001 + end +end + +subsection Material model + set Model name = Solitary Wave + + subsection Solitary wave + set Reference permeability = 5e-9 + end +end + +subsection Mesh refinement + set Coarsening fraction = 0.0 + set Refinement fraction = 0.0 + set Initial adaptive refinement = 0 + set Initial global refinement = 4 + set Strategy = composition + set Time steps between mesh refinement = 0 +end + +subsection Melt settings + set Include melt transport = true +end + +subsection Postprocess + set List of postprocessors = visualization,composition statistics,velocity statistics,solitary wave statistics + + subsection Visualization + set List of output variables = density, viscosity, thermal expansivity, melt material properties + + # VTU file output supports grouping files from several CPUs into one file + # using MPI I/O when writing on a parallel filesystem. Select 0 for no + # grouping. This will disable parallel file output and instead write one + # file per processor in a background thread. A value of 1 will generate + # one big file containing the whole solution. + set Number of grouped files = 0 + + # The file format to be used for graphical output. + set Output format = vtu + + # The time interval between each generation of graphical output files. A + # value of zero indicates that output should be generated in each time + # step. Units: years if the 'Use years in output instead of seconds' + # parameter is set; seconds otherwise. + set Time between graphical output = 5e5 + + subsection Melt material properties + set List of properties = fluid density, permeability, fluid viscosity, compaction viscosity + end + end +end + +subsection Solver parameters + set Composition solver tolerance = 1e-14 + set Temperature solver tolerance = 1e-14 + + subsection Stokes solver parameters + set Linear solver tolerance = 1e-10 + set Number of cheap Stokes solver steps = 0 + end +end diff --git a/benchmarks/solkz/compositional_fields/solkz_compositional_fields.cc.bak b/benchmarks/solkz/compositional_fields/solkz_compositional_fields.cc.bak new file mode 100644 index 00000000000..b9fab75725b --- /dev/null +++ b/benchmarks/solkz/compositional_fields/solkz_compositional_fields.cc.bak @@ -0,0 +1,45 @@ +/* + Copyright (C) 2011 - 2018 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include "solkz_compositional_fields.h" + + + +// explicit instantiations +namespace aspect +{ + namespace InclusionBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(SolKzCompositionalMaterial, + "SolKzCompositionalMaterial", + "A material model that corresponds to the 'SolKz' benchmark " + "defined in Duretz et al., G-Cubed, 2011. using " + "compositional fields. ") + + + ASPECT_REGISTER_POSTPROCESSOR(SolKzPostprocessor, + "SolKzPostprocessor", + "A postprocessor that compares the solution of the benchmarks from " + "the Duretz et al., G-Cubed, 2011, paper with the one computed by ASPECT " + "and reports the error. Specifically, it can compute the errors for " + "the SolCx, SolKz and inclusion benchmarks. The postprocessor inquires " + "which material model is currently being used and adjusts " + "which exact solution to use accordingly.") + } +} diff --git a/benchmarks/solkz/compositional_fields/solkz_compositional_fields.h.bak b/benchmarks/solkz/compositional_fields/solkz_compositional_fields.h.bak new file mode 100644 index 00000000000..8e2e4e7232e --- /dev/null +++ b/benchmarks/solkz/compositional_fields/solkz_compositional_fields.h.bak @@ -0,0 +1,33 @@ +#ifndef ASPECT_SOLKZ_COMPOSITIONAL_FIELDS_H +#define ASPECT_SOLKZ_COMPOSITIONAL_FIELDS_H + + +#include "../solkz.h" + + + +namespace aspect +{ + namespace InclusionBenchmark + { + using namespace dealii; + + template + class SolKzCompositionalMaterial : public SolKzMaterial + { + public: + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + SolKzMaterial::evaluate(in, out); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + out.densities[i] = in.composition[i][0]; + out.viscosities[i] = in.composition[i][1]; + } + } + }; + } +} +#endif diff --git a/benchmarks/solkz/compositional_fields/solkz_compositional_fields.prm.bak b/benchmarks/solkz/compositional_fields/solkz_compositional_fields.prm.bak new file mode 100644 index 00000000000..67f3ebe888c --- /dev/null +++ b/benchmarks/solkz/compositional_fields/solkz_compositional_fields.prm.bak @@ -0,0 +1,93 @@ +# A description of the SolKZ benchmark using compositional fields +# for which a known solution is available. See the manual for +# more information. + +set Additional shared libraries = ./libsolkz_compositional_fields.so + +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output +set Pressure normalization = volume +set Nonlinear solver scheme = no Advection, iterated Stokes + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Material model + set Model name = SolKzCompositionalMaterial +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = perturbed box +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = false + + # Whether to use a composition discretization that is discontinuous as + # opposed to continuous. This then requires the assembly of face terms + # between cells, and weak imposition of boundary terms for the composition + # field via the discontinuous Galerkin method. + + set Use discontinuous composition discretization = true +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 +end + +############### Parameters describing the compositional field + +subsection Compositional fields + set Number of fields = 2 + set Names of fields = density_comp, viscosity_comp + set Compositional field methods = field, field +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = pi = 3.1415926536 + set Function expression = -1 * sin(2*z) * cos(3*pi*x); exp(log(1e6)*z) + end +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, SolKzPostprocessor + + subsection Visualization + set Output format = vtu + set Number of grouped files = 1 + set Time between graphical output = 0 + set List of output variables = density, viscosity + end +end diff --git a/benchmarks/solkz/compositional_fields/solkz_particles.prm.bak b/benchmarks/solkz/compositional_fields/solkz_particles.prm.bak new file mode 100644 index 00000000000..44f32cc289b --- /dev/null +++ b/benchmarks/solkz/compositional_fields/solkz_particles.prm.bak @@ -0,0 +1,117 @@ +# A description of the SolKZ benchmark using active particles +# to interpolate both density and viscosity onto the compositional +# fields for which a known solution is available. See the manual +# for more information. + +set Additional shared libraries = ./libsolkz_compositional_fields.so + +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output +set Pressure normalization = volume + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Material model + set Model name = SolKzCompositionalMaterial +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = perturbed box +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = false + set Use discontinuous composition discretization = true +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 +end + +############### Parameters describing the compositional field +# Note: The compositional field is what drives the flow +# in this example + +subsection Compositional fields + set Number of fields = 2 + set Names of fields = density_comp, viscosity_comp + set Compositional field methods = particles, particles + set Mapped particle properties = density_comp:function[0], viscosity_comp:function[1] +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = pi=3.1415926, eta_b=1e6 + set Function expression = -1 * sin(2*z) * cos(3*pi*x); exp(log(eta_b)*z) + end +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = particles, visualization, SolKzPostprocessor + + subsection Visualization + set Output format = vtu + set Number of grouped files = 1 + set Time between graphical output = 0 + set List of output variables = density, viscosity + end + + subsection Particles + set Time between data output = 0 + set Data output format = vtu + end +end + +subsection Particles + set List of particle properties = function + set Integration scheme = rk2 + set Interpolation scheme = cell average + set Maximum particles per cell = 16384 + set Update ghost particles = true + set Particle generator name = reference cell + + subsection Function + set Number of components = 2 + set Variable names = x, z + set Function constants = pi=3.1415926, eta_b=1e6 + set Function expression = -1 * sin(2*z) * cos(3*pi*x); exp(log(eta_b)*z) + end + + subsection Generator + subsection Reference cell + set Number of particles per cell per direction = 4 + end + end +end diff --git a/benchmarks/solkz/doc/solkz.prm.bak b/benchmarks/solkz/doc/solkz.prm.bak new file mode 100644 index 00000000000..99e6a93d934 --- /dev/null +++ b/benchmarks/solkz/doc/solkz.prm.bak @@ -0,0 +1,60 @@ +# A description of the SolKZ benchmark for which a known solution +# is available. See the manual for more information. + +set Additional shared libraries = ./libsolkz.so + +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output +set Pressure normalization = volume + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Material model + set Model name = SolKzMaterial +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + + +subsection Initial temperature model + set Model name = perturbed box +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = false +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 4 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = SolKzPostprocessor, visualization +end diff --git a/benchmarks/solkz/solkz.cc.bak b/benchmarks/solkz/solkz.cc.bak new file mode 100644 index 00000000000..cc972af1460 --- /dev/null +++ b/benchmarks/solkz/solkz.cc.bak @@ -0,0 +1,44 @@ +/* + Copyright (C) 2011 - 2018 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include "solkz.h" + + + +// explicit instantiations +namespace aspect +{ + namespace InclusionBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(SolKzMaterial, + "SolKzMaterial", + "A material model that corresponds to the 'SolKz' benchmark " + "defined in Duretz et al., G-Cubed, 2011.") + + + ASPECT_REGISTER_POSTPROCESSOR(SolKzPostprocessor, + "SolKzPostprocessor", + "A postprocessor that compares the solution of the benchmarks from " + "the Duretz et al., G-Cubed, 2011, paper with the one computed by ASPECT " + "and reports the error. Specifically, it can compute the errors for " + "the SolCx, SolKz and inclusion benchmarks. The postprocessor inquires " + "which material model is currently being used and adjusts " + "which exact solution to use accordingly.") + } +} diff --git a/benchmarks/solkz/solkz.h.bak b/benchmarks/solkz/solkz.h.bak new file mode 100644 index 00000000000..50d8e0765e2 --- /dev/null +++ b/benchmarks/solkz/solkz.h.bak @@ -0,0 +1,799 @@ +#ifndef ASPECT_SOLKZ_H +#define ASPECT_SOLKZ_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + + +namespace aspect +{ + /** + * This is the "Sol Kz" benchmark defined in the following paper: + * @code + * @Article{DMGT11, + * author = {T. Duretz and D. A. May and T. V. Gerya and P. J. Tackley}, + * title = {Discretization errors and free surface stabilization in the + * finite difference and marker-in-cell method for applied + * geodynamics: {A} numerical study}, + * journal = {Geochemistry Geophysics Geosystems}, + * year = 2011, + * volume = 12, + * pages = {Q07004/1--26}} + * @endcode + * + * The results are published in Kronbichler, Heister and Bangerth paper. + */ + namespace InclusionBenchmark + { + using namespace dealii; + + namespace AnalyticSolutions + { + // based on http://geodynamics.org/hg/cs/AMR/Discontinuous_Stokes with permission + // The following code has been taken from http://www.underworldproject.org/, + // release 1.7.0. As mentioned in the Underworld Manual, this code has been + // released under the GNU General Public License (GPL). + + void _Velic_solKz( + double pos[], + double _sigma, /* density */ + double _km, int _n, /* wavelength in z, wavenumber in x */ + double _B, /* viscosity parameter */ + double vel[], double *presssure, + double total_stress[], double strain_rate[]) + { + double Z; + double u1, u2, u3, u4, u5, u6, SS; + double sum1, sum2, sum3, sum4, sum5, sum6, sum7, x, z; + double sigma; + int n; + double kn; + double _C1, _C2, _C3, _C4; + double B, Rp, UU, VV; + double rho, a, b, r, _aa, _bb, AA, BB, Rm, km; + + + double t1, t2, t3, t4, t5, t6, t7, t8, t9, t10; + double t11, t12, t13, t14, t15, t16, t17, t18, t19, t20; + double t21, t22, t23, t24, t25, t26, t27, t28, t29, t31; + double t33, t34, t35, t37, t38, t40, t41, t42, t43, t45; + double t47, t51, t52, t53, t54, t55, t56, t57, t58, t59; + double t60, t61, t62, t64, t65, t66, t67, t68, t69, t70; + double t71, t72, t73, t74, t75, t76, t77, t78, t79, t80; + double t81, t82, t83, t84, t85, t86, t89, t90, t92, t94; + double t96, t97, t98, t99, t100, t101, t103, t104, t105, t106; + double t107, t108, t109, t110, t111, t112, t113, t114, t115, t116; + double t117, t118, t119, t120, t121, t122, t123, t124, t125, t126; + double t127, t130, t131, t132, t134, t135, t141, t144, t147, t148; + double t150, t151, t152, t161, t171; + + + + /*************************************************************************/ + /*************************************************************************/ + /* rho = -sigma*sin(km*z)*cos(kn*x) */ + /* viscosity Z= exp(2*B*z) */ + B = _B; /* viscosity parameter must be non-zero*/ + km = _km; /* solution valid for km not zero -- should get trivial solution if km=0 */ + n = _n; /* solution valid for n not zero */ + sigma = _sigma; + /*************************************************************************/ + /*************************************************************************/ + kn = (double) _n * M_PI; + a = B * B + kn * kn; + b = 2.0 * kn * B; + r = sqrt(a * a + b * b); + Rp = sqrt((r + a) / 2.0); + Rm = sqrt((r - a) / 2.0); + UU = Rp - B; + VV = Rp + B; + + + x = pos[0]; + z = pos[1]; + + sum1 = 0.0; + sum2 = 0.0; + sum3 = 0.0; + sum4 = 0.0; + sum5 = 0.0; + sum6 = 0.0; + sum7 = 0.0; + + + + + /*******************************************/ + /* calculate the constants */ + /*******************************************/ + + t3 = kn * kn; + t4 = km * km; + t6 = B * B; + t8 = 0.4e1 * t3 * t6; + t10 = 0.4e1 * t4 * t6; + t13 = 0.8e1 * kn * t6 * km; + t14 = t4 * t4; + t16 = 0.2e1 * t3 * t4; + t17 = t3 * t3; + _aa = -0.4e1 * B * km * kn * (t3 + t4) / (t8 + t10 + t13 + t14 + t16 + t17) / + (-t13 + t8 + t10 + t14 + t16 + t17); + + t1 = kn * kn; + t2 = t1 * t1; + t3 = B * B; + t5 = 0.4e1 * t1 * t3; + t6 = km * km; + t7 = t6 * t6; + t9 = 0.2e1 * t1 * t6; + t11 = 0.4e1 * t3 * t6; + t16 = 0.8e1 * kn * t3 * km; + _bb = kn * (t2 + t5 + t7 + t9 - t11) / (t5 + t11 + t16 + t7 + t9 + t2) / + (-t16 + t5 + t11 + t7 + t9 + t2); + + AA = _aa; + BB = _bb; + + t1 = B * B; + t2 = t1 * Rp; + t4 = Rm * Rm; + t5 = t4 * Rp; + t7 = t4 * B; + t8 = km * km; + t12 = Rp * Rp; + t13 = B * t12; + t21 = 0.8e1 * t1 * km * BB * Rp; + t23 = 0.2e1 * Rm; + t24 = cos(t23); + t26 = Rm * Rp; + t38 = sin(t23); + t51 = exp(-0.2e1 * Rp); + t53 = B + Rp; + t54 = Rm * t53; + t55 = Rm * B; + t57 = 0.2e1 * B * km; + t58 = t55 + t57 - t26; + t62 = 0.3e1 * t1; + t64 = 0.2e1 * Rp * B; + t65 = t62 + t64 + t4 - t8 - t12; + t67 = t54 * t65 * BB; + t69 = Rm - km; + t70 = cos(t69); + t72 = -t57 + t55 - t26; + t77 = Rm + km; + t78 = cos(t77); + t81 = t54 * t65 * AA; + t86 = sin(t77); + t92 = sin(t69); + t96 = exp(-t53); + t98 = B - Rp; + t99 = Rm * t98; + t100 = t55 + t57 + t26; + t104 = t62 - t64 + t4 - t8 - t12; + t106 = t99 * t104 * BB; + t109 = -t57 + t55 + t26; + t116 = t99 * t104 * AA; + t130 = exp(-0.3e1 * Rp - B); + t135 = exp(-0.4e1 * Rp); + t144 = t4 * t1; + t150 = t4 * t12; + _C1 = (((0.2e1 * Rp * (0.2e1 * t2 + 0.2e1 * t5 + t7 + B * t8 - 0.3e1 * t1 * B + t13) * AA + t21) * t24 + + (-0.2e1 * t26 * (t4 - t8 - t12 + 0.5e1 * t1) * AA + 0.8e1 * B * BB * km * Rm * Rp) * t38 - + 0.2e1 * B * (0.2e1 * t13 + t12 * Rp - 0.3e1 * t2 + t5 + 0.2e1 * t7 + t8 * Rp) * AA - t21) * + t51 + ((0.2e1 * t54 * t58 * AA + t67) * t70 + (0.2e1 * t54 * t72 * AA - t67) * t78 + + (t81 + 0.2e1 * t54 * t72 * BB) * t86 + (t81 - 0.2e1 * t54 * t58 * BB) * t92) * t96 + + ((-0.2e1 * t99 * t100 * AA - t106) * t70 + (-0.2e1 * t99 * t109 * AA + t106) * t78 + + (-t116 - 0.2e1 * t99 * t109 * BB) * t86 + (-t116 + 0.2e1 * t99 * t100 * BB) * t92) * t130 + + 0.4e1 * t4 * t98 * t53 * AA * t135) / + (((-0.8e1 * t4 - 0.8e1 * t1) * t12 * t24 + 0.8e1 * t144 + 0.8e1 * t12 * t1) * t51 + + (0.4e1 * t150 - 0.4e1 * t144) * t135 + 0.4e1 * t150 - 0.4e1 * t144); + + t1 = Rm * Rp; + t2 = Rm * Rm; + t3 = km * km; + t4 = Rp * Rp; + t5 = B * B; + t12 = km * Rm; + t17 = 0.2e1 * Rm; + t18 = cos(t17); + t22 = t2 * Rp; + t25 = B * t3; + t26 = t5 * B; + t33 = t5 * km; + t38 = sin(t17); + t40 = Rm * B; + t41 = 0.3e1 * t5; + t51 = exp(-0.2e1 * Rp); + t53 = B + Rp; + t54 = Rm * t53; + t57 = t41 + 0.2e1 * Rp * B + t2 - t3 - t4; + t59 = t54 * t57 * AA; + t60 = B * km; + t61 = 0.2e1 * t60; + t62 = t40 + t61 - t1; + t67 = Rm - km; + t68 = cos(t67); + t70 = -t61 + t40 - t1; + t75 = Rm + km; + t76 = cos(t75); + t82 = t54 * t57 * BB; + t84 = sin(t75); + t90 = sin(t67); + t94 = exp(-t53); + t97 = 0.3e1 * Rm * t26; + t98 = t2 * Rm; + t99 = t98 * B; + t100 = t3 * Rm; + t101 = t100 * Rp; + t103 = Rm * t4 * B; + t104 = t4 * Rp; + t105 = Rm * t104; + t107 = 0.8e1 * t33 * Rp; + t109 = 0.5e1 * t1 * t5; + t110 = t98 * Rp; + t111 = t100 * B; + t112 = t97 + t99 - t101 + t103 - t105 + t107 + t109 + t110 - t111; + t114 = t2 * t4; + t116 = 0.2e1 * t60 * t1; + t117 = t2 * t5; + t119 = 0.3e1 * t26 * Rp; + t120 = t104 * B; + t121 = t4 * t5; + t122 = 0.2e1 * t121; + t123 = t22 * B; + t125 = 0.2e1 * t33 * Rm; + t126 = t25 * Rp; + t127 = t114 + t116 + t117 - t119 + t120 + t122 + t123 + t125 + t126; + t132 = -t107 + t103 - t105 - t101 + t97 - t111 + t110 + t109 + t99; + t134 = t120 - t125 + t123 - t116 + t122 + t117 + t114 + t126 - t119; + t152 = exp(-0.3e1 * Rp - B); + t161 = exp(-0.4e1 * Rp); + _C2 = (((0.2e1 * t1 * (t2 - t3 - t4 + 0.5e1 * t5) * AA - 0.8e1 * B * BB * t12 * Rp) * t18 + + (0.2e1 * Rp * (0.2e1 * t5 * Rp + 0.2e1 * t22 + t2 * B + t25 - 0.3e1 * t26 + B * t4) * AA + + 0.8e1 * t33 * BB * Rp) * t38 + 0.2e1 * t40 * (t41 + t4 + t2 - t3) * AA - + 0.8e1 * t5 * BB * t12) * t51 + + ((-t59 + 0.2e1 * t54 * t62 * BB) * t68 + (-t59 - 0.2e1 * t54 * t70 * BB) * t76 + + (0.2e1 * t54 * t70 * AA - t82) * t84 + (0.2e1 * t54 * t62 * AA + t82) * t90) * t94 + + ((t112 * AA - 0.2e1 * t127 * BB) * t68 + (t132 * AA + 0.2e1 * t134 * BB) * t76 + + (-0.2e1 * t134 * AA + t132 * BB) * t84 + (-0.2e1 * t127 * AA - t112 * BB) * t90) * t152 + + (-0.2e1 * t59 + 0.8e1 * t40 * km * t53 * BB) * t161) / + (((-0.8e1 * t2 - 0.8e1 * t5) * t4 * t18 + 0.8e1 * t117 + 0.8e1 * t121) * t51 + + (0.4e1 * t114 - 0.4e1 * t117) * t161 + 0.4e1 * t114 - 0.4e1 * t117); + + t1 = B * B; + t2 = t1 * Rp; + t4 = Rm * Rm; + t5 = t4 * Rp; + t7 = Rp * Rp; + t8 = B * t7; + t11 = km * km; + t13 = t4 * B; + t21 = 0.8e1 * t1 * km * BB * Rp; + t23 = 0.2e1 * Rm; + t24 = cos(t23); + t26 = Rm * Rp; + t38 = sin(t23); + t51 = exp(-0.2e1 * Rp); + t53 = B + Rp; + t54 = Rm * t53; + t55 = Rm * B; + t57 = 0.2e1 * B * km; + t58 = t55 + t57 - t26; + t62 = 0.3e1 * t1; + t64 = 0.2e1 * Rp * B; + t65 = t62 + t64 + t4 - t11 - t7; + t67 = t54 * t65 * BB; + t69 = Rm - km; + t70 = cos(t69); + t72 = -t57 + t55 - t26; + t77 = Rm + km; + t78 = cos(t77); + t81 = t54 * t65 * AA; + t86 = sin(t77); + t92 = sin(t69); + t96 = exp(-t53); + t98 = B - Rp; + t99 = Rm * t98; + t100 = t55 + t57 + t26; + t104 = t62 - t64 + t4 - t11 - t7; + t106 = t99 * t104 * BB; + t109 = -t57 + t55 + t26; + t116 = t99 * t104 * AA; + t130 = exp(-0.3e1 * Rp - B); + t141 = t4 * t1; + t147 = t4 * t7; + t151 = exp(-0.4e1 * Rp); + _C3 = (((-0.2e1 * Rp * (-0.2e1 * t2 - 0.2e1 * t5 + t8 - 0.3e1 * t1 * B + B * t11 + t13) * AA - t21) * + t24 + (0.2e1 * t26 * (t4 - t11 - t7 + 0.5e1 * t1) * AA - 0.8e1 * B * BB * km * Rm * Rp) * t38 - + 0.2e1 * B * (0.2e1 * t8 + 0.2e1 * t13 + 0.3e1 * t2 - t7 * Rp - t5 - t11 * Rp) * AA + t21) * + t51 + ((-0.2e1 * t54 * t58 * AA - t67) * t70 + (-0.2e1 * t54 * t72 * AA + t67) * t78 + + (-t81 - 0.2e1 * t54 * t72 * BB) * t86 + (-t81 + 0.2e1 * t54 * t58 * BB) * t92) * t96 + + ((0.2e1 * t99 * t100 * AA + t106) * t70 + (0.2e1 * t99 * t109 * AA - t106) * t78 + + (t116 + 0.2e1 * t99 * t109 * BB) * t86 + (t116 - 0.2e1 * t99 * t100 * BB) * t92) * t130 + + 0.4e1 * t4 * t98 * t53 * AA) / + (((-0.8e1 * t4 - 0.8e1 * t1) * t7 * t24 + 0.8e1 * t141 + 0.8e1 * t7 * t1) * t51 + + (0.4e1 * t147 - 0.4e1 * t141) * t151 + 0.4e1 * t147 - 0.4e1 * t141); + + t1 = Rm * Rp; + t2 = Rm * Rm; + t3 = km * km; + t4 = Rp * Rp; + t5 = B * B; + t12 = km * Rm; + t17 = 0.2e1 * Rm; + t18 = cos(t17); + t22 = t2 * Rp; + t25 = t5 * B; + t27 = B * t3; + t33 = t5 * km; + t38 = sin(t17); + t40 = Rm * B; + t41 = 0.3e1 * t5; + t51 = exp(-0.2e1 * Rp); + t53 = t2 * Rm; + t54 = t53 * B; + t56 = 0.5e1 * t1 * t5; + t58 = Rm * t4 * B; + t59 = t3 * Rm; + t60 = t59 * Rp; + t62 = 0.8e1 * t33 * Rp; + t64 = 0.3e1 * Rm * t25; + t65 = t53 * Rp; + t66 = t59 * B; + t67 = t4 * Rp; + t68 = Rm * t67; + t69 = t54 - t56 + t58 + t60 - t62 + t64 - t65 - t66 + t68; + t71 = t2 * t4; + t73 = 0.3e1 * t25 * Rp; + t74 = t2 * t5; + t75 = t27 * Rp; + t76 = B * km; + t78 = 0.2e1 * t76 * t1; + t80 = 0.2e1 * t33 * Rm; + t81 = t22 * B; + t82 = t4 * t5; + t83 = 0.2e1 * t82; + t84 = t67 * B; + t85 = t71 + t73 + t74 - t75 - t78 + t80 - t81 + t83 - t84; + t89 = Rm - km; + t90 = cos(t89); + t92 = t60 - t66 - t65 + t58 + t54 - t56 + t62 + t68 + t64; + t94 = t73 + t78 - t81 + t74 - t80 - t84 - t75 + t83 + t71; + t98 = Rm + km; + t99 = cos(t98); + t105 = sin(t98); + t111 = sin(t89); + t115 = exp(-Rp - B); + t117 = B - Rp; + t118 = Rm * t117; + t121 = t41 - 0.2e1 * Rp * B + t2 - t3 - t4; + t123 = t118 * t121 * AA; + t124 = 0.2e1 * t76; + t125 = t40 + t124 + t1; + t131 = -t124 + t40 + t1; + t141 = t118 * t121 * BB; + t152 = exp(-0.3e1 * Rp - B); + t171 = exp(-0.4e1 * Rp); + _C4 = (((-0.2e1 * t1 * (t2 - t3 - t4 + 0.5e1 * t5) * AA + 0.8e1 * B * BB * t12 * Rp) * t18 + + (-0.2e1 * Rp * (-0.2e1 * t5 * Rp - 0.2e1 * t22 + t4 * B - 0.3e1 * t25 + t27 + t2 * B) * AA - + 0.8e1 * t33 * BB * Rp) * t38 + 0.2e1 * t40 * (t41 + t4 + t2 - t3) * AA - + 0.8e1 * t5 * BB * t12) * t51 + + ((t69 * AA - 0.2e1 * t85 * BB) * t90 + (t92 * AA + 0.2e1 * t94 * BB) * t99 + + (-0.2e1 * t94 * AA + t92 * BB) * t105 + (-0.2e1 * t85 * AA - t69 * BB) * t111) * t115 + + ((-t123 + 0.2e1 * t118 * t125 * BB) * t90 + (-t123 - 0.2e1 * t118 * t131 * BB) * t99 + + (0.2e1 * t118 * t131 * AA - t141) * t105 + (0.2e1 * t118 * t125 * AA + t141) * t111) * t152 - + 0.2e1 * t123 + 0.8e1 * t40 * km * t117 * BB) / + (((-0.8e1 * t2 - 0.8e1 * t5) * t4 * t18 + 0.8e1 * t74 + 0.8e1 * t82) * t51 + + (0.4e1 * t71 - 0.4e1 * t74) * t171 + 0.4e1 * t71 - 0.4e1 * t74); + + /******************************************************************/ + /******************************************************************/ + + /*******************************************/ + /* calculate the velocities etc */ + /*******************************************/ + + t2 = exp(UU * z); + t3 = Rm * z; + t4 = cos(t3); + t6 = sin(t3); + t11 = exp(-VV * z); + t18 = exp(-0.2e1 * z * B); + t19 = km * z; + t20 = cos(t19); + t22 = sin(t19); + u1 = kn * (t2 * (_C1 * t4 + _C2 * t6) + t11 * (_C3 * t4 + _C4 * t6) + t18 * (AA * t20 + BB * t22)); + + t1 = Rm * z; + t2 = cos(t1); + t4 = sin(t1); + t14 = exp(UU * z); + t26 = exp(-VV * z); + t28 = km * z; + t29 = cos(t28); + t31 = sin(t28); + t43 = exp(-0.2e1 * z * B); + u2 = (-UU * (_C1 * t2 + _C2 * t4) + _C1 * t4 * Rm - _C2 * t2 * Rm) * t14 + + (VV * (_C3 * t2 + _C4 * t4) + _C3 * t4 * Rm - _C4 * t2 * Rm) * t26 + + (0.2e1 * B * (AA * t29 + BB * t31) + AA * t31 * km - BB * t29 * km) * t43; + + t2 = 0.2e1 * z * B; + t3 = exp(t2); + t4 = t3 * kn; + t5 = Rm * z; + t6 = cos(t5); + t8 = sin(t5); + t18 = exp(UU * z); + t31 = exp(-VV * z); + t34 = km * z; + t35 = cos(t34); + t37 = sin(t34); + t47 = exp(-t2); + u3 = 0.2e1 * t4 * (UU * (_C1 * t6 + _C2 * t8) - _C1 * t8 * Rm + _C2 * t6 * Rm) * t18 + + 0.2e1 * t4 * (-VV * (_C3 * t6 + _C4 * t8) - _C3 * t8 * Rm + _C4 * t6 * Rm) * t31 + + 0.2e1 * t4 * (-0.2e1 * B * (AA * t35 + BB * t37) - AA * t37 * km + BB * t35 * km) * t47; + + t1 = Rm * Rm; + t3 = UU * UU; + t8 = kn * kn; + t11 = Rm * z; + t12 = sin(t11); + t14 = cos(t11); + t20 = t14 * Rm; + t27 = 0.2e1 * z * B; + t28 = exp(t27); + t31 = exp(UU * z); + t38 = VV * VV; + t54 = exp(-VV * z); + t56 = km * km; + t59 = B * B; + t66 = km * z; + t67 = sin(t66); + t69 = cos(t66); + t83 = exp(-t27); + u4 = ((_C2 * t1 - t3 * _C2 + 0.2e1 * UU * _C1 * Rm - _C2 * t8) * t12 + _C1 * t14 * t1 - t3 * _C1 * t14 - + 0.2e1 * UU * _C2 * t20 - t8 * _C1 * t14) * t28 * t31 + + ((-0.2e1 * VV * _C3 * Rm + _C4 * t1 - _C4 * t8 - t38 * _C4) * t12 + 0.2e1 * VV * _C4 * t20 + + _C3 * t14 * t1 - t8 * _C3 * t14 - t38 * _C3 * t14) * t28 * t54 + + ((BB * t56 - t8 * BB - 0.4e1 * t59 * BB - 0.4e1 * B * AA * km) * t67 + AA * t69 * t56 - + t8 * AA * t69 - 0.4e1 * t59 * AA * t69 + 0.4e1 * B * BB * t69 * km) * t28 * t83; + + + t1 = Rm * z; + t2 = sin(t1); + t3 = Rm * Rm; + t4 = t3 * Rm; + t5 = t2 * t4; + t6 = UU * UU; + t7 = t6 * UU; + t8 = cos(t1); + t15 = 0.2e1 * B * t8 * t3; + t19 = B * UU; + t20 = t2 * Rm; + t23 = kn * kn; + t24 = B * t23; + t26 = 0.2e1 * t24 * t8; + t27 = t23 * UU; + t29 = B * t6; + t33 = t23 * t2 * Rm; + t35 = 0.1e1 / kn; + t42 = 0.2e1 * B * t2 * t3; + t43 = t8 * t4; + t45 = 0.2e1 * t24 * t2; + t52 = t23 * t8 * Rm; + t53 = t8 * Rm; + t64 = 0.2e1 * z * B; + t65 = exp(t64); + t68 = exp(UU * z); + t70 = B * VV; + t76 = t23 * VV; + t78 = VV * VV; + t79 = t78 * VV; + t84 = B * t78; + t108 = exp(-VV * z); + t111 = km * z; + t112 = sin(t111); + t113 = km * km; + t118 = cos(t111); + t119 = t118 * km; + t121 = B * B; + t123 = t112 * km; + t130 = t113 * km; + t148 = exp(-t64); + u5 = (-(-t5 - t7 * t8 + 0.3e1 * UU * t8 * t3 + t15 + 0.3e1 * t6 * t2 * Rm + 0.4e1 * t19 * t20 - t26 + + t27 * t8 - 0.2e1 * t29 * t8 - t33) * t35 * _C1 - + (-t7 * t2 + t27 * t2 + t42 + t43 - t45 + 0.3e1 * UU * t2 * t3 - 0.2e1 * t29 * t2 + t52 - + 0.4e1 * t19 * t53 - 0.3e1 * t6 * t8 * Rm) * t35 * _C2) * t65 * t68 + + (-(t15 - 0.4e1 * t70 * t20 - t33 - 0.3e1 * VV * t8 * t3 - t76 * t8 + t79 * t8 + + 0.3e1 * t78 * t2 * Rm - 0.2e1 * t84 * t8 - t26 - t5) * t35 * _C3 - + (t52 - 0.3e1 * VV * t2 * t3 + t79 * t2 + 0.4e1 * t70 * t53 - 0.3e1 * t78 * t8 * Rm - + 0.2e1 * t84 * t2 + t43 - t76 * t2 + t42 - t45) * t35 * _C4) * t65 * t108 - t65 * + (-0.4e1 * B * BB * + t112 * t113 + + t23 * BB * t119 + + 0.4e1 * t121 * AA * + t123 - + 0.4e1 * t121 * BB * + t119 + + BB * t118 * t130 - + AA * t112 * t130 - + 0.4e1 * B * AA * + t118 * t113 - + t23 * AA * t123 - + 0.4e1 * t24 * AA * + t118 - + 0.4e1 * t24 * BB * + t112) * t35 * t148; + + + t2 = 0.2e1 * z * B; + t3 = exp(t2); + t4 = t3 * kn; + t5 = Rm * z; + t6 = cos(t5); + t8 = sin(t5); + t18 = exp(UU * z); + t31 = exp(-VV * z); + t34 = km * z; + t35 = cos(t34); + t37 = sin(t34); + t47 = exp(-t2); + u6 = -0.2e1 * t4 * (UU * (_C1 * t6 + _C2 * t8) - _C1 * t8 * Rm + _C2 * t6 * Rm) * t18 - + 0.2e1 * t4 * (-VV * (_C3 * t6 + _C4 * t8) - _C3 * t8 * Rm + _C4 * t6 * Rm) * t31 - + 0.2e1 * t4 * (-0.2e1 * B * (AA * t35 + BB * t37) - AA * t37 * km + BB * t35 * km) * t47; + + + + + /******************************************************************/ + /******************************************************************/ + + + + sum5 += u5 * cos(n * M_PI * x); /* pressure */ + u6 -= u5; /* get total stress */ + sum6 += u6 * cos(n * M_PI * x); /* xx stress */ + + u1 *= cos(n * M_PI * x); /* z velocity */ + sum1 += u1; + u2 *= sin(n * M_PI * x); /* x velocity */ + sum2 += u2; + u3 -= u5; /* get total stress */ + u3 *= cos(n * M_PI * x); /* zz stress */ + sum3 += u3; + u4 *= sin(n * M_PI * x); /* zx stress */ + sum4 += u4; + + rho = -sigma * sin(km * z) * cos(kn * x); /* density */ + sum7 += rho; + + SS = exp(UU * z) * (_C1 * cos(Rm * z) + _C2 * sin(Rm * z)) + + exp(-VV * z) * (_C3 * cos(Rm * z) + _C4 * sin(Rm * z)) + + exp(-2 * z * B) * (AA * cos(km * z) + BB * sin(km * z)); + SS *= sin(kn * x); /* stream function */ + + //mag = sqrt(u1 * u1 + u2 * u2); + /*printf("%0.7f %0.7f %0.7f %0.7f %0.7f %0.7f %0.7f %0.7f %0.7f %0.7f %0.7f\n",x,z,sum1,sum2,sum3,sum4,sum5,sum6,mag,sum7,SS);*/ + + + /* Output */ + if (vel != nullptr) + { + vel[0] = sum2; + vel[1] = sum1; + } + if (presssure != nullptr) + { + (*presssure) = sum5; + } + if (total_stress != nullptr) + { + total_stress[0] = sum6; + total_stress[1] = sum3; + total_stress[2] = sum4; + } + if (strain_rate != nullptr) + { + /* sigma = tau - p, tau = sigma + p, tau[] = 2*eta*strain_rate[] */ + Z = exp(2.0 * B * z); + strain_rate[0] = (sum6 + sum5) / (2.0 * Z); + strain_rate[1] = (sum3 + sum5) / (2.0 * Z); + strain_rate[2] = (sum4) / (2.0 * Z); + } + /* Value checks, could be cleaned up if needed. Julian Giordani 9-Oct-2006*/ + if (fabs(sum5 - (-0.5 * (sum6 + sum3))) > 1e-5) + { + assert(0); + } + } + + + + /** + * The exact solution for the SolKz benchmark. + */ + template + class FunctionSolKz : public Function + { + public: + FunctionSolKz(unsigned int n_components) : Function(n_components) {} + + void vector_value(const Point &p, + Vector &values) const override + { + double pos[2] = {p(0), p(1)}; + double total_stress[3], strain_rate[3]; + static const double B = 0.5 * std::log(1e6); + AnalyticSolutions::_Velic_solKz + (pos, + 1.0, 2, 3, + B, + &values[0], &values[2], total_stress, strain_rate); + } + }; + + + } + + + + template + class SolKzMaterial : public MaterialModel::Interface + { + public: + /** + * @name Physical parameters used in the basic equations + * @{ + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + + const Point &pos = in.position[i]; + + static const double B = 0.5 * std::log(1e6); + out.viscosities[i] = std::exp(2 * B * pos[1]); + + out.densities[i] = -std::sin(2 * pos[1]) * std::cos(3 * numbers::PI * pos[0]); + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + } + } + + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + * Incompressibility does not necessarily imply that the density is + * constant; rather, it may still depend on temperature or pressure. + * In the current context, compressibility means whether we should + * solve the continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + bool is_compressible() const override + { + return false; + } + /** + * @} + */ + + void + parse_parameters(ParameterHandler &/*prm*/) override + { + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + }; + + + + /** + * A postprocessor that evaluates the accuracy of the solution. + * + * The implementation of error evaluators that correspond to the + * benchmarks defined in the paper Duretz et al. reference above. + */ + template + class SolKzPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Generate graphical output from the current solution. + */ + std::pair + execute(TableHandler &/*statistics*/) override + { + AnalyticSolutions::FunctionSolKz ref_func(this->introspection().n_components); + + AssertThrow(Plugins::plugin_type_matches>(this->get_material_model()), + ExcMessage( + "Postprocessor SolKzPostprocessor only works with the material model SolKzn.")); + + const QGauss quadrature_formula(this->introspection().polynomial_degree.velocities + 2); + + Vector cellwise_errors_u(this->get_triangulation().n_active_cells()); + Vector cellwise_errors_p(this->get_triangulation().n_active_cells()); + Vector cellwise_errors_ul2(this->get_triangulation().n_active_cells()); + Vector cellwise_errors_pl2(this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_u(std::pair(0, dim), + this->get_fe().n_components()); + ComponentSelectFunction comp_p(dim, + this->get_fe().n_components()); + + VectorTools::integrate_difference(this->get_mapping(), this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_u, + quadrature_formula, + VectorTools::L1_norm, + &comp_u); + VectorTools::integrate_difference(this->get_mapping(), this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_p, + quadrature_formula, + VectorTools::L1_norm, + &comp_p); + VectorTools::integrate_difference(this->get_mapping(), this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_ul2, + quadrature_formula, + VectorTools::L2_norm, + &comp_u); + VectorTools::integrate_difference(this->get_mapping(), this->get_dof_handler(), + this->get_solution(), + ref_func, + cellwise_errors_pl2, + quadrature_formula, + VectorTools::L2_norm, + &comp_p); + + const double u_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_u, VectorTools::L1_norm); + const double p_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_p, VectorTools::L1_norm); + const double u_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_ul2, VectorTools::L2_norm); + const double p_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_pl2, VectorTools::L2_norm); + + std::ostringstream os; + os << std::scientific << u_l1 + << ", " << p_l1 + << ", " << u_l2 + << ", " << p_l2; + + return std::make_pair("Errors u_L1, p_L1, u_L2, p_L2:", os.str()); + } + }; + + } +} + +#endif diff --git a/benchmarks/solkz/solkz.prm.bak b/benchmarks/solkz/solkz.prm.bak new file mode 100644 index 00000000000..399ef6b1f1c --- /dev/null +++ b/benchmarks/solkz/solkz.prm.bak @@ -0,0 +1,62 @@ +# A description of the SolKZ benchmark for which a known solution +# is available. See the manual for more information. + +set Additional shared libraries = ./libsolkz.so + +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output +set Pressure normalization = volume +set Nonlinear solver scheme = no Advection, iterated Stokes +set Use years in output instead of seconds = false + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Material model + set Model name = SolKzMaterial +end + +subsection Gravity model + set Model name = vertical +end + +############### Parameters describing the temperature field + + +subsection Initial temperature model + set Model name = perturbed box +end + +############### Parameters describing the discretization + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = false +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = SolKzPostprocessor, visualization +end diff --git a/benchmarks/solubility/plugin/solubility.cc b/benchmarks/solubility/plugin/solubility.cc index c899cb5ed8c..896ed59ffa9 100644 --- a/benchmarks/solubility/plugin/solubility.cc +++ b/benchmarks/solubility/plugin/solubility.cc @@ -359,7 +359,7 @@ namespace aspect melt_fractions (const MaterialModel::MaterialModelInputs &in, std::vector &melt_fractions) const { - for (unsigned int q=0; qintrospection().compositional_index_for_name("water_content"); const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); @@ -399,7 +399,7 @@ namespace aspect if (this->get_parameters().use_operator_splitting && out.template get_additional_output>() == nullptr) { - const unsigned int n_points = out.viscosities.size(); + const unsigned int n_points = out.n_evaluation_points(); out.additional_outputs.push_back( std::make_unique> (n_points, this->n_compositional_fields())); } diff --git a/benchmarks/solubility/plugin/solubility.cc.bak b/benchmarks/solubility/plugin/solubility.cc.bak new file mode 100644 index 00000000000..c899cb5ed8c --- /dev/null +++ b/benchmarks/solubility/plugin/solubility.cc.bak @@ -0,0 +1,424 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * Volatiles material model. + * @ingroup MaterialModels + */ + template + class Volatiles : public MaterialModel::MeltInterface, public ::aspect::SimulatorAccess, public MaterialModel::MeltFractionModel + { + public: + /** + * Initialize the base model at the beginning of the run. + */ + void initialize() override; + + /** + * Update the base model at the beginning of each timestep. + */ + void update() override; + + /** + * Function to compute the material properties in @p out given the + * inputs in @p in. + */ + void + evaluate (const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + + /** + * Method that indicates whether material is compressible. The model is compressible + * if and only if base model is compressible. + */ + bool is_compressible () const override; + + /** + * Compute the free fluid fraction that can be present in the material based on the + * fluid content of the material and the fluid solubility for the given input conditions. + * @p in and @p melt_fractions need to have the same size. + * + * @param in Object that contains the current conditions. + * @param melt_fractions Vector of doubles that is filled with the + * allowable free fluid fraction for each given input conditions. + */ + void melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const override; + + double reference_darcy_coefficient () const override; + + /** + * Method to declare parameters related to volatile model + */ + static void + declare_parameters (ParameterHandler &prm); + + /** + * Method to parse parameters related to volatile model + */ + void + parse_parameters (ParameterHandler &prm) override; + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + private: + /** + * Pointer to the material model used as the base model + */ + std::unique_ptr> base_model; + + // Variables that describe the properties of the fluid, i.e. its density, + // viscosity, and compressibility. + // Properties of the solid are defined in the base model. + double reference_rho_f; + double eta_f; + double fluid_compressibility; + + // Material properties governing the transport of the fluid with respect + // to the solid, i.e., the bulk viscosity (relative to the shear viscosity), + // the permeability, and how much the solid viscosity changes in the presence + // of fluids. + double shear_to_bulk_viscosity_ratio; + double reference_permeability; + double alpha_phi; + + // Time scale for fluid release and absorption. + double fluid_reaction_time_scale; + }; + + + + template + void + Volatiles::initialize() + { + base_model->initialize(); + } + + + + template + void + Volatiles::update() + { + base_model->update(); + } + + + + template + void + Volatiles::evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const + { + base_model->evaluate(in,out); + + // Modify the viscosity from the base model based on the presence of fluid. + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + + if (in.requests_property(MaterialProperties::viscosity)) + { + // Scale the base model viscosity value based on the porosity. + for (unsigned int q=0; q *fluid_out = out.template get_additional_output>(); + + if (fluid_out != nullptr) + { + for (unsigned int q=0; qfluid_viscosities[q] = eta_f; + fluid_out->permeabilities[q] = reference_permeability * std::pow(porosity,3) * std::pow(1.0-porosity,2); + + fluid_out->fluid_densities[q] = reference_rho_f * std::exp(fluid_compressibility * (in.pressure[q] - this->get_surface_pressure())); + + if (in.requests_property(MaterialProperties::viscosity)) + { + const double phi_0 = 0.05; + porosity = std::max(porosity,1e-8); + fluid_out->compaction_viscosities[q] = out.viscosities[q] * shear_to_bulk_viscosity_ratio * phi_0/porosity; + } + } + } + + ReactionRateOutputs *reaction_rate_out = out.template get_additional_output>(); + const unsigned int water_idx = this->introspection().compositional_index_for_name("water_content"); + + // Fill reaction rate outputs if the model uses operator splitting. + // Specifically, change the porosity (representing the amount of free water) + // based on the water solubility and the water content. + if (this->get_parameters().use_operator_splitting && reaction_rate_out != nullptr) + { + std::vector eq_free_fluid_fractions(out.n_evaluation_points()); + melt_fractions(in, eq_free_fluid_fractions); + + for (unsigned int q=0; qget_timestep_number() > 0) + reaction_rate_out->reaction_rates[q][c] = - porosity_change / fluid_reaction_time_scale + + in.composition[q][water_idx] * trace(in.strain_rate[q]); + else if (c == porosity_idx && this->get_timestep_number() > 0) + reaction_rate_out->reaction_rates[q][c] = porosity_change / fluid_reaction_time_scale; + else + reaction_rate_out->reaction_rates[q][c] = 0.0; + } + } + } + + + + template + void + Volatiles::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Volatile model"); + { + prm.declare_entry("Base model","visco plastic", + Patterns::Selection(MaterialModel::get_valid_model_names_pattern()), + "The name of a material model that will be modified by the " + "addition of fluids. Valid values for this parameter " + "are the names of models that are also valid for the " + "``Material models/Model name'' parameter. See the documentation for " + "that for more information."); + prm.declare_entry ("Reference fluid density", "2500", + Patterns::Double (0), + "Reference density of the melt/fluid$\\rho_{f,0}$. Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Shear to bulk viscosity ratio", "0.1", + Patterns::Double (0), + "Ratio between shear and bulk viscosity at the reference " + "permeability $\\phi_0=0.05$. The bulk viscosity additionally " + "scales with $\\phi_0/\\phi$. The shear viscosity is read in " + "from the base model. Units: dimensionless."); + prm.declare_entry ("Reference fluid viscosity", "10", + Patterns::Double (0), + "The value of the constant melt/fluid viscosity $\\eta_f$. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Exponential fluid weakening factor", "27", + Patterns::Double (0), + "The porosity dependence of the viscosity. Units: dimensionless."); + prm.declare_entry ("Reference permeability", "1e-8", + Patterns::Double(), + "Reference permeability of the solid host rock." + "Units: \\si{\\meter\\squared}."); + prm.declare_entry ("Fluid compressibility", "0.0", + Patterns::Double (0), + "The value of the compressibility of the fluid. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("Fluid reaction time scale for operator splitting", "1e3", + Patterns::Double (0), + "In case the operator splitting scheme is used, the porosity field can not " + "be set to a new equilibrium fluid fraction instantly, but the model has to " + "provide a reaction time scale instead. This time scale defines how fast fluid " + "release and absorption happen, or more specifically, the parameter defines the " + "time after which the deviation of the porosity from the free fluid fraction " + "that would be in equilibrium with the solid will be reduced to a fraction of " + "$1/e$. So if the fluid reaction time scale is small compared " + "to the time step size, the reaction will be so fast that the porosity is very " + "close to this equilibrium value after reactions are computed. Conversely, " + "if the fluid reaction time scale is large compared to the time step size, almost no " + "fluid release and absorption will occur." + "\n\n" + "Also note that the fluid reaction time scale has to be larger than or equal to the reaction " + "time step used in the operator splitting scheme, otherwise reactions can not be " + "computed. If the model does not use operator splitting, this parameter is not used. " + "Units: yr or s, depending on the ``Use years " + "in output instead of seconds'' parameter."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + Volatiles::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Volatile model"); + { + AssertThrow( prm.get("Base model") != "volatiles", + ExcMessage("You may not use ``volatiles'' as the base model for " + "a the volatile model itself.") ); + + reference_rho_f = prm.get_double ("Reference fluid density"); + shear_to_bulk_viscosity_ratio = prm.get_double ("Shear to bulk viscosity ratio"); + eta_f = prm.get_double ("Reference fluid viscosity"); + reference_permeability = prm.get_double ("Reference permeability"); + alpha_phi = prm.get_double ("Exponential fluid weakening factor"); + fluid_compressibility = prm.get_double ("Fluid compressibility"); + fluid_reaction_time_scale = prm.get_double ("Fluid reaction time scale for operator splitting"); + + // Create the base model and initialize its SimulatorAccess base + // class; it will get a chance to read its parameters below after we + // leave the current section. + base_model = create_material_model(prm.get("Base model")); + if (SimulatorAccess *sim = dynamic_cast*>(base_model.get())) + sim->initialize_simulator (this->get_simulator()); + + if (this->convert_output_to_years() == true) + fluid_reaction_time_scale *= year_in_seconds; + + if (this->get_parameters().use_operator_splitting) + { + AssertThrow(fluid_reaction_time_scale >= this->get_parameters().reaction_time_step, + ExcMessage("The reaction time step " + Utilities::to_string(this->get_parameters().reaction_time_step) + + " in the operator splitting scheme is too large to compute melting rates! " + "You have to choose it in such a way that it is smaller than the 'Melting time scale for " + "operator splitting' chosen in the material model, which is currently " + + Utilities::to_string(fluid_reaction_time_scale) + ".")); + AssertThrow(fluid_reaction_time_scale > 0, + ExcMessage("The Fluid reaction time scale for operator splitting must be larger than 0!")); + } + + AssertThrow(this->introspection().compositional_name_exists("porosity"), + ExcMessage("Material model Volatiles only " + "works if there is a compositional field called porosity.")); + + AssertThrow(this->introspection().compositional_name_exists("water_content"), + ExcMessage("Material model Volatiles only " + "works if there is a compositional field called water_content.")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // After parsing the parameters for this model, parse parameters related to the base model. + base_model->parse_parameters(prm); + this->model_dependence = base_model->get_model_dependence(); + } + + + + template + bool + Volatiles:: + is_compressible () const + { + return base_model->is_compressible(); + } + + + + template + void + Volatiles:: + melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const + { + for (unsigned int q=0; qintrospection().compositional_index_for_name("water_content"); + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + + // A very simple model for water solubility: + // There are three layers, the top layer (<30 km depth) and the bottom layer (>60 km depth) + // can accommodate an unlimited amount of bound water (equivalent to a zero porosity). + // The middle layer between the two can not accommodate any water, therefore, any water + // present will be in the form of free water (and the porosity equals the total water available, + // which is the sum free and bound water, i.e. porosity + water_content. + if (this->get_geometry_model().depth(in.position[q]) < 3e4 + || this->get_geometry_model().depth(in.position[q]) > 6e4) + + melt_fractions[q] = 0.0; + else + melt_fractions[q] = in.composition[q][water_idx] + in.composition[q][porosity_idx]; + } + } + + + + template + double + Volatiles:: + reference_darcy_coefficient () const + { + // 0.01 = 1% melt + return reference_permeability * std::pow(0.01,3.0) / eta_f; + } + + + + template + void + Volatiles::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (this->get_parameters().use_operator_splitting + && out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.viscosities.size(); + out.additional_outputs.push_back( + std::make_unique> (n_points, this->n_compositional_fields())); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(Volatiles, + "volatiles", + "Material model that is designed to advect fluids and compute " + "fluid release and absorption based on a very simple model for " + "water solubility consisting of three layers with water only being " + "present as a free phase in the middle layer. " + "The properties of the solid can be taken from another material " + "model that is used as a base model.") + } +} diff --git a/benchmarks/solubility/solubility.prm.bak b/benchmarks/solubility/solubility.prm.bak new file mode 100644 index 00000000000..aa8fa56c0be --- /dev/null +++ b/benchmarks/solubility/solubility.prm.bak @@ -0,0 +1,162 @@ +# This is a 1D test case for the solubility of fluids in interaction +# with porous flow. Material with a given water content flows into the +# model from the bottom. The model has three layers with different +# water solubility, specifically, an infinite solubility above 30 km +# depth and below 60 km depth, and a zero solubility in between. When +# the upwelling material reaches the boundary at 60 km depth, water is +# being released and can move relative to the solid as a free fluid +# phase. Due to its lower density, it moves upwards twice as fast as the +# solid, until it reaches 30 km depth where it is reabsorbed into the +# solid. In steady state, the water content should be the same in the +# top and bottom layer, and in the middle layer it should be zero (at +# least the water_content field, representing the bound water in the +# solid). The porosity (free water) should be 0.1, which is half of the +# bound water content in the upper and lower layer (which follows from +# mass conservation, since the free fluid moves twice as fast). + +set Additional shared libraries = ./plugin/libsolubility.so +set Adiabatic surface temperature = 1600 +set Nonlinear solver scheme = iterated Advection and Stokes +set Output directory = output +set Max nonlinear iterations = 10 +set Nonlinear solver tolerance = 1e-5 + +# The number of space dimensions you want to run this program in. +set Dimension = 2 +set End time = 6e6 + +# Because the model includes reactions that might be on a faster time scale +# than the time step of the model (melting and the freezing of melt), we use +# the operator splitting scheme. +set Use operator splitting = true + +# There are two compositional fields, one that tracks the amount of free water +# (the porosity) and one that tracks the amount of bound water (the water_content). +subsection Compositional fields + set Number of fields = 2 + set Names of fields = porosity, water_content +end + +# Initially, there is no free water (the porosity is zero) and the water content +# of the material is 1%. +subsection Initial composition model + set Model name = function + + subsection Function + set Function expression = 0.0; 0.01 + end +end + +# The material flowing in from the bottom has the same water content as prescribed +# in the initial condition. +subsection Boundary composition model + set Fixed composition boundary indicators = bottom + set List of model names = initial composition +end + +# We prescribe an upwelling velocity of 1 cm/yr at the bottom, +# the left and right boundaries are closed and the top is open. +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right + set Prescribed velocity boundary indicators = bottom:function + + subsection Function + set Function expression = 0; 1e-2 + end +end + +# The model is 1 km wide and extends 100 km in vertical direction. +# This is because for this specific test material model, the transitions +# between the three layers with different water solubilities are at +# 30 km and 60 km depth. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2e2 + set Y extent = 1e5 + set Y repetitions = 500 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +# The temperature is not important for this model, so we simply +# set it to 1600 K everywhere (including the boundary). +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1600 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = initial temperature + + subsection Initial temperature + set Maximal temperature = 1600 + set Minimal temperature = 1600 + end +end + +# We use a custom material model that implements the layers with +# different solubility. +subsection Material model + set Model name = volatiles + + subsection Volatile model + set Base model = visco plastic + set Reference fluid density = 2995 + set Shear to bulk viscosity ratio = 0.1 + set Reference fluid viscosity = 10 + set Reference permeability = 2.5e-6 + set Exponential fluid weakening factor = 27 + set Fluid reaction time scale for operator splitting = 5e4 + end + + subsection Visco Plastic + set Reference temperature = 1600 + set Prefactors for diffusion creep = 5e-21 + set Viscous flow law = diffusion + set Densities = 3000 + set Viscosity averaging scheme = harmonic + set Minimum viscosity = 1e19 + set Maximum viscosity = 1e19 + end +end + +subsection Mesh refinement + set Coarsening fraction = 0.0 + set Refinement fraction = 0.0 + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Strategy = composition + set Time steps between mesh refinement = 0 +end + +subsection Melt settings + set Include melt transport = true +end + +subsection Postprocess + set List of postprocessors = visualization, composition statistics, velocity statistics + + subsection Visualization + set List of output variables = density, viscosity, thermal expansivity, melt material properties, melt fraction + set Output format = vtu + set Time between graphical output = 0 + set Interpolate output = false + + subsection Melt material properties + set List of properties = fluid density, permeability, fluid viscosity, compaction viscosity + end + end +end diff --git a/benchmarks/tangurnis/ba/tan.prm.bak b/benchmarks/tangurnis/ba/tan.prm.bak new file mode 100644 index 00000000000..73442056e32 --- /dev/null +++ b/benchmarks/tangurnis/ba/tan.prm.bak @@ -0,0 +1,130 @@ +# Listing of Parameters +# --------------------- + +set Additional shared libraries = ./code/libtangurnis.so +set Dimension = 2 +set CFL number = 1.0 + +# We only need a single time step. +set Start time = 0 +set End time = 0.0001 + +# The temperature is prescibed, so we only need to +# solve the Stokes system +set Nonlinear solver scheme = no Advection, iterated Stokes +set Use years in output instead of seconds = false +set Adiabatic surface temperature = 0 +set Surface pressure = 0 + +# In this section we define the adiabatic profiles of temperature, +# pressure and density. The temperature and pressure profiles are +# not used for this benchmark (and set to zero). +# gamma is the grueneisen parameter, which defines the compressibility +# of the material, and we have to choose the same value for gamma as +# in the material model below. +subsection Adiabatic conditions model + set Model name = function + + subsection Function + set Function constants = Di=0.0, gamma=1.0 + set Function expression = 0;0;exp(Di/gamma*depth) # T,p,rho + set Variable names = depth + end +end + +# This case of the benchmark uses the Boussinesq approximation. +subsection Formulation + set Formulation = custom # equivalent to Boussinesq approximation + set Mass conservation = incompressible + set Temperature equation = reference density profile +end + +# We define our own boundary condition that implements a boundary +# temperature according to the prescibed temperature of the Tan & Gurnis +# benchmark. +subsection Boundary temperature model + set Fixed temperature boundary indicators = left, right, bottom, top + set List of model names = Tan Gurnis +end + +subsection Discretization + subsection Stabilization parameters + # The exponent $\alpha$ in the entropy viscosity stabilization. Units: + # None. + set alpha = 2 + + # The $\beta$ factor in the artificial viscosity stabilization. An + # appropriate value for 2d is 0.052 and 0.078 for 3d. Units: None. + set beta = 0.078 + + # The $c_R$ factor in the entropy viscosity stabilization. Units: None. + set cR = 0.5 + end +end + +# The model domain is the unit square. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + set Z extent = 1 + end +end + +subsection Gravity model + set Model name = vertical +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = sin(pi*y)*cos(pi*1*x) + end +end + +# The benchmark is defined in terms of the nondimensional numbers +# Di (dissipation number) and gamma (grueneisen parameter). +# As ASPECT uses physical properties instead of these dimensionless +# numbers in its equations, we replicate the benchmark formulation +# by using a new material model that fixes all of the material +# constants to 1, except for the thermal expansivity and the viscosity, +# which is set to Di, and the density profile, which depends on Di and +# gamma. +# For the Boussinesq case, Di=0 and gamma=infinity, and all parameters +# are constant, except for the density, which depends on the temperature. +subsection Material model + set Model name = Tan Gurnis + + subsection Tan Gurnis model + set Di = 0 + set gamma = 1 # infinity really, but is not used if Di=0 + set a = 0 # constant viscosity + set wavenumber = 1 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 6 +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Postprocess + set List of postprocessors = Tan Gurnis error, visualization + + subsection Depth average + set Time between graphical output = 1e8 + end + + subsection Visualization + set Number of grouped files = 0 + set Output format = vtu + set Time between graphical output = 0 + end +end diff --git a/benchmarks/tangurnis/code/tangurnis.cc.bak b/benchmarks/tangurnis/code/tangurnis.cc.bak new file mode 100644 index 00000000000..d4c6c372457 --- /dev/null +++ b/benchmarks/tangurnis/code/tangurnis.cc.bak @@ -0,0 +1,461 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + + +namespace aspect +{ + using namespace dealii; + + + + /** + * This benchmark is from the article + * @code + * @article{tan2007compressible, + * title={Compressible thermochemical convection and application to lower mantle structures}, + * author={Tan, E. and Gurnis, M.}, + * journal={JOURNAL OF GEOPHYSICAL RESEARCH-ALL SERIES-}, + * volume={112}, + * number={B6}, + * pages={6304}, + * year={2007}, + * publisher={AGU AMERICAN GEOPHYSICAL UNION} + * } + * @endcode + * + * @ingroup Postprocessing + */ + + + + namespace MaterialModel + { + + template + class TanGurnis : public MaterialModel::Interface + { + public: + + TanGurnis(); + + /** + * @name Physical parameters used in the basic equations + * @{ + */ + + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + /** + * @name Physical parameters used in the basic equations + * @{ + */ + + const Point &pos = in.position[i]; + const double depth = 1.0 - pos[dim-1]; + const double temperature = sin(numbers::PI*pos(dim-1))*cos(numbers::PI*wavenumber*pos(0)); + + out.viscosities[i] = ( Di==0.0 ? 1.0 : Di ) * exp( a * depth ); + out.densities[i] = ( Di==0.0 ? 1.0 : Di ) * (-1.0 * temperature ) * exp( Di/gamma * (depth) ); + out.specific_heat[i] = 1.0; + out.thermal_conductivities[i] = 1.0; + out.thermal_expansion_coefficients[i] = ( Di==0.0 ) ? 1.0 : Di; + out.compressibilities[i] = numbers::signaling_nan();; + } + } + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + + + double parameter_a() const; + double parameter_wavenumber() const; + double parameter_Di() const; + double parameter_gamma() const; + + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + private: + + double a; + double wavenumber; + double Di; + double gamma; + + }; + + template + TanGurnis::TanGurnis() + { + // a=0 for a constant viscosity or + // a=2 for a depth-dependent viscosity (case tala_c) + a=0; + + // for BA: Di=0; gamma=inf + // however, we do not use gamma if Di=0, so the actual value does not matter + + //TALA: + Di=0.5; + gamma=1.0; + + wavenumber=1; + } + + + template + bool + TanGurnis:: + is_compressible () const + { + return Di != 0.0; + } + + + + template + double + TanGurnis:: + parameter_a() const + { + return a; + } + + + + template + double + TanGurnis:: + parameter_wavenumber() const + { + return wavenumber; + } + + + + template + double + TanGurnis:: + parameter_Di() const + { + return Di; + } + + + + template + double + TanGurnis:: + parameter_gamma() const + { + return gamma; + } + + + + template + void + TanGurnis::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Tan Gurnis model"); + { + prm.declare_entry ("a", "0", + Patterns::Double (0), + ""); + prm.declare_entry ("Di", "0.5", + Patterns::Double (0), + ""); + prm.declare_entry ("gamma", "1", + Patterns::Double (0), + ""); + prm.declare_entry ("wavenumber", "1", + Patterns::Double (0), + ""); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + TanGurnis::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Tan Gurnis model"); + { + a = prm.get_double("a"); + Di = prm.get_double("Di"); + gamma = prm.get_double("gamma"); + wavenumber = prm.get_double("wavenumber"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::none; + this->model_dependence.density = NonlinearDependence::none; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + } + } + + + /** + * A class that implements a temperature boundary condition for the + * tan/gurnis benchmark in a box geometry. + * + * @ingroup BoundaryTemperatures + */ + template + class TanGurnisBoundary : public BoundaryTemperature::Interface + { + public: + double boundary_temperature (const types::boundary_id /*boundary_indicator*/, + const Point &position) const override + { + double wavenumber=1; + return sin(numbers::PI*position(dim-1))*cos(numbers::PI*wavenumber*position(0)); + } + + double minimal_temperature (const std::set &fixed_boundary_ids) const override; + + double maximal_temperature (const std::set &fixed_boundary_ids) const override; + }; + + template + double + TanGurnisBoundary:: + minimal_temperature (const std::set &/*fixed_boundary_ids*/) const + { + return 0; + } + + + + template + double + TanGurnisBoundary:: + maximal_temperature (const std::set &/*fixed_boundary_ids*/) const + { + return 1; + } + + + + /* + * A postprocessor that evaluates the accuracy of the solution of the + * aspect::MaterialModel::TanGurnis material model. + * + * The implementation writes out the solution to be read in by a matlab + * script. + */ + template + class TanGurnisPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + std::pair + execute (TableHandler &statistics) override; + }; + + template + std::pair + TanGurnisPostprocessor::execute (TableHandler &/*statistics*/) + { + AssertThrow(Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()) == 1, + ExcNotImplemented()); + + AssertThrow(Plugins::plugin_type_matches>(this->get_material_model()), + ExcMessage("tan gurnis postprocessor only works with tan gurnis material model")); + + const MaterialModel::TanGurnis & + material_model = Plugins::get_plugin_as_type>(this->get_material_model()); + + double ref=1.0/this->get_triangulation().begin_active()->minimum_vertex_distance(); + + std::stringstream output; + output.precision (16); + output << material_model.parameter_Di() << ' ' + << material_model.parameter_gamma() << ' ' + << material_model.parameter_wavenumber() << ' ' + << material_model.parameter_a(); + + // pad the first line to the same number ooutputcolumns as the data below to make MATLAB happy + for (unsigned int i=4; i<7+this->get_heating_model_manager().get_active_heating_models().size(); ++i) + output<< " -1"; + + output<< std::endl; + output<< std::scientific; + + + const QGauss quadrature_formula (this->introspection().polynomial_degree.velocities+2); + + const unsigned int n_q_points = quadrature_formula.size(); + FEValues fe_values (this->get_mapping(), this->get_fe(), quadrature_formula, + update_JxW_values | update_values | + update_gradients | update_quadrature_points); + + MaterialModel::MaterialModelInputs in(fe_values.n_quadrature_points, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(fe_values.n_quadrature_points, this->n_compositional_fields()); + + const std::list>> &heating_model_objects = this->get_heating_model_manager().get_active_heating_models(); + + std::vector heating_model_outputs (heating_model_objects.size(), + HeatingModel::HeatingModelOutputs (n_q_points, this->n_compositional_fields())); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + in.reinit(fe_values,cell,this->introspection(),this->get_solution()); + + this->get_material_model().evaluate(in, out); + + if (this->get_parameters().formulation_temperature_equation == + Parameters::Formulation::TemperatureEquation::reference_density_profile) + { + for (unsigned int q=0; qget_adiabatic_conditions().density(in.position[q]); + } + } + + unsigned int index = 0; + for (typename std::list>>::const_iterator + heating_model = heating_model_objects.begin(); + heating_model != heating_model_objects.end(); ++heating_model, ++index) + { + (*heating_model)->evaluate(in, out, heating_model_outputs[index]); + } + + + for (unsigned int q = 0; q < n_q_points; ++q) + { + output + << fe_values.quadrature_point (q) (0) + << ' ' << fe_values.quadrature_point (q) (1) + << ' ' << in.velocity[q][0] + << ' ' << in.velocity[q][1] + << ' ' << fe_values.JxW (q) + << ' ' << in.pressure[q] + << ' ' << in.temperature[q]; + + for (unsigned int i = 0; i < heating_model_objects.size(); ++i) + output << ' ' << heating_model_outputs[i].heating_source_terms[q]; + + output << std::endl; + } + } + + const std::string filename = this->get_output_directory() + "vel_" + + Utilities::int_to_string(static_cast(ref)) + + ".csv"; + Utilities::collect_and_write_file_content(filename, output.str(), this->get_mpi_communicator()); + + return std::make_pair("writing:", "output.csv"); + } + +} + + + +// explicit instantiations +namespace aspect +{ + ASPECT_REGISTER_POSTPROCESSOR(TanGurnisPostprocessor, + "Tan Gurnis error", + "A postprocessor that compares the solution of the benchmarks from " + "the Tan/Gurnis (2007) paper with the one computed by ASPECT " + "by outputting data that is compared using a matlab script.") + + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(TanGurnis, + "Tan Gurnis", + "A simple compressible material model based on a benchmark" + " from the paper of Tan/Gurnis (2007). This does not use the" + " temperature equation, but has a hardcoded temperature.") + } + + ASPECT_REGISTER_BOUNDARY_TEMPERATURE_MODEL(TanGurnisBoundary, + "Tan Gurnis", + "A model for the Tan/Gurnis benchmark.") +} diff --git a/benchmarks/tangurnis/tala/tan.prm.bak b/benchmarks/tangurnis/tala/tan.prm.bak new file mode 100644 index 00000000000..737d7863d79 --- /dev/null +++ b/benchmarks/tangurnis/tala/tan.prm.bak @@ -0,0 +1,140 @@ +# Listing of Parameters +# --------------------- + +set Additional shared libraries = ./code/libtangurnis.so +set Dimension = 2 +set CFL number = 1.0 + +# We only need a single time step. +set Start time = 0 +set End time = 0.0001 +set Output directory = output_tala + +# The temperature is prescibed, so we only need to +# solve the Stokes system +set Nonlinear solver scheme = no Advection, iterated Stokes +set Use years in output instead of seconds = false +set Adiabatic surface temperature = 0 +set Surface pressure = 0 + +# In this section we define the adiabatic profiles of temperature, +# pressure and density. The temperature and pressure profiles are +# not used for this benchmark (and set to zero). +# gamma is the grueneisen parameter, which defines the compressibility +# of the material, and we have to choose the same value for gamma as +# in the material model below. +subsection Adiabatic conditions model + set Model name = function + + subsection Function + set Function constants = Di=0.5, gamma=1.0 + set Function expression = 0;0;exp(Di/gamma*depth) # T,p,rho + set Variable names = depth + end +end + +# This case of the benchmark uses the truncated anelastic liquid approximation. +subsection Formulation + set Formulation = custom # equivalent to TALA or ALA depending on material model + set Mass conservation = reference density profile + set Temperature equation = reference density profile +end + +# We define our own boundary condition that implements a boundary +# temperature according to the prescibed temperature of the Tan & Gurnis +# benchmark. +subsection Boundary temperature model + set Fixed temperature boundary indicators = left, right, bottom, top + set List of model names = Tan Gurnis +end + +subsection Discretization + subsection Stabilization parameters + # The exponent $\alpha$ in the entropy viscosity stabilization. Units: + # None. + set alpha = 2 + + # The $\beta$ factor in the artificial viscosity stabilization. An + # appropriate value for 2d is 0.052 and 0.078 for 3d. Units: None. + set beta = 0.078 + + # The $c_R$ factor in the entropy viscosity stabilization. Units: None. + set cR = 0.5 + end +end + +# The model domain is the unit square. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + set Z extent = 1 + end +end + +subsection Gravity model + set Model name = vertical +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = sin(pi*y)*cos(pi*1*x) + end +end + +# The benchmark is defined in terms of the nondimensional numbers +# Di (dissipation number) and gamma (grueneisen parameter). +# As ASPECT uses physical properties instead of these dimensionless +# numbers in its equations, we replicate the benchmark formulation +# by using a new material model that fixes all of the material +# constants to 1, except for the thermal expansivity and the viscosity, +# which is set to Di, and the density profile, which depends on Di and +# gamma. +subsection Material model + set Model name = Tan Gurnis + + subsection Tan Gurnis model + set Di = 0.5 + set gamma = 1 + set a = 0 # constant viscosity + set wavenumber = 1 + end +end + +# This subsection describes which heating models we want to use. +# This case includes adiabatic heating and shear heating. +subsection Heating model + set List of model names = adiabatic heating, shear heating + + subsection Adiabatic heating + set Use simplified adiabatic heating = true + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 6 +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Postprocess + set List of postprocessors = Tan Gurnis error, visualization, heating statistics + + subsection Depth average + set Time between graphical output = 1e8 + end + + subsection Visualization + set List of output variables = density, adiabat + set Number of grouped files = 0 + set Output format = vtu + set Time between graphical output = 0 + end +end diff --git a/benchmarks/tangurnis/tala_c/tan.prm.bak b/benchmarks/tangurnis/tala_c/tan.prm.bak new file mode 100644 index 00000000000..d5d7f6b1c26 --- /dev/null +++ b/benchmarks/tangurnis/tala_c/tan.prm.bak @@ -0,0 +1,139 @@ +# Listing of Parameters +# --------------------- + +set Additional shared libraries = ./code/libtangurnis.so +set Dimension = 2 +set CFL number = 1.0 + +# We only need a single time step. +set Start time = 0 +set End time = 0.0001 + +# The temperature is prescibed, so we only need to +# solve the Stokes system +set Nonlinear solver scheme = no Advection, iterated Stokes +set Use years in output instead of seconds = false +set Adiabatic surface temperature = 0 +set Surface pressure = 0 + +# In this section we define the adiabatic profiles of temperature, +# pressure and density. The temperature and pressure profiles are +# not used for this benchmark (and set to zero). +# gamma is the grueneisen parameter, which defines the compressibility +# of the material, and we have to choose the same value for gamma as +# in the material model below. +subsection Adiabatic conditions model + set Model name = function + + subsection Function + set Function constants = Di=0.5, gamma=1.0 + set Function expression = 0;0;exp(Di/gamma*depth) # T,p,rho + set Variable names = depth + end +end + +# This case of the benchmark uses the truncated anelastic liquid approximation. +subsection Formulation + set Formulation = custom # equivalent to TALA or ALA depending on material model + set Mass conservation = reference density profile + set Temperature equation = reference density profile +end + +# We define our own boundary condition that implements a boundary +# temperature according to the prescibed temperature of the Tan & Gurnis +# benchmark. +subsection Boundary temperature model + set Fixed temperature boundary indicators = left, right, bottom, top + set List of model names = Tan Gurnis +end + +subsection Discretization + subsection Stabilization parameters + # The exponent $\alpha$ in the entropy viscosity stabilization. Units: + # None. + set alpha = 2 + + # The $\beta$ factor in the artificial viscosity stabilization. An + # appropriate value for 2d is 0.052 and 0.078 for 3d. Units: None. + set beta = 0.078 + + # The $c_R$ factor in the entropy viscosity stabilization. Units: None. + set cR = 0.5 + end +end + +# The model domain is the unit square. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + set Z extent = 1 + end +end + +subsection Gravity model + set Model name = vertical +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = sin(pi*y)*cos(pi*1*x) + end +end + +# The benchmark is defined in terms of the nondimensional numbers +# Di (dissipation number) and gamma (grueneisen parameter). +# As ASPECT uses physical properties instead of these dimensionless +# numbers in its equations, we replicate the benchmark formulation +# by using a new material model that fixes all of the material +# constants to 1, except for the thermal expansivity and the viscosity, +# which is set to Di, and the density profile, which depends on Di and +# gamma. +subsection Material model + set Model name = Tan Gurnis + + subsection Tan Gurnis model + set Di = 0.5 + set gamma = 1 + set a = 2 # depth-dependent viscosity + set wavenumber = 1 + end +end + +# This subsection describes which heating models we want to use. +# This case includes adiabatic heating and shear heating. +subsection Heating model + set List of model names = adiabatic heating, shear heating + + subsection Adiabatic heating + set Use simplified adiabatic heating = true + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 6 +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Postprocess + set List of postprocessors = Tan Gurnis error, visualization, heating statistics + + subsection Depth average + set Time between graphical output = 1e8 + end + + subsection Visualization + set List of output variables = density, adiabat + set Number of grouped files = 0 + set Output format = vtu + set Time between graphical output = 0 + end +end diff --git a/benchmarks/time_dependent_annulus/plugin/time_dependent_annulus.cc.bak b/benchmarks/time_dependent_annulus/plugin/time_dependent_annulus.cc.bak new file mode 100644 index 00000000000..7f85d60857b --- /dev/null +++ b/benchmarks/time_dependent_annulus/plugin/time_dependent_annulus.cc.bak @@ -0,0 +1,55 @@ +/* + Copyright (C) 2018 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include "time_dependent_annulus.h" + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(TimeDependentAnnulus, + "time dependent annulus", + "This is the material model setup " + "for the time dependent annular flow benchmark from Section 5 of " + "``Gassmoeller, Lokavarapu, Bangerth, Puckett (2019): " + "Evaluating the Accuracy of Hybrid Finite Element/Particle-In-Cell " + "Methods for Modeling Incompressible Stokes Flow. Geophys. J. Int. " + "submitted.'' " + "The model " + "can either use the analytic density, or whatever is stored in the " + "first compositional field as the density that enters the Stokes equations. " + "This allows testing different advection schemes for the density.") + } + + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(TimeDependentAnnulus, + "time dependent annulus", + "This is the error postprocessor " + "for the time dependent annular flow benchmark from Section 5 of " + "``Gassmoeller, Lokavarapu, Bangerth, Puckett (2019): " + "Evaluating the Accuracy of Hybrid Finite Element/Particle-In-Cell " + "Methods for Modeling Incompressible Stokes Flow. Geophys. J. Int. " + "submitted.'' " + "Specifically, it can compute the errors for " + "the velocity, pressure, and density variables.") + } +} diff --git a/benchmarks/time_dependent_annulus/plugin/time_dependent_annulus.h.bak b/benchmarks/time_dependent_annulus/plugin/time_dependent_annulus.h.bak new file mode 100644 index 00000000000..624ad9158bd --- /dev/null +++ b/benchmarks/time_dependent_annulus/plugin/time_dependent_annulus.h.bak @@ -0,0 +1,377 @@ +/* + Copyright (C) 2019 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +namespace aspect +{ + /** + * This is the analytic solution, postprocessor, and material model setup + * for the time dependent annular flow benchmark from Section 5 of + * + * Gassmoeller, Lokavarapu, Bangerth, Puckett (2019): + * Evaluating the Accuracy of Hybrid Finite Element/Particle-In-Cell + * Methods for Modeling Incompressible Stokes Flow. Geophys. J. Int. + * submitted. + * + * It features a spherical annulus with a circular flow and a + * time-independent analytical, but a time-dependent numerical solution, + * which allows to quantify how errors in the advection equation + * influence the accuracy of the Stokes equation. In this example + * the benchmark uses particles to carry density, but it can be + * used for other advection methods as well. + */ + namespace AnalyticSolutions + { + template + void analytic_solution( + double pos[], + double vel[], + double *pressure, + double *density, + std::shared_ptr> pressure_function, + std::shared_ptr> velocity_function, + std::shared_ptr> density_function) + { + /****************************************************************************************/ + /****************************************************************************************/ + /* Output */ + for (unsigned int i=0; i < dim; i++) + vel[i] = velocity_function->value(Point(pos[0],pos[1]), i); + + (*pressure) = pressure_function->value(Point(pos[0], pos[1])); + + (*density) = density_function->value(Point(pos[0], pos[1])); + } + + /** + * The exact solution for the benchmark. + */ + template + class FunctionStreamline : public Function + { + public: + FunctionStreamline (std::shared_ptr> pressure, + std::shared_ptr> velocity, + std::shared_ptr> density, + const unsigned int n_components) + : + Function(n_components), + pressure_function (pressure), + velocity_function (velocity), + density_function (density) + {} + + void vector_value (const Point &p, + Vector &values) const override + { + double pos[2]= {p(0),p(1)}; + + AnalyticSolutions::analytic_solution + (pos, + &values[0], &values[2], &values[4], pressure_function, velocity_function, density_function); + } + private: + std::shared_ptr> pressure_function; + std::shared_ptr> velocity_function; + std::shared_ptr> density_function; + }; + } + + namespace MaterialModel + { + using namespace dealii; + + template + class TimeDependentAnnulus : public MaterialModel::Interface + { + private: + std::shared_ptr> density_function, pressure_function, velocity_function; + + public: + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + if (use_analytic_density) + out.densities[i] = density_function->value(in.position[i]); + else + out.densities[i] = in.composition[i][0]; + + out.viscosities[i] = 1; + out.compressibilities[i] = 0; + out.specific_heat[i] = 0; + out.thermal_expansion_coefficients[i] = 0; + out.thermal_conductivities[i] = 0.0; + } + } + + bool is_compressible () const override + { + return false; + } + + static + void + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Time dependent annulus"); + { + prm.declare_entry ("Use analytic density", "false", + Patterns::Bool(), + "Whether to use the analytic density for the computations, or whatever" + "density is stored in the first compositional field."); + + prm.enter_subsection("Analytical density"); + { + prm.enter_subsection("Function"); + { + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + prm.enter_subsection("Analytical pressure"); + { + prm.enter_subsection("Function"); + { + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + prm.enter_subsection("Analytical velocity"); + { + prm.enter_subsection("Function"); + { + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Time dependent annulus"); + { + use_analytic_density = prm.get_bool ("Use analytic density"); + + prm.enter_subsection("Analytical density"); + { + prm.enter_subsection("Function"); + { + density_function = std::make_unique>(1); + density_function->parse_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + prm.enter_subsection("Analytical pressure"); + { + prm.enter_subsection("Function"); + { + pressure_function = std::make_unique>(1); + pressure_function->parse_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + prm.enter_subsection("Analytical velocity"); + { + prm.enter_subsection("Function"); + { + try + { + velocity_function = std::make_unique>(dim); + velocity_function->parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Analytical velocity.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'\n" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + /** + * Returns the analytic solutions of this model. See the + * corresponding member variable of this class for more information. + */ + std::shared_ptr> get_pressure() const + { + return pressure_function; + } + + std::shared_ptr> get_velocity() const + { + return velocity_function; + } + + std::shared_ptr> get_density() const + { + return density_function; + } + + private: + /** + * Whether to use the analytic density for the benchmark or whatever density is + * stored in the first compositional field. + */ + bool use_analytic_density; + }; + } + + namespace Postprocess + { + /** + * A postprocessor that evaluates the accuracy of the solution. + * + */ + template + class TimeDependentAnnulus : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + private: + std::shared_ptr> ref_func; + + public: + void + initialize () override + { + const MaterialModel::TimeDependentAnnulus &material_model = + Plugins::get_plugin_as_type>(this->get_material_model()); + + ref_func = std::make_unique>(material_model.get_pressure(), + material_model.get_velocity(), + material_model.get_density(), + 1 + dim + 1 + this->n_compositional_fields()); + } + + std::pair + execute (TableHandler &statistics) override + { + const QGauss quadrature_formula (this->get_fe().base_element(this->introspection().base_elements.velocities).degree+2); + + Vector cellwise_errors_ul2 (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_pl2 (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_rhol2 (this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_u(std::pair(0,dim), + this->get_fe().n_components()); + ComponentSelectFunction comp_p(dim, this->get_fe().n_components()); + ComponentSelectFunction comp_rho(dim+2, this->get_fe().n_components()); + + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_ul2, + quadrature_formula, + VectorTools::L2_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_pl2, + quadrature_formula, + VectorTools::L2_norm, + &comp_p); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_rhol2, + quadrature_formula, + VectorTools::L2_norm, + &comp_rho); + + const double u_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_ul2, VectorTools::L2_norm); + const double p_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_pl2, VectorTools::L2_norm); + const double rho_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_rhol2, VectorTools::L2_norm); + + statistics.add_value ("Error_u_l2", u_l2); + statistics.add_value ("Error_p_l2", p_l2); + statistics.add_value ("Error_rho_l2", rho_l2); + + statistics.set_scientific ("Error_u_l2", true); + statistics.set_scientific ("Error_p_l2", true); + statistics.set_scientific ("Error_rho_l2", true); + + std::ostringstream os; + os << std::scientific + << u_l2 + << ", " << p_l2 + << ", " << rho_l2; + + return std::make_pair("Errors u_L2, p_L2, rho_L2", os.str()); + } + }; + } +} diff --git a/benchmarks/time_dependent_annulus/time_dependent_annulus.prm.bak b/benchmarks/time_dependent_annulus/time_dependent_annulus.prm.bak new file mode 100644 index 00000000000..7e9b37ee662 --- /dev/null +++ b/benchmarks/time_dependent_annulus/time_dependent_annulus.prm.bak @@ -0,0 +1,179 @@ +# This is the setup of the time dependent annular flow benchmark +# from Section 5 of +# +# Gassmoeller, Lokavarapu, Bangerth, Puckett (2019): +# Evaluating the Accuracy of Hybrid Finite Element/Particle-In-Cell +# Methods for Modeling Incompressible Stokes Flow. Geophys. J. Int. +# submitted. +# +# It features a spherical annulus with a circular flow and a +# time-independent analytical, but a time-dependent numerical solution, +# which allows to quantify how errors in the advection equation +# influence the accuracy of the Stokes equation. In this example +# the benchmark uses particles to carry density, but it can be +# used for other advection methods as well. + + +set Additional shared libraries = ./plugin/libtime_dependent_annulus.so +set Dimension = 2 +set End time = 0.09817477042468103 +set Output directory = output-time_dependent_annulus +set Use years in output instead of seconds = false + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 1 + set Outer radius = 2 + set Opening angle = 360 + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = 0: function, 1: function + + subsection Function + set Function constants = pi=3.1415926 + set Variable names = x,y + set Function expression = y*sqrt(x^2 + y^2)^6;-x*sqrt(x^2 + y^2)^6 + end +end + +subsection Material model + set Model name = time dependent annulus + set Material averaging = none + + subsection Time dependent annulus + set Use analytic density = false + + subsection Analytical density + subsection Function + set Variable names = x, y + set Function expression = 48*sqrt(x^2 + y^2)^5 + end + end + + subsection Analytical pressure + subsection Function + # The term 512/72 causes the pressure to be zero at the outer boundary R = 2 + set Function expression = (sqrt(x^2 + y^2)^9)/72 - 512/72 + end + end + + subsection Analytical velocity + subsection Function + set Variable names = x, y + set Function expression = y*sqrt(x^2 + y^2)^6;-x*sqrt(x^2 + y^2)^6 + end + end + end +end + +subsection Gravity model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = (x*(x^2 + y^2)/384) + (-y/sqrt(x^2 + y^2)); \ + (y*(x^2 + y^2)/384) + (x/sqrt(x^2 + y^2)) + end +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = density_comp + set Compositional field methods = particles + set Mapped particle properties = density_comp:function[0] +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = 48*sqrt(x^2 + y^2)^5 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +subsection Adiabatic conditions model + set Model name = function + + subsection Function + set Function constants = + set Function expression = 0; 0; 0 + set Variable names = depth + end +end + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = false + set Use discontinuous composition discretization = true +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + end +end + +subsection Mesh refinement + set Initial global refinement = 3 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 + set Refinement fraction = 0 + set Coarsening fraction = 0 +end + +subsection Postprocess + set List of postprocessors = time dependent annulus, particles, visualization + + subsection Visualization + set Output format = vtu + set Number of grouped files = 1 + set Time between graphical output = 0.0009817477042468104 + set List of output variables = density, gravity + end + + subsection Particles + set Time between data output = 0.0009817477042468104 + end +end + +subsection Termination criteria + set Checkpoint on termination = true +end + +subsection Checkpointing + set Time between checkpoint = 7200 +end + +subsection Particles + set Integration scheme = rk2 # or rk4 + set Interpolation scheme = bilinear least squares # or cell average + set List of particle properties = function + set Update ghost particles = true + set Particle generator name = reference cell + set Load balancing strategy = none # not necessary for uniform mesh + + subsection Generator + subsection Reference cell + set Number of particles per cell per direction = 4 # or 5, 6, 7, 10, 15, 20, 32, 45, 64, 80 + end + end + + subsection Function + set Number of components = 2 + set Variable names = x,y + set Function expression = 48*sqrt(x^2 + y^2)^5;if(0. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace aspect +{ + /** + * This is the material model used for the viscoplastic convection + * benchmark models that were presented in the open access Tosi et al. (2015) paper: + * @code + * @Article{T15, + * Author = {Tosi, N. and Stein, C. and Noack, L. and H\"uttig, C. and Maierova, P. and Samuel, H. and Davies, D. R. and Wilson, C. R. and Kramer, S. C. and Thieulot, C. and Glerum, A. and Fraters, M. and Spakman, W. and Rozel, A. and Tackley, P. J.}, + * Title = {A community benchmark for viscoplastic thermal convection in a 2-D square box}, + * Journal = {Geochemistry, Geophysics, Geosystems}, + * Year = {2015} + * Pages = {2175-2196}, + * Volume = {16}, + * Doi = {10.1002/2015GC005807}} + * @endcode + * + * It is a material model that consists of globally constant values for all + * material parameters except density and viscosity. Density is temperature dependent, + * but practically constant through a small value of the thermal expansivity, + * and viscosity depends on temperature, depth and strain rate. + * + * The model is considered incompressible, following the definition + * described in Interface::is_compressible. + * + * @ingroup MaterialModels + */ + namespace TosiBenchmark + { + using namespace dealii; + + + /** + * @ingroup MaterialModels + */ + template + class TosiMaterial : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + /** + * As described in Tosi et al (2015), the viscosity \eta is computed as the + * harmonic average of a linear and nonlinear part. + * + * The linear part is calculated as follows + * (see below for the meaning of the used parameter names): + * $\eta_{lin}(T,z) = \exp(-\ln(\text{eta\_T} * T + \ln(\text{eta\_Z}) * z)$ + * while the strain rate dependent nonlinear part is computed as: + * $\eta_{plast}(\dot\epsilon) = \text{eta\_asterisk} + \frac{\text{sigma\_yield}}{\sqrt(\dot\epsilon:\dot\epsilon)}$ + */ + + //set up additional output for the derivatives + MaterialModel::MaterialModelDerivatives *derivatives; + derivatives = out.template get_additional_output>(); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + if (in.requests_property(MaterialModel::MaterialProperties::viscosity)) + { + out.viscosities[i] = viscosity (in.temperature[i], + in.pressure[i], + in.composition[i], + in.strain_rate[i], + in.position[i]); + } + + out.densities[i] = reference_rho * (1.0 - thermal_alpha * (in.temperature[i] - reference_T)); + out.thermal_expansion_coefficients[i] = thermal_alpha; + out.specific_heat[i] = reference_specific_heat; + out.thermal_conductivities[i] = thermal_k; + out.compressibilities[i] = 0.0; + // Pressure derivative of entropy at the given positions. + out.entropy_derivative_pressure[i] = 0.0; + // Temperature derivative of entropy at the given positions. + out.entropy_derivative_temperature[i] = 0.0; + // Change in composition due to chemical reactions at the + // given positions. The term reaction_terms[i][c] is the + // change in compositional field c at point i. + for (unsigned int c=0; cviscosity_derivative_wrt_strain_rate[i] = 0; + derivatives->viscosity_derivative_wrt_pressure[i] = 0; + } + else + { + const double deviator_strain_rate_norm = in.strain_rate[i].norm(); + const double part1 = (eta_asterisk * deviator_strain_rate_norm + sigma_yield); + + derivatives->viscosity_derivative_wrt_strain_rate[i] = -(0.5*out.viscosities[i]*out.viscosities[i]) + * (sigma_yield/(part1 * part1 * deviator_strain_rate_norm)) * in.strain_rate[i]; + derivatives->viscosity_derivative_wrt_pressure[i] = 0; + } + } + else + { + // finite difference derivative + const double finite_difference_accuracy = 1e-7; + + SymmetricTensor<2,dim> &deta = derivatives->viscosity_derivative_wrt_strain_rate[i]; + + // derivative in xx direction + SymmetricTensor<2,dim> dstrain_rate = in.strain_rate[i]; + dstrain_rate[0][0] += std::fabs(in.strain_rate[i][0][0]) * finite_difference_accuracy; + const double eta_zero_zero = viscosity(in.temperature[i], in.pressure[i], in.composition[i], dstrain_rate, in.position[i]); + deta[0][0] = eta_zero_zero - out.viscosities[i]; + + if (dstrain_rate[0][0] != 0) + deta[0][0] /= std::fabs(in.strain_rate[i][0][0]) * finite_difference_accuracy; + else + deta[0][0] = 0; + + // derivative in xy direction + dstrain_rate = in.strain_rate[i]; + // dstrain_rate in yx direction is multiplied by 0.5, because the symmetric tensor + // is modified by 0.5 in xy and yx direction simultaneously and we compute the combined + // derivative + dstrain_rate[1][0] += 0.5 * std::fabs(in.strain_rate[i][1][0]) * finite_difference_accuracy; + const double eta_one_zero = viscosity(in.temperature[i], in.pressure[i], in.composition[i], dstrain_rate, in.position[i]); + deta[1][0] = eta_one_zero - out.viscosities[i]; + + if (dstrain_rate[1][0] != 0) + deta[1][0] /= std::fabs(in.strain_rate[i][1][0]) * finite_difference_accuracy; + else + deta[1][0] = 0; + + // derivative in yy direction + dstrain_rate = in.strain_rate[i]; + dstrain_rate[1][1] += std::fabs(in.strain_rate[i][1][1]) * finite_difference_accuracy; + const double eta_one_one = viscosity(in.temperature[i], in.pressure[i], in.composition[i], dstrain_rate, in.position[i]); + deta[1][1] = eta_one_one - out.viscosities[i]; + + if (dstrain_rate[1][1] != 0) + deta[1][1] /= std::fabs(in.strain_rate[i][1][1]) * finite_difference_accuracy; + else + deta[1][1] = 0; + + derivatives->viscosity_derivative_wrt_pressure[i] = 0; + } + } + + } + + } + + + + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + * Incompressibility does not necessarily imply that the density is + * constant; rather, it may still depend on temperature or pressure. + * In the current context, compressibility means whether we should + * solve the continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + double viscosity (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const SymmetricTensor<2,dim> &strain_rate, + const Point &position) const; + + /* + * Function to compute the linear viscosity + * according to equation (7) of Tosi et al. 2015. + */ + double viscolin(const double etaT, + const double etaZ, + const double T, + const double depth) const; + + /* + * Function to compute the plastic viscosity + * according to equation (8) of the paper. + */ + double viscoplast(const double eta_asterisk, + const double stress_y, + const double strain_rate_norm) const; + + /** + * The density at reference temperature + */ + double reference_rho; + + /* + * The reference temperature + */ + double reference_T; + + /* + * The thermal expansivity + */ + double thermal_alpha; + + /* + * The reference specific heat + */ + double reference_specific_heat; + + /** + * The thermal conductivity. + */ + double thermal_k; + + /* + * The linear viscosity parameter pertaining to + * the viscosity contrast due to temperature + */ + double eta_T; + + /* + * The linear viscosity parameter pertaining to + * the viscosity contrast due to pressure (depth) + */ + double eta_Z; + + /* + * The effective viscosity at high stresses that is + * part of the plastic viscosity + */ + double eta_asterisk; + + /* + * The constant yield stress that is used in the + * plastic viscosity formula + */ + double sigma_yield; + + /* + * The lower viscosity cut-off value + */ + double eta_minimum; + + /* + * The upper viscosity cut-off value + */ + double eta_maximum; + + /* + * The initial guess of the viscosity + */ + double eta_initial; + + /** + * Whether to use analytical or finite-difference viscosity derivatives + * if the Newton solver is used. + */ + bool use_analytical_derivative; + + }; + + /* + * Function to calculate the viscosity according + * to equation (6) of the paper. + */ + template + double + TosiMaterial:: + viscosity (const double temperature, + const double, + const std::vector &, + const SymmetricTensor<2,dim> &strain_rate, + const Point &) const + { + + // In the first nonlinear iteration of the (pre-refinement steps of the) first time step, + // strain rate is zero, so we set viscosity to eta_initial, a user-defined guess of the viscosity. + if (strain_rate.norm() == 0) + { + return eta_initial; + } + + // Otherwise we compute the linear viscosity and, if needed, the plastic viscosity. + double viscosity = 0.0; + const double visc_linear = viscolin(eta_T,eta_Z,temperature,0); + + if (eta_asterisk == 0.0 && sigma_yield == 0.0) + { + viscosity = visc_linear; + } + else + { + const double visc_plastic = viscoplast(eta_asterisk,sigma_yield,strain_rate.norm()); + + // Compute the harmonic average (equation (6) of the paper) + viscosity = 2.0 / ((1.0 / visc_linear) + (1.0 / visc_plastic)); + } + + // Cut-off the viscosity by user-defined values to avoid possible very large viscosity ratios + viscosity = std::max(std::min(viscosity,eta_maximum),eta_minimum); + + return viscosity; + } + + /* + * Function to compute the linear viscosity + * according to equation (7) of Tosi et al. 2015. + */ + template + double + TosiMaterial:: + viscolin(const double etaT, + const double etaZ, + const double T, + const double z) const + { + + return std::exp((-1.0 * std::log(etaT) * T ) + (std::log(etaZ) * z)); + } + + /* + * Function to compute the plastic viscosity + * according to equation (8) of the paper. + */ + template + double + TosiMaterial:: + viscoplast(const double etaasterisk, + const double stressy, + const double strainratenorm) const + { + return etaasterisk + (stressy/strainratenorm); + } + + + + template + bool + TosiMaterial:: + is_compressible () const + { + return false; + } + + template + void + TosiMaterial::declare_parameters (ParameterHandler &prm) + { + // Default values are for Case 1 of Tosi et al. (2015). + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Tosi benchmark"); + { + prm.declare_entry ("Reference density", "1", + Patterns::Double (0), + "The value of the reference density $\\rho_0$."); + prm.declare_entry ("Reference temperature", "0", + Patterns::Double (0), + "The value of the reference temperature $T_0$. The reference temperature is used " + "in the density calculation."); + prm.declare_entry ("Minimum viscosity", "1e-6", + Patterns::Double (0), + "The value of the minimum cut-off viscosity $\\eta_min$."); + prm.declare_entry ("Maximum viscosity", "1e1", + Patterns::Double (0), + "The value of the maximum cut-off viscosity $\\eta_max$."); + prm.declare_entry ("Initial viscosity", "1e-1", + Patterns::Double (0), + "The value of the initial viscosity guess $\\eta_init$."); + prm.declare_entry ("Thermal conductivity", "1", + Patterns::Double (0), + "The value of the thermal conductivity $k$."); + prm.declare_entry ("Reference specific heat", "1", + Patterns::Double (0), + "The value of the specific heat $cp$."); + prm.declare_entry ("Thermal expansion coefficient", "1e-6", + Patterns::Double (0), + "The value of the thermal expansion coefficient $\\alpha$."); + prm.declare_entry ("Thermal viscosity parameter", "1e5", + Patterns::Double (0), + "The value of the thermal viscosity parameter $\\eta_T$, " + "as used in equation (7) of the paper."); + prm.declare_entry ("Pressure viscosity parameter", "1e0", + Patterns::Double (0), + "The value of the pressure viscosity parameter $\\eta_Z$, " + "as used in equation (7) of the paper."); + prm.declare_entry ("Yield stress", "0", + Patterns::Double (0), + "The value of the plastic viscosity yield stress $\\sigma_yield$, " + "as used in equation (8) of the paper."); + prm.declare_entry ("Nonlinear viscosity constant", "0", + Patterns::Double (0), + "The value of the plastic viscosity constant $\\eta_asterisk$, " + "as used in equation (8) of the paper."); + prm.declare_entry ("Use analytical derivative", "false", + Patterns::Bool (), + "Whether to use the analytical or the finite difference derivative for the Newton method."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + TosiMaterial::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Tosi benchmark"); + { + reference_rho = prm.get_double ("Reference density"); + reference_T = prm.get_double ("Reference temperature"); + thermal_k = prm.get_double ("Thermal conductivity"); + reference_specific_heat = prm.get_double ("Reference specific heat"); + thermal_alpha = prm.get_double ("Thermal expansion coefficient"); + eta_T = prm.get_double ("Thermal viscosity parameter"); + eta_Z = prm.get_double ("Pressure viscosity parameter"); + sigma_yield = prm.get_double ("Yield stress"); + eta_asterisk = prm.get_double ("Nonlinear viscosity constant"); + eta_minimum = prm.get_double ("Minimum viscosity"); + eta_maximum = prm.get_double ("Maximum viscosity"); + eta_initial = prm.get_double ("Initial viscosity"); + use_analytical_derivative = prm.get_bool ("Use analytical derivative"); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = (sigma_yield != 0.0) ? MaterialModel::NonlinearDependence::strain_rate | MaterialModel::NonlinearDependence::temperature | MaterialModel::NonlinearDependence::pressure : MaterialModel::NonlinearDependence::temperature | MaterialModel::NonlinearDependence::pressure; + this->model_dependence.density = MaterialModel::NonlinearDependence::temperature; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + + /** + * A postprocessor that computes some statistics about the + * rate of viscous dissipation, the rate of work done against gravity + * and the error between the two. These diagnostic quantities + * are reported in the Tosi et al. (2015) paper for a visco-plastic + * 2D thermal convection model. + * + * @ingroup Postprocessing + */ + template + class TosiPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for statistics on the rate of viscous dissipation, + * rate of work and the error between the two. + */ + std::pair + execute (TableHandler &statistics) override; + }; + + template + std::pair + TosiPostprocessor::execute (TableHandler &statistics) + { + AssertThrow(this->get_geometry_model().natural_coordinate_system() == aspect::Utilities::Coordinates::CoordinateSystem::cartesian, + ExcMessage("The current calculation of rate of work only makes sense in a Cartesian geometry.")); + + AssertThrow(Plugins::plugin_type_matches>(this->get_material_model()), + ExcMessage("The current calculation of viscous dissipation is only for incompressible models " + "and specifically computes the difference between work and dissipation as requested " + "in the paper of Tosi et al. 2015.")); + + const QGauss quadrature_formula (this->get_fe() + .base_element(this->introspection().base_elements.velocities) + .degree+1); + + const unsigned int n_q_points = quadrature_formula.size(); + std::vector> velocities(n_q_points); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_quadrature_points | + update_gradients | + update_JxW_values); + + // the local integral values of rate of viscous dissipation and work against gravity + double local_dissipation_integral = 0.0; + double local_work = 0.0; + + // the values of the compositional fields are stored as blockvectors for each field + // we have to extract them in this structure + std::vector> prelim_composition_values (this->n_compositional_fields(), + std::vector (n_q_points)); + + typename MaterialModel::Interface::MaterialModelInputs in(n_q_points, + this->n_compositional_fields()); + typename MaterialModel::Interface::MaterialModelOutputs out(n_q_points, + this->n_compositional_fields()); + in.requested_properties = MaterialModel::MaterialProperties::viscosity; + + // loop over active, locally owned cells and + // extract material model input and compute integrals + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + + // retrieve velocities + fe_values[this->introspection().extractors.velocities].get_function_values (this->get_solution(), + velocities); + + // retrieve the input for the material model + in.position = fe_values.get_quadrature_points(); + + fe_values[this->introspection().extractors.pressure].get_function_values (this->get_solution(), + in.pressure); + + fe_values[this->introspection().extractors.temperature].get_function_values (this->get_solution(), + in.temperature); + + for (unsigned int c=0; cn_compositional_fields(); ++c) + fe_values[this->introspection().extractors.compositional_fields[c]].get_function_values + (this->get_solution(),prelim_composition_values[c]); + + for (unsigned int i=0; in_compositional_fields(); ++c) + in.composition[i][c] = prelim_composition_values[c][i]; + } + + fe_values[this->introspection().extractors.velocities].get_function_symmetric_gradients (this->get_solution(), + in.strain_rate); + + // get the output from the material model + this->get_material_model().evaluate(in, out); + + // calculate the local viscous dissipation integral and local rate of work against gravity + for (unsigned int q = 0; q < n_q_points; ++q) + { + const SymmetricTensor<2,dim> strain_rate_dev = deviator(in.strain_rate[q]); + local_dissipation_integral += 2.0 * out.viscosities[q] * strain_rate_dev * strain_rate_dev * fe_values.JxW(q); + local_work += in.temperature[q] * velocities[q][dim-1] * fe_values.JxW(q); + } + } + + // compute the integrals on the whole domain + const double viscous_dissipation + = Utilities::MPI::sum (local_dissipation_integral, this->get_mpi_communicator()); + + const double work + = Utilities::MPI::sum(local_work, this->get_mpi_communicator()); + + // compute the percentage error between rate of dissipation (divided by the surface rayleigh number of the Tosi et al. (2015) + // benchmark (Ra=100)) and rate of work (see equation (21) of the paper) + const double error = 100.0 * (std::abs(work - (viscous_dissipation / 100.0)) / std::max(work, viscous_dissipation / 100.0)); + + if (this->convert_output_to_years() == true) + { + // fill statistics file + // make sure that the columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.add_value ("Viscous dissipation (J/yr)", viscous_dissipation * year_in_seconds); + statistics.set_precision ("Viscous dissipation (J/yr)", 8); + statistics.set_scientific ("Viscous dissipation (J/yr)", true); + statistics.add_value ("Rate of work (Km/yr)", work * year_in_seconds); + statistics.set_precision ("Rate of work (Km/yr)", 8); + statistics.set_scientific ("Rate of work (Km/yr)", true); + statistics.add_value ("Error", error); + statistics.set_precision ("Error", 8); + statistics.set_scientific ("Error", true); + } + else + { + // fill statistics file + // make sure that the columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.add_value ("Viscous dissipation (W)", viscous_dissipation); + statistics.set_precision ("Viscous dissipation (W)", 8); + statistics.set_scientific ("Viscous dissipation (W)", true); + statistics.add_value ("Rate of work (W)", work); + statistics.set_precision ("Rate of work (W)", 8); + statistics.set_scientific ("Rate of work (W)", true); + statistics.add_value ("Error", error); + statistics.set_precision ("Error", 8); + statistics.set_scientific ("Error", true); + } + + std::ostringstream output; + output.precision(3); + if (this->convert_output_to_years() == true) + output << viscous_dissipation *year_in_seconds + << " J/yr " + << work *year_in_seconds + << " J/yr " + << error + << " error"; + else + output << viscous_dissipation + << " W " + << work + << " W " + << error + << " error"; + + return std::pair ("Viscous dissipation, rate of work, error:", + output.str()); + } + + + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace TosiBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(TosiMaterial, + "TosiMaterial", + "A material model that has constant values " + "for all coefficients except the density and viscosity as described in the " + "open access paper of Tosi et al. 2015. " + "The default parameter values are chosen according to Case 1 of the paper. " + "All of the values that define this model are read " + "from a section ``Material model/Tosi model'' in the input file, see " + "Section~\\ref{parameters:Material_model/Tosi_model}." + "\n\n" + "This model uses the following set of equations for the two coefficients that " + "are non-constant (see equation (6) - (10) of the paper): " + "\\begin{align}" + " \\eta(T,z,\\dot \\epsilon) &= 2\\frac{1}{\\frac{1}{\\eta_{lin}(T,z)}\\frac{1}{\\eta_{plast}(\\dot\\epsilon}}, \\\\" + " \\rho(T) &= \\left(1-\\alpha (T-T_0)\\right)\\rho_0," + "\\end{align}" + "where $z$ represents depth." + "\n\n" + "The linear and plastic viscosity parts are defined as follows:" + "\\begin{align}" + " \\eta_{lin}(T,z) &= \\exp(-\\ln(\\eta_T)T+\\ln(\\eta_z)z), \\\\" + " \\eta_{plast}(\\dot\\epsilon) &= \\eta^{*}+\\frac{\\sigma_y}{\\sqrt(\\dot\\epsilon : \\dot\\epsilon)} " + "\\end{align} " + "\n\n" + "Note that this model uses the formulation that assumes an incompressible " + "medium despite the fact that the density follows the law " + "$\\rho(T)=\\rho_0(1-\\alpha(T-T_0))$. ") + ASPECT_REGISTER_POSTPROCESSOR(TosiPostprocessor, + "TosiPostprocessor", + "A postprocessor that computes the viscous dissipation" + "for the whole domain as: " + "$\\left<\\Phi\\right>=\\int_{V} \\tau : \\dot{\\epsilon}dV$ " + "= $\\int_{V} 2\\mu\\dot{\\epsilon}:\\dot{\\epsilon} dV$. " + "Besides the dissipation, for the Tosi et al. (2015) benchmark " + "the rate of work against gravity is " + "calculated, as well as the percentage error between the two: " + "$W$ = $\\int_{V} T u_{y} dV$ and " + "$\\delta$ = $ \\frac{|W - \\frac{\\left<\\Phi\\right>}{Ra}|}{\\max\\left(\\left,\\frac{\\left<\\Phi\\right>}{Ra}\\right)}$. " + "This error W should tend to zero if in steady state the thermal energy is accurately preserved." + "Note that this postprocessor only makes sense for box geometries.") + } +} diff --git a/benchmarks/viscoelastic_beam_modified/20km_opentopbot.prm.bak b/benchmarks/viscoelastic_beam_modified/20km_opentopbot.prm.bak new file mode 100644 index 00000000000..b27baca2f91 --- /dev/null +++ b/benchmarks/viscoelastic_beam_modified/20km_opentopbot.prm.bak @@ -0,0 +1,96 @@ +# This parameter file modifies the 2D benchmark 'viscoelastic_bending_beam'. +# It has been modified to model a much larger beam, and to have an open top +# and bottom boundary to allow the inelastic, low viscosity fluid surrounding the beam to +# be more easily displaced while the beam flexes. +# +# The benchmark examines bending of a viscoelastic beam surrounded by a less dense +# and viscous (inelastic) fluid. Gravitational forces drive initial bending +# (elastic strain) of the beam. The analytic solution is from Geodynamics 3rd Edition by +# Turcotte and Schubert, Chapter 3.10 (eq. 3.85 for flexure and 3.86 for stress). +# Models have been tested for deflections that are no greater than half the thickness of +# the beam. More flexure could potentially lead to a breakdown of the fit since the analytic +# solution assumes small deflection relative to the thickness. + +include $ASPECT_SOURCE_DIR/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam.prm + + +# Global parameters +set Start time = 0 +set End time = 200e3 +set Use years in output instead of seconds = true +set Maximum time step = 1e3 +set Output directory = 20kmh_05drho + +# Model geometry (240x160 km, 1 km spacing) +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 160 + set Y repetitions = 80 + set X extent = 320e3 + set Y extent = 160e3 + end +end + +# Mesh refinement +subsection Mesh refinement + set Initial adaptive refinement = 3 + set Initial global refinement = 0 + set Time steps between mesh refinement = 1 + set Strategy = viscosity +end + +# override boundary conditions: +subsection Boundary velocity model + set Zero velocity boundary indicators = left + set Tangential velocity boundary indicators = right +end + +# Traction Boundary Conditions +subsection Boundary traction model + set Prescribed traction boundary indicators = top: initial lithostatic pressure, bottom: initial lithostatic pressure + + # Set the point for the open top and bottom boundaries + + subsection Initial lithostatic pressure + set Representative point = 320e3, 0 + set Number of integration points = 10000 + end +end + +# Spatial domain of different compositional fields +# Make the beam 9x longer than it is wide to ensure the 'thin' approximation is valid +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = + set Function expression = 0; 0; 0; if ( 180e3>=x && y>=100e3 && y<=120e3, 1, 0) + end +end + +# Material model +# The density contrast has to be small with such a large beam to preserve the small deflection approximation +subsection Material model + set Model name = viscoelastic + + subsection Viscoelastic + set Densities = 2800, 2800, 2800, 2800, 2805 + set Viscosities = 1.e18, 1.e18, 1.e18, 1.e18, 1.e24 + set Elastic shear moduli = 1.e11, 1.e11, 1.e11, 1.e11, 1.e10 + end +end + +# Post processing +subsection Postprocess + subsection Visualization + set Number of grouped files = 1 + end +end + +# Termination criteria +subsection Termination criteria + set Termination criteria = end time +end diff --git a/benchmarks/viscoelastic_beam_modified/20km_opentopbot_weno.prm b/benchmarks/viscoelastic_beam_modified/20km_opentopbot_weno.prm index 3eab684ad1d..5f10ad30d36 100644 --- a/benchmarks/viscoelastic_beam_modified/20km_opentopbot_weno.prm +++ b/benchmarks/viscoelastic_beam_modified/20km_opentopbot_weno.prm @@ -5,17 +5,18 @@ include $ASPECT_SOURCE_DIR/benchmarks/viscoelastic_bending_beam/20km_opentopbot. set Output directory = 20kmh_05drho_weno - subsection Discretization subsection Stabilization parameters # Use WENO limiter for viscoelastic stress components, while using the # bound-preserving limiter for the chemical field set Limiter for discontinuous composition solution = WENO, WENO, WENO, bound preserving + # In this benchmark, the spurious oscillations at the boundaries of the beam # are extremely serious, so we set the linear weight of neighbor cells one # magnitude greater than the default value to make the reconstructed solution # smoother. set WENO linear weight of neighbor cells = 0.01 + # The global maximum and minimum values are only used by the chemical field. set Global composition maximum = 1.0 set Global composition minimum = 0.0 @@ -26,6 +27,7 @@ end subsection Postprocess subsection Visualization set List of output variables = material properties, strain rate, kxrcf indicator + subsection KXRCF indicator set Name of advection field = ve_stress_xy end diff --git a/benchmarks/viscoelastic_beam_modified/20km_opentopbot_weno.prm.bak b/benchmarks/viscoelastic_beam_modified/20km_opentopbot_weno.prm.bak new file mode 100644 index 00000000000..3eab684ad1d --- /dev/null +++ b/benchmarks/viscoelastic_beam_modified/20km_opentopbot_weno.prm.bak @@ -0,0 +1,33 @@ +# This parameter file modifies the benchmark 20kmh_05drho.prm to use the WENO limiter +# for viscoelastic stress components. + +include $ASPECT_SOURCE_DIR/benchmarks/viscoelastic_bending_beam/20km_opentopbot.prm + +set Output directory = 20kmh_05drho_weno + + +subsection Discretization + subsection Stabilization parameters + # Use WENO limiter for viscoelastic stress components, while using the + # bound-preserving limiter for the chemical field + set Limiter for discontinuous composition solution = WENO, WENO, WENO, bound preserving + # In this benchmark, the spurious oscillations at the boundaries of the beam + # are extremely serious, so we set the linear weight of neighbor cells one + # magnitude greater than the default value to make the reconstructed solution + # smoother. + set WENO linear weight of neighbor cells = 0.01 + # The global maximum and minimum values are only used by the chemical field. + set Global composition maximum = 1.0 + set Global composition minimum = 0.0 + end +end + +# Visualize the KXRCF indicator for ve_stress_xy +subsection Postprocess + subsection Visualization + set List of output variables = material properties, strain rate, kxrcf indicator + subsection KXRCF indicator + set Name of advection field = ve_stress_xy + end + end +end diff --git a/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam.prm b/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam.prm index 3d14a096e72..ca656ef8389 100644 --- a/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam.prm +++ b/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam.prm @@ -74,9 +74,9 @@ subsection Discretization set Use discontinuous composition discretization = true subsection Stabilization parameters - set Use limiter for discontinuous composition solution = true set Global composition maximum = 1.e11, 1.e11, 1.e11, 1.0 set Global composition minimum = -1.e11, -1.e11, -1.e11, 0.0 + set Limiter for discontinuous composition solution = bound preserving end end diff --git a/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam.prm.bak b/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam.prm.bak new file mode 100644 index 00000000000..3d14a096e72 --- /dev/null +++ b/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam.prm.bak @@ -0,0 +1,185 @@ +# This parameter file reproduces a 2D benchmark for viscoelastic deformation +# published in "Numerical modelling of magma dynamics coupled to tectonic +# deformation of lithosphere and crust" by Keller, May and Kaus, 2013, +# Geophys. J. Int., v. 195, p. 1406-1422. The model setup and results are +# described in detail in section B.2.3 and figure B5. +# +# The benchmark examines bending and unbending (e.g., recovery) of a +# viscoelastic beam surrounded by a less dense and viscous (inelastic) fluid. +# Gravitational forces drive initial bending (elastic strain) of the beam for +# 50 Kyr, which then recovers its shape over ~ 500 Kyr if gravity is turned +# off. The recovery is driven by the accumulated elastic stresses and thus +# provides a basic test for the viscoelasticity implementation. +# +# Compositional fields are used to track the viscoelastic stresses and material +# representing the beam. To improve the accuracy of tracking the beam interface, +# a discontinuous discretization and bound preserving limiter is used for the +# compositional fields. Significantly, the time step is limited to 1 Kyr through +# the "Maximum time step" parameter and a relatively high (0.5) CFL value. Using +# a constant time step ensures the effective (viscoelastic) viscosity of the +# viscoelastic beam and viscous fluid remains constants throughout the model run. +# +# As currently constructed, the model will run for 50 Kyr with a gravitational +# acceleration of 10 m/s^2. To produce unbending of the beam after the model +# has finished, change the parameter "End time" to 500 Kyr and set the +# gravitational acceleration to 0 m/s^2. A restart file is written every 10 Kyr +# and the parameter "Resume computation = auto" specifies that a model should +# restart from a checkpoint file if one is present. + +# Global parameters +set Dimension = 2 +set Start time = 0 +set End time = 50e3 +set Use years in output instead of seconds = true +set Resume computation = auto +set CFL number = 0.5 +set Maximum time step = 1e3 +set Output directory = output +set Pressure normalization = surface +set Surface pressure = 0. + +# Solver settings +subsection Solver parameters + subsection Stokes solver parameters + set Number of cheap Stokes solver steps = 2000 + end +end + +# Model geometry (7.5x5 km, 0.1 km spacing) +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 75 + set Y repetitions = 50 + set X extent = 7.5e3 + set Y extent = 5e3 + end +end + +# Mesh refinement specifications +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +# Element types +subsection Discretization + set Composition polynomial degree = 2 + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 1 + set Use locally conservative discretization = false + set Use discontinuous temperature discretization = false + set Use discontinuous composition discretization = true + + subsection Stabilization parameters + set Use limiter for discontinuous composition solution = true + set Global composition maximum = 1.e11, 1.e11, 1.e11, 1.0 + set Global composition minimum = -1.e11, -1.e11, -1.e11, 0.0 + end +end + +# Formulation classification +subsection Formulation + set Enable elasticity = true +end + +# Velocity boundary conditions +subsection Boundary velocity model + set Zero velocity boundary indicators = left + set Tangential velocity boundary indicators = bottom, top, right +end + +# Number and name of compositional fields +subsection Compositional fields + set Number of fields = 4 + set Names of fields = ve_stress_xx, ve_stress_yy, ve_stress_xy, beam +end + +# Spatial domain of different compositional fields +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = + set Function expression = 0; 0; 0; if (x<=4.5e3 && y>=2.5e3 && y<=3.0e3, 1, 0) + end +end + +# Composition boundary conditions +subsection Boundary composition model + set Fixed composition boundary indicators = bottom, top, right + set List of model names = initial composition +end + +# Temperature boundary conditions +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top, left, right + set List of model names = box + + subsection Box + set Bottom temperature = 293 + set Left temperature = 293 + set Right temperature = 293 + set Top temperature = 293 + end +end + +# Temperature initial conditions +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 293 + end +end + +# Material model +subsection Material model + set Model name = viscoelastic + + subsection Viscoelastic + set Densities = 2800, 2800, 2800, 2800, 3300 + set Viscosities = 1.e18, 1.e18, 1.e18, 1.e18, 1.e24 + set Elastic shear moduli = 1.e11, 1.e11, 1.e11, 1.e11, 1.e10 + set Fixed elastic time step = 1e3 + set Use fixed elastic time step = false + set Viscosity averaging scheme = maximum composition + end +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10. + end +end + +# Post processing +subsection Postprocess + set List of postprocessors = velocity statistics, basic statistics, temperature statistics, visualization + + subsection Visualization + set List of output variables = material properties, strain rate + set Time between graphical output = 0 + set Interpolate output = true + + subsection Material properties + set List of material properties = density, viscosity + end + end +end + +# Termination criteria +subsection Termination criteria + set Termination criteria = end step + set End step = 500 +end + +subsection Checkpointing + set Steps between checkpoint = 10 +end diff --git a/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_particles.prm.bak b/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_particles.prm.bak new file mode 100644 index 00000000000..f48b09ce194 --- /dev/null +++ b/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_particles.prm.bak @@ -0,0 +1,41 @@ +# This parameter file modifies the benchmark viscoealastic_bending_beam.prm +# to use particles, rather than compositional fields, to track viscoleastic +# stresses and location of the beam. + +include $ASPECT_SOURCE_DIR/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam.prm + +set Output directory = output_viscoelastic_bending_beam_particles + +# Number and name of compositional fields +subsection Compositional fields + set Number of fields = 4 + set Compositional field methods = particles, particles, particles, particles + set Names of fields = ve_stress_xx, ve_stress_yy, ve_stress_xy, beam + set Mapped particle properties = ve_stress_xx:ve_stress_xx, ve_stress_yy:ve_stress_yy, ve_stress_xy:ve_stress_xy, beam:initial beam +end + +# Post processing +subsection Postprocess + set List of postprocessors = velocity statistics, basic statistics, particles, temperature statistics, visualization + + subsection Particles + set Time between data output = 0 + set Data output format = vtu + end +end + +subsection Particles + set Minimum particles per cell = 95 + set Maximum particles per cell = 105 + set Load balancing strategy = remove and add particles + set List of particle properties = initial composition, elastic stress + set Interpolation scheme = nearest neighbor + set Update ghost particles = true + set Particle generator name = random uniform + + subsection Generator + subsection Probability density function + set Number of particles = 4e5 + end + end +end diff --git a/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_weno.prm b/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_weno.prm index d6a698d676f..34f163cfdd1 100644 --- a/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_weno.prm +++ b/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_weno.prm @@ -10,11 +10,13 @@ subsection Discretization # Use WENO limiter for viscoelastic stress components, while using the # bound-preserving limiter for the chemical field set Limiter for discontinuous composition solution = WENO, WENO, WENO, bound preserving + # In this benchmark, the spurious oscillations at the boundaries of the beam # are extremely serious, so we set the linear weight of neighbor cells one # magnitude greater than the default value to make the reconstructed solution # smoother. set WENO linear weight of neighbor cells = 0.01 + # The global maximum and minimum values are only used by the chemical field. set Global composition maximum = 1.0 set Global composition minimum = 0.0 @@ -25,6 +27,7 @@ end subsection Postprocess subsection Visualization set List of output variables = material properties, strain rate, kxrcf indicator + subsection KXRCF indicator set Name of advection field = ve_stress_xy end diff --git a/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_weno.prm.bak b/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_weno.prm.bak new file mode 100644 index 00000000000..d6a698d676f --- /dev/null +++ b/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam_weno.prm.bak @@ -0,0 +1,32 @@ +# This parameter file modifies the benchmark viscoealastic_bending_beam.prm +# to use the WENO limiter for viscoelastic stress components. + +include $ASPECT_SOURCE_DIR/benchmarks/viscoelastic_bending_beam/viscoelastic_bending_beam.prm + +set Output directory = output_viscoelastic_bending_beam_weno + +subsection Discretization + subsection Stabilization parameters + # Use WENO limiter for viscoelastic stress components, while using the + # bound-preserving limiter for the chemical field + set Limiter for discontinuous composition solution = WENO, WENO, WENO, bound preserving + # In this benchmark, the spurious oscillations at the boundaries of the beam + # are extremely serious, so we set the linear weight of neighbor cells one + # magnitude greater than the default value to make the reconstructed solution + # smoother. + set WENO linear weight of neighbor cells = 0.01 + # The global maximum and minimum values are only used by the chemical field. + set Global composition maximum = 1.0 + set Global composition minimum = 0.0 + end +end + +# Visualize the KXRCF indicator for ve_stress_xy +subsection Postprocess + subsection Visualization + set List of output variables = material properties, strain rate, kxrcf indicator + subsection KXRCF indicator + set Name of advection field = ve_stress_xy + end + end +end diff --git a/benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vep.prm.bak b/benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vep.prm.bak new file mode 100644 index 00000000000..ac107463d2e --- /dev/null +++ b/benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vep.prm.bak @@ -0,0 +1,61 @@ +# This parameter file modifies the benchmark gerya_2019_vp.prm +# to include viscoelasticity. + +include $ASPECT_SOURCE_DIR/benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vp.prm + + +# Global parameters +set End time = 500 +set Output directory = output_gerya_2019_vep + +subsection Formulation + set Enable elasticity = true +end + +# Number and name of compositional fields +subsection Compositional fields + set Number of fields = 6 + set Names of fields = ve_stress_xx, ve_stress_yy, ve_stress_xy, block, air, inclusion +end + +# Spatial domain of different compositional fields +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = + set Function expression = 0; 0; 0; \ + if ( ( x<43.75e3 && y>25.e3 && y<75.e3) || (x>56.25e3 && y>25.e3 && y<75.e3) || (y>56.25e3 && y<75.e3 && x>=43.75e3 && x<=56.25e3) || (y<43.75e3 && y>25.e3 && x>=43.75e3 && x<=56.25e3), 1, 0); \ + if (y<=25.e3 || y>=75.e3, 1, 0); \ + if (y<=56.25e3 && y>=43.75e3 && x>=43.75e3 && x<=56.25e3, 1, 0); + end +end + +# Material model +subsection Material model + set Material averaging = harmonic average only viscosity + set Model name = visco plastic + + subsection Visco Plastic + # For identification purposes, nonsensical Prefactor values (1e-50) are assigned to the compositional + # fields tracking elastic stresses, which are not included in the volume fractions computation. + set Prefactors for dislocation creep = 5e-24, 1e-50, 1e-50, 1e-50, 5e-24, 5.e-18, 5e-18 + set Stress exponents for dislocation creep = 1.0 + set Activation energies for dislocation creep = 0. + set Activation volumes for dislocation creep = 0. + set Elastic shear moduli = 1e11 + set Use fixed elastic time step = false + set Fixed elastic time step = 20 + set Viscosity averaging scheme = harmonic + + # Nonsensical cohesion values (1e50) are assigned to the compositional fields tracking elastic stresses + set Angles of internal friction = 37., 0., 0., 0., 37., 0., 0. + set Cohesions = 100.e6, 1.e50, 1.e50, 1.e50, 100.e6, 10.e6, 10.e6 + end +end + +# Post processing +subsection Postprocess + set Run postprocessors on nonlinear iterations = false +end diff --git a/benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vp.prm.bak b/benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vp.prm.bak new file mode 100644 index 00000000000..2768acc033c --- /dev/null +++ b/benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vp.prm.bak @@ -0,0 +1,190 @@ +# Shortening of a visco-plastic block in the absence of gravity +# modified from Exercise 13.2 in Gerya 2019 (Introduction to +# Numerical Geodynamic Modeling). The benchmark has been modified +# to remove viscoelasticity and use slightly different geometries +# for different materials, which allows the edges of features to +# always align with the edges of the mesh with additional global +# refinements. The viscoelastic-plastic version of this setup is +# provided by gerya_2019_vep.prm within this folder. +# +# In detail, the benchmark examines shortening of a viscoelastic +# plastic (here, visco-plastic) block, which contains a weak +# inclusion in the center and a weak medium layer (i.e., sticky +# air) on the top and bottom. The thickness of the weak layers +# and dimensions of the square inclusion have also been modified +# so that element edges always align with these material interfaces +# for uniformly refined meshes of level 3 and up. The velocity on +# the boundaries is 5e-9 m/s, giving a background strain rate of +# 1e-13 1/s. The weak medium and weak inclusion have the following +# material properties: viscosity = 1e17 Pa s, cohesion = 1e7 Pa, +# and internal friction angle = 0. The visco-plastic block has +# the following material properties: viscosity = 1e23 Pa s, +# cohesion = 1e8 Pa, and internal friction angle = 37 degrees. +# Gravity is set to zero and the average pressure is required +# to be equal to zero. + +# Global parameters +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = true +set Nonlinear solver scheme = single Advection, iterated Newton Stokes +set Nonlinear solver tolerance = 1e-5 +set Max nonlinear iterations = 500 +set CFL number = 0.5 +set Maximum time step = 20 +set Output directory = output_gerya_2019_vp +set Timing output frequency = 1 +set Pressure normalization = volume + +# Solver parameters +subsection Solver parameters + subsection Stokes solver parameters + set Stokes solver type = block AMG + set Linear solver tolerance = 1e-7 + set Number of cheap Stokes solver steps = 200 + end + + subsection Newton solver parameters + set Max Newton line search iterations = 0 + set Max pre-Newton nonlinear iterations = 500 # Ensures only defect-correction Picard method is used + set Maximum linear Stokes solver tolerance = 1e-2 + set Nonlinear Newton solver switch tolerance = 1e-5 + set SPD safety factor = 0.9 + set Stabilization preconditioner = SPD + set Stabilization velocity block = SPD + set Use Newton failsafe = false + set Use Newton residual scaling method = false + set Use Eisenstat Walker method for Picard iterations = true + end +end + +# Model geometry (100x100 km, initial 50 km spacing) +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 2 + set Y repetitions = 2 + set X extent = 100e3 + set Y extent = 100e3 + end +end + +# Globally refine the mesh. A minimum of 3 global refinements +# is needed to resolve the edges of the weak viscous inclusion. +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Time steps between mesh refinement = 0 +end + +# Element types +subsection Discretization + set Composition polynomial degree = 2 + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 1 +end + +# Velocity boundary conditions (5e-9 m/s on each boundary) +# The imposed velocity produces a background strain-rate +# of 10e-13 1/s. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left x: function, right x:function, top y: function, bottom y: function + + subsection Function + set Variable names = x,y + set Function constants = vel=0.15778463 + set Function expression = if (x<50e3, vel, -vel); if (y<50e3, -vel, vel); + end +end + +# Number and name of compositional fields +subsection Compositional fields + set Number of fields = 3 + set Names of fields = block, air, inclusion +end + +# Spatial domain of different compositional fields +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = + set Function expression = if ( ( x<43.75e3 && y>25.e3 && y<75.e3) || (x>56.25e3 && y>25.e3 && y<75.e3) || (y>56.25e3 && y<75.e3 && x>=43.75e3 && x<=56.25e3) || (y<43.75e3 && y>25.e3 && x>=43.75e3 && x<=56.25e3), 1, 0); \ + if (y<=25.e3 || y>=75.e3, 1, 0); \ + if (y<=56.25e3 && y>=43.75e3 && x>=43.75e3 && x<=56.25e3, 1, 0); + end +end + +# Composition boundary conditions +subsection Boundary composition model + set Fixed composition boundary indicators = + set List of model names = initial composition +end + +# Temperature boundary conditions +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top, left, right + set List of model names = initial temperature +end + +# Temperature initial conditions (isothermal) +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 293 + end +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0. + end +end + +# Material model +subsection Material model + set Material averaging = harmonic average + set Model name = visco plastic + + subsection Visco Plastic + set Densities = 2700 + set Reference strain rate = 1.e-13 + set Maximum viscosity = 1.e23 + set Minimum viscosity = 1.e17 + set Prefactors for dislocation creep = 5e-24, 5e-24, 5.e-18, 5e-18 + set Stress exponents for dislocation creep = 1.0 + set Activation energies for dislocation creep = 0. + set Activation volumes for dislocation creep = 0. + set Angles of internal friction = 37., 37., 0., 0. + set Cohesions = 100.e6, 100.e6, 10.e6, 10.e6 + end +end + +# Post processing +subsection Postprocess + set List of postprocessors = basic statistics, composition statistics, velocity statistics, visualization + set Run postprocessors on nonlinear iterations = true + + subsection Visualization + set List of output variables = material properties, strain rate, named additional outputs + set Time between graphical output = 0e3 + set Interpolate output = true + set Write higher order output = true + + subsection Material properties + set List of material properties = density, viscosity + end + end +end + +# Termination criteria +subsection Termination criteria + set Termination criteria = end time +end diff --git a/benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vp_damper.prm.bak b/benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vp_damper.prm.bak new file mode 100644 index 00000000000..86000583382 --- /dev/null +++ b/benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vp_damper.prm.bak @@ -0,0 +1,20 @@ +# This parameter file modifies the benchmark gerya_2019_vp.prm +# to include a viscous damper in the plastic viscosity calculation. + +include $ASPECT_SOURCE_DIR/benchmarks/viscoelastic_plastic_shear_bands/gerya_2019/gerya_2019_vp.prm + +set Output directory = output_gerya_2019_damper + +subsection Mesh refinement + set Initial global refinement = 5 +end + +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + set Allow negative pressures in plasticity = true + set Use plastic damper = true + set Plastic damper viscosity = 1e19 + end +end diff --git a/benchmarks/viscoelastic_plastic_shear_bands/kaus_2010/kaus_2010_extension.prm.bak b/benchmarks/viscoelastic_plastic_shear_bands/kaus_2010/kaus_2010_extension.prm.bak new file mode 100644 index 00000000000..f60c43f46c0 --- /dev/null +++ b/benchmarks/viscoelastic_plastic_shear_bands/kaus_2010/kaus_2010_extension.prm.bak @@ -0,0 +1,238 @@ +# This parameter file examines shear band development in a viscoelastic-plastic +# medium that contains a weak viscous inclusion. The experiment is based +# directly on the setup used in Kaus, 2010, Tectonophysics, v. 484, p. 36-47. +# This paper examines both compressional and extensional test cases, and this +# parameter file examines the extensional case. One notable exception to the +# Kaus et al. models and this setup is the lack of cohesion strain-softerning, +# which helps localize deformation along the shear bands. +# +# The key feature of the model is the inclusion of viscoelasticity, +# which leads to a gradual (as opposed to instantaneous for visco-plasticity) +# development of the plastic shear bands above the weak viscous inclusion. +# Kaus (2010) and many other studies (e.g., Glerum et al. 2018, Solid Earth) +# have shown that the shear band angle is directly dependent on the mesh +# resolution. Here, the model contains a very coarse resolution of 100x25 +# grid points (0.4 km grid spacing. Increasing the "Initial global refinement" +# parameter from 0 to 1 or 2 (resolution increases by 2x or 4x) should lead +# to an increase in the shear band angle from 45 degrees to close to 60 +# degrees. Additional key features of the model include the use of the +# Newton solver for improved nonlinear solver convergence and a plastic +# damper term (Duretz et al., 2019) to provide a quasi length-scale +# and smoother viscosity for plastic shear bands. + +# Global parameters +set Dimension = 2 +set Start time = 0 +set End time = 20e3 +set Use years in output instead of seconds = true +set Nonlinear solver scheme = single Advection, iterated Newton Stokes +set Nonlinear solver tolerance = 1e-4 +set Max nonlinear iterations = 100 +set CFL number = 0.5 +set Maximum time step = 1000 +set Output directory = output_kaus_2010_extension +set Timing output frequency = 1 +set Pressure normalization = no + +# Solver settings +subsection Solver parameters + subsection Stokes solver parameters + set Stokes solver type = block AMG + set Number of cheap Stokes solver steps = 2000 + set Linear solver tolerance = 1e-7 + set GMRES solver restart length = 50 + set Use full A block as preconditioner = true + end + + subsection Newton solver parameters + set Max pre-Newton nonlinear iterations = 5 + set SPD safety factor = 0.9 + set Nonlinear Newton solver switch tolerance = 1e-4 + set Max Newton line search iterations = 5 + set Maximum linear Stokes solver tolerance = 1e-7 + set Use Newton residual scaling method = false + set Use Newton failsafe = true + set Stabilization preconditioner = SPD + set Stabilization velocity block = SPD + set Use Eisenstat Walker method for Picard iterations = false + end +end + +# Model geometry (40x10 km, 0.4 km spacing) +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 100 + set Y repetitions = 25 + set X extent = 40e3 + set Y extent = 10e3 + end +end + +# Mesh refinement specifications. +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +# Element types +subsection Discretization + set Composition polynomial degree = 2 + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 1 +end + +# Formulation classification +subsection Formulation + set Enable elasticity = true +end + +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + set Additional tangential mesh velocity boundary indicators = left, right + + subsection Free surface + set Surface velocity projection = normal + end +end + +# Velocity boundary conditions +# The imposed velocity produces a background strain-rate of 2e-15. +subsection Boundary velocity model + set Tangential velocity boundary indicators = bottom + set Prescribed velocity boundary indicators = left x: function, right x:function + + subsection Function + set Variable names = x,y + set Function constants = cm=0.01, year=1, vel=0.12616 + set Function expression = if (x<20e3 , -vel*cm/year, vel*cm/year); 0; + end +end + +# Number and name of compositional fields +subsection Compositional fields + set Number of fields = 5 + set Names of fields = ve_stress_xx, ve_stress_yy, ve_stress_xy, plastic_strain, inclusion + set Types of fields = stress, stress, stress, strain, chemical composition + set Compositional field methods = particles + set Mapped particle properties = ve_stress_xx: ve_stress_xx, \ + ve_stress_yy: ve_stress_yy, \ + ve_stress_xy: ve_stress_xy, \ + plastic_strain: plastic_strain, \ + inclusion: initial inclusion +end + +# Spatial domain of different compositional fields +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = + set Function expression = 0; 0; 0; 0; \ + if (y<=0.4e3 && x>=19.6e3 && x<=20.4e3, 1, 0); + end +end + +# Composition boundary conditions +subsection Boundary composition model + set Fixed composition boundary indicators = + set List of model names = initial composition +end + +# Temperature boundary conditions +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top, left, right + set List of model names = initial temperature +end + +# Temperature initial conditions (isothermal) +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 293 + end +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10. + end +end + +# Material model +subsection Material model + set Model name = visco plastic + set Material averaging = harmonic average only viscosity + + subsection Visco Plastic + set Densities = 2700 + set Reference strain rate = 1.e-15 + set Maximum viscosity = 1.e25 + set Minimum viscosity = 1.e20 + set Prefactors for dislocation creep = 5e-26, 5e-26, 5e-26, 5e-26, 5e-26, 5e-21 + set Stress exponents for dislocation creep = 1.0 + set Activation energies for dislocation creep = 0. + set Activation volumes for dislocation creep = 0. + set Elastic shear moduli = 5.e10, 5.e10, 5.e10, 5.e10, 5.e10, 1.e50 + set Use fixed elastic time step = false + set Fixed elastic time step = 1e3 + set Viscosity averaging scheme = harmonic + set Angles of internal friction = 30. + set Cohesions = 40.e6, 40.e6, 40.e6, 40.e6, 40.e6, 1.e20 + set Strain weakening mechanism = plastic weakening with plastic strain only + set Start plasticity strain weakening intervals = 0.0 + set End plasticity strain weakening intervals = 0.1 + set Cohesion strain weakening factors = 0.1 + set Friction strain weakening factors = 1.0 + set Use plastic damper = true + set Plastic damper viscosity = 1e20 + end +end + +# Post processing +subsection Postprocess + set List of postprocessors = basic statistics, composition statistics, particles, temperature statistics, velocity statistics, visualization + + subsection Visualization + set List of output variables = material properties, strain rate + set Time between graphical output = 0e3 + set Interpolate output = true + + subsection Material properties + set List of material properties = density, viscosity + end + end + + subsection Particles + set Time between data output = 0.e3 + set Data output format = vtu + end +end + +# Termination criteria +subsection Termination criteria + set Termination criteria = end time +end + +subsection Particles + set Minimum particles per cell = 40 + set Maximum particles per cell = 60 + set Load balancing strategy = remove and add particles + set List of particle properties = initial composition, viscoplastic strain invariants, elastic stress + set Interpolation scheme = cell average + set Update ghost particles = true + set Particle generator name = reference cell + + subsection Generator + subsection Reference cell + set Number of particles per cell per direction = 7 + end + end +end diff --git a/benchmarks/viscoelastic_plastic_simple_shear/viscoelastic_plastic_simple_shear.prm.bak b/benchmarks/viscoelastic_plastic_simple_shear/viscoelastic_plastic_simple_shear.prm.bak new file mode 100644 index 00000000000..33285ea8f23 --- /dev/null +++ b/benchmarks/viscoelastic_plastic_simple_shear/viscoelastic_plastic_simple_shear.prm.bak @@ -0,0 +1,146 @@ +# This parameter file constructs a simple shear benchmark, which is adapted from Farrington et al. 2014, +# (Geophysics, Geochemistry, Geosystems). A uniform material undergoes simple shear at a constant rate +# up until time=1. At this point the shearing velocity is reduced to zero, and elastic stresses relax. +# The rheology is viscoelastic plastic, with a cohesion value of 3.5. This value is slightly +# higher than the visco-elastic stress at time=1, meaning that yielding does not occur, and the +# analytic (visco-elastic) solution should be reasonably well approximated. If the cohesion value is reduced +# to below the shear stress value at time t=1 (~3.1411), the shear stress will reach and remain +# at this value until after time t=1 when stresses begin to relax. +# This setup demonstrates an important difference between viscoelastic plastic, and visco-plastic rheology. +# In a comparable setup, the visco-plastic rheology will exhibit yielding in the first velocity iteration, +# as the value pre-yield stress magnitude is 3.5. +# The analytic solution follows the expression in Farrington et al., and describes the +# non-viscous portion of the total stress. This is equivalent to the magnitude of the stored stress +# history tensor. The three independent components of this tensor are tracked with compositional fields +# (ve_stress_xx, ve_stress_yy, ve_stress_xy). The choice of elastic time step (Fixed elastic time step) and +# numerical timestep (Maximum time step) determine the degree of convergence with the analytic +# solution. The values set in the parameter file (0.01) produce a close fit to the analytical solution. +# The stress values are tracked through time in the log file using the composition statistics postprocessor, +# which reports the min, max, and average value of each compositional field after each time step. Given +# that there is no discrepancy between the numerical and elastic time steps and stress averaging is not invoked, +# the min, max, and average stress values remain equal over time. + +# Global parameters +set Dimension = 2 +set Start time = 0 +set End time = 8 +set Use years in output instead of seconds = false +set Maximum time step = 0.01 +set Output directory = output-viscoelastic_plastic_simple_shear +set Pressure normalization = surface +set Surface pressure = 0. +set Nonlinear solver scheme = single Advection, iterated Stokes +set Max nonlinear iterations = 30 +set Nonlinear solver tolerance = 1e-5 +set Max nonlinear iterations in pre-refinement = 0 + +# Solver settings +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-9 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1.0 + set Y extent = 1.0 + set X repetitions = 2 + set Y repetitions = 2 + set X periodic = true + end +end + +# Velocity boundary conditions + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = bottom:function, top:function + + subsection Function + set Function expression = if(t<1, if (y > 0.5, 0.05, 0), 0); \ + 0 + end +end + +# Formulation classification +subsection Formulation + set Enable elasticity = true +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +# Number and name of compositional fields +subsection Compositional fields + set Number of fields = 3 + set Names of fields = ve_stress_xx, ve_stress_yy, ve_stress_xy +end + +# Composition boundary conditions +subsection Boundary composition model + set List of model names = initial composition +end + +# Spatial domain of different compositional fields. +# The elastic stress tensor components are set to 0 initially. +subsection Initial composition model + set Model name = function + + subsection Function + set Function expression = 0.0;0.0;0.0 + end +end + +# Material model +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + # Because we set the stress exponent n=1, the strain rate term of the dislocation creep + # equation becomes 1 as it is set to the power of 0. Furthermore E=0 and P=0 so the exponential + # term equals 1 as well. This leads to a simplification of the dislocation creep equation to: + # eta = 1/2*prefactor^(-1/stress_exponent) + # So this parameter file gives a viscosity eta = 1/2*0.005(⁻1/1) = 100 + set Prefactors for dislocation creep = 0.005 + set Stress exponents for dislocation creep = 1.0 + set Activation energies for dislocation creep = 0. + set Activation volumes for dislocation creep = 0. + set Viscous flow law = dislocation + set Densities = 1 + set Elastic shear moduli = 1.e2 + + # Even though we do not use a fixed elastic time step, + # this parameters needs to be set equal to the "maximum time step" + # as it is used to compute time step 0. + set Fixed elastic time step = 0.01 + set Use fixed elastic time step = false + set Viscosity averaging scheme = maximum composition + set Cohesions = 3.5 + set Angles of internal friction = 0. + set Minimum viscosity = 1e-3 + set Maximum viscosity = 1e3 + end +end + +# The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 293 + end +end + +# Post processing +subsection Postprocess + set List of postprocessors = composition statistics +end diff --git a/benchmarks/viscoelastic_plate_flexure/viscoelastic_plate_flexure.prm b/benchmarks/viscoelastic_plate_flexure/viscoelastic_plate_flexure.prm index 8b4f09583d9..ae3a3bc71a8 100644 --- a/benchmarks/viscoelastic_plate_flexure/viscoelastic_plate_flexure.prm +++ b/benchmarks/viscoelastic_plate_flexure/viscoelastic_plate_flexure.prm @@ -61,9 +61,9 @@ subsection Discretization set Use discontinuous composition discretization = true subsection Stabilization parameters - set Use limiter for discontinuous composition solution = true set Global composition maximum = 1.e11, 1.e11, 1.e11, 1.0, 1.0 set Global composition minimum = -1.e11, -1.e11, -1.e11, 0.0, 0.0 + set Limiter for discontinuous composition solution = bound preserving end end diff --git a/benchmarks/viscoelastic_plate_flexure/viscoelastic_plate_flexure.prm.bak b/benchmarks/viscoelastic_plate_flexure/viscoelastic_plate_flexure.prm.bak new file mode 100644 index 00000000000..8b4f09583d9 --- /dev/null +++ b/benchmarks/viscoelastic_plate_flexure/viscoelastic_plate_flexure.prm.bak @@ -0,0 +1,177 @@ +# This benchmark examines flexure of a finite-length elastic plate based +# on the setup described in Choi et al., 2013, JGR, v.118, p.2429-2444, +# doi:10.1002/jgrb.50148. The model setup has a 50 km long and 5 km thick +# elastic plate (shear modulus: 30 GPa, viscosity: 1e35 Pa s) overlaying a +# viscous layer (viscosity: 1e17 Pa s, 12.5 km thick), which both have a density +# of 2700 kg/m^3. The top of the model is a free surface, while the bottom +# boundary is zero-slip and the sides are free-slip. The upper right corner +# of the viscous layer is replaced with a low density (1890 kg/m^3) elastic +# block, which drives flexure of the elastic plate (right side goes up, left +# side goes down). The total topography obtained after the model has reached +# equilibrium is 330 m, with -146.5 m and 183.5 m of topography, respectively, +# on the left and right sides. The summed value and profiles differ slightly +# from those reported in Choi et al. (see viscoelastic_plate_flexure.png within +# the doc/ subdirectory of this folder), but closely match more recent experiments +# performed by Cedric Thieulot. The curves from the experiments performed by +# Cedric Thieulot are labeled 'ELEFANT, nelx=150', 'ELEFANT, nelx=250', and +# '100x35'. For further details on these additional experiments, visit: +# https://github.com/naliboff/fieldstone/blob/master/python_codes/fieldstone_64/results/flexureplate +# The figure in this folder (viscoelastic_plate_flexure.png) was made and +# provided by Cedric Thieulot. + +# Global parameters +set Dimension = 2 +set Start time = 0 +set End time = 1e3 +set Use years in output instead of seconds = true +set Nonlinear solver scheme = single Advection, single Stokes +set CFL number = 0.1 +set Maximum time step = 5 +set Output directory = output-viscoelastic_plate_flexure +set Pressure normalization = no + +# Model geometry (500 m initial resolution) +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 100 + set Y repetitions = 35 + set X extent = 50.0e3 + set Y extent = 17.5e3 + end +end + +# Mesh refinement specifications (refine to 250 m) +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 1 + set Time steps between mesh refinement = 0 +end + +# Element types. The temperature polynomial degree is reduced +# from the default value of 2 to 1, as temperature is not +# relevant in this problem. +subsection Discretization + set Composition polynomial degree = 2 + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 1 + set Use locally conservative discretization = true + set Use discontinuous temperature discretization = false + set Use discontinuous composition discretization = true + + subsection Stabilization parameters + set Use limiter for discontinuous composition solution = true + set Global composition maximum = 1.e11, 1.e11, 1.e11, 1.0, 1.0 + set Global composition minimum = -1.e11, -1.e11, -1.e11, 0.0, 0.0 + end +end + +# Formulation classification +subsection Formulation + set Enable elasticity = true +end + +# Velocity boundary conditions +subsection Boundary velocity model + set Zero velocity boundary indicators = bottom + set Tangential velocity boundary indicators = left, right +end + +# Free surface advection (vertical or normal) +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + set Additional tangential mesh velocity boundary indicators = left, right + + subsection Free surface + set Surface velocity projection = normal + end +end + +# Number and name of compositional fields +subsection Compositional fields + set Number of fields = 5 + set Names of fields = ve_stress_xx, ve_stress_yy, ve_stress_xy, plate, inclusion +end + +# Spatial domain of different compositional fields +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = + set Function expression = 0; 0; 0; \ + if (y>12.5e3, 1, 0); \ + if (x>=45e3 && y>=7.5e3 && y<=12.5e3, 1, 0); + end +end + +# Composition boundary conditions +subsection Boundary composition model + set Fixed composition boundary indicators = + set List of model names = initial composition +end + +# Temperature boundary and initial conditions +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top, left, right + set List of model names = initial temperature +end + +# Initial temperature is constant +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 273 + end +end + +# Material model +subsection Material model + set Model name = viscoelastic + + subsection Viscoelastic + set Densities = 2700, 2700, 2700, 2700, 2700, 1890 + set Viscosities = 1.e17, 1.e17, 1.e17, 1.e17, 1.e35, 1.e35 + set Elastic shear moduli = 1.e50, 1.e50, 1.e50, 1.e50, 3.e10, 3.e10 + set Fixed elastic time step = 5 + set Use fixed elastic time step = false + set Viscosity averaging scheme = maximum composition + end +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +# Post processing +subsection Postprocess + set List of postprocessors = basic statistics, material statistics, velocity statistics, topography, visualization + + subsection Visualization + set List of output variables = material properties, strain rate, named additional outputs + set Time between graphical output = 100 + set Interpolate output = true + + subsection Material properties + set List of material properties = density, viscosity + end + end + + subsection Topography + set Output to file = true + set Time between text output = 100 + end +end + +# Termination criteria +subsection Termination criteria + set Termination criteria = end time +end diff --git a/benchmarks/viscoelastic_sheared_torsion/viscoelastic_sheared_torsion.prm.bak b/benchmarks/viscoelastic_sheared_torsion/viscoelastic_sheared_torsion.prm.bak new file mode 100644 index 00000000000..f5c6bf5106f --- /dev/null +++ b/benchmarks/viscoelastic_sheared_torsion/viscoelastic_sheared_torsion.prm.bak @@ -0,0 +1,172 @@ +# This parameter file constructs a 3D cube which is rotated around its vertical axis and sheared in the +# xz-plane. It is adapted from Farrington et al. 2014 (Geophysics, Geochemistry, Geosystems), section "3.4. +# Torsion Test in 3-D". According to the authors this is essentially an extension of the simple shear test +# (see the viscoelastic_plastic_simple_shear benchmark prm file) into the third dimension. +# While the model always rotates with a constant rate of 42/360 per unit time, shearing is only applied until +# t = 0.5. At this point the shearing velocity is reduced to zero, and elastic stresses relax. +# For t < 0.5 the analytical expression of the stress is given by: +# tau = exp(-mu/eta*t)*(C2*cos(V*t/h)-C1*sin(V*t/h))-C2 +# and for t >= 0.5: +# tau = exp(-mu/eta*tmax)*(C2*cos(V*tmax/h)-C1*sin(V*tmax/h))-C2)*exp(-mu/eta*(t-tmax)) +# with: +# tmax = 0.5 [s] # time at which shearing stops +# eta = 100 [Pa s] # the shear viscosity +# mu = 100 [Pa] # the shear modulus +# V = 0.3 [m/s] # the shearing velocity +# h = 1 [m] # the height of the box +# omega = 42 [deg/s] # the rotation rate +# C1 = -(V^2*eta^2*mu)/(mu^2*h^2+V^2*eta^2) +# C2 = -(V*h*eta*mu^2)/(mu^2*h^2+V^2*eta^2) +# +# These analytical stresses can be directly compared to the xz-component of the stress output (in the composition +# statistics) from this parameter file. +# Farrington et al., however, look at the stresses in an unrotated frame (their Fig. 1b), in which case both +# the analytical stress and the ASPECT stress component need to be multiplied with cos(omega*t). Note that in the +# Farrington paper the vertical axis is the y-axis, such that their stress component xy is ASPECT's stress +# component xz. +# With the time step size given in this parameter file, stresses are underestimated compared to the analytical +# solution by about 0.9% for t < 0.5 and about 2% for t > 0.5. The fit of the numerical stress to the analytical +# solution can be enhanced by choosing a smaller time step size. + + +# Global parameters +set Dimension = 3 +set Start time = 0 +set End time = 2 +set Use years in output instead of seconds = false + +# This will limit all time steps sizes to equal the "maximum time step" size +set Maximum time step = 0.01 +set Output directory = output-viscoelastic_sheared_torsion +set Pressure normalization = surface +set Surface pressure = 0. +set Nonlinear solver scheme = single Advection, iterated Stokes +set Max nonlinear iterations = 30 +set Nonlinear solver tolerance = 1e-5 +set Max nonlinear iterations in pre-refinement = 0 + +# Solver settings +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-6 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1.0 + set Y extent = 1.0 + set Z extent = 1.0 + set X repetitions = 5 + set Y repetitions = 5 + set Z repetitions = 5 + + # The axes' origins are offset such that the vertical axis runs through the middle of + # the box. This facilitates the velocity boundary condition of the rotational movement. + set Box origin X coordinate = -0.5 + set Box origin Y coordinate = -0.5 + end +end + +subsection Mesh refinement + set Initial global refinement = 0 +end + +# Velocity boundary conditions +subsection Boundary velocity model + set Prescribed velocity boundary indicators = 0:function, 1:function, 2:function, 3:function, 4:function, 5:function + + subsection Function + # circular rotation plus shearing until t=0.5 + set Function expression = if(t<0.5, -sin(atan2(y,x))*sqrt(y*y+x*x)*42/360 + 0.3*z, -sin(atan2(y,x))*sqrt(y*y+x*x)*42/360) ;\ + cos(atan2(y,x))*sqrt(y*y+x*x)*42/360 ;\ + 0 + end +end + +# Formulation classification +subsection Formulation + set Enable elasticity = true +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +# Number and name of compositional fields +subsection Compositional fields + set Number of fields = 6 + set Names of fields = ve_stress_xx, ve_stress_yy, ve_stress_zz, ve_stress_xy, ve_stress_xz, ve_stress_yz +end + +# Composition boundary conditions +subsection Boundary composition model + set List of model names = initial composition +end + +# Spatial domain of different compositional fields. +# The elastic stress tensor components are set to 0 initially. +subsection Initial composition model + set Model name = function + + subsection Function + set Function expression = 0.0;0.0;0.0;0.0;0.0;0.0 + end +end + +# Material model +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + # We use the dislocation creep law to prescribe a constant viscous viscosity. + # Because we set the stress exponent n=1, the strain rate term of the dislocation creep + # equation becomes 1 as it is set to the power of 0. Furthermore E=0 and P=0 so the exponential + # term equals 1 as well. This leads to a simplification of the dislocation creep equation to: + # eta = 1/2*prefactor^(-1/stress_exponent) + # So this parameter file gives a viscosity eta = 1/2*0.005(-1/1) = 100 + set Prefactors for dislocation creep = 0.005 + set Stress exponents for dislocation creep = 1.0 + set Activation energies for dislocation creep = 0. + set Activation volumes for dislocation creep = 0. + set Viscous flow law = dislocation + set Densities = 1 + set Elastic shear moduli = 1.e2 + + # Even though we do not use a fixed elastic time step, + # this parameters needs to be set equal to the "maximum time step" + # as it is used to compute the elastic time step during time step 0. + set Fixed elastic time step = 0.01 + set Use fixed elastic time step = false + set Viscosity averaging scheme = maximum composition + + # Cohesion is set higher than the maximum stress expected in this benchmark, + # such that yielding does not occur + set Cohesions = 15 + set Angles of internal friction = 0. + set Minimum viscosity = 1e-3 + set Maximum viscosity = 1e3 + end +end + +# The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 293 + end +end + +# Postprocessing +subsection Postprocess + set List of postprocessors = composition statistics +end diff --git a/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up.prm.bak b/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up.prm.bak new file mode 100644 index 00000000000..aa4b2f544da --- /dev/null +++ b/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up.prm.bak @@ -0,0 +1,191 @@ +# This parameter file reproduces a 2D analytical benchmark for the build-up +# of stress in an initially unstressed viscoelastic medium subject to a +# constant strain-rate. This benchmark is described in "Robust +# characteristics method for modelling multiphase visco-elasto-plastic +# thermo-mechanical problems" by Gerya and Yuen, 2007, Phys. Earth. Planet. +# Inter., v. 163, p. 83-105. Full details of the benchmark are located in +# section 3.1 and figure 3 of this manuscript. +# +# The analytical solution for viscoelastic stress build-up in +# an incompressible medium with a constant strain-rate is: +# sigma_ij = 2 * edot_ii * eta * (1 - e^(-mu*t/eta)), +# where sigma_ij is the elastic deviatoric stress tensor, edot_ij is +# the deviatoric strain-rate, eta is the background viscosity, mu is the +# shear modulus and t is time. +# +# Following the conditions described in section 3.1 and figure 3 from +# Gerya and Yuen (2007), a 100x100 km body is subject to a constant +# strain-rate of 1.e-14 s^-1 in both the horizontal and vertical directions. +# Constant deformation is driven by inflow and outflow, respectively, +# on the right and bottom walls. The top and left walls are free-slip. +# The material has a viscosity of 1e22 Pa s and a shear modulus of 1e10 Pa. +# With these values, the analytical solution predicts a horizontal +# or vertical viscoelastic stress magnitude of ~ 200 MPa after 250 Kyr +# of deformation. Significantly, the effective "viscoelastic" viscosity +# is enforced to be constant through time by using a constant time step. +# This is achieved by setting a maximum time step (1000 years) much lower +# than the time step size given by the CFL number of 0.5. +# +# This result can be observed by viewing the compositional field values +# representing the horizontal (ve_stress_xx) or vertical (ve_stress_yy) components +# of the viscoelastic stress tensor. Significantly, the composition is not +# fixed on any boundary in order to prevent the formation of boundary artifacts +# in the compositional fields tracking viscoelastic stresses. + +# Global parameters +set Dimension = 2 +set Start time = 0 +set End time = 250e3 +set Use years in output instead of seconds = true +set Nonlinear solver scheme = single Advection, single Stokes +set Nonlinear solver tolerance = 1e-5 +set Max nonlinear iterations = 1 +set CFL number = 0.5 +set Maximum time step = 1000 +set Output directory = output +set Timing output frequency = 1 +set Pressure normalization = surface +set Surface pressure = 0. + +# Solver settings +subsection Solver parameters + subsection Stokes solver parameters + set Use direct solver for Stokes system = false + set Linear solver tolerance = 1e-7 + set Number of cheap Stokes solver steps = 2000 + end +end + +# Model geometry (100x100 km, 2 km spacing) +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 50 + set Y repetitions = 50 + set X extent = 100e3 + set Y extent = 100e3 + end +end + +# Mesh refinement specifications +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +# Element types +subsection Discretization + set Composition polynomial degree = 2 + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 1 +end + +# Formulation classification +subsection Formulation + set Enable elasticity = true +end + +# Velocity boundary conditions +subsection Boundary velocity model + set Tangential velocity boundary indicators = top, left + set Prescribed velocity boundary indicators = bottom y:function, right x:function + + subsection Function + set Variable names = x,y + set Function constants = cm=0.01, year=1, vel=3.154 + set Function expression = if (x>50e3 , vel*cm/year, 0.); if (y<50e3 , vel*cm/year, 0.); + end +end + +# Number and name of compositional fields +subsection Compositional fields + set Number of fields = 3 + set Names of fields = ve_stress_xx, ve_stress_yy, ve_stress_xy +end + +# Spatial domain of different compositional fields +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = + set Function expression = 0; 0; 0; + end +end + +# Composition boundary conditions +# We specify that no boundaries have a fixed composition +# in order to prevent boundary effects from developing +# in the compositional fields tracking viscoelastic stresses. +subsection Boundary composition model + set Fixed composition boundary indicators = + set List of model names = initial composition +end + +# Temperature boundary conditions +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top, left, right + set List of model names = box + + subsection Box + set Bottom temperature = 293 + set Left temperature = 293 + set Right temperature = 293 + set Top temperature = 293 + end +end + +# Temperature initial conditions +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 293 + end +end + +# Material model +subsection Material model + set Model name = viscoelastic + + subsection Viscoelastic + set Densities = 2800 + set Viscosities = 1.e22 + set Elastic shear moduli = 1.e10 + set Use fixed elastic time step = false + set Fixed elastic time step = 1e3 + set Viscosity averaging scheme = harmonic + end +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0. + end +end + +# Post processing +subsection Postprocess + set List of postprocessors = basic statistics, composition statistics, temperature statistics, velocity statistics, visualization + + subsection Visualization + set List of output variables = material properties, strain rate + set Time between graphical output = 10e3 + set Interpolate output = true + + subsection Material properties + set List of material properties = density, viscosity + end + end +end + +# Termination criteria +subsection Termination criteria + set Termination criteria = end time +end diff --git a/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_particles.prm.bak b/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_particles.prm.bak new file mode 100644 index 00000000000..220b661bdd5 --- /dev/null +++ b/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_particles.prm.bak @@ -0,0 +1,43 @@ +# This parameter file modifies the benchmark viscoelastic_stress_build_up.prm +# to use particles, rather than compositional fields, to track viscoleastic +# stresses. + +include $ASPECT_SOURCE_DIR/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up.prm + +set Output directory = output_viscoelastic_stress_build-up_particles + +# Number and name of compositional fields +subsection Compositional fields + set Compositional field methods = particles, particles, particles + set Mapped particle properties = ve_stress_xx:ve_stress_xx, ve_stress_yy:ve_stress_yy, ve_stress_xy:ve_stress_xy +end + +# Post processing +subsection Postprocess + set List of postprocessors = basic statistics, composition statistics, particles, temperature statistics, velocity statistics, visualization + + subsection Visualization + set Time between graphical output = 0e3 + end + + subsection Particles + set Time between data output = 0 + set Data output format = vtu + end +end + +subsection Particles + set Minimum particles per cell = 25 + set Maximum particles per cell = 35 + set Load balancing strategy = remove and add particles + set List of particle properties = initial composition, elastic stress + set Interpolation scheme = bilinear least squares + set Update ghost particles = true + set Particle generator name = random uniform + + subsection Generator + subsection Probability density function + set Number of particles = 1e5 + end + end +end diff --git a/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_yield.prm.bak b/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_yield.prm.bak new file mode 100644 index 00000000000..a0d946e36fc --- /dev/null +++ b/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_yield.prm.bak @@ -0,0 +1,43 @@ +# This parameter file modifies the benchmark viscoelastic_stress_build-up.prm +# to use the Visco Plastic material model and include a constant +# yield stress of 100 MPa. Without the imposed yield stress, the viscoelastic +# stress will build up to ~ 200 MPa. However, the imposed yield stress will +# truncate the viscoelastic stresses at the yield stress magnitude. +# For additional information on the model setup and analytical solution, +# see viscoelastic_stress_build-up.prm, which is located in this folder. +# +# The results can be observed by viewing the compositional field values +# representing the horizontal (ve_stress_xx) or vertical (ve_stress_yy) components +# of the viscoelastic stress tensor. Significantly, the stress near the +# model boundaries is incorrect due to the compositional field boundary +# conditions, which are based on the initial compositional values (e.g., zero). +# This leads to oscillations in the stress field near the boundaries, which +# decay towards a constant value in the model interior as the stresses build up to +# 100 MPa. + +include $ASPECT_SOURCE_DIR/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up.prm + +set Nonlinear solver scheme = single Advection, iterated Stokes +set Nonlinear solver tolerance = 1e-5 +set Max nonlinear iterations = 100 +set End time = 100e3 + +# Material model +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + set Viscous flow law = dislocation + set Prefactors for dislocation creep = 5e-23 + set Stress exponents for dislocation creep = 1.0 + set Activation energies for dislocation creep = 0. + set Activation volumes for dislocation creep = 0. + set Elastic shear moduli = 1.e10 + set Use fixed elastic time step = false + set Fixed elastic time step = 1e3 + set Viscosity averaging scheme = harmonic + set Angles of internal friction = 0. + set Cohesions = 100.e6 + set Densities = 2800 + end +end diff --git a/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_yield_particles.prm.bak b/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_yield_particles.prm.bak new file mode 100644 index 00000000000..fb937f42ef6 --- /dev/null +++ b/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up_yield_particles.prm.bak @@ -0,0 +1,74 @@ +# This parameter file modifies the benchmark viscoelastic_stress_build-up.prm +# to use the Visco Plastic material model and include a constant +# yield stress of 100 MPa. Without the imposed yield stress, the viscoelastic +# stress will build up to ~ 200 MPa. However, the imposed yield stress will +# truncate the viscoelastic stresses at the yield stress magnitude. +# For additional information on the model setup and analytical solution, +# see viscoelastic_stress_build-up.prm, which is located in this folder. +# +# The results can be observed by viewing the compositional field values +# representing the horizontal (ve_stress_xx) or vertical (ve_stress_yy) components +# of the viscoelastic stress tensor or the equivalent values on particles, +# which are used to store and track the viscoelastic stresses. This parameter +# file differs from viscoelastic_stress_build-up_yield.prm only in the use +# of active particles to track the elastic stresses. + +include $ASPECT_SOURCE_DIR/benchmarks/viscoelastic_stress_build-up/viscoelastic_stress_build-up.prm + +set Nonlinear solver scheme = single Advection, iterated Stokes +set Nonlinear solver tolerance = 1e-5 +set Max nonlinear iterations = 100 +set End time = 100e3 +set Output directory = output_viscoelastic_stress_build-up_yield_particles + +# Number and name of compositional fields +subsection Compositional fields + set Compositional field methods = particles, particles, particles + set Mapped particle properties = ve_stress_xx:ve_stress_xx, ve_stress_yy:ve_stress_yy, ve_stress_xy:ve_stress_xy +end + +# Material model +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + set Viscous flow law = dislocation + set Prefactors for dislocation creep = 5e-23 + set Stress exponents for dislocation creep = 1.0 + set Activation energies for dislocation creep = 0. + set Activation volumes for dislocation creep = 0. + set Elastic shear moduli = 1.e10 + set Use fixed elastic time step = false + set Fixed elastic time step = 1e3 + set Viscosity averaging scheme = harmonic + set Angles of internal friction = 0. + set Cohesions = 100.e6 + set Densities = 2800 + end +end + +# Post processing +subsection Postprocess + set List of postprocessors = basic statistics, composition statistics, particles, temperature statistics, velocity statistics, visualization + + subsection Particles + set Time between data output = 0 + set Data output format = vtu + end +end + +subsection Particles + set Minimum particles per cell = 25 + set Maximum particles per cell = 35 + set Load balancing strategy = remove and add particles + set List of particle properties = initial composition, elastic stress + set Interpolation scheme = bilinear least squares + set Update ghost particles = true + set Particle generator name = random uniform + + subsection Generator + subsection Probability density function + set Number of particles = 1e5 + end + end +end diff --git a/benchmarks/viscosity_grooves/viscosity_grooves.cc.bak b/benchmarks/viscosity_grooves/viscosity_grooves.cc.bak new file mode 100644 index 00000000000..9b0eddf9ac3 --- /dev/null +++ b/benchmarks/viscosity_grooves/viscosity_grooves.cc.bak @@ -0,0 +1,473 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace ViscosityGroovesBenchmark + { + using namespace dealii; + + namespace AnalyticSolutions + { + + + Tensor<1,2> + ViscosityGrooves_velocity (const Point<2> &pos) + { + const double x = pos[0]; + const double y = pos[1]; + const double v_x = x*x*x*y+x*x+x*y+x; + const double v_y = -1.5*x*x*y*y-2*x*y-0.5*y*y-y; + return Point<2> (v_x,v_y); + } + + double + ViscosityGrooves_pressure (const Point<2> &pos, + const GeometryModel::Interface<2> &geometry_model) + { + const double x = pos[0]; + const double y = pos[1]; + const GeometryModel::Box<2> *geometry + = dynamic_cast*> (&geometry_model); + const double L=geometry->get_extents()[0]; + return x*x*y*y+x*y+5. - pow(L,4.)/9.-pow(L,2.)/4.-5.; + } + + double + ViscosityGrooves_pressure (const Point<2> &, const GeometryModel::Interface<3> &) + { + Assert (false, ExcNotImplemented()); + return 0.; + } + + template + class FunctionViscosityGrooves : public Function + { + public: + FunctionViscosityGrooves (const GeometryModel::Interface &geometry_model) + : + Function(dim+2), + geometry_model (geometry_model) + {} + + void vector_value (const Point &pos, + Vector &values) const override + { + Assert (dim == 2, ExcNotImplemented()); + Assert (values.size() >= 4, ExcInternalError()); + + const Point<2> p (pos[0], pos[1]); + + const Tensor<1,2> v = AnalyticSolutions::ViscosityGrooves_velocity (p); + values[0] = v[0]; + values[1] = v[1]; + values[2] = AnalyticSolutions::ViscosityGrooves_pressure (p, geometry_model); + } + + private: + const GeometryModel::Interface &geometry_model; + }; + } + + + template + class ViscosityGroovesBoundary : public BoundaryVelocity::Interface, public aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + ViscosityGroovesBoundary(); + + /** + * Return the boundary velocity as a function of position. + */ + Tensor<1,dim> + boundary_velocity (const types::boundary_id , + const Point &position) const override; + + private: + const double epsilon; + + }; + + + /** + * @note This benchmark only talks about the flow field, not about a + * temperature field. All quantities related to the temperature are + * therefore set to zero in the implementation of this class. + * + * @ingroup MaterialModels + */ + template + class ViscosityGroovesMaterial : public MaterialModel::Interface + { + public: + /** + * @name Physical parameters used in the basic equations + * @{ + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const Point &pos = in.position[i]; + const double x = pos[0]; + const double y = pos[1]; + out.viscosities[i] = -std::sin(x*x*y*y+x*y+5.)+1.+epsilon; + out.densities[i] = 1.; + out.compressibilities[i] = 0.; + out.specific_heat[i] = 0.; + out.thermal_expansion_coefficients[i] = 0.; + out.thermal_conductivities[i] = 0.; + } + } + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + * Incompressibility does not necessarily imply that the density is + * constant; rather, it may still depend on temperature or pressure. + * In the current context, compressibility means whether we should + * solve the continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + double get_epsilon() const; + + double epsilon; + + }; + + + template + bool + ViscosityGroovesMaterial:: + is_compressible () const + { + return false; + } + + template + void + ViscosityGroovesMaterial::declare_parameters (ParameterHandler &prm) + { + //create a global section in the parameter file for parameters + //that describe this benchmark. note that we declare them here + //in the material model, but other kinds of plugins (e.g., the gravity + //model below) may also read these parameters even though they do not + //declare them + prm.enter_subsection("ViscosityGrooves benchmark"); + { + prm.declare_entry("Viscosity parameter", "0.1", + Patterns::Double (0.), + "Viscosity parameter epsilon in the ViscosityGrooves benchmark."); + } + prm.leave_subsection(); + } + + + template + void + ViscosityGroovesMaterial::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("ViscosityGrooves benchmark"); + { + epsilon = prm.get_double ("Viscosity parameter"); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = MaterialModel::NonlinearDependence::none; + this->model_dependence.density = MaterialModel::NonlinearDependence::none; + this->model_dependence.compressibility = MaterialModel::NonlinearDependence::none; + this->model_dependence.specific_heat = MaterialModel::NonlinearDependence::none; + this->model_dependence.thermal_conductivity = MaterialModel::NonlinearDependence::none; + } + + template + double + ViscosityGroovesMaterial::get_epsilon() const + { + return epsilon; + } + + template + ViscosityGroovesBoundary::ViscosityGroovesBoundary () + : + epsilon (0.) + {} + + template <> + Tensor<1,2> + ViscosityGroovesBoundary<2>:: + boundary_velocity (const types::boundary_id , + const Point<2> &p) const + { + return AnalyticSolutions::ViscosityGrooves_velocity (p); + } + + + template <> + Tensor<1,3> + ViscosityGroovesBoundary<3>:: + boundary_velocity (const types::boundary_id , + const Point<3> &) const + { + Assert (false, ExcNotImplemented()); + return Tensor<1,3>(); + } + + /** + * Gravity model for the ViscosityGrooves benchmark + */ + + template + class ViscosityGroovesGravity : public aspect::GravityModel::Interface + { + public: + Tensor<1,dim> gravity_vector (const Point &pos) const override; + + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + double epsilon; + + }; + + template + Tensor<1,dim> + ViscosityGroovesGravity:: + gravity_vector(const Point &pos) const + { + const double x=pos[0]; + const double y=pos[1]; + Tensor<1,dim> g; + + const double eta=-std::sin(x*x*y*y+x*y+5.)+1.+epsilon; + + const double costerm=std::cos(x*x*y*y+x*y+5.); + + const double deta_dx=-y*(2.*x*y+1.)*costerm; + const double deta_dy=-x*(2.*x*y+1.)*costerm; + + const double dpdx=2. * x *y*y +y ; + const double dpdy=2. * x*x*y +x ; + + const double exx= 3.*x*x * y +2.*x +y +1.; + const double eyy=-3.*x*x * y -2.*x -y -1.; + + const double exy=0.5*(x*x*x + x -3.*x*y*y -2.*y); + const double eyx=0.5*(x*x*x + x -3.*x*y*y -2.*y); + + const double dexxdx= 6.*x*y+2.; + const double deyxdy=-3.*x*y-1.; + + const double dexydx= 0.5*(3.*x*x +1. -3.*y*y); + const double deyydy= -3.*x*x -1.; + + const double gx =-dpdx + 2.*eta*dexxdx + 2.*deta_dx*exx + 2.*eta*deyxdy + 2.*deta_dy*eyx; + const double gy =-dpdy + 2.*eta*dexydx + 2.*deta_dx*exy + 2.*eta*deyydy + 2.*deta_dy*eyy; + + g[0]=-gx; + g[1]=-gy; + + return g; + } + + template + void + ViscosityGroovesGravity::declare_parameters (ParameterHandler &) + { + //nothing to declare here. This plugin will however, read parameters + //declared by the material model in the "ViscosityGrooves benchmark" section + } + + template + void + ViscosityGroovesGravity::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("ViscosityGrooves benchmark"); + { + epsilon = prm.get_double ("Viscosity parameter"); + } + prm.leave_subsection(); + } + + + /** + * A postprocessor that evaluates the accuracy of the solution. + * + * The implementation of error evaluators that correspond to the + * benchmarks defined in the Donea and Huerta FEM book (see manual). + */ + template + class ViscosityGroovesPostprocessor : public Postprocess::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &statistics) override; + }; + + template + std::pair + ViscosityGroovesPostprocessor::execute (TableHandler &) + { + std::shared_ptr> ref_func; + { + + ref_func = std::make_unique>(this->get_geometry_model()); + } + + const QGauss quadrature_formula (this->introspection().polynomial_degree.velocities+2); + + Vector cellwise_errors_u (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_p (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_ul2 (this->get_triangulation().n_active_cells()); + Vector cellwise_errors_pl2 (this->get_triangulation().n_active_cells()); + + ComponentSelectFunction comp_u(std::pair(0,dim), + dim+2); + ComponentSelectFunction comp_p(dim, dim+2); + + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_u, + quadrature_formula, + VectorTools::L1_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_p, + quadrature_formula, + VectorTools::L1_norm, + &comp_p); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_ul2, + quadrature_formula, + VectorTools::L2_norm, + &comp_u); + VectorTools::integrate_difference (this->get_mapping(),this->get_dof_handler(), + this->get_solution(), + *ref_func, + cellwise_errors_pl2, + quadrature_formula, + VectorTools::L2_norm, + &comp_p); + + const double u_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_u, VectorTools::L1_norm); + const double p_l1 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_p, VectorTools::L1_norm); + const double u_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_ul2, VectorTools::L2_norm); + const double p_l2 = VectorTools::compute_global_error(this->get_triangulation(), cellwise_errors_pl2, VectorTools::L2_norm); + + std::ostringstream os; + + os << std::scientific << u_l1 + << ", " << p_l1 + << ", " << u_l2 + << ", " << p_l2; + + return std::make_pair("Errors u_L1, p_L1, u_L2, p_L2:", os.str()); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace ViscosityGroovesBenchmark + { + ASPECT_REGISTER_MATERIAL_MODEL(ViscosityGroovesMaterial, + "ViscosityGroovesMaterial", + "A material model that corresponds to the `ViscosityGrooves' benchmark. " + "See the manual for more information.") + + ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(ViscosityGroovesBoundary, + "ViscosityGroovesBoundary", + "Implementation of the velocity boundary conditions for the " + "`ViscosityGrooves' benchmark. See the manual for more information about this " + "benchmark.") + + ASPECT_REGISTER_POSTPROCESSOR(ViscosityGroovesPostprocessor, + "ViscosityGroovesPostprocessor", + "A postprocessor that compares the solution of the `ViscosityGrooves' benchmark " + "with the one computed by ASPECT " + "and reports the error. See the manual for more information.") + + ASPECT_REGISTER_GRAVITY_MODEL(ViscosityGroovesGravity, + "ViscosityGroovesGravity", + "A gravity model in corresponding to the `ViscosityGrooves' benchmark. " + "See the manual for more information.") + } +} diff --git a/benchmarks/viscosity_grooves/viscosity_grooves.prm.bak b/benchmarks/viscosity_grooves/viscosity_grooves.prm.bak new file mode 100644 index 00000000000..d7c2da3015f --- /dev/null +++ b/benchmarks/viscosity_grooves/viscosity_grooves.prm.bak @@ -0,0 +1,82 @@ +############### Global parameters +# This is a manufactured solution by Dave May (unpublished). + +set Additional shared libraries = ./libviscosity_grooves.so +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = false +set Nonlinear solver scheme = single Advection, single Stokes +set Output directory = output_viscosity_grooves +set Pressure normalization = volume + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 2 + end +end + +#Boundary conditions + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = 0 : ViscosityGroovesBoundary, \ + 1 : ViscosityGroovesBoundary, \ + 2 : ViscosityGroovesBoundary, \ + 3 : ViscosityGroovesBoundary +end + +subsection Material model + set Model name = ViscosityGroovesMaterial +end + +subsection Gravity model + set Model name = ViscosityGroovesGravity +end + +# This is the epsilon parameter + +subsection ViscosityGrooves benchmark + set Viscosity parameter = 0.01 +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the discretization + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, ViscosityGroovesPostprocessor + + subsection Visualization + set Output format = vtu + set List of output variables = density, viscosity, strain rate, gravity + end +end + +# Because it is a benchmark lower solver tolerance is set. + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-12 + set Number of cheap Stokes solver steps = 0 + end +end diff --git a/benchmarks/yamauchi_takei_2016_anelasticity/anelasticity_temperature.cc.bak b/benchmarks/yamauchi_takei_2016_anelasticity/anelasticity_temperature.cc.bak new file mode 100644 index 00000000000..e4b7e8fe57a --- /dev/null +++ b/benchmarks/yamauchi_takei_2016_anelasticity/anelasticity_temperature.cc.bak @@ -0,0 +1,402 @@ +/* + Copyright (C) 2016 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include "anelasticity_temperature.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace InitialTemperature + { + template + AnelasticVs2T::AnelasticVs2T () + {} + + template + void + AnelasticVs2T::initialize () + { + Utilities::AsciiDataInitial::initialize(1); + } + +// set up Vs function that Brent minimization operates on + template + double + AnelasticVs2T:: + fVs (double x, + const double depth, + const double absolute_Vs, + const double mu0, + const double dmudT, + const double dmudP, + const double viscosity_prefactor, + const double activation_energy, + const double activation_volume, + const double solidus_gradient, + const bool use_original_model) const + { + return std::abs(yamauchi_takei_Vs(x,depth,mu0,dmudT,dmudP,viscosity_prefactor,activation_energy,activation_volume + ,solidus_gradient,use_original_model)-absolute_Vs); + } + +// set up volume change function that Brent minimization operates on + template + double + AnelasticVs2T:: + fdV (double x, const double bulk_modulus, const double bulk_modulus_pressure_derivative, const double pressure ) const + { + return std::abs((bulk_modulus*(3./2.)*(std::pow(x,7./3.)-std::pow(x,5./3.))*(1+(((3./4.)* + (bulk_modulus_pressure_derivative-4))*(std::pow(x,2./3.)-1))))-pressure); + } + +// set up initial temperature + template + double + AnelasticVs2T:: + initial_temperature (const Point &position) const + { + // determine depth + double depth; + depth = this->get_geometry_model().depth(position); + + // declare temperature + double temperature; + + // read absolute Vs in from ascii file + const double absolute_Vs = Utilities::AsciiDataInitial::get_data_component(position,0); + + if (depth >= no_perturbation_depth) + { + // convert absolute Vs into temperature + // check if using Yamauchi & Takei 2016 parameterization + if (use_yamauchi_takei == true) + { + // specify anelasticity parameters + const double mu0=72.45; + const double dmudT=-0.01094; + const double dmudP=1.987; + const double viscosity_prefactor=6.22e21; + const double activation_energy=462.5e3; + const double activation_volume=7.913e-6; + const double solidus_gradient=1.018; + // specify Brent algorithm parameters + const double a=273; + const double b=3273; + using Result = std::pair; + // create fVs function to use in Brent minimization and calculate temperature + auto bfunc = [ &,this] (double x) + { + return fVs(x, depth, absolute_Vs, mu0, dmudT,dmudP, + viscosity_prefactor,activation_energy,activation_volume,solidus_gradient,use_original_model); + }; + // determine maximum Vs + double maximum_Vs; + int fail; + maximum_Vs=yamauchi_takei_Vs(273.,depth,mu0,dmudT,dmudP,viscosity_prefactor,activation_energy,activation_volume + ,solidus_gradient,use_original_model); + + // set number of fails to zero + fail=0; + // where absolute Vs exceeds maximum Vs, set temperature to 273 K + if (absolute_Vs>maximum_Vs) + { + temperature=273.; + fail=fail+1; + std::cout << "Vs too fast for sensible temperature for " << fail << " points!" << std::endl; + } + else + { + Result r1 = boost::math::tools::brent_find_minima(bfunc,a,b,16); + temperature=r1.first; + } + } + else + { + Assert (false, ExcNotImplemented()); + return 273.; + } + } + else + { + // set temperature to constant above specified depth + temperature = reference_temperature; + } + // return the absolute temperature in Kelvin + return temperature; + } + + template + double + AnelasticVs2T:: + yamauchi_takei_Vs (double temperature, + double depth, + const double mu0, + const double dmudT, + const double dmudP, + const double viscosity_prefactor, + const double activation_energy, + const double activation_volume, + const double solidus_gradient, + const bool use_original_model) const + { + // specify anelasticity parameters + const double critical_homologous_temperature = 0.94; + const double reduction_factor = 5; + const double background_amplitude = 0.664; + const double background_slope = 0.38; + const double peak_period = 6e-5; + const double melt_viscosity_factor = 0; + const double melt_peak_factor = 0; + const double reference_temperature = 1473; + const double reference_pressure = 1.5e9; + const double grain_size = 1e-3; + const double reference_grain_size = 1e-3; + const double grain_size_exponent = 3; + const double pressure_gradient = 3e-5; + const double gas_constant=8.3145; + // specify Grose & Afonso (2013) density parameters + const double a=1; + const double b=3; + const double bulk_modulus=130e9; + const double bulk_modulus_pressure_derivative=4.8; + const double gruneisen_parameter=6; + const double reference_density=3330; + // specify original density parameters + const double original_density=3291; + const double original_thermal_expansivity=3.59e-5; + const double original_bulk_modulus=115.2; + // initialize solidus + const double T_solidus = 1326.0 + 273 + (((depth-50000)/1e3)*solidus_gradient); + // initialize homologous_temperature + double homologous_temperature = temperature/T_solidus; + // initialize pressures + double pressure = depth/pressure_gradient; + // declare other parameters + double viscosity,viscosity_reduction_factor,peak_amplitude,peak_width,isothermal_volume_change; + double compressibility,pressure_dependent_density,integrated_thermal_expansivity,density; + double unrelaxed_compliance,storage_compliance,period,anelastic_Vs; + // begin calculation of Vs + if (homologous_temperature=critical_homologous_temperature) && (homologous_temperature<1)) + { + viscosity_reduction_factor=std::exp((-1*((homologous_temperature-critical_homologous_temperature)/(homologous_temperature- + (homologous_temperature*critical_homologous_temperature))))*std::log(reduction_factor)); + } + else + { + viscosity_reduction_factor=(1/reduction_factor)*std::exp(-melt_viscosity_factor); + } + viscosity = std::pow(grain_size/reference_grain_size,grain_size_exponent)*viscosity_prefactor*std::exp((activation_energy/gas_constant) + *(1/temperature-1/reference_temperature))*std::exp((activation_volume/gas_constant)*(pressure/temperature-reference_pressure/ + reference_temperature))*viscosity_reduction_factor; + unrelaxed_compliance=1./(1e9*(mu0+(dmudP*pressure*1e-9)+(dmudT*(temperature-273)))); + if (temperature<273) + { + // Vs is too high to give realistic temperature so viscosity, attenuation and unrelaxed compliance are reset + viscosity=1e40; + unrelaxed_compliance=1./(1e9*(mu0+(dmudP*pressure*1e-9))); + // attenuation=1e-9; + } + // evaluate Maxwell normalized shear wave period + double maxwell_relaxation_time=viscosity*unrelaxed_compliance; + if (use_original_model == true) + { + // set shear wave period as constant + period=100; + } + else + { + // calculate shear wave period incorporating depth dependence of Forsyth 1992 + period=(3*depth)/4200; + } + double normalized_period=period/(2*M_PI*maxwell_relaxation_time); + // determine peak amplitudes + if (homologous_temperature < 0.91) + { + peak_amplitude=0.01; + } + else if ((homologous_temperature >= 0.91) && (homologous_temperature < 0.96)) + { + peak_amplitude=0.01+(0.4*(homologous_temperature-0.91)); + } + else if ((homologous_temperature >= 0.96) && (homologous_temperature < 1)) + { + peak_amplitude=0.03; + } + else + { + peak_amplitude=0.03+melt_peak_factor; + } + // determine peak widths + if (homologous_temperature < 0.92) + { + peak_width=4; + } + else if ((homologous_temperature >= 0.92) && (homologous_temperature < 1)) + { + peak_width=4+(37.5*(homologous_temperature-0.92)); + } + else + { + peak_width=7; + } + // determine density + if (use_original_model == true) + { + // calculate density using original parameters from Yamauchi & Takei (2016) + density=original_density*(1-(original_thermal_expansivity*((temperature-273)-600))+((pressure*1e-9)/original_bulk_modulus)); + } + else + { + // create fdV function to use in Brent minimization and calculate isothermal_volume_change and density using + // expressions in Grose & Afonso 2013 + using Result2 = std::pair; + auto vfunc = [ &,this] (double x) + { + return fdV(x, bulk_modulus, bulk_modulus_pressure_derivative, pressure); + }; + Result2 r2 = boost::math::tools::brent_find_minima(vfunc,a,b,16); + isothermal_volume_change=r2.first; + compressibility=isothermal_volume_change*std::exp((gruneisen_parameter+1)*(std::pow(isothermal_volume_change,-1)-1)); + pressure_dependent_density=reference_density*isothermal_volume_change; + integrated_thermal_expansivity=(2.832e-5*(temperature-273))+((0.758e-8/2)*(std::pow(temperature,2)-std::pow(273,2))); + density=pressure_dependent_density*(1-(compressibility*integrated_thermal_expansivity)); + } + // determine J1 term (real part of complex compliance) + storage_compliance=unrelaxed_compliance*(1+((background_amplitude*std::pow(normalized_period,background_slope)) + /background_slope)+((std::sqrt(2*M_PI)/2)*peak_amplitude*peak_width*(1- + std::erf((std::log(peak_period/normalized_period))/(std::sqrt(2)*peak_width))))); + // determine J2 term (imaginary part of complex compliance) + //double loss_compliance=unrelaxed_compliance*(M_PI/2)*(background_amplitude*(std::pow(normalized_period,background_slope))+ + // (peak_amplitude*std::exp(-1*(std::pow(std::log(peak_period/normalized_period),2)/ + // (2*std::pow(peak_width,2))))))+(unrelaxed_compliance*normalized_period); + // calculate anharmonic Vs + // anharmonic_Vs=1/(std::sqrt(density*unrelaxed_compliance)*1e3); + // calculate Vs + anelastic_Vs=1/(std::sqrt(density*storage_compliance)*1e3); + // calculate attenuation + // attenuation=loss_compliance/storage_compliance; + return anelastic_Vs; + } + + template + void + AnelasticVs2T::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.declare_entry ("Remove temperature heterogeneity down to specified depth", + boost::lexical_cast(-std::numeric_limits::max()), + Patterns::Double (), + "This will remove temperature variations prescribed by the input model " + "down to the specified depth (in meters). Note that your resolution has " + "to be adequate to capture this cutoff. For example if you specify a depth " + "of 660km, but your closest spherical depth layers are only at 500km and " + "750km (due to a coarse resolution) it will only remove heterogeneities " + "down to 500km. Similar caution has to be taken when using adaptive meshing."); + prm.declare_entry ("Set reference temperature down to specified depth", "1600", + Patterns::Double (), + "This parameter sets the a constant value of temperature down to the specified depth."); + prm.declare_entry ("Use Yamauchi and Takei parameterization", "true", + Patterns::Bool(), + "This parameter determines whether to use the anelasticity model of " + "Yamauchi & Takei (2016) to convert absolute Vs into temperature"); + prm.declare_entry ("Use original density and frequency model of Yamauchi and Takei", "true", + Patterns::Bool(), + "Use original density and frequency model of Yamauchi & Takei (2016) where density" + "has simple pressure-dependence and shear wave is period set at 100s"); + + Utilities::AsciiDataBase::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/initial-temperature/ascii-data/test/", + "box_2d_Vs_YT16.txt"); + } + prm.leave_subsection(); + } + + + template + void + AnelasticVs2T::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + no_perturbation_depth = prm.get_double ("Remove temperature heterogeneity down to specified depth"); + reference_temperature = prm.get_double ("Set reference temperature down to specified depth"); + use_yamauchi_takei = prm.get_bool ("Use Yamauchi and Takei parameterization"); + use_original_model = prm.get_bool ("Use original density and frequency model of Yamauchi and Takei"); + + Utilities::AsciiDataBase::parse_parameters(prm); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(AnelasticVs2T, + "anelastic Vs to temperature", + "Implementation of a model in which the initial temperature is calculated " + "from files containing absolute shear wave velocity (Vs) data in ascii format. " + "This plug-in allows you to select from a number of different models that" + "convert Vs into temperature, accounting for the anelastic behavior of mantle material." + "Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example `# POINTS: 3 3'. " + "The order of the data columns " + "has to be `x', `y', `Temperature [K]' in a 2d model and " + " `x', `y', `z', `Temperature [K]' in a 3d model, which means that " + "there has to be a single column " + "containing the temperature. " + "Note that the data in the input " + "files need to be sorted in a specific order: " + "the first coordinate needs to ascend first, " + "followed by the second and the third at last in order to " + "assign the correct data to the prescribed coordinates. " + "If you use a spherical model, " + "then the assumed grid changes. `x' will be replaced by " + "the radial distance of the point to the bottom of the model, " + "`y' by the azimuth angle and `z' by the polar angle measured " + "positive from the north pole. The grid will be assumed to be " + "a latitude-longitude grid. Note that the order " + "of spherical coordinates is `r', `phi', `theta' " + "and not `r', `theta', `phi', since this allows " + "for dimension independent expressions.") + } +} diff --git a/benchmarks/yamauchi_takei_2016_anelasticity/anelasticity_temperature.h.bak b/benchmarks/yamauchi_takei_2016_anelasticity/anelasticity_temperature.h.bak new file mode 100644 index 00000000000..b6744f31e42 --- /dev/null +++ b/benchmarks/yamauchi_takei_2016_anelasticity/anelasticity_temperature.h.bak @@ -0,0 +1,135 @@ +/* + Copyright (C) 2016 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_anelasticity_temperature_h +#define _aspect_initial_temperature_anelasticity_temperature_h + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that describes an initial temperature field for a 2D or 3D shear wave velocity (Vs) model. + * Vs values are converted to temperature using the anelasticity parameterization of Yamauchi & Takei (2016). + * + * @ingroup InitialTemperatures + */ + template + class AnelasticVs2T : public Utilities::AsciiDataInitial, public Interface + { + public: + /** + * Constructor. Initialize variables. + */ + AnelasticVs2T (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + // Avoid -Woverloaded-virtual: + using Utilities::AsciiDataInitial::initialize; + + /** + * Return the boundary temperature as a function of position. For the + * current class, this function returns value from the text files. + */ + double + initial_temperature (const Point &position) const override; + + /** + * Declare the parameters for the input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * Function that assesses difference between input and calculated Vs for Brent minimization + */ + double + fVs(double x, double depth, double absolute_Vs, double mu0, double dmudT, + double dmudP, double viscosity_prefactor, double activation_energy, double activation_volume, + double solidus_gradient, bool density_model_flag) const; + + /** + * Function that assesses difference between input and calculated pressure for Brent minimization + */ + double + fdV(double x, double bulk_modulus, double bulk_modulus_pressure_derivative, double pressure) const; + + /** + * Function to calculate Vs using Yamauchi & Takei 2016 anelasticity parameterization + */ + double + yamauchi_takei_Vs(double temperature, double depth, double mu0, double dmudT, + double dmudP, double viscosity_prefactor, double activation_energy, + double activation_volume, double solidus_gradient, bool density_model_flag) const; + + /** + * Whether to remove temperature heterogeneity upper parts of model + */ + double no_perturbation_depth; + + /** + * Constant temperature to set where variations have been removed + */ + double reference_temperature; + + /** + * Whether to use Yamauchi & Takei (2016) anelasticity + * parameterization + */ + bool use_yamauchi_takei; + + /** + * Whether to use original parameters published in Yamauchi & Takei + * (2016) or an updated version that accounts for non-linear pressure + * dependence of thermal expansivity and depth dependence of shear + * wave period + */ + bool use_original_model; + + }; + } +} + +#endif diff --git a/benchmarks/yamauchi_takei_2016_anelasticity/yamauchi_takei_2016_anelasticity.prm.bak b/benchmarks/yamauchi_takei_2016_anelasticity/yamauchi_takei_2016_anelasticity.prm.bak new file mode 100644 index 00000000000..f704bf05f74 --- /dev/null +++ b/benchmarks/yamauchi_takei_2016_anelasticity/yamauchi_takei_2016_anelasticity.prm.bak @@ -0,0 +1,79 @@ +# This benchmark tests the ASPECT implementation of an initial temperature model +# that converts absolute shear wave velocity to temperature using the anelasticity model of +# Yamauchi & Takei 2016 (JGR). This .prm aims to recreate Figure 20 in the paper. +# Output can be plotted and compared to results in Figure 20 by running plot_output.gmt +# in the plot_output folder. + + +set Dimension = 2 +set Use years in output instead of seconds = true +set Start time = 0 +set End time = 0 +set Additional shared libraries = ./libanelasticity_temperature.so +set Output directory = output_yamauchi_takei_2016_anelasticity + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 52000 + set Y extent = 100000 + end +end + +subsection Initial temperature model + set Model name = anelastic Vs to temperature + set Remove temperature heterogeneity down to specified depth = 25000 + set Set reference temperature down to specified depth = 600 + set Use Yamauchi and Takei parameterization = true + set Use original density and frequency model of Yamauchi and Takei = true + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/data/initial-temperature/ascii-data/test/ + set Data file name = box_2d_Vs_YT16.txt + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = bottom:function,left:function,right:function,top:function + + subsection Function + set Function expression = 1;0 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Viscosity = 1e21 + end +end + +subsection Mesh refinement + set Initial global refinement = 6 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 + set Strategy = temperature +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics, point values + + subsection Point values + set Evaluation points = 0,25000;2000,25000;4000,25000;\ + 6000,25000;8000,25000;10000,25000;12000,25000;14000,25000;16000,25000;18000,25000;20000,25000;22000,25000;24000,25000;26000,25000;\ + 28000,25000;30000,25000;32000,25000;34000,25000;36000,25000;38000,25000;40000,25000;42000,25000;44000,25000;46000,25000;\ + 48000,25000;50000,25000;52000,25000;0,50000;2000,50000;4000,50000;6000,50000;8000,50000;10000,50000;12000,50000;14000,50000;16000,50000;\ + 18000,50000;20000,50000;22000,50000;24000,50000;26000,50000;28000,50000;30000,50000;32000,50000;34000,50000;36000,50000;\ + 38000,50000;40000,50000;42000,50000;44000,50000;46000,50000;48000,50000;50000,50000;52000,50000 + end +end diff --git a/benchmarks/zhong_et_al_93/zhong_case1.prm.bak b/benchmarks/zhong_et_al_93/zhong_case1.prm.bak new file mode 100644 index 00000000000..0f3500e7267 --- /dev/null +++ b/benchmarks/zhong_et_al_93/zhong_case1.prm.bak @@ -0,0 +1,105 @@ +set Dimension = 2 +set End time = 0 +set Output directory = output +set Pressure normalization = surface +set Surface pressure = 0 + +# Use a one by one box +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +# Approximate a delta function +# perturbation at depth +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x1,x2 + set Function constants = lambda=1, pi=3.1415926536, L=1, depth=62, sigma = 0.5, N=64 + set Function expression = 1/(sigma/N*L * sqrt( 2 * pi) ) * exp( -0.5*(x2-depth/N)*(x2-depth/N)/sigma/sigma/L/L*N*N ) * cos(2*pi/lambda*x1/L) + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 0 + set Top temperature = 0 + end +end + +# Boussinesq approximation +subsection Formulation + set Mass conservation = incompressible + set Temperature equation = reference density profile +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +subsection Material model + set Model name = nondimensional + + subsection Nondimensional model + set Di = 0.0 + set Ra = 1.0 + set Reference density = 1 + set Reference specific heat = 1 + set Use TALA = false + end + + subsection Simple model + set Reference density = 1 + set Reference specific heat = 1 + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1 + set Viscosity = 1 + end +end + +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = dynamic topography, visualization + + subsection Visualization + set Output format = vtu + set List of output variables = dynamic topography + set Time between graphical output = 1e6 + set Number of grouped files = 0 + end + + subsection Dynamic topography + set Density above = 0 + end + + subsection Depth average + set Time between graphical output = 1e6 + end +end + +subsection Solver parameters + set Temperature solver tolerance = 1e-10 +end diff --git a/contrib/opendap/prm_files/aspect_test.prm.bak b/contrib/opendap/prm_files/aspect_test.prm.bak new file mode 100644 index 00000000000..23b8dda81c2 --- /dev/null +++ b/contrib/opendap/prm_files/aspect_test.prm.bak @@ -0,0 +1,82 @@ +# Test the aspect simulator using local data match the file used +# with the opendap client. See aspect_url_test.prm for an example +# of that version. + +set Dimension = 3 +set Use years in output instead of seconds = true +set End time = 0 +set Output directory = output-adiabatic_boundary-no-url-test +set Nonlinear solver scheme = single Advection, iterated Stokes +set Nonlinear solver tolerance = 1e-5 +set Max nonlinear iterations = 50 +set Pressure normalization = surface +set Surface pressure = 0 + +subsection Formulation + set Formulation = Boussinesq approximation +end + +subsection Geometry model + set Model name = chunk + + subsection Chunk + set Chunk minimum longitude = 35 + set Chunk maximum longitude = 55 + set Chunk minimum latitude = -28 + set Chunk maximum latitude = -8 + set Chunk inner radius = 5878137 + set Chunk outer radius = 6378137 + end +end + +subsection Initial temperature model + set Model name = adiabatic boundary + + subsection Adiabatic boundary + set Data directory = $ASPECT_SOURCE_DIR/contrib/opendap/input_files/ + set Data file name = lithospheric_thickness.txt + end +end + +subsection Boundary temperature model + set List of model names = initial temperature + set Fixed temperature boundary indicators = inner, outer + + subsection Initial temperature + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = inner, outer, west, east, south, north +end + +subsection Gravity model + set Model name = ascii data +end + +subsection Material model + set Model name = simpler +end + +subsection Mesh refinement + set Initial global refinement = 3 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, basic statistics + + subsection Visualization + set List of output variables = viscosity, density, strain rate + set Time between graphical output = 1.0 + set Output format = vtu + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-6 + set Number of cheap Stokes solver steps = 50 + end +end diff --git a/contrib/opendap/prm_files/aspect_url_test.prm.bak b/contrib/opendap/prm_files/aspect_url_test.prm.bak new file mode 100644 index 00000000000..b5532978ba4 --- /dev/null +++ b/contrib/opendap/prm_files/aspect_url_test.prm.bak @@ -0,0 +1,78 @@ +set Dimension = 3 +set Use years in output instead of seconds = true +set End time = 0 +set Output directory = output-adiabatic_boundary-url-test +set Nonlinear solver scheme = single Advection, iterated Stokes +set Nonlinear solver tolerance = 1e-5 +set Max nonlinear iterations = 50 +set Pressure normalization = surface +set Surface pressure = 0 + +subsection Formulation + set Formulation = Boussinesq approximation +end + +subsection Geometry model + set Model name = chunk + + subsection Chunk + set Chunk minimum longitude = 35 + set Chunk maximum longitude = 55 + set Chunk minimum latitude = -28 + set Chunk maximum latitude = -8 + set Chunk inner radius = 5878137 + set Chunk outer radius = 6378137 + end +end + +subsection Initial temperature model + set Model name = adiabatic boundary + + subsection Adiabatic boundary + set Data directory = + set Data file name = http://balto.opendap.org/opendap/lithosphere_thickness/lithospheric_thickness.csv + end +end + +subsection Boundary temperature model + set List of model names = initial temperature + set Fixed temperature boundary indicators = inner, outer + + subsection Initial temperature + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = inner, outer, west, east, south, north +end + +subsection Gravity model + set Model name = ascii data +end + +subsection Material model + set Model name = simpler +end + +subsection Mesh refinement + set Initial global refinement = 3 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, basic statistics + + subsection Visualization + set List of output variables = viscosity, density, strain rate + set Time between graphical output = 1.0 + set Output format = vtu + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-6 + set Number of cheap Stokes solver steps = 50 + end +end diff --git a/contrib/perplex/perplex_lookup_composition.prm.bak b/contrib/perplex/perplex_lookup_composition.prm.bak new file mode 100644 index 00000000000..8b519f72792 --- /dev/null +++ b/contrib/perplex/perplex_lookup_composition.prm.bak @@ -0,0 +1,84 @@ +# This test ensures that the PerpleX lookup material model works +# with compositional fields enabled + +# WARNING: Please understand that the PerpleX Lookup material model is only a +# proof-of-concept; the number of P-T-X evaluations is extremely large, which +# means that ASPECT will be interminably slow for any real problems. + +set Dimension = 2 +set End time = 0 +set Adiabatic surface temperature = 1300 + +# KLB composition in the CFMAS system +# The bulk composition is given by five compositional fields +# which correspond to the components in the PerpleX input +# file (in this case, SiO2, Al2O3, FeO and MgO). +# As defined in the PerpleX input file, the composition is +# given in weight amount. The total amount is normalized +# by the PerpleX routines, so it doesn't need to equal 1 or 100. + +subsection Compositional fields + set Number of fields = 4 +end + +subsection Initial composition model + set List of model names = function + + subsection Function + set Function expression = 0.44; 0.04; 0.08; 0.44 + end +end + +subsection Material model + set Model name = perplex lookup + + subsection PerpleX lookup model + set PerpleX input file name = pyrolite + set Viscosity = 1e21 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 200e3 + set X repetitions = 1 + set Y extent = 800e3 + set Y repetitions = 16 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1300 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, top, bottom +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 1 +end + +subsection Postprocess + set List of postprocessors = depth average + + subsection Depth average + set Output format = gnuplot + set Number of zones = 200 + end +end diff --git a/contrib/python/notebooks/read_output_files/convection-box.prm.bak b/contrib/python/notebooks/read_output_files/convection-box.prm.bak new file mode 100644 index 00000000000..055f18b7567 --- /dev/null +++ b/contrib/python/notebooks/read_output_files/convection-box.prm.bak @@ -0,0 +1,10 @@ +include $ASPECT_SOURCE_DIR/cookbooks/convection-box.prm + +set End time = 0.1 +set Output directory = output + +subsection Postprocess + subsection Visualization + set Output format = gnuplot + end +end diff --git a/contrib/python/scripts/__pycache__/aspect_input.cpython-312.pyc b/contrib/python/scripts/__pycache__/aspect_input.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f20772791edaa5583f3825072f4f8ffb89c04f7a GIT binary patch literal 8883 zcmcgyT}&HUmaekPKiFk#Y`}yhxIzfv4#6RTg#2~qhy0O*PUp8f(`n1N3NSIYyQ&<5 zV|q|)9!MvvCfm}+y%WuNrPVI0JS-2p61xwpNb?eDMk5zy6|a>Cq#0?|Z!~FbOT6r! zbL+z1b&6{tTc;=Rwx7=cQ>o2HV7TyM}mA6A{<7=R`^A2chcqg|T8XF(wOKERjmf+(;}Ay`9}DaYDTha>)_y#MR5E zPhI1_LD_~fE!V~bE|QkVlA?sYGCXP{qDfxJG@eSPro`Cjn9S|lyKjG&)|v619lFk) zy?l||$0bEB9+3qxsxKEgTj19Wzpw8>^MuOMS?Vq&+Ou%C1>W$ay-H=N0qS;;qNYvI zVZZT*e4Oo28#=^G%zxW}dlokc{uhnxiI~x=JzB6ce;$irm@Q zT_M3mI6fAYW64BBoWgacB4T7h0I4NzGA55fza)$4sGJr-9g>5C3ssR!2wW7DD+@d~ zJVn$THb}#$;Lczdyau`iA-Effrv*Z;DbpCO&Vx)xi9`vQzni;4NF{CvXNnR16Y2_C zOyUwr*vw=)!FQ9svW3i2X5^`qP4v0iAY8UnXD)gvMiusfkcZOpXI%DKrWiN)Lx3QVJeJ-Jxg_NMpkxu)lar zjtNpIo#H`9VJRxcQa}I}N0cLly1TW1sVT6rL`WZ@@(L3}?FI|8fdr&+p*%b^Gt_D= zWoKtIifv2Dy(QPCxC42c;_fWiJ69S4YZOznWA-%m>{8rZz7cxnFBaYXubOtx4=$vY zu49X%O4peeOtIS` zi}tBm?osHOf@iSYcCcJC^q7g|sx7mr<*I#}8F8le!)6)r`1uz_`hXq*^ZlD44g4>*12XMVyRDf=W)zP{ac*B65hh z4d39&M~eoMA6m3%$8j~-p!JG~!iF7-PJHFon;qB}h2{;LY75Rf=6V%-Q_ip0ca+>7 zVpZmv?VDPauRWhx*rjyzFZz{^6VH2JG!%XB7p`6_`mX)Q)@`dcpj&lNtV?8Jo~Qv@ z@L-tKIJ^auqVVs=i>IGyZ>MS5Fvu*$o3eB>rT6`?XB^eF;d-V$>r@%g4FasnYaEZ- zhKmOP)!}p;b-LlwITEO~@TO*J8obsxYI(zzW%OC689Xw)B?BXn;%$;nTe6mMJoy_g z-l}sGeN}6>=x=$;odMWrpypMnELkRN$(lyYSE-;aa|YlQ{UXZf>1EHneW~*ioj$S`cuZ=7P2|GZIViWpi9el&vE8 zj##Q}6NOYf5(Q|LQh26 zu@y%3!mspuXy7ndDWCsI@NqDA>Z|UV3*R}YrmeZ&Je%KI*t)0a@BSy>!nMV&#Uq8j zvoHIGl)j;2-{oS@2a5lL0#gsfTwDHP{%3_i&&$9eC2(l5{kgXo7sM|9$SgNak()73~_fD~H*UTW9d+vU|=kfI1X9aKjOYa`VyQk<4&0JWu zQ+D4=+jhmaJr`ZJwf?O%f27!PaB;^{$B|Owj{J^%>s)fyx#Db?yI*MQEjW7%Os{(G zszVS22s}xz{|#D*zGyrH1JoRS`!@u(&6}OWH!PjTphDaW;YC$YB6ec9QDu$B>3o}o z<0;61g_9Fh&5eEp{5Cz47Qh5;J#Rge49G(hH&QDbC$e%5c`NpbY}N#$)FA0|xMzqo zrbn|tZ6)r@M#gdaI5<_tC~$xOtBe}Ig)ATg;b$lO=J=Y;PBx5k@XiXdZK?rSm#zUs zh%9}V7QH+zBe0VzX6T-`^XyYIgqap}&-j^8qYx%v{&8oZuZM9TBb) z`Eny-asu8M7*7%&$b%qWseW5Y0<^dTH|v}KhHIVvc%62LUU(*P$U41~L?L25zCqj{ z3YyEdXmSFPT8%kKr~-#e4MECg@G|8ZLxdnB8hz^(kmpp8Cvi^M7E46qXTbuBhwgXSqV zV$%#wnZcEpt!kWJZo+&~^&H`(7_R7%c!)B4C7qCC6T)dxOp3vpvV(-_B%&u_SJ@Yd zM$;2%O#Aq-u99sykA=9dvb(~PIIF5atp$cj7-OKbB9|Ji?T1$)Ht*wre+J|O2gOob zw-*@yil_NCb<{FM&oU*q@5{`C%){&~11^O1%Q_AdbIht49G*I~=xqi1x`rq0V>Wjqf3oQ5c{g=)8Pyaela<}G(i|)>nXJ=kkJi8UoP8e0|o!jx?X3qS@C!~L=(qHiGEU|%n z@82K&o1+WX1+lpEu)@N>0JyhW-(1gw4|Cg=T)RpwJAOU(^;kYV|H1r~{8X`}=Vi+w zrRC6K+oD)(IXV0Oin}F0uDJJ>4j=s;^Ww^H?S)$-O84lTBljLiu>$!|NO8Y2e@Jon zEqa&SM@pV%(ldX)=sB?1rg+|kzbkCx+|L!ZW4@-y?kgNPudwIgrqtS2U;{>H!O|L2H&?(b@QIu=Igc?xS(y-)e zdDV6Nd3~|#jKT(I2j+Gawggvpzx$%0z{|kl=ky?Q;4YYE2j^sk-3GHS!R#(C(Z!Y} zS8K`F_@w`Ff9^E8_}uxTuYGo)RNn~kcz`PaK{c~;gxUGcnV~Q%xL>#*{TB*1J}e}X zWEH27Y|nrR)OSqr1WWCmuum(#?Mv+T?;siq6auGTFiPNJ(R-=DURs@^(dt$|qbd8= z-0+f(EA2h?Vz@9eTKF`hwB3gU;uz)*EnLCA72=Ts)9{w~UoC}H3K|vfwISv=yj~x~ z?XnT!1NIv|G{n^Sqx%#Ze9cvAC)Gnq^duBOKB8#&!FTt}A5oKZ&>Xo9PDBM!1EL5@ zs==;S!+4`kqE<%YaWyEGx;Y1)SJGUAI)+LD;8a0X4od@(SVDp#3ZfMhr(ht4t9o&% z0t{V*5nvfXK&Za}njp3!wi^}|03p6WI*bW%_KJ);7c#rXLvuiCt*k-^GJ;0}EKZDesqU$w7FEhh1xP}L zR2Q6x3|Im(bPClbc?@blBk2UG?Px4OV4TJ%`E+xqCsOhhtRCJcHc@6L>IQcOG^_D| z%G9PqVYZkI)g}-wsJchcpOKtseoIqAB0VuIh`6b$I|E(HlL8dl$X;V5l4LC$W-Z#Z z;Iyh;F(xG4+%;Sy{7Xw* z%d`kFg4hH8tIQ;UhPX3`8X#AU3##X&M{op@#E@^$&aWqas*GrT~z)d(Q;y{+nDUBXN# z=L(ts(Q?T4Mzsr}1;u&&SI}T-LJP(Q{zQ?&^h_&K3{ba2S~8;s*Y#P`IC9!>@eq<{ zU>2PYAZgQam||6jhBWo42P?RwhI^j745vy>(%(41U7Q@b1J)hEL!3k#BBm2fiV!); za2R;lod{NaHRuvC+!LW{N0G2@C}<*a5=1RnHrE2Sa%~C{dDw9+9Tzd86*0Pbv%XZ` zLa6lkCme%J{a#GMgC^p}{R>iDhK3~CcK2NC=hLP7txqmJzLak()_1H?=9)HeaBkn6 z_(cZdmM4zKj@8Ny{t}xt2sbo zVpKR`$93*@B7@4^#MdNfNID?N+;o;2)oyqPT1A$@maj25Igu0E6?xB+F{IFBj39H7 zUK_R*nR#Z~{OB)?ajHgKs0aAk@U@|n|GU+{eSNh=c6EIlB+W8auHRSz@5Z(N*d4;v zLTYG%L<{THzuUwbJj4d3fAW>ry=CPz?9fsu;~z)K~(rq z_Mbos1mm)kq{Ct2dr9TLTuZ_b#9+c;V?9(ngS6QE27V<8#3A1Te10f5S}E_g*VGmZ zH)|^U-JBDa+&kwT3w=uGp~axmIq<@?)H$dFcJH!>d&Ta` zk1sSR?FScYl=hR)hYHs|TxLH4&bvbMX{D`iVN_{*_j&75+rZaXU$o8+>EJHqK2iL; z=SLKOFMP7{A6=B5-zr?buAIJ6xEWJUk1OwuEB^7qL`w0eO3j_$n(3xsX?Nd(pzJ=n zcvIPZ8sD6uOXn`)%_aIfigpdrE6sri7gk*UoJDc9-h zE;)Nkns%#c|AaDEG=HcGG@t(iVN=?VKkqJF zxv|XNtPI$o{ZYl=x6B?WZLT$4#6QOX2+P%7u=v$ZO8+*5M?t^vpb*E+!;M;_uH=XC z^~A{UAQLpd;clTKtA9j| zDASV|iX8zRkTVMCfFY|Ic#%_o3?4T`U-fGAwIOuA00U_VTcks9LkdWZ{+XdyBy8UQ zum!{B6LhZUm3>G4o%zIKWZ8ZkBj*$Jij)1`qTQ$w^Ov>l=D)LqY(ZDq77p{tXgFLp zC8e?>99I9s1U$RK5dLZZK>{9~;cz?_6%vvV4y&KE$v4PWTnv`BM2zeS=#h1bDD6K$ zZ64oZ>3-dQbRx;8nvSEs~;!-2k+U>p8x;= literal 0 HcmV?d00001 diff --git a/contrib/world_builder/include/app/main.h.bak b/contrib/world_builder/include/app/main.h.bak new file mode 100644 index 00000000000..097d0caf137 --- /dev/null +++ b/contrib/world_builder/include/app/main.h.bak @@ -0,0 +1,27 @@ +/* + Copyright (C) 2020 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_APP_MAIN_H_ +#define WORLD_BUILDER_APP_MAIN_H_ + +#include + +bool find_command_line_option(char **begin, char **end, const std::string &option); + +#endif diff --git a/contrib/world_builder/include/glm/glm.h.bak b/contrib/world_builder/include/glm/glm.h.bak new file mode 100644 index 00000000000..3089ebc6876 --- /dev/null +++ b/contrib/world_builder/include/glm/glm.h.bak @@ -0,0 +1,248 @@ +#ifndef _glm_h +#define _glm_h +#include +#include +#include + +namespace WorldBuilder +{ + /** + * The code in this file is derived from the OpenGL Mathematics (GLM) library, which + * is available under two version of MIT Lincense (see below). The derived work in + * this file is avaible under the same licenses. + * + * The changes are mainly specializing and isolation functions which are needed in + * the World Builder. + * + * ================================================================================ + * OpenGL Mathematics (GLM) + * -------------------------------------------------------------------------------- + * GLM is licensed under The Happy Bunny License and MIT License + * + * ================================================================================ + * The Happy Bunny License (Modified MIT License) + * -------------------------------------------------------------------------------- + * Copyright (c) 2005 - 2014 G-Truc Creation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * Restrictions: + * By making use of the Software for military purposes, you choose to make a + * Bunny unhappy. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * ================================================================================ + * The MIT License + * -------------------------------------------------------------------------------- + * Copyright (c) 2005 - 2014 G-Truc Creation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + namespace glm + { + namespace quaternion + { + struct quat + { + quat(double w_, double x_, double y_, double z_) + : + w(w_), + x(x_), + y(y_), + z(z_) + {} + + + const quat operator-() const + { + return quat(-w, -x, -y, -z); + } + + const quat operator-(quat &p) const + { + return quat(p.w-w, p.x-x, p.y-y, p.z-z); + } + + quat operator*(double const &s) const + { + return quat( + w * s, x * s, y * s, z * s); + } + + + quat operator/( double const &s) + { + return quat( + w / s, x / s, y / s, z / s); + } + + quat operator+(quat const &p) + { + return quat(w + p.w, x + p.x, y + p.y, z + p.z); + } + + double w, x, y, z; + }; + + inline quat operator*(double const &s,quat const &q) + { + return quat( + q.w * s, q.x * s, q.y * s, q.z * s); + } + + + + inline double dot(quat u, quat v) + { + return u.w * v.w + u.x * v.x + u.y * v.y + u.z * v.z; + } + + inline double mix(double const &x, + double const &y, + double const &a ) + { + return x * (1.0 - a) + y * a; + } + + inline quat quat_cast(std::array,3> const &m) + { + double fourXSquaredMinus1 = m[0][0] - m[1][1] - m[2][2]; + double fourYSquaredMinus1 = m[1][1] - m[0][0] - m[2][2]; + double fourZSquaredMinus1 = m[2][2] - m[0][0] - m[1][1]; + double fourWSquaredMinus1 = m[0][0] + m[1][1] + m[2][2]; + + int biggestIndex = 0; + double fourBiggestSquaredMinus1 = fourWSquaredMinus1; + if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourXSquaredMinus1; + biggestIndex = 1; + } + if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourYSquaredMinus1; + biggestIndex = 2; + } + if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourZSquaredMinus1; + biggestIndex = 3; + } + + double biggestVal = sqrt(fourBiggestSquaredMinus1 + static_cast(1)) * static_cast(0.5); + double mult = static_cast(0.25) / biggestVal; + + switch (biggestIndex) + { + case 0: + return quat {biggestVal, (m[1][2] - m[2][1]) *mult, (m[2][0] - m[0][2]) *mult, (m[0][1] - m[1][0]) *mult}; + case 1: + return quat {(m[1][2] - m[2][1]) *mult, biggestVal, (m[0][1] + m[1][0]) *mult, (m[2][0] + m[0][2]) *mult}; + case 2: + return quat {(m[2][0] - m[0][2]) *mult, (m[0][1] + m[1][0]) *mult, biggestVal, (m[1][2] + m[2][1]) *mult}; + case 3: + return quat {(m[0][1] - m[1][0]) *mult, (m[2][0] + m[0][2]) *mult, (m[1][2] + m[2][1]) *mult, biggestVal}; + default: // Silence a -Wswitch-default warning in GCC. Should never actually get here. Assert is just for sanity. + throw (false); + return quat {1, 0, 0, 0}; + } + } + + + + inline std::array,3> mat3_cast(quat const &q) + { + std::array,3> Result; + double qxx(q.x * q.x); + double qyy(q.y * q.y); + double qzz(q.z * q.z); + double qxz(q.x * q.z); + double qxy(q.x * q.y); + double qyz(q.y * q.z); + double qwx(q.w * q.x); + double qwy(q.w * q.y); + double qwz(q.w * q.z); + + Result[0][0] = double(1) - double(2) * (qyy + qzz); + Result[0][1] = double(2) * (qxy + qwz); + Result[0][2] = double(2) * (qxz - qwy); + + Result[1][0] = double(2) * (qxy - qwz); + Result[1][1] = double(1) - double(2) * (qxx + qzz); + Result[1][2] = double(2) * (qyz + qwx); + + Result[2][0] = double(2) * (qxz + qwy); + Result[2][1] = double(2) * (qyz - qwx); + Result[2][2] = double(1) - double(2) * (qxx + qyy); + return Result; + } + + inline quat slerp(quat const &x, quat const &y, double a) + { + static_assert(std::numeric_limits::is_iec559, "'slerp' only accept floating-point inputs"); + + quat z = y; + + double cosTheta = dot(x, y); + + // If cosTheta < 0, the interpolation will take the long way around the sphere. + // To fix this, one quat must be negated. + if (cosTheta < static_cast(0)) + { + z = -y; + + cosTheta = -cosTheta; + } + + // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator + if (cosTheta > 1.0 - std::numeric_limits::epsilon()) + { + // Linear interpolation + return quat( + mix(x.w, z.w, a), + mix(x.x, z.x, a), + mix(x.y, z.y, a), + mix(x.z, z.z, a)); + } + else + { + // Essential Mathematics, page 467 + double angle = acos(cosTheta); + return (sin((1.0 - a) * angle) * x + sin(a * angle) * z) / sin(angle); + } + } + } + } +} +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/rapidjson/allocators.h.bak b/contrib/world_builder/include/rapidjson/allocators.h.bak new file mode 100644 index 00000000000..9e2aa49f7a3 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/allocators.h.bak @@ -0,0 +1,308 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ALLOCATORS_H_ +#define RAPIDJSON_ALLOCATORS_H_ + +#include "rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Allocator + +/*! \class rapidjson::Allocator + \brief Concept for allocating, resizing and freeing memory block. + + Note that Malloc() and Realloc() are non-static but Free() is static. + + So if an allocator need to support Free(), it needs to put its pointer in + the header of memory block. + +\code +concept Allocator { + static const bool kNeedFree; //!< Whether this allocator needs to call Free(). + + // Allocate a memory block. + // \param size of the memory block in bytes. + // \returns pointer to the memory block. + void* Malloc(size_t size); + + // Resize a memory block. + // \param originalPtr The pointer to current memory block. Null pointer is permitted. + // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) + // \param newSize the new size in bytes. + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); + + // Free a memory block. + // \param pointer to the memory block. Null pointer is permitted. + static void Free(void *ptr); +}; +\endcode +*/ + + +/*! \def RAPIDJSON_ALLOCATOR_DEFUALT_CHUNK_CAPACITY + \ingroup RAPIDJSON_CONFIG + \brief User-defined kDefaultChunkCapacity definition. + + User can define this as any \c size that is a power of 2. +*/ + +#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY +#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024) +#endif + + +/////////////////////////////////////////////////////////////////////////////// +// CrtAllocator + +//! C-runtime library allocator. +/*! This class is just wrapper for standard C library memory routines. + \note implements Allocator concept +*/ +class CrtAllocator +{ + public: + static const bool kNeedFree = true; + void *Malloc(size_t size) + { + if (size) // behavior of malloc(0) is implementation defined. + return std::malloc(size); + else + return NULL; // standardize to returning NULL. + } + void *Realloc(void *originalPtr, size_t originalSize, size_t newSize) + { + (void)originalSize; + if (newSize == 0) + { + std::free(originalPtr); + return NULL; + } + return std::realloc(originalPtr, newSize); + } + static void Free(void *ptr) + { + std::free(ptr); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// MemoryPoolAllocator + +//! Default memory allocator used by the parser and DOM. +/*! This allocator allocate memory blocks from pre-allocated memory chunks. + + It does not free memory blocks. And Realloc() only allocate new memory. + + The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. + + User may also supply a buffer as the first chunk. + + If the user-buffer is full then additional chunks are allocated by BaseAllocator. + + The user-buffer is not deallocated by this allocator. + + \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. + \note implements Allocator concept +*/ +template +class MemoryPoolAllocator +{ + public: + static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) + + //! Constructor with chunkSize. + /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator *baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + } + + //! Constructor with user-supplied buffer. + /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. + + The user buffer will not be deallocated when this allocator is destructed. + + \param buffer User supplied buffer. + \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). + \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator *baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + RAPIDJSON_ASSERT(buffer != 0); + RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); + chunkHead_ = reinterpret_cast(buffer); + chunkHead_->capacity = size - sizeof(ChunkHeader); + chunkHead_->size = 0; + chunkHead_->next = 0; + } + + //! Destructor. + /*! This deallocates all memory chunks, excluding the user-supplied buffer. + */ + ~MemoryPoolAllocator() + { + Clear(); + RAPIDJSON_DELETE(ownBaseAllocator_); + } + + //! Deallocates all memory chunks, excluding the user-supplied buffer. + void Clear() + { + while (chunkHead_ && chunkHead_ != userBuffer_) + { + ChunkHeader *next = chunkHead_->next; + baseAllocator_->Free(chunkHead_); + chunkHead_ = next; + } + if (chunkHead_ && chunkHead_ == userBuffer_) + chunkHead_->size = 0; // Clear user buffer + } + + //! Computes the total capacity of allocated memory chunks. + /*! \return total capacity in bytes. + */ + size_t Capacity() const + { + size_t capacity = 0; + for (ChunkHeader *c = chunkHead_; c != 0; c = c->next) + capacity += c->capacity; + return capacity; + } + + //! Computes the memory blocks allocated. + /*! \return total used bytes. + */ + size_t Size() const + { + size_t size = 0; + for (ChunkHeader *c = chunkHead_; c != 0; c = c->next) + size += c->size; + return size; + } + + //! Allocates a memory block. (concept Allocator) + void *Malloc(size_t size) + { + if (!size) + return NULL; + + size = RAPIDJSON_ALIGN(size); + if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) + if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) + return NULL; + + void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; + chunkHead_->size += size; + return buffer; + } + + //! Resizes a memory block (concept Allocator) + void *Realloc(void *originalPtr, size_t originalSize, size_t newSize) + { + if (originalPtr == 0) + return Malloc(newSize); + + if (newSize == 0) + return NULL; + + originalSize = RAPIDJSON_ALIGN(originalSize); + newSize = RAPIDJSON_ALIGN(newSize); + + // Do not shrink if new size is smaller than original + if (originalSize >= newSize) + return originalPtr; + + // Simply expand it if it is the last allocation and there is sufficient space + if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) + { + size_t increment = static_cast(newSize - originalSize); + if (chunkHead_->size + increment <= chunkHead_->capacity) + { + chunkHead_->size += increment; + return originalPtr; + } + } + + // Realloc process: allocate and copy memory, do not free original buffer. + if (void *newBuffer = Malloc(newSize)) + { + if (originalSize) + std::memcpy(newBuffer, originalPtr, originalSize); + return newBuffer; + } + else + return NULL; + } + + //! Frees a memory block (concept Allocator) + static void Free(void *ptr) + { + (void)ptr; // Do nothing + } + + private: + //! Copy constructor is not permitted. + MemoryPoolAllocator(const MemoryPoolAllocator &rhs) /* = delete */; + //! Copy assignment operator is not permitted. + MemoryPoolAllocator &operator=(const MemoryPoolAllocator &rhs) /* = delete */; + + //! Creates a new chunk. + /*! \param capacity Capacity of the chunk in bytes. + \return true if success. + */ + bool AddChunk(size_t capacity) + { + if (!baseAllocator_) + ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); + if (ChunkHeader *chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) + { + chunk->capacity = capacity; + chunk->size = 0; + chunk->next = chunkHead_; + chunkHead_ = chunk; + return true; + } + else + return false; + } + + static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity. + + //! Chunk header for perpending to each chunk. + /*! Chunks are stored as a singly linked list. + */ + struct ChunkHeader + { + size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). + size_t size; //!< Current size of allocated memory in bytes. + ChunkHeader *next; //!< Next chunk in the linked list. + }; + + ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. + size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. + void *userBuffer_; //!< User supplied buffer. + BaseAllocator *baseAllocator_; //!< base allocator for allocating memory chunks. + BaseAllocator *ownBaseAllocator_; //!< base allocator created by this object. +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/contrib/world_builder/include/rapidjson/cursorstreamwrapper.h.bak b/contrib/world_builder/include/rapidjson/cursorstreamwrapper.h.bak new file mode 100644 index 00000000000..fdaffb4e386 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/cursorstreamwrapper.h.bak @@ -0,0 +1,89 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ +#define RAPIDJSON_CURSORSTREAMWRAPPER_H_ + +#include "stream.h" + +#if defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + + +//! Cursor stream wrapper for counting line and column number if error exists. +/*! + \tparam InputStream Any stream that implements Stream Concept +*/ +template > +class CursorStreamWrapper : public GenericStreamWrapper +{ + public: + typedef typename Encoding::Ch Ch; + + CursorStreamWrapper(InputStream &is): + GenericStreamWrapper(is), line_(1), col_(0) {} + + // counting line and column number + Ch Take() + { + Ch ch = this->is_.Take(); + if (ch == '\n') + { + line_ ++; + col_ = 0; + } + else + { + col_ ++; + } + return ch; + } + + //! Get the error line number, if error exists. + size_t GetLine() const + { + return line_; + } + //! Get the error column number, if error exists. + size_t GetColumn() const + { + return col_; + } + + private: + size_t line_; //!< Current Line + size_t col_; //!< Current Column +}; + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_POP +#endif + +#if defined(__GNUC__) +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ diff --git a/contrib/world_builder/include/rapidjson/encodedstream.h.bak b/contrib/world_builder/include/rapidjson/encodedstream.h.bak new file mode 100644 index 00000000000..38b259332db --- /dev/null +++ b/contrib/world_builder/include/rapidjson/encodedstream.h.bak @@ -0,0 +1,485 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ENCODEDSTREAM_H_ +#define RAPIDJSON_ENCODEDSTREAM_H_ + +#include "stream.h" +#include "memorystream.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Input byte stream wrapper with a statically bound encoding. +/*! + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. + \tparam InputByteStream Type of input byte stream. For example, FileReadStream. +*/ +template +class EncodedInputStream +{ + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + public: + typedef typename Encoding::Ch Ch; + + EncodedInputStream(InputByteStream &is) : is_(is) + { + current_ = Encoding::TakeBOM(is_); + } + + Ch Peek() const + { + return current_; + } + Ch Take() + { + Ch c = current_; + current_ = Encoding::Take(is_); + return c; + } + size_t Tell() const + { + return is_.Tell(); + } + + // Not implemented + void Put(Ch) + { + RAPIDJSON_ASSERT(false); + } + void Flush() + { + RAPIDJSON_ASSERT(false); + } + Ch *PutBegin() + { + RAPIDJSON_ASSERT(false); + return 0; + } + size_t PutEnd(Ch *) + { + RAPIDJSON_ASSERT(false); + return 0; + } + + private: + EncodedInputStream(const EncodedInputStream &); + EncodedInputStream &operator=(const EncodedInputStream &); + + InputByteStream &is_; + Ch current_; +}; + +//! Specialized for UTF8 MemoryStream. +template <> +class EncodedInputStream, MemoryStream> +{ + public: + typedef UTF8<>::Ch Ch; + + EncodedInputStream(MemoryStream &is) : is_(is) + { + if (static_cast(is_.Peek()) == 0xEFu) is_.Take(); + if (static_cast(is_.Peek()) == 0xBBu) is_.Take(); + if (static_cast(is_.Peek()) == 0xBFu) is_.Take(); + } + Ch Peek() const + { + return is_.Peek(); + } + Ch Take() + { + return is_.Take(); + } + size_t Tell() const + { + return is_.Tell(); + } + + // Not implemented + void Put(Ch) {} + void Flush() {} + Ch *PutBegin() + { + return 0; + } + size_t PutEnd(Ch *) + { + return 0; + } + + MemoryStream &is_; + + private: + EncodedInputStream(const EncodedInputStream &); + EncodedInputStream &operator=(const EncodedInputStream &); +}; + +//! Output byte stream wrapper with statically bound encoding. +/*! + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. + \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. +*/ +template +class EncodedOutputStream +{ + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + public: + typedef typename Encoding::Ch Ch; + + EncodedOutputStream(OutputByteStream &os, bool putBOM = true) : os_(os) + { + if (putBOM) + Encoding::PutBOM(os_); + } + + void Put(Ch c) + { + Encoding::Put(os_, c); + } + void Flush() + { + os_.Flush(); + } + + // Not implemented + Ch Peek() const + { + RAPIDJSON_ASSERT(false); + return 0; + } + Ch Take() + { + RAPIDJSON_ASSERT(false); + return 0; + } + size_t Tell() const + { + RAPIDJSON_ASSERT(false); + return 0; + } + Ch *PutBegin() + { + RAPIDJSON_ASSERT(false); + return 0; + } + size_t PutEnd(Ch *) + { + RAPIDJSON_ASSERT(false); + return 0; + } + + private: + EncodedOutputStream(const EncodedOutputStream &); + EncodedOutputStream &operator=(const EncodedOutputStream &); + + OutputByteStream &os_; +}; + +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x + +//! Input stream wrapper with dynamically bound encoding and automatic encoding detection. +/*! + \tparam CharType Type of character for reading. + \tparam InputByteStream type of input byte stream to be wrapped. +*/ +template +class AutoUTFInputStream +{ + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + public: + typedef CharType Ch; + + //! Constructor. + /*! + \param is input stream to be wrapped. + \param type UTF encoding type if it is not detected from the stream. + */ + AutoUTFInputStream(InputByteStream &is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) + { + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + DetectType(); + static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; + takeFunc_ = f[type_]; + current_ = takeFunc_(*is_); + } + + UTFType GetType() const + { + return type_; + } + bool HasBOM() const + { + return hasBOM_; + } + + Ch Peek() const + { + return current_; + } + Ch Take() + { + Ch c = current_; + current_ = takeFunc_(*is_); + return c; + } + size_t Tell() const + { + return is_->Tell(); + } + + // Not implemented + void Put(Ch) + { + RAPIDJSON_ASSERT(false); + } + void Flush() + { + RAPIDJSON_ASSERT(false); + } + Ch *PutBegin() + { + RAPIDJSON_ASSERT(false); + return 0; + } + size_t PutEnd(Ch *) + { + RAPIDJSON_ASSERT(false); + return 0; + } + + private: + AutoUTFInputStream(const AutoUTFInputStream &); + AutoUTFInputStream &operator=(const AutoUTFInputStream &); + + // Detect encoding type with BOM or RFC 4627 + void DetectType() + { + // BOM (Byte Order Mark): + // 00 00 FE FF UTF-32BE + // FF FE 00 00 UTF-32LE + // FE FF UTF-16BE + // FF FE UTF-16LE + // EF BB BF UTF-8 + + const unsigned char *c = reinterpret_cast(is_->Peek4()); + if (!c) + return; + + unsigned bom = static_cast(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); + hasBOM_ = false; + if (bom == 0xFFFE0000) + { + type_ = kUTF32BE; + hasBOM_ = true; + is_->Take(); + is_->Take(); + is_->Take(); + is_->Take(); + } + else if (bom == 0x0000FEFF) + { + type_ = kUTF32LE; + hasBOM_ = true; + is_->Take(); + is_->Take(); + is_->Take(); + is_->Take(); + } + else if ((bom & 0xFFFF) == 0xFFFE) + { + type_ = kUTF16BE; + hasBOM_ = true; + is_->Take(); + is_->Take(); + } + else if ((bom & 0xFFFF) == 0xFEFF) + { + type_ = kUTF16LE; + hasBOM_ = true; + is_->Take(); + is_->Take(); + } + else if ((bom & 0xFFFFFF) == 0xBFBBEF) + { + type_ = kUTF8; + hasBOM_ = true; + is_->Take(); + is_->Take(); + is_->Take(); + } + + // RFC 4627: Section 3 + // "Since the first two characters of a JSON text will always be ASCII + // characters [RFC0020], it is possible to determine whether an octet + // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking + // at the pattern of nulls in the first four octets." + // 00 00 00 xx UTF-32BE + // 00 xx 00 xx UTF-16BE + // xx 00 00 00 UTF-32LE + // xx 00 xx 00 UTF-16LE + // xx xx xx xx UTF-8 + + if (!hasBOM_) + { + int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); + switch (pattern) + { + case 0x08: + type_ = kUTF32BE; + break; + case 0x0A: + type_ = kUTF16BE; + break; + case 0x01: + type_ = kUTF32LE; + break; + case 0x05: + type_ = kUTF16LE; + break; + case 0x0F: + type_ = kUTF8; + break; + default: + break; // Use type defined by user. + } + } + + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + } + + typedef Ch (*TakeFunc)(InputByteStream &is); + InputByteStream *is_; + UTFType type_; + Ch current_; + TakeFunc takeFunc_; + bool hasBOM_; +}; + +//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. +/*! + \tparam CharType Type of character for writing. + \tparam OutputByteStream type of output byte stream to be wrapped. +*/ +template +class AutoUTFOutputStream +{ + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + public: + typedef CharType Ch; + + //! Constructor. + /*! + \param os output stream to be wrapped. + \param type UTF encoding type. + \param putBOM Whether to write BOM at the beginning of the stream. + */ + AutoUTFOutputStream(OutputByteStream &os, UTFType type, bool putBOM) : os_(&os), type_(type) + { + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); + + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + + static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; + putFunc_ = f[type_]; + + if (putBOM) + PutBOM(); + } + + UTFType GetType() const + { + return type_; + } + + void Put(Ch c) + { + putFunc_(*os_, c); + } + void Flush() + { + os_->Flush(); + } + + // Not implemented + Ch Peek() const + { + RAPIDJSON_ASSERT(false); + return 0; + } + Ch Take() + { + RAPIDJSON_ASSERT(false); + return 0; + } + size_t Tell() const + { + RAPIDJSON_ASSERT(false); + return 0; + } + Ch *PutBegin() + { + RAPIDJSON_ASSERT(false); + return 0; + } + size_t PutEnd(Ch *) + { + RAPIDJSON_ASSERT(false); + return 0; + } + + private: + AutoUTFOutputStream(const AutoUTFOutputStream &); + AutoUTFOutputStream &operator=(const AutoUTFOutputStream &); + + void PutBOM() + { + typedef void (*PutBOMFunc)(OutputByteStream &); + static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; + f[type_](*os_); + } + + typedef void (*PutFunc)(OutputByteStream &, Ch); + + OutputByteStream *os_; + UTFType type_; + PutFunc putFunc_; +}; + +#undef RAPIDJSON_ENCODINGS_FUNC + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/contrib/world_builder/include/rapidjson/encodings.h.bak b/contrib/world_builder/include/rapidjson/encodings.h.bak new file mode 100644 index 00000000000..8d966002514 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/encodings.h.bak @@ -0,0 +1,855 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ENCODINGS_H_ +#define RAPIDJSON_ENCODINGS_H_ + +#include "rapidjson.h" + +#if defined(_MSC_VER) && !defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data +RAPIDJSON_DIAG_OFF(4702) // unreachable code +#elif defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(overflow) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Encoding + +/*! \class rapidjson::Encoding + \brief Concept for encoding of Unicode characters. + +\code +concept Encoding { + typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. + + enum { supportUnicode = 1 }; // or 0 if not supporting unicode + + //! \brief Encode a Unicode codepoint to an output stream. + //! \param os Output stream. + //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. + template + static void Encode(OutputStream& os, unsigned codepoint); + + //! \brief Decode a Unicode codepoint from an input stream. + //! \param is Input stream. + //! \param codepoint Output of the unicode codepoint. + //! \return true if a valid codepoint can be decoded from the stream. + template + static bool Decode(InputStream& is, unsigned* codepoint); + + //! \brief Validate one Unicode codepoint from an encoded stream. + //! \param is Input stream to obtain codepoint. + //! \param os Output for copying one codepoint. + //! \return true if it is valid. + //! \note This function just validating and copying the codepoint without actually decode it. + template + static bool Validate(InputStream& is, OutputStream& os); + + // The following functions are deal with byte streams. + + //! Take a character from input byte stream, skip BOM if exist. + template + static CharType TakeBOM(InputByteStream& is); + + //! Take a character from input byte stream. + template + static Ch Take(InputByteStream& is); + + //! Put BOM to output byte stream. + template + static void PutBOM(OutputByteStream& os); + + //! Put a character to output byte stream. + template + static void Put(OutputByteStream& os, Ch c); +}; +\endcode +*/ + +/////////////////////////////////////////////////////////////////////////////// +// UTF8 + +//! UTF-8 encoding. +/*! http://en.wikipedia.org/wiki/UTF-8 + http://tools.ietf.org/html/rfc3629 + \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. + \note implements Encoding concept +*/ +template +struct UTF8 +{ + typedef CharType Ch; + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream &os, unsigned codepoint) + { + if (codepoint <= 0x7F) + os.Put(static_cast(codepoint & 0xFF)); + else if (codepoint <= 0x7FF) + { + os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); + } + else if (codepoint <= 0xFFFF) + { + os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + os.Put(static_cast(0x80 | (codepoint & 0x3F))); + } + else + { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + os.Put(static_cast(0x80 | (codepoint & 0x3F))); + } + } + + template + static void EncodeUnsafe(OutputStream &os, unsigned codepoint) + { + if (codepoint <= 0x7F) + PutUnsafe(os, static_cast(codepoint & 0xFF)); + else if (codepoint <= 0x7FF) + { + PutUnsafe(os, static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint & 0x3F)))); + } + else if (codepoint <= 0xFFFF) + { + PutUnsafe(os, static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); + } + else + { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + PutUnsafe(os, static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); + } + } + + template + static bool Decode(InputStream &is, unsigned *codepoint) + { +#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) +#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) +#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) + typename InputStream::Ch c = is.Take(); + if (!(c & 0x80)) + { + *codepoint = static_cast(c); + return true; + } + + unsigned char type = GetRange(static_cast(c)); + if (type >= 32) + { + *codepoint = 0; + } + else + { + *codepoint = (0xFFu >> type) & static_cast(c); + } + bool result = true; + switch (type) + { + case 2: + RAPIDJSON_TAIL(); + return result; + case 3: + RAPIDJSON_TAIL(); + RAPIDJSON_TAIL(); + return result; + case 4: + RAPIDJSON_COPY(); + RAPIDJSON_TRANS(0x50); + RAPIDJSON_TAIL(); + return result; + case 5: + RAPIDJSON_COPY(); + RAPIDJSON_TRANS(0x10); + RAPIDJSON_TAIL(); + RAPIDJSON_TAIL(); + return result; + case 6: + RAPIDJSON_TAIL(); + RAPIDJSON_TAIL(); + RAPIDJSON_TAIL(); + return result; + case 10: + RAPIDJSON_COPY(); + RAPIDJSON_TRANS(0x20); + RAPIDJSON_TAIL(); + return result; + case 11: + RAPIDJSON_COPY(); + RAPIDJSON_TRANS(0x60); + RAPIDJSON_TAIL(); + RAPIDJSON_TAIL(); + return result; + default: + return false; + } +#undef RAPIDJSON_COPY +#undef RAPIDJSON_TRANS +#undef RAPIDJSON_TAIL + } + + template + static bool Validate(InputStream &is, OutputStream &os) + { +#define RAPIDJSON_COPY() os.Put(c = is.Take()) +#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) +#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) + Ch c; + RAPIDJSON_COPY(); + if (!(c & 0x80)) + return true; + + bool result = true; + switch (GetRange(static_cast(c))) + { + case 2: + RAPIDJSON_TAIL(); + return result; + case 3: + RAPIDJSON_TAIL(); + RAPIDJSON_TAIL(); + return result; + case 4: + RAPIDJSON_COPY(); + RAPIDJSON_TRANS(0x50); + RAPIDJSON_TAIL(); + return result; + case 5: + RAPIDJSON_COPY(); + RAPIDJSON_TRANS(0x10); + RAPIDJSON_TAIL(); + RAPIDJSON_TAIL(); + return result; + case 6: + RAPIDJSON_TAIL(); + RAPIDJSON_TAIL(); + RAPIDJSON_TAIL(); + return result; + case 10: + RAPIDJSON_COPY(); + RAPIDJSON_TRANS(0x20); + RAPIDJSON_TAIL(); + return result; + case 11: + RAPIDJSON_COPY(); + RAPIDJSON_TRANS(0x60); + RAPIDJSON_TAIL(); + RAPIDJSON_TAIL(); + return result; + default: + return false; + } +#undef RAPIDJSON_COPY +#undef RAPIDJSON_TRANS +#undef RAPIDJSON_TAIL + } + + static unsigned char GetRange(unsigned char c) + { + // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. + static const unsigned char type[] = + { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, + }; + return type[c]; + } + + template + static CharType TakeBOM(InputByteStream &is) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + typename InputByteStream::Ch c = Take(is); + if (static_cast(c) != 0xEFu) return c; + c = is.Take(); + if (static_cast(c) != 0xBBu) return c; + c = is.Take(); + if (static_cast(c) != 0xBFu) return c; + c = is.Take(); + return c; + } + + template + static Ch Take(InputByteStream &is) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + return static_cast(is.Take()); + } + + template + static void PutBOM(OutputByteStream &os) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xEFu)); + os.Put(static_cast(0xBBu)); + os.Put(static_cast(0xBFu)); + } + + template + static void Put(OutputByteStream &os, Ch c) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// UTF16 + +//! UTF-16 encoding. +/*! http://en.wikipedia.org/wiki/UTF-16 + http://tools.ietf.org/html/rfc2781 + \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. + \note implements Encoding concept + + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. + For streaming, use UTF16LE and UTF16BE, which handle endianness. +*/ +template +struct UTF16 +{ + typedef CharType Ch; + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream &os, unsigned codepoint) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + if (codepoint <= 0xFFFF) + { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + os.Put(static_cast(codepoint)); + } + else + { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + os.Put(static_cast((v >> 10) | 0xD800)); + os.Put(static_cast((v & 0x3FF) | 0xDC00)); + } + } + + + template + static void EncodeUnsafe(OutputStream &os, unsigned codepoint) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + if (codepoint <= 0xFFFF) + { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + PutUnsafe(os, static_cast(codepoint)); + } + else + { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + PutUnsafe(os, static_cast((v >> 10) | 0xD800)); + PutUnsafe(os, static_cast((v & 0x3FF) | 0xDC00)); + } + } + + template + static bool Decode(InputStream &is, unsigned *codepoint) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + typename InputStream::Ch c = is.Take(); + if (c < 0xD800 || c > 0xDFFF) + { + *codepoint = static_cast(c); + return true; + } + else if (c <= 0xDBFF) + { + *codepoint = (static_cast(c) & 0x3FF) << 10; + c = is.Take(); + *codepoint |= (static_cast(c) & 0x3FF); + *codepoint += 0x10000; + return c >= 0xDC00 && c <= 0xDFFF; + } + return false; + } + + template + static bool Validate(InputStream &is, OutputStream &os) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + typename InputStream::Ch c; + os.Put(static_cast(c = is.Take())); + if (c < 0xD800 || c > 0xDFFF) + return true; + else if (c <= 0xDBFF) + { + os.Put(c = is.Take()); + return c >= 0xDC00 && c <= 0xDFFF; + } + return false; + } +}; + +//! UTF-16 little endian encoding. +template +struct UTF16LE : UTF16 +{ + template + static CharType TakeBOM(InputByteStream &is) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0xFEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream &is) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())) << 8; + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream &os) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xFFu)); + os.Put(static_cast(0xFEu)); + } + + template + static void Put(OutputByteStream &os, CharType c) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(static_cast(c) & 0xFFu)); + os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); + } +}; + +//! UTF-16 big endian encoding. +template +struct UTF16BE : UTF16 +{ + template + static CharType TakeBOM(InputByteStream &is) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0xFEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream &is) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())); + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream &os) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0xFFu)); + } + + template + static void Put(OutputByteStream &os, CharType c) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); + os.Put(static_cast(static_cast(c) & 0xFFu)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// UTF32 + +//! UTF-32 encoding. +/*! http://en.wikipedia.org/wiki/UTF-32 + \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. + \note implements Encoding concept + + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. + For streaming, use UTF32LE and UTF32BE, which handle endianness. +*/ +template +struct UTF32 +{ + typedef CharType Ch; + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); + + enum { supportUnicode = 1 }; + + template + static void Encode(OutputStream &os, unsigned codepoint) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + os.Put(codepoint); + } + + template + static void EncodeUnsafe(OutputStream &os, unsigned codepoint) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + PutUnsafe(os, codepoint); + } + + template + static bool Decode(InputStream &is, unsigned *codepoint) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + Ch c = is.Take(); + *codepoint = c; + return c <= 0x10FFFF; + } + + template + static bool Validate(InputStream &is, OutputStream &os) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + Ch c; + os.Put(c = is.Take()); + return c <= 0x10FFFF; + } +}; + +//! UTF-32 little endian enocoding. +template +struct UTF32LE : UTF32 +{ + template + static CharType TakeBOM(InputByteStream &is) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0x0000FEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream &is) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())) << 16; + c |= static_cast(static_cast(is.Take())) << 24; + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream &os) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0xFFu)); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0x00u)); + } + + template + static void Put(OutputByteStream &os, CharType c) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c & 0xFFu)); + os.Put(static_cast((c >> 8) & 0xFFu)); + os.Put(static_cast((c >> 16) & 0xFFu)); + os.Put(static_cast((c >> 24) & 0xFFu)); + } +}; + +//! UTF-32 big endian encoding. +template +struct UTF32BE : UTF32 +{ + template + static CharType TakeBOM(InputByteStream &is) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return static_cast(c) == 0x0000FEFFu ? Take(is) : c; + } + + template + static CharType Take(InputByteStream &is) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + unsigned c = static_cast(static_cast(is.Take())) << 24; + c |= static_cast(static_cast(is.Take())) << 16; + c |= static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())); + return static_cast(c); + } + + template + static void PutBOM(OutputByteStream &os) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0xFFu)); + } + + template + static void Put(OutputByteStream &os, CharType c) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast((c >> 24) & 0xFFu)); + os.Put(static_cast((c >> 16) & 0xFFu)); + os.Put(static_cast((c >> 8) & 0xFFu)); + os.Put(static_cast(c & 0xFFu)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// ASCII + +//! ASCII encoding. +/*! http://en.wikipedia.org/wiki/ASCII + \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. + \note implements Encoding concept +*/ +template +struct ASCII +{ + typedef CharType Ch; + + enum { supportUnicode = 0 }; + + template + static void Encode(OutputStream &os, unsigned codepoint) + { + RAPIDJSON_ASSERT(codepoint <= 0x7F); + os.Put(static_cast(codepoint & 0xFF)); + } + + template + static void EncodeUnsafe(OutputStream &os, unsigned codepoint) + { + RAPIDJSON_ASSERT(codepoint <= 0x7F); + PutUnsafe(os, static_cast(codepoint & 0xFF)); + } + + template + static bool Decode(InputStream &is, unsigned *codepoint) + { + uint8_t c = static_cast(is.Take()); + *codepoint = c; + return c <= 0X7F; + } + + template + static bool Validate(InputStream &is, OutputStream &os) + { + uint8_t c = static_cast(is.Take()); + os.Put(static_cast(c)); + return c <= 0x7F; + } + + template + static CharType TakeBOM(InputByteStream &is) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + uint8_t c = static_cast(Take(is)); + return static_cast(c); + } + + template + static Ch Take(InputByteStream &is) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + return static_cast(is.Take()); + } + + template + static void PutBOM(OutputByteStream &os) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + (void)os; + } + + template + static void Put(OutputByteStream &os, Ch c) + { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// AutoUTF + +//! Runtime-specified UTF encoding type of a stream. +enum UTFType +{ + kUTF8 = 0, //!< UTF-8. + kUTF16LE = 1, //!< UTF-16 little endian. + kUTF16BE = 2, //!< UTF-16 big endian. + kUTF32LE = 3, //!< UTF-32 little endian. + kUTF32BE = 4 //!< UTF-32 big endian. +}; + +//! Dynamically select encoding according to stream's runtime-specified UTF encoding type. +/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). +*/ +template +struct AutoUTF +{ + typedef CharType Ch; + + enum { supportUnicode = 1 }; + +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x + + template + static RAPIDJSON_FORCEINLINE void Encode(OutputStream &os, unsigned codepoint) + { + typedef void (*EncodeFunc)(OutputStream &, unsigned); + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; + (*f[os.GetType()])(os, codepoint); + } + + template + static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream &os, unsigned codepoint) + { + typedef void (*EncodeFunc)(OutputStream &, unsigned); + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; + (*f[os.GetType()])(os, codepoint); + } + + template + static RAPIDJSON_FORCEINLINE bool Decode(InputStream &is, unsigned *codepoint) + { + typedef bool (*DecodeFunc)(InputStream &, unsigned *); + static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; + return (*f[is.GetType()])(is, codepoint); + } + + template + static RAPIDJSON_FORCEINLINE bool Validate(InputStream &is, OutputStream &os) + { + typedef bool (*ValidateFunc)(InputStream &, OutputStream &); + static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; + return (*f[is.GetType()])(is, os); + } + +#undef RAPIDJSON_ENCODINGS_FUNC +}; + +/////////////////////////////////////////////////////////////////////////////// +// Transcoder + +//! Encoding conversion. +template +struct Transcoder +{ + //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. + template + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream &is, OutputStream &os) + { + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + TargetEncoding::Encode(os, codepoint); + return true; + } + + template + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream &is, OutputStream &os) + { + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + TargetEncoding::EncodeUnsafe(os, codepoint); + return true; + } + + //! Validate one Unicode codepoint from an encoded stream. + template + static RAPIDJSON_FORCEINLINE bool Validate(InputStream &is, OutputStream &os) + { + return Transcode(is, os); // Since source/target encoding is different, must transcode. + } +}; + +// Forward declaration. +template +inline void PutUnsafe(Stream &stream, typename Stream::Ch c); + +//! Specialization of Transcoder with same source and target encoding. +template +struct Transcoder +{ + template + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream &is, OutputStream &os) + { + os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. + return true; + } + + template + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream &is, OutputStream &os) + { + PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. + return true; + } + + template + static RAPIDJSON_FORCEINLINE bool Validate(InputStream &is, OutputStream &os) + { + return Encoding::Validate(is, os); // source/target encoding are the same + } +}; + +RAPIDJSON_NAMESPACE_END + +#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__)) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ENCODINGS_H_ diff --git a/contrib/world_builder/include/rapidjson/error/en.h.bak b/contrib/world_builder/include/rapidjson/error/en.h.bak new file mode 100644 index 00000000000..d817e0c5825 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/error/en.h.bak @@ -0,0 +1,95 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ERROR_EN_H_ +#define RAPIDJSON_ERROR_EN_H_ + +#include "error.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +//RAPIDJSON_DIAG_OFF(switch -enum) +// RAPIDJSON_DIAG_OFF(covered-switch -default) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Maps error code of parsing into error message. +/*! + \ingroup RAPIDJSON_ERRORS + \param parseErrorCode Error code obtained in parsing. + \return the error message. + \note User can make a copy of this function for localization. + Using switch-case is safer for future modification of error codes. +*/ +inline const RAPIDJSON_ERROR_CHARTYPE *GetParseError_En(ParseErrorCode parseErrorCode) +{ + switch (parseErrorCode) + { + case kParseErrorNone: + return RAPIDJSON_ERROR_STRING("No error."); + + case kParseErrorDocumentEmpty: + return RAPIDJSON_ERROR_STRING("The document is empty."); + case kParseErrorDocumentRootNotSingular: + return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); + + case kParseErrorValueInvalid: + return RAPIDJSON_ERROR_STRING("Invalid value."); + + case kParseErrorObjectMissName: + return RAPIDJSON_ERROR_STRING("Missing a name for object member."); + case kParseErrorObjectMissColon: + return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); + case kParseErrorObjectMissCommaOrCurlyBracket: + return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); + + case kParseErrorArrayMissCommaOrSquareBracket: + return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); + + case kParseErrorStringUnicodeEscapeInvalidHex: + return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); + case kParseErrorStringUnicodeSurrogateInvalid: + return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); + case kParseErrorStringEscapeInvalid: + return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); + case kParseErrorStringMissQuotationMark: + return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); + case kParseErrorStringInvalidEncoding: + return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); + + case kParseErrorNumberTooBig: + return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); + case kParseErrorNumberMissFraction: + return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); + case kParseErrorNumberMissExponent: + return RAPIDJSON_ERROR_STRING("Miss exponent in number."); + + case kParseErrorTermination: + return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); + case kParseErrorUnspecificSyntaxError: + return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); + + default: + return RAPIDJSON_ERROR_STRING("Unknown error."); + } +} + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_EN_H_ diff --git a/contrib/world_builder/include/rapidjson/error/error.h.bak b/contrib/world_builder/include/rapidjson/error/error.h.bak new file mode 100644 index 00000000000..3e4058097da --- /dev/null +++ b/contrib/world_builder/include/rapidjson/error/error.h.bak @@ -0,0 +1,200 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ERROR_ERROR_H_ +#define RAPIDJSON_ERROR_ERROR_H_ + +#include "../rapidjson.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +/*! \file error.h */ + +/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ERROR_CHARTYPE + +//! Character type of error messages. +/*! \ingroup RAPIDJSON_ERRORS + The default character type is \c char. + On Windows, user can define this macro as \c TCHAR for supporting both + unicode/non-unicode settings. +*/ +#ifndef RAPIDJSON_ERROR_CHARTYPE +#define RAPIDJSON_ERROR_CHARTYPE char +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ERROR_STRING + +//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. +/*! \ingroup RAPIDJSON_ERRORS + By default this conversion macro does nothing. + On Windows, user can define this macro as \c _T(x) for supporting both + unicode/non-unicode settings. +*/ +#ifndef RAPIDJSON_ERROR_STRING +#define RAPIDJSON_ERROR_STRING(x) x +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// ParseErrorCode + +//! Error code of parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericReader::Parse, GenericReader::GetParseErrorCode +*/ +enum ParseErrorCode +{ + kParseErrorNone = 0, //!< No error. + + kParseErrorDocumentEmpty, //!< The document is empty. + kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. + + kParseErrorValueInvalid, //!< Invalid value. + + kParseErrorObjectMissName, //!< Missing a name for object member. + kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. + kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. + + kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. + + kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. + kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. + kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. + kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. + kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. + + kParseErrorNumberTooBig, //!< Number too big to be stored in double. + kParseErrorNumberMissFraction, //!< Miss fraction part in number. + kParseErrorNumberMissExponent, //!< Miss exponent in number. + + kParseErrorTermination, //!< Parsing was terminated. + kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. +}; + +//! Result of parsing (wraps ParseErrorCode) +/*! + \ingroup RAPIDJSON_ERRORS + \code + Document doc; + ParseResult ok = doc.Parse("[42]"); + if (!ok) { + fprintf(stderr, "JSON parse error: %s (%u)", + GetParseError_En(ok.Code()), ok.Offset()); + exit(EXIT_FAILURE); + } + \endcode + \see GenericReader::Parse, GenericDocument::Parse +*/ +struct ParseResult +{ + //!! Unspecified boolean type + typedef bool (ParseResult::*BooleanType)() const; + public: + //! Default constructor, no error. + ParseResult() : code_(kParseErrorNone), offset_(0) {} + //! Constructor to set an error. + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} + + //! Get the error code. + ParseErrorCode Code() const + { + return code_; + } + //! Get the error offset, if \ref IsError(), 0 otherwise. + size_t Offset() const + { + return offset_; + } + + //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). + operator BooleanType() const + { + return !IsError() ? &ParseResult::IsError : NULL; + } + //! Whether the result is an error. + bool IsError() const + { + return code_ != kParseErrorNone; + } + + bool operator==(const ParseResult &that) const + { + return code_ == that.code_; + } + bool operator==(ParseErrorCode code) const + { + return code_ == code; + } + friend bool operator==(ParseErrorCode code, const ParseResult &err) + { + return code == err.code_; + } + + bool operator!=(const ParseResult &that) const + { + return !(*this == that); + } + bool operator!=(ParseErrorCode code) const + { + return !(*this == code); + } + friend bool operator!=(ParseErrorCode code, const ParseResult &err) + { + return err != code; + } + + //! Reset error code. + void Clear() + { + Set(kParseErrorNone); + } + //! Update error code and offset. + void Set(ParseErrorCode code, size_t offset = 0) + { + code_ = code; + offset_ = offset; + } + + private: + ParseErrorCode code_; + size_t offset_; +}; + +//! Function pointer type of GetParseError(). +/*! \ingroup RAPIDJSON_ERRORS + + This is the prototype for \c GetParseError_X(), where \c X is a locale. + User can dynamically change locale in runtime, e.g.: +\code + GetParseErrorFunc GetParseError = GetParseError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); +\endcode +*/ +typedef const RAPIDJSON_ERROR_CHARTYPE *(*GetParseErrorFunc)(ParseErrorCode); + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_ERROR_H_ diff --git a/contrib/world_builder/include/rapidjson/filereadstream.h.bak b/contrib/world_builder/include/rapidjson/filereadstream.h.bak new file mode 100644 index 00000000000..076e0e48f0f --- /dev/null +++ b/contrib/world_builder/include/rapidjson/filereadstream.h.bak @@ -0,0 +1,130 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FILEREADSTREAM_H_ +#define RAPIDJSON_FILEREADSTREAM_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! File byte stream for input using fread(). +/*! + \note implements Stream concept +*/ +class FileReadStream +{ + public: + typedef char Ch; //!< Character type (byte). + + //! Constructor. + /*! + \param fp File pointer opened for read. + \param buffer user-supplied buffer. + \param bufferSize size of buffer in bytes. Must >=4 bytes. + */ + FileReadStream(std::FILE *fp, char *buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) + { + RAPIDJSON_ASSERT(fp_ != 0); + RAPIDJSON_ASSERT(bufferSize >= 4); + Read(); + } + + Ch Peek() const + { + return *current_; + } + Ch Take() + { + Ch c = *current_; + Read(); + return c; + } + size_t Tell() const + { + return count_ + static_cast(current_ - buffer_); + } + + // Not implemented + void Put(Ch) + { + RAPIDJSON_ASSERT(false); + } + void Flush() + { + RAPIDJSON_ASSERT(false); + } + Ch *PutBegin() + { + RAPIDJSON_ASSERT(false); + return 0; + } + size_t PutEnd(Ch *) + { + RAPIDJSON_ASSERT(false); + return 0; + } + + // For encoding detection only. + const Ch *Peek4() const + { + return (current_ + 4 <= bufferLast_) ? current_ : 0; + } + + private: + void Read() + { + if (current_ < bufferLast_) + ++current_; + else if (!eof_) + { + count_ += readCount_; + readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); + bufferLast_ = buffer_ + readCount_ - 1; + current_ = buffer_; + + if (readCount_ < bufferSize_) + { + buffer_[readCount_] = '\0'; + ++bufferLast_; + eof_ = true; + } + } + } + + std::FILE *fp_; + Ch *buffer_; + size_t bufferSize_; + Ch *bufferLast_; + Ch *current_; + size_t readCount_; + size_t count_; //!< Number of characters read + bool eof_; +}; + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/contrib/world_builder/include/rapidjson/filewritestream.h.bak b/contrib/world_builder/include/rapidjson/filewritestream.h.bak new file mode 100644 index 00000000000..291e6991c87 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/filewritestream.h.bak @@ -0,0 +1,134 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FILEWRITESTREAM_H_ +#define RAPIDJSON_FILEWRITESTREAM_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of C file stream for output using fwrite(). +/*! + \note implements Stream concept +*/ +class FileWriteStream +{ + public: + typedef char Ch; //!< Character type. Only support char. + + FileWriteStream(std::FILE *fp, char *buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) + { + RAPIDJSON_ASSERT(fp_ != 0); + } + + void Put(char c) + { + if (current_ >= bufferEnd_) + Flush(); + + *current_++ = c; + } + + void PutN(char c, size_t n) + { + size_t avail = static_cast(bufferEnd_ - current_); + while (n > avail) + { + std::memset(current_, c, avail); + current_ += avail; + Flush(); + n -= avail; + avail = static_cast(bufferEnd_ - current_); + } + + if (n > 0) + { + std::memset(current_, c, n); + current_ += n; + } + } + + void Flush() + { + if (current_ != buffer_) + { + size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + if (result < static_cast(current_ - buffer_)) + { + // failure deliberately ignored at this time + // added to avoid warn_unused_result build errors + } + current_ = buffer_; + } + } + + // Not implemented + char Peek() const + { + RAPIDJSON_ASSERT(false); + return 0; + } + char Take() + { + RAPIDJSON_ASSERT(false); + return 0; + } + size_t Tell() const + { + RAPIDJSON_ASSERT(false); + return 0; + } + char *PutBegin() + { + RAPIDJSON_ASSERT(false); + return 0; + } + size_t PutEnd(char *) + { + RAPIDJSON_ASSERT(false); + return 0; + } + + private: + // Prohibit copy constructor & assignment operator. + FileWriteStream(const FileWriteStream &); + FileWriteStream &operator=(const FileWriteStream &); + + std::FILE *fp_; + char *buffer_; + char *bufferEnd_; + char *current_; +}; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(FileWriteStream &stream, char c, size_t n) +{ + stream.PutN(c, n); +} + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_FILESTREAM_H_ diff --git a/contrib/world_builder/include/rapidjson/fwd.h.bak b/contrib/world_builder/include/rapidjson/fwd.h.bak new file mode 100644 index 00000000000..f280a4ea30b --- /dev/null +++ b/contrib/world_builder/include/rapidjson/fwd.h.bak @@ -0,0 +1,151 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FWD_H_ +#define RAPIDJSON_FWD_H_ + +#include "rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN + +// encodings.h + +template struct UTF8; +template struct UTF16; +template struct UTF16BE; +template struct UTF16LE; +template struct UTF32; +template struct UTF32BE; +template struct UTF32LE; +template struct ASCII; +template struct AutoUTF; + +template +struct Transcoder; + +// allocators.h + +class CrtAllocator; + +template +class MemoryPoolAllocator; + +// stream.h + +template +struct GenericStringStream; + +typedef GenericStringStream > StringStream; + +template +struct GenericInsituStringStream; + +typedef GenericInsituStringStream > InsituStringStream; + +// stringbuffer.h + +template +class GenericStringBuffer; + +typedef GenericStringBuffer, CrtAllocator> StringBuffer; + +// filereadstream.h + +class FileReadStream; + +// filewritestream.h + +class FileWriteStream; + +// memorybuffer.h + +template +struct GenericMemoryBuffer; + +typedef GenericMemoryBuffer MemoryBuffer; + +// memorystream.h + +struct MemoryStream; + +// reader.h + +template +struct BaseReaderHandler; + +template +class GenericReader; + +typedef GenericReader, UTF8, CrtAllocator> Reader; + +// writer.h + +template +class Writer; + +// prettywriter.h + +template +class PrettyWriter; + +// document.h + +template +struct GenericMember; + +template +class GenericMemberIterator; + +template +struct GenericStringRef; + +template +class GenericValue; + +typedef GenericValue, MemoryPoolAllocator > Value; + +template +class GenericDocument; + +typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; + +// pointer.h + +template +class GenericPointer; + +typedef GenericPointer Pointer; + +// schema.h + +template +class IGenericRemoteSchemaDocumentProvider; + +template +class GenericSchemaDocument; + +typedef GenericSchemaDocument SchemaDocument; +typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; + +template < + typename SchemaDocumentType, + typename OutputHandler, + typename StateAllocator> +class GenericSchemaValidator; + +typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_RAPIDJSONFWD_H_ diff --git a/contrib/world_builder/include/rapidjson/internal/biginteger.h.bak b/contrib/world_builder/include/rapidjson/internal/biginteger.h.bak new file mode 100644 index 00000000000..04a30c670a7 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/internal/biginteger.h.bak @@ -0,0 +1,340 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_BIGINTEGER_H_ +#define RAPIDJSON_BIGINTEGER_H_ + +#include "../rapidjson.h" + +#if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64) +#include // for _umul128 +#pragma intrinsic(_umul128) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal +{ + + class BigInteger + { + public: + typedef uint64_t Type; + + BigInteger(const BigInteger &rhs) : count_(rhs.count_) + { + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); + } + + explicit BigInteger(uint64_t u) : count_(1) + { + digits_[0] = u; + } + + BigInteger(const char *decimals, size_t length) : count_(1) + { + RAPIDJSON_ASSERT(length > 0); + digits_[0] = 0; + size_t i = 0; + const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 + while (length >= kMaxDigitPerIteration) + { + AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); + length -= kMaxDigitPerIteration; + i += kMaxDigitPerIteration; + } + + if (length > 0) + AppendDecimal64(decimals + i, decimals + i + length); + } + + BigInteger &operator=(const BigInteger &rhs) + { + if (this != &rhs) + { + count_ = rhs.count_; + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); + } + return *this; + } + + BigInteger &operator=(uint64_t u) + { + digits_[0] = u; + count_ = 1; + return *this; + } + + BigInteger &operator+=(uint64_t u) + { + Type backup = digits_[0]; + digits_[0] += u; + for (size_t i = 0; i < count_ - 1; i++) + { + if (digits_[i] >= backup) + return *this; // no carry + backup = digits_[i + 1]; + digits_[i + 1] += 1; + } + + // Last carry + if (digits_[count_ - 1] < backup) + PushBack(1); + + return *this; + } + + BigInteger &operator*=(uint64_t u) + { + if (u == 0) return *this = 0; + if (u == 1) return *this; + if (*this == 1) return *this = u; + + uint64_t k = 0; + for (size_t i = 0; i < count_; i++) + { + uint64_t hi; + digits_[i] = MulAdd64(digits_[i], u, k, &hi); + k = hi; + } + + if (k > 0) + PushBack(k); + + return *this; + } + + BigInteger &operator*=(uint32_t u) + { + if (u == 0) return *this = 0; + if (u == 1) return *this; + if (*this == 1) return *this = u; + + uint64_t k = 0; + for (size_t i = 0; i < count_; i++) + { + const uint64_t c = digits_[i] >> 32; + const uint64_t d = digits_[i] & 0xFFFFFFFF; + const uint64_t uc = u * c; + const uint64_t ud = u * d; + const uint64_t p0 = ud + k; + const uint64_t p1 = uc + (p0 >> 32); + digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32); + k = p1 >> 32; + } + + if (k > 0) + PushBack(k); + + return *this; + } + + BigInteger &operator<<=(size_t shift) + { + if (IsZero() || shift == 0) return *this; + + size_t offset = shift / kTypeBit; + size_t interShift = shift % kTypeBit; + RAPIDJSON_ASSERT(count_ + offset <= kCapacity); + + if (interShift == 0) + { + std::memmove(digits_ + offset, digits_, count_ * sizeof(Type)); + count_ += offset; + } + else + { + digits_[count_] = 0; + for (size_t i = count_; i > 0; i--) + digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); + digits_[offset] = digits_[0] << interShift; + count_ += offset; + if (digits_[count_]) + count_++; + } + + std::memset(digits_, 0, offset * sizeof(Type)); + + return *this; + } + + bool operator==(const BigInteger &rhs) const + { + return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; + } + + bool operator==(const Type rhs) const + { + return count_ == 1 && digits_[0] == rhs; + } + + BigInteger &MultiplyPow5(unsigned exp) + { + static const uint32_t kPow5[12] = + { + 5, + 5 * 5, + 5 * 5 * 5, + 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 + }; + if (exp == 0) return *this; + for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 + for (; exp >= 13; exp -= 13) *this *= static_cast(1220703125u); // 5^13 + if (exp > 0) *this *= kPow5[exp - 1]; + return *this; + } + + // Compute absolute difference of this and rhs. + // Assume this != rhs + bool Difference(const BigInteger &rhs, BigInteger *out) const + { + int cmp = Compare(rhs); + RAPIDJSON_ASSERT(cmp != 0); + const BigInteger *a, *b; // Makes a > b + bool ret; + if (cmp < 0) + { + a = &rhs; + b = this; + ret = true; + } + else + { + a = this; + b = &rhs; + ret = false; + } + + Type borrow = 0; + for (size_t i = 0; i < a->count_; i++) + { + Type d = a->digits_[i] - borrow; + if (i < b->count_) + d -= b->digits_[i]; + borrow = (d > a->digits_[i]) ? 1 : 0; + out->digits_[i] = d; + if (d != 0) + out->count_ = i + 1; + } + + return ret; + } + + int Compare(const BigInteger &rhs) const + { + if (count_ != rhs.count_) + return count_ < rhs.count_ ? -1 : 1; + + for (size_t i = count_; i-- > 0;) + if (digits_[i] != rhs.digits_[i]) + return digits_[i] < rhs.digits_[i] ? -1 : 1; + + return 0; + } + + size_t GetCount() const + { + return count_; + } + Type GetDigit(size_t index) const + { + RAPIDJSON_ASSERT(index < count_); + return digits_[index]; + } + bool IsZero() const + { + return count_ == 1 && digits_[0] == 0; + } + + private: + void AppendDecimal64(const char *begin, const char *end) + { + uint64_t u = ParseUint64(begin, end); + if (IsZero()) + *this = u; + else + { + unsigned exp = static_cast(end - begin); + (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u + } + } + + void PushBack(Type digit) + { + RAPIDJSON_ASSERT(count_ < kCapacity); + digits_[count_++] = digit; + } + + static uint64_t ParseUint64(const char *begin, const char *end) + { + uint64_t r = 0; + for (const char *p = begin; p != end; ++p) + { + RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); + r = r * 10u + static_cast(*p - '0'); + } + return r; + } + + // Assume a * b + k < 2^128 + static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t *outHigh) + { +#if defined(_MSC_VER) && defined(_M_AMD64) + uint64_t low = _umul128(a, b, outHigh) + k; + if (low < k) + (*outHigh)++; + return low; +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) + __extension__ typedef unsigned __int128 uint128; + uint128 p = static_cast(a) * static_cast(b); + p += k; + *outHigh = static_cast(p >> 64); + return static_cast(p); +#else + const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; + uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; + x1 += (x0 >> 32); // can't give carry + x1 += x2; + if (x1 < x2) + x3 += (static_cast(1) << 32); + uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); + uint64_t hi = x3 + (x1 >> 32); + + lo += k; + if (lo < k) + hi++; + *outHigh = hi; + return lo; +#endif + } + + static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 + static const size_t kCapacity = kBitCount / sizeof(Type); + static const size_t kTypeBit = sizeof(Type) * 8; + + Type digits_[kCapacity]; + size_t count_; + }; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_BIGINTEGER_H_ diff --git a/contrib/world_builder/include/rapidjson/internal/diyfp.h.bak b/contrib/world_builder/include/rapidjson/internal/diyfp.h.bak new file mode 100644 index 00000000000..09de0161156 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/internal/diyfp.h.bak @@ -0,0 +1,293 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// This is a C++ header-only implementation of Grisu2 algorithm from the publication: +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with +// integers." ACM Sigplan Notices 45.6 (2010): 233-243. + +#ifndef RAPIDJSON_DIYFP_H_ +#define RAPIDJSON_DIYFP_H_ + +#include "../rapidjson.h" +#include + +#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) +#include +#pragma intrinsic(_BitScanReverse64) +#pragma intrinsic(_umul128) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal +{ + +#ifdef __GNUC__ + RAPIDJSON_DIAG_PUSH + RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ + RAPIDJSON_DIAG_PUSH + RAPIDJSON_DIAG_OFF(padded) +#endif + + struct DiyFp + { + DiyFp() : f(), e() {} + + DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} + + explicit DiyFp(double d) + { + union + { + double d; + uint64_t u64; + } u = { d }; + + int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); + uint64_t significand = (u.u64 & kDpSignificandMask); + if (biased_e != 0) + { + f = significand + kDpHiddenBit; + e = biased_e - kDpExponentBias; + } + else + { + f = significand; + e = kDpMinExponent + 1; + } + } + + DiyFp operator-(const DiyFp &rhs) const + { + return DiyFp(f - rhs.f, e); + } + + DiyFp operator*(const DiyFp &rhs) const + { +#if defined(_MSC_VER) && defined(_M_AMD64) + uint64_t h; + uint64_t l = _umul128(f, rhs.f, &h); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) + __extension__ typedef unsigned __int128 uint128; + uint128 p = static_cast(f) * static_cast(rhs.f); + uint64_t h = static_cast(p >> 64); + uint64_t l = static_cast(p); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); +#else + const uint64_t M32 = 0xFFFFFFFF; + const uint64_t a = f >> 32; + const uint64_t b = f & M32; + const uint64_t c = rhs.f >> 32; + const uint64_t d = rhs.f & M32; + const uint64_t ac = a * c; + const uint64_t bc = b * c; + const uint64_t ad = a * d; + const uint64_t bd = b * d; + uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); + tmp += 1U << 31; /// mult_round + return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); +#endif + } + + DiyFp Normalize() const + { + RAPIDJSON_ASSERT(f != 0); // https://stackoverflow.com/a/26809183/291737 +#if defined(_MSC_VER) && defined(_M_AMD64) + unsigned long index; + _BitScanReverse64(&index, f); + return DiyFp(f << (63 - index), e - (63 - index)); +#elif defined(__GNUC__) && __GNUC__ >= 4 + int s = __builtin_clzll(f); + return DiyFp(f << s, e - s); +#else + DiyFp res = *this; + while (!(res.f & (static_cast(1) << 63))) + { + res.f <<= 1; + res.e--; + } + return res; +#endif + } + + DiyFp NormalizeBoundary() const + { + DiyFp res = *this; + while (!(res.f & (kDpHiddenBit << 1))) + { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); + return res; + } + + void NormalizedBoundaries(DiyFp *minus, DiyFp *plus) const + { + DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); + DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *plus = pl; + *minus = mi; + } + + double ToDouble() const + { + union + { + double d; + uint64_t u64; + } u; + RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask); + if (e < kDpDenormalExponent) + { + // Underflow. + return 0.0; + } + if (e >= kDpMaxExponent) + { + // Overflow. + return std::numeric_limits::infinity(); + } + const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : + static_cast(e + kDpExponentBias); + u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); + return u.d; + } + + static const int kDiySignificandSize = 64; + static const int kDpSignificandSize = 52; + static const int kDpExponentBias = 0x3FF + kDpSignificandSize; + static const int kDpMaxExponent = 0x7FF - kDpExponentBias; + static const int kDpMinExponent = -kDpExponentBias; + static const int kDpDenormalExponent = -kDpExponentBias + 1; + static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + + uint64_t f; + int e; + }; + + inline DiyFp GetCachedPowerByIndex(size_t index) + { + // 10^-348, 10^-340, ..., 10^340 + static const uint64_t kCachedPowers_F[] = + { + RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), + RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), + RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), + RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), + RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), + RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), + RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), + RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), + RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), + RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), + RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), + RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), + RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), + RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), + RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), + RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), + RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), + RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), + RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), + RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), + RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), + RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), + RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), + RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), + RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), + RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), + RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), + RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), + RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), + RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), + RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), + RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), + RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), + RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), + RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), + RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), + RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), + RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), + RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), + RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), + RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), + RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), + RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), + RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) + }; + static const int16_t kCachedPowers_E[] = + { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, + -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, + -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, + -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, + -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, + 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, + 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, + 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, + 907, 933, 960, 986, 1013, 1039, 1066 + }; + RAPIDJSON_ASSERT(index < 87); + return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); + } + + inline DiyFp GetCachedPower(int e, int *K) + { + + //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; + double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive + int k = static_cast(dk); + if (dk - k > 0.0) + k++; + + unsigned index = static_cast((k >> 3) + 1); + *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table + + return GetCachedPowerByIndex(index); + } + + inline DiyFp GetCachedPower10(int exp, int *outExp) + { + RAPIDJSON_ASSERT(exp >= -348); + unsigned index = static_cast(exp + 348) / 8u; + *outExp = -348 + static_cast(index) * 8; + return GetCachedPowerByIndex(index); + } + +#ifdef __GNUC__ + RAPIDJSON_DIAG_POP +#endif + +#ifdef __clang__ + RAPIDJSON_DIAG_POP + RAPIDJSON_DIAG_OFF(padded) +#endif + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_DIYFP_H_ diff --git a/contrib/world_builder/include/rapidjson/internal/dtoa.h.bak b/contrib/world_builder/include/rapidjson/internal/dtoa.h.bak new file mode 100644 index 00000000000..2655748aac6 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/internal/dtoa.h.bak @@ -0,0 +1,301 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// This is a C++ header-only implementation of Grisu2 algorithm from the publication: +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with +// integers." ACM Sigplan Notices 45.6 (2010): 233-243. + +#ifndef RAPIDJSON_DTOA_ +#define RAPIDJSON_DTOA_ + +#include "itoa.h" // GetDigitsLut() +#include "diyfp.h" +#include "ieee754.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal +{ + +#ifdef __GNUC__ + RAPIDJSON_DIAG_PUSH + RAPIDJSON_DIAG_OFF(effc++) + RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 +#endif + + inline void GrisuRound(char *buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) + { + while (rest < wp_w && delta - rest >= ten_kappa && + (rest + ten_kappa < wp_w || /// closer + wp_w - rest > rest + ten_kappa - wp_w)) + { + buffer[len - 1]--; + rest += ten_kappa; + } + } + + inline int CountDecimalDigit32(uint32_t n) + { + // Simple pure C++ implementation was faster than __builtin_clz version in this situation. + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1000) return 3; + if (n < 10000) return 4; + if (n < 100000) return 5; + if (n < 1000000) return 6; + if (n < 10000000) return 7; + if (n < 100000000) return 8; + // Will not reach 10 digits in DigitGen() + //if (n < 1000000000) return 9; + //return 10; + return 9; + } + + inline void DigitGen(const DiyFp &W, const DiyFp &Mp, uint64_t delta, char *buffer, int *len, int *K) + { + static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); + const DiyFp wp_w = Mp - W; + uint32_t p1 = static_cast(Mp.f >> -one.e); + uint64_t p2 = Mp.f & (one.f - 1); + int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] + *len = 0; + + while (kappa > 0) + { + uint32_t d = 0; + switch (kappa) + { + case 9: + d = p1 / 100000000; + p1 %= 100000000; + break; + case 8: + d = p1 / 10000000; + p1 %= 10000000; + break; + case 7: + d = p1 / 1000000; + p1 %= 1000000; + break; + case 6: + d = p1 / 100000; + p1 %= 100000; + break; + case 5: + d = p1 / 10000; + p1 %= 10000; + break; + case 4: + d = p1 / 1000; + p1 %= 1000; + break; + case 3: + d = p1 / 100; + p1 %= 100; + break; + case 2: + d = p1 / 10; + p1 %= 10; + break; + case 1: + d = p1; + p1 = 0; + break; + default: + ; + } + if (d || *len) + buffer[(*len)++] = static_cast('0' + static_cast(d)); + kappa--; + uint64_t tmp = (static_cast(p1) << -one.e) + p2; + if (tmp <= delta) + { + *K += kappa; + GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); + return; + } + } + + // kappa = 0 + for (;;) + { + p2 *= 10; + delta *= 10; + char d = static_cast(p2 >> -one.e); + if (d || *len) + buffer[(*len)++] = static_cast('0' + d); + p2 &= one.f - 1; + kappa--; + if (p2 < delta) + { + *K += kappa; + int index = -kappa; + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0)); + return; + } + } + } + + inline void Grisu2(double value, char *buffer, int *length, int *K) + { + const DiyFp v(value); + DiyFp w_m, w_p; + v.NormalizedBoundaries(&w_m, &w_p); + + const DiyFp c_mk = GetCachedPower(w_p.e, K); + const DiyFp W = v.Normalize() * c_mk; + DiyFp Wp = w_p * c_mk; + DiyFp Wm = w_m * c_mk; + Wm.f++; + Wp.f--; + DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); + } + + inline char *WriteExponent(int K, char *buffer) + { + if (K < 0) + { + *buffer++ = '-'; + K = -K; + } + + if (K >= 100) + { + *buffer++ = static_cast('0' + static_cast(K / 100)); + K %= 100; + const char *d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else if (K >= 10) + { + const char *d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else + *buffer++ = static_cast('0' + static_cast(K)); + + return buffer; + } + + inline char *Prettify(char *buffer, int length, int k, int maxDecimalPlaces) + { + const int kk = length + k; // 10^(kk-1) <= v < 10^kk + + if (0 <= k && kk <= 21) + { + // 1234e7 -> 12340000000 + for (int i = length; i < kk; i++) + buffer[i] = '0'; + buffer[kk] = '.'; + buffer[kk + 1] = '0'; + return &buffer[kk + 2]; + } + else if (0 < kk && kk <= 21) + { + // 1234e-2 -> 12.34 + std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); + buffer[kk] = '.'; + if (0 > k + maxDecimalPlaces) + { + // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[kk + 2]; // Reserve one zero + } + else + return &buffer[length + 1]; + } + else if (-6 < kk && kk <= 0) + { + // 1234e-6 -> 0.001234 + const int offset = 2 - kk; + std::memmove(&buffer[offset], &buffer[0], static_cast(length)); + buffer[0] = '0'; + buffer[1] = '.'; + for (int i = 2; i < offset; i++) + buffer[i] = '0'; + if (length - kk > maxDecimalPlaces) + { + // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = maxDecimalPlaces + 1; i > 2; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[3]; // Reserve one zero + } + else + return &buffer[length + offset]; + } + else if (kk < -maxDecimalPlaces) + { + // Truncate to zero + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + else if (length == 1) + { + // 1e30 + buffer[1] = 'e'; + return WriteExponent(kk - 1, &buffer[2]); + } + else + { + // 1234e30 -> 1.234e33 + std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); + buffer[1] = '.'; + buffer[length + 1] = 'e'; + return WriteExponent(kk - 1, &buffer[0 + length + 2]); + } + } + + inline char *dtoa(double value, char *buffer, int maxDecimalPlaces = 324) + { + RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); + Double d(value); + if (d.IsZero()) + { + if (d.Sign()) + *buffer++ = '-'; // -0.0, Issue #289 + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + else + { + if (value < 0) + { + *buffer++ = '-'; + value = -value; + } + int length, K; + Grisu2(value, buffer, &length, &K); + return Prettify(buffer, length, K, maxDecimalPlaces); + } + } + +#ifdef __GNUC__ + RAPIDJSON_DIAG_POP +#endif + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_DTOA_ diff --git a/contrib/world_builder/include/rapidjson/internal/ieee754.h.bak b/contrib/world_builder/include/rapidjson/internal/ieee754.h.bak new file mode 100644 index 00000000000..44db4b48955 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/internal/ieee754.h.bak @@ -0,0 +1,122 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_IEEE754_ +#define RAPIDJSON_IEEE754_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal +{ + + class Double + { + public: + Double() {} + Double(double d) : d_(d) {} + Double(uint64_t u) : u_(u) {} + + double Value() const + { + return d_; + } + uint64_t Uint64Value() const + { + return u_; + } + + double NextPositiveDouble() const + { + RAPIDJSON_ASSERT(!Sign()); + return Double(u_ + 1).Value(); + } + + bool Sign() const + { + return (u_ & kSignMask) != 0; + } + uint64_t Significand() const + { + return u_ & kSignificandMask; + } + int Exponent() const + { + return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); + } + + bool IsNan() const + { + return (u_ & kExponentMask) == kExponentMask && Significand() != 0; + } + bool IsInf() const + { + return (u_ & kExponentMask) == kExponentMask && Significand() == 0; + } + bool IsNanOrInf() const + { + return (u_ & kExponentMask) == kExponentMask; + } + bool IsNormal() const + { + return (u_ & kExponentMask) != 0 || Significand() == 0; + } + bool IsZero() const + { + return (u_ & (kExponentMask | kSignificandMask)) == 0; + } + + uint64_t IntegerSignificand() const + { + return IsNormal() ? Significand() | kHiddenBit : Significand(); + } + int IntegerExponent() const + { + return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; + } + uint64_t ToBias() const + { + return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; + } + + static int EffectiveSignificandSize(int order) + { + if (order >= -1021) + return 53; + else if (order <= -1074) + return 0; + else + return order + 1074; + } + + private: + static const int kSignificandSize = 52; + static const int kExponentBias = 0x3FF; + static const int kDenormalExponent = 1 - kExponentBias; + static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); + static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + + union + { + double d_; + uint64_t u_; + }; + }; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_IEEE754_ diff --git a/contrib/world_builder/include/rapidjson/internal/itoa.h.bak b/contrib/world_builder/include/rapidjson/internal/itoa.h.bak new file mode 100644 index 00000000000..23016b08a4d --- /dev/null +++ b/contrib/world_builder/include/rapidjson/internal/itoa.h.bak @@ -0,0 +1,329 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ITOA_ +#define RAPIDJSON_ITOA_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal +{ + + inline const char *GetDigitsLut() + { + static const char cDigitsLut[200] = + { + '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', + '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', + '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', + '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', + '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', + '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', + '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', + '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', + '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', + '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' + }; + return cDigitsLut; + } + + inline char *u32toa(uint32_t value, char *buffer) + { + RAPIDJSON_ASSERT(buffer != 0); + + const char *cDigitsLut = GetDigitsLut(); + + if (value < 10000) + { + const uint32_t d1 = (value / 100) << 1; + const uint32_t d2 = (value % 100) << 1; + + if (value >= 1000) + *buffer++ = cDigitsLut[d1]; + if (value >= 100) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 10) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + } + else if (value < 100000000) + { + // value = bbbbcccc + const uint32_t b = value / 10000; + const uint32_t c = value % 10000; + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + if (value >= 10000000) + *buffer++ = cDigitsLut[d1]; + if (value >= 1000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 100000) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + else + { + // value = aabbbbcccc in decimal + + const uint32_t a = value / 100000000; // 1 to 42 + value %= 100000000; + + if (a >= 10) + { + const unsigned i = a << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else + *buffer++ = static_cast('0' + static_cast(a)); + + const uint32_t b = value / 10000; // 0 to 9999 + const uint32_t c = value % 10000; // 0 to 9999 + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + *buffer++ = cDigitsLut[d1]; + *buffer++ = cDigitsLut[d1 + 1]; + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + return buffer; + } + + inline char *i32toa(int32_t value, char *buffer) + { + RAPIDJSON_ASSERT(buffer != 0); + uint32_t u = static_cast(value); + if (value < 0) + { + *buffer++ = '-'; + u = ~u + 1; + } + + return u32toa(u, buffer); + } + + inline char *u64toa(uint64_t value, char *buffer) + { + RAPIDJSON_ASSERT(buffer != 0); + const char *cDigitsLut = GetDigitsLut(); + const uint64_t kTen8 = 100000000; + const uint64_t kTen9 = kTen8 * 10; + const uint64_t kTen10 = kTen8 * 100; + const uint64_t kTen11 = kTen8 * 1000; + const uint64_t kTen12 = kTen8 * 10000; + const uint64_t kTen13 = kTen8 * 100000; + const uint64_t kTen14 = kTen8 * 1000000; + const uint64_t kTen15 = kTen8 * 10000000; + const uint64_t kTen16 = kTen8 * kTen8; + + if (value < kTen8) + { + uint32_t v = static_cast(value); + if (v < 10000) + { + const uint32_t d1 = (v / 100) << 1; + const uint32_t d2 = (v % 100) << 1; + + if (v >= 1000) + *buffer++ = cDigitsLut[d1]; + if (v >= 100) + *buffer++ = cDigitsLut[d1 + 1]; + if (v >= 10) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + } + else + { + // value = bbbbcccc + const uint32_t b = v / 10000; + const uint32_t c = v % 10000; + + const uint32_t d1 = (b / 100) << 1; + const uint32_t d2 = (b % 100) << 1; + + const uint32_t d3 = (c / 100) << 1; + const uint32_t d4 = (c % 100) << 1; + + if (value >= 10000000) + *buffer++ = cDigitsLut[d1]; + if (value >= 1000000) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= 100000) + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + } + } + else if (value < kTen16) + { + const uint32_t v0 = static_cast(value / kTen8); + const uint32_t v1 = static_cast(value % kTen8); + + const uint32_t b0 = v0 / 10000; + const uint32_t c0 = v0 % 10000; + + const uint32_t d1 = (b0 / 100) << 1; + const uint32_t d2 = (b0 % 100) << 1; + + const uint32_t d3 = (c0 / 100) << 1; + const uint32_t d4 = (c0 % 100) << 1; + + const uint32_t b1 = v1 / 10000; + const uint32_t c1 = v1 % 10000; + + const uint32_t d5 = (b1 / 100) << 1; + const uint32_t d6 = (b1 % 100) << 1; + + const uint32_t d7 = (c1 / 100) << 1; + const uint32_t d8 = (c1 % 100) << 1; + + if (value >= kTen15) + *buffer++ = cDigitsLut[d1]; + if (value >= kTen14) + *buffer++ = cDigitsLut[d1 + 1]; + if (value >= kTen13) + *buffer++ = cDigitsLut[d2]; + if (value >= kTen12) + *buffer++ = cDigitsLut[d2 + 1]; + if (value >= kTen11) + *buffer++ = cDigitsLut[d3]; + if (value >= kTen10) + *buffer++ = cDigitsLut[d3 + 1]; + if (value >= kTen9) + *buffer++ = cDigitsLut[d4]; + + *buffer++ = cDigitsLut[d4 + 1]; + *buffer++ = cDigitsLut[d5]; + *buffer++ = cDigitsLut[d5 + 1]; + *buffer++ = cDigitsLut[d6]; + *buffer++ = cDigitsLut[d6 + 1]; + *buffer++ = cDigitsLut[d7]; + *buffer++ = cDigitsLut[d7 + 1]; + *buffer++ = cDigitsLut[d8]; + *buffer++ = cDigitsLut[d8 + 1]; + } + else + { + const uint32_t a = static_cast(value / kTen16); // 1 to 1844 + value %= kTen16; + + if (a < 10) + *buffer++ = static_cast('0' + static_cast(a)); + else if (a < 100) + { + const uint32_t i = a << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else if (a < 1000) + { + *buffer++ = static_cast('0' + static_cast(a / 100)); + + const uint32_t i = (a % 100) << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + } + else + { + const uint32_t i = (a / 100) << 1; + const uint32_t j = (a % 100) << 1; + *buffer++ = cDigitsLut[i]; + *buffer++ = cDigitsLut[i + 1]; + *buffer++ = cDigitsLut[j]; + *buffer++ = cDigitsLut[j + 1]; + } + + const uint32_t v0 = static_cast(value / kTen8); + const uint32_t v1 = static_cast(value % kTen8); + + const uint32_t b0 = v0 / 10000; + const uint32_t c0 = v0 % 10000; + + const uint32_t d1 = (b0 / 100) << 1; + const uint32_t d2 = (b0 % 100) << 1; + + const uint32_t d3 = (c0 / 100) << 1; + const uint32_t d4 = (c0 % 100) << 1; + + const uint32_t b1 = v1 / 10000; + const uint32_t c1 = v1 % 10000; + + const uint32_t d5 = (b1 / 100) << 1; + const uint32_t d6 = (b1 % 100) << 1; + + const uint32_t d7 = (c1 / 100) << 1; + const uint32_t d8 = (c1 % 100) << 1; + + *buffer++ = cDigitsLut[d1]; + *buffer++ = cDigitsLut[d1 + 1]; + *buffer++ = cDigitsLut[d2]; + *buffer++ = cDigitsLut[d2 + 1]; + *buffer++ = cDigitsLut[d3]; + *buffer++ = cDigitsLut[d3 + 1]; + *buffer++ = cDigitsLut[d4]; + *buffer++ = cDigitsLut[d4 + 1]; + *buffer++ = cDigitsLut[d5]; + *buffer++ = cDigitsLut[d5 + 1]; + *buffer++ = cDigitsLut[d6]; + *buffer++ = cDigitsLut[d6 + 1]; + *buffer++ = cDigitsLut[d7]; + *buffer++ = cDigitsLut[d7 + 1]; + *buffer++ = cDigitsLut[d8]; + *buffer++ = cDigitsLut[d8 + 1]; + } + + return buffer; + } + + inline char *i64toa(int64_t value, char *buffer) + { + RAPIDJSON_ASSERT(buffer != 0); + uint64_t u = static_cast(value); + if (value < 0) + { + *buffer++ = '-'; + u = ~u + 1; + } + + return u64toa(u, buffer); + } + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ITOA_ diff --git a/contrib/world_builder/include/rapidjson/internal/meta.h.bak b/contrib/world_builder/include/rapidjson/internal/meta.h.bak new file mode 100644 index 00000000000..3b61258b9a0 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/internal/meta.h.bak @@ -0,0 +1,229 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_META_H_ +#define RAPIDJSON_INTERNAL_META_H_ + +#include "../rapidjson.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(6334) +#endif + +#if RAPIDJSON_HAS_CXX11_TYPETRAITS +#include +#endif + +//@cond RAPIDJSON_INTERNAL +RAPIDJSON_NAMESPACE_BEGIN +namespace internal +{ + +// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching + template struct Void + { + typedef void Type; + }; + +/////////////////////////////////////////////////////////////////////////////// +// BoolType, TrueType, FalseType +// + template struct BoolType + { + static const bool Value = Cond; + typedef BoolType Type; + }; + typedef BoolType TrueType; + typedef BoolType FalseType; + + +/////////////////////////////////////////////////////////////////////////////// +// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr +// + + template struct SelectIfImpl + { + template struct Apply + { + typedef T1 Type; + }; + }; + template <> struct SelectIfImpl + { + template struct Apply + { + typedef T2 Type; + }; + }; + template struct SelectIfCond : SelectIfImpl::template Apply {}; + template struct SelectIf : SelectIfCond {}; + + template struct AndExprCond : FalseType {}; + template <> struct AndExprCond : TrueType {}; + template struct OrExprCond : TrueType {}; + template <> struct OrExprCond : FalseType {}; + + template struct BoolExpr : SelectIf::Type {}; + template struct NotExpr : SelectIf::Type {}; + template struct AndExpr : AndExprCond::Type {}; + template struct OrExpr : OrExprCond::Type {}; + + +/////////////////////////////////////////////////////////////////////////////// +// AddConst, MaybeAddConst, RemoveConst + template struct AddConst + { + typedef const T Type; + }; + template struct MaybeAddConst : SelectIfCond {}; + template struct RemoveConst + { + typedef T Type; + }; + template struct RemoveConst + { + typedef T Type; + }; + + +/////////////////////////////////////////////////////////////////////////////// +// IsSame, IsConst, IsMoreConst, IsPointer +// + template struct IsSame : FalseType {}; + template struct IsSame : TrueType {}; + + template struct IsConst : FalseType {}; + template struct IsConst : TrueType {}; + + template + struct IsMoreConst + : AndExpr::Type, typename RemoveConst::Type>, + BoolType::Value >= IsConst::Value> >::Type {}; + + template struct IsPointer : FalseType {}; + template struct IsPointer : TrueType {}; + +/////////////////////////////////////////////////////////////////////////////// +// IsBaseOf +// +#if RAPIDJSON_HAS_CXX11_TYPETRAITS + + template struct IsBaseOf + : BoolType< ::std::is_base_of::value> {}; + +#else // simplified version adopted from Boost + + template struct IsBaseOfImpl + { + RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); + RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); + + typedef char (&Yes)[1]; + typedef char (&No) [2]; + + template + static Yes Check(const D *, T); + static No Check(const B *, int); + + struct Host + { + operator const B *() const; + operator const D *(); + }; + + enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; + }; + + template struct IsBaseOf + : OrExpr, BoolExpr > >::Type {}; + +#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS + + +////////////////////////////////////////////////////////////////////////// +// EnableIf / DisableIf +// + template struct EnableIfCond + { + typedef T Type; + }; + template struct EnableIfCond + { + /* empty */ + }; + + template struct DisableIfCond + { + typedef T Type; + }; + template struct DisableIfCond + { + /* empty */ + }; + + template + struct EnableIf : EnableIfCond {}; + + template + struct DisableIf : DisableIfCond {}; + +// SFINAE helpers + struct SfinaeTag {}; + template struct RemoveSfinaeTag; + template struct RemoveSfinaeTag + { + typedef T Type; + }; + +#define RAPIDJSON_REMOVEFPTR_(type) \ + typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ + < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type + +#define RAPIDJSON_ENABLEIF(cond) \ + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ + ::Type * = NULL + +#define RAPIDJSON_DISABLEIF(cond) \ + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ + ::Type * = NULL + +#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ + ::Type + +#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ + ::Type + +} // namespace internal +RAPIDJSON_NAMESPACE_END +//@endcond + +#if defined(_MSC_VER) && !defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_META_H_ diff --git a/contrib/world_builder/include/rapidjson/internal/pow10.h.bak b/contrib/world_builder/include/rapidjson/internal/pow10.h.bak new file mode 100644 index 00000000000..579502aa633 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/internal/pow10.h.bak @@ -0,0 +1,58 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_POW10_ +#define RAPIDJSON_POW10_ + +#include "../rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal +{ + +//! Computes integer powers of 10 in double (10.0^n). + /*! This function uses lookup table for fast and accurate results. + \param n non-negative exponent. Must <= 308. + \return 10.0^n + */ + inline double Pow10(int n) + { + static const double e[] = // 1e-0...1e308: 309 * 8 bytes = 2472 bytes + { + 1e+0, + 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, + 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, + 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, + 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, + 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, + 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, + 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, + 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, + 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, + 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, + 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, + 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, + 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, + 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, + 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, + 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 + }; + RAPIDJSON_ASSERT(n >= 0 && n <= 308); + return e[n]; + } + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_POW10_ diff --git a/contrib/world_builder/include/rapidjson/internal/regex.h.bak b/contrib/world_builder/include/rapidjson/internal/regex.h.bak new file mode 100644 index 00000000000..88274ba2a59 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/internal/regex.h.bak @@ -0,0 +1,820 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_REGEX_H_ +#define RAPIDJSON_INTERNAL_REGEX_H_ + +#include "../allocators.h" +#include "../stream.h" +#include "stack.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +//RAPIDJSON_DIAG_OFF(switch -enum) +RAPIDJSON_DIAG_OFF(implicit-fallthrough) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#if __GNUC__ >= 7 +RAPIDJSON_DIAG_OFF(implicit-fallthrough) +#endif +#endif + +#ifndef RAPIDJSON_REGEX_VERBOSE +#define RAPIDJSON_REGEX_VERBOSE 0 +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal +{ + +/////////////////////////////////////////////////////////////////////////////// +// DecodedStream + + template + class DecodedStream + { + public: + DecodedStream(SourceStream &ss) : ss_(ss), codepoint_() + { + Decode(); + } + unsigned Peek() + { + return codepoint_; + } + unsigned Take() + { + unsigned c = codepoint_; + if (c) // No further decoding when '\0' + Decode(); + return c; + } + + private: + void Decode() + { + if (!Encoding::Decode(ss_, &codepoint_)) + codepoint_ = 0; + } + + SourceStream &ss_; + unsigned codepoint_; + }; + +/////////////////////////////////////////////////////////////////////////////// +// GenericRegex + + static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 + static const SizeType kRegexInvalidRange = ~SizeType(0); + + template + class GenericRegexSearch; + +//! Regular expression engine with subset of ECMAscript grammar. + /*! + Supported regular expression syntax: + - \c ab Concatenation + - \c a|b Alternation + - \c a? Zero or one + - \c a* Zero or more + - \c a+ One or more + - \c a{3} Exactly 3 times + - \c a{3,} At least 3 times + - \c a{3,5} 3 to 5 times + - \c (ab) Grouping + - \c ^a At the beginning + - \c a$ At the end + - \c . Any character + - \c [abc] Character classes + - \c [a-c] Character class range + - \c [a-z0-9_] Character class combination + - \c [^abc] Negated character classes + - \c [^a-c] Negated character class range + - \c [\b] Backspace (U+0008) + - \c \\| \\\\ ... Escape characters + - \c \\f Form feed (U+000C) + - \c \\n Line feed (U+000A) + - \c \\r Carriage return (U+000D) + - \c \\t Tab (U+0009) + - \c \\v Vertical tab (U+000B) + + \note This is a Thompson NFA engine, implemented with reference to + Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", + https://swtch.com/~rsc/regexp/regexp1.html + */ + template + class GenericRegex + { + public: + typedef Encoding EncodingType; + typedef typename Encoding::Ch Ch; + template friend class GenericRegexSearch; + + GenericRegex(const Ch *source, Allocator *allocator = 0) : + states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), + anchorBegin_(), anchorEnd_() + { + GenericStringStream ss(source); + DecodedStream, Encoding> ds(ss); + Parse(ds); + } + + ~GenericRegex() {} + + bool IsValid() const + { + return root_ != kRegexInvalidState; + } + + private: + enum Operator + { + kZeroOrOne, + kZeroOrMore, + kOneOrMore, + kConcatenation, + kAlternation, + kLeftParenthesis + }; + + static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.' + static const unsigned kRangeCharacterClass = 0xFFFFFFFE; + static const unsigned kRangeNegationFlag = 0x80000000; + + struct Range + { + unsigned start; // + unsigned end; + SizeType next; + }; + + struct State + { + SizeType out; //!< Equals to kInvalid for matching state + SizeType out1; //!< Equals to non-kInvalid for split + SizeType rangeStart; + unsigned codepoint; + }; + + struct Frag + { + Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {} + SizeType start; + SizeType out; //!< link-list of all output states + SizeType minIndex; + }; + + State &GetState(SizeType index) + { + RAPIDJSON_ASSERT(index < stateCount_); + return states_.template Bottom()[index]; + } + + const State &GetState(SizeType index) const + { + RAPIDJSON_ASSERT(index < stateCount_); + return states_.template Bottom()[index]; + } + + Range &GetRange(SizeType index) + { + RAPIDJSON_ASSERT(index < rangeCount_); + return ranges_.template Bottom()[index]; + } + + const Range &GetRange(SizeType index) const + { + RAPIDJSON_ASSERT(index < rangeCount_); + return ranges_.template Bottom()[index]; + } + + template + void Parse(DecodedStream &ds) + { + Allocator allocator; + Stack operandStack(&allocator, 256); // Frag + Stack operatorStack(&allocator, 256); // Operator + Stack atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis) + + *atomCountStack.template Push() = 0; + + unsigned codepoint; + while (ds.Peek() != 0) + { + switch (codepoint = ds.Take()) + { + case '^': + anchorBegin_ = true; + break; + + case '$': + anchorEnd_ = true; + break; + + case '|': + while (!operatorStack.Empty() && *operatorStack.template Top() < kAlternation) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + *operatorStack.template Push() = kAlternation; + *atomCountStack.template Top() = 0; + break; + + case '(': + *operatorStack.template Push() = kLeftParenthesis; + *atomCountStack.template Push() = 0; + break; + + case ')': + while (!operatorStack.Empty() && *operatorStack.template Top() != kLeftParenthesis) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + if (operatorStack.Empty()) + return; + operatorStack.template Pop(1); + atomCountStack.template Pop(1); + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '?': + if (!Eval(operandStack, kZeroOrOne)) + return; + break; + + case '*': + if (!Eval(operandStack, kZeroOrMore)) + return; + break; + + case '+': + if (!Eval(operandStack, kOneOrMore)) + return; + break; + + case '{': + { + unsigned n = 0; + unsigned m = 0; + if (!ParseUnsigned(ds, &n)) + return; + + if (ds.Peek() == ',') + { + ds.Take(); + if (ds.Peek() == '}') + m = kInfinityQuantifier; + else if (!ParseUnsigned(ds, &m) || m < n) + return; + } + else + m = n; + + if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') + return; + ds.Take(); + } + break; + + case '.': + PushOperand(operandStack, kAnyCharacterClass); + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '[': + { + SizeType range; + if (!ParseRange(ds, &range)) + return; + SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass); + GetState(s).rangeStart = range; + *operandStack.template Push() = Frag(s, s, s); + } + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '\\': // Escape character + if (!CharacterEscape(ds, &codepoint)) + return; // Unsupported escape character + // fall through to default + + default: // Pattern character + PushOperand(operandStack, codepoint); + ImplicitConcatenation(atomCountStack, operatorStack); + } + } + + while (!operatorStack.Empty()) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + + // Link the operand to matching state. + if (operandStack.GetSize() == sizeof(Frag)) + { + Frag *e = operandStack.template Pop(1); + Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); + root_ = e->start; + +#if RAPIDJSON_REGEX_VERBOSE + printf("root: %d\n", root_); + for (SizeType i = 0; i < stateCount_ ; i++) + { + State &s = GetState(i); + printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint); + } + printf("\n"); +#endif + } + } + + SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) + { + State *s = states_.template Push(); + s->out = out; + s->out1 = out1; + s->codepoint = codepoint; + s->rangeStart = kRegexInvalidRange; + return stateCount_++; + } + + void PushOperand(Stack &operandStack, unsigned codepoint) + { + SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint); + *operandStack.template Push() = Frag(s, s, s); + } + + void ImplicitConcatenation(Stack &atomCountStack, Stack &operatorStack) + { + if (*atomCountStack.template Top()) + *operatorStack.template Push() = kConcatenation; + (*atomCountStack.template Top())++; + } + + SizeType Append(SizeType l1, SizeType l2) + { + SizeType old = l1; + while (GetState(l1).out != kRegexInvalidState) + l1 = GetState(l1).out; + GetState(l1).out = l2; + return old; + } + + void Patch(SizeType l, SizeType s) + { + for (SizeType next; l != kRegexInvalidState; l = next) + { + next = GetState(l).out; + GetState(l).out = s; + } + } + + bool Eval(Stack &operandStack, Operator op) + { + switch (op) + { + case kConcatenation: + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); + { + Frag e2 = *operandStack.template Pop(1); + Frag e1 = *operandStack.template Pop(1); + Patch(e1.out, e2.start); + *operandStack.template Push() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); + } + return true; + + case kAlternation: + if (operandStack.GetSize() >= sizeof(Frag) * 2) + { + Frag e2 = *operandStack.template Pop(1); + Frag e1 = *operandStack.template Pop(1); + SizeType s = NewState(e1.start, e2.start, 0); + *operandStack.template Push() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex)); + return true; + } + return false; + + case kZeroOrOne: + if (operandStack.GetSize() >= sizeof(Frag)) + { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + *operandStack.template Push() = Frag(s, Append(e.out, s), e.minIndex); + return true; + } + return false; + + case kZeroOrMore: + if (operandStack.GetSize() >= sizeof(Frag)) + { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + Patch(e.out, s); + *operandStack.template Push() = Frag(s, s, e.minIndex); + return true; + } + return false; + + default: + RAPIDJSON_ASSERT(op == kOneOrMore); + if (operandStack.GetSize() >= sizeof(Frag)) + { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + Patch(e.out, s); + *operandStack.template Push() = Frag(e.start, s, e.minIndex); + return true; + } + return false; + } + } + + bool EvalQuantifier(Stack &operandStack, unsigned n, unsigned m) + { + RAPIDJSON_ASSERT(n <= m); + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); + + if (n == 0) + { + if (m == 0) // a{0} not support + return false; + else if (m == kInfinityQuantifier) + Eval(operandStack, kZeroOrMore); // a{0,} -> a* + else + { + Eval(operandStack, kZeroOrOne); // a{0,5} -> a? + for (unsigned i = 0; i < m - 1; i++) + CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a? + for (unsigned i = 0; i < m - 1; i++) + Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? + } + return true; + } + + for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a + CloneTopOperand(operandStack); + + if (m == kInfinityQuantifier) + Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ + else if (m > n) + { + CloneTopOperand(operandStack); // a{3,5} -> a a a a + Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a? + for (unsigned i = n; i < m - 1; i++) + CloneTopOperand(operandStack); // a{3,5} -> a a a a? a? + for (unsigned i = n; i < m; i++) + Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? + } + + for (unsigned i = 0; i < n - 1; i++) + Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a? + + return true; + } + + static SizeType Min(SizeType a, SizeType b) + { + return a < b ? a : b; + } + + void CloneTopOperand(Stack &operandStack) + { + const Frag src = *operandStack.template Top(); // Copy constructor to prevent invalidation + SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) + State *s = states_.template Push(count); + memcpy(s, &GetState(src.minIndex), count * sizeof(State)); + for (SizeType j = 0; j < count; j++) + { + if (s[j].out != kRegexInvalidState) + s[j].out += count; + if (s[j].out1 != kRegexInvalidState) + s[j].out1 += count; + } + *operandStack.template Push() = Frag(src.start + count, src.out + count, src.minIndex + count); + stateCount_ += count; + } + + template + bool ParseUnsigned(DecodedStream &ds, unsigned *u) + { + unsigned r = 0; + if (ds.Peek() < '0' || ds.Peek() > '9') + return false; + while (ds.Peek() >= '0' && ds.Peek() <= '9') + { + if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 + return false; // overflow + r = r * 10 + (ds.Take() - '0'); + } + *u = r; + return true; + } + + template + bool ParseRange(DecodedStream &ds, SizeType *range) + { + bool isBegin = true; + bool negate = false; + int step = 0; + SizeType start = kRegexInvalidRange; + SizeType current = kRegexInvalidRange; + unsigned codepoint; + while ((codepoint = ds.Take()) != 0) + { + if (isBegin) + { + isBegin = false; + if (codepoint == '^') + { + negate = true; + continue; + } + } + + switch (codepoint) + { + case ']': + if (start == kRegexInvalidRange) + return false; // Error: nothing inside [] + if (step == 2) // Add trailing '-' + { + SizeType r = NewRange('-'); + RAPIDJSON_ASSERT(current != kRegexInvalidRange); + GetRange(current).next = r; + } + if (negate) + GetRange(start).start |= kRangeNegationFlag; + *range = start; + return true; + + case '\\': + if (ds.Peek() == 'b') + { + ds.Take(); + codepoint = 0x0008; // Escape backspace character + } + else if (!CharacterEscape(ds, &codepoint)) + return false; + // fall through to default + + default: + switch (step) + { + case 1: + if (codepoint == '-') + { + step++; + break; + } + // fall through to step 0 for other characters + + case 0: + { + SizeType r = NewRange(codepoint); + if (current != kRegexInvalidRange) + GetRange(current).next = r; + if (start == kRegexInvalidRange) + start = r; + current = r; + } + step = 1; + break; + + default: + RAPIDJSON_ASSERT(step == 2); + GetRange(current).end = codepoint; + step = 0; + } + } + } + return false; + } + + SizeType NewRange(unsigned codepoint) + { + Range *r = ranges_.template Push(); + r->start = r->end = codepoint; + r->next = kRegexInvalidRange; + return rangeCount_++; + } + + template + bool CharacterEscape(DecodedStream &ds, unsigned *escapedCodepoint) + { + unsigned codepoint; + switch (codepoint = ds.Take()) + { + case '^': + case '$': + case '|': + case '(': + case ')': + case '?': + case '*': + case '+': + case '.': + case '[': + case ']': + case '{': + case '}': + case '\\': + *escapedCodepoint = codepoint; + return true; + case 'f': + *escapedCodepoint = 0x000C; + return true; + case 'n': + *escapedCodepoint = 0x000A; + return true; + case 'r': + *escapedCodepoint = 0x000D; + return true; + case 't': + *escapedCodepoint = 0x0009; + return true; + case 'v': + *escapedCodepoint = 0x000B; + return true; + default: + return false; // Unsupported escape character + } + } + + Stack states_; + Stack ranges_; + SizeType root_; + SizeType stateCount_; + SizeType rangeCount_; + + static const unsigned kInfinityQuantifier = ~0u; + + // For SearchWithAnchoring() + bool anchorBegin_; + bool anchorEnd_; + }; + + template + class GenericRegexSearch + { + public: + typedef typename RegexType::EncodingType Encoding; + typedef typename Encoding::Ch Ch; + + GenericRegexSearch(const RegexType ®ex, Allocator *allocator = 0) : + regex_(regex), allocator_(allocator), ownAllocator_(0), + state0_(allocator, 0), state1_(allocator, 0), stateSet_() + { + RAPIDJSON_ASSERT(regex_.IsValid()); + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + stateSet_ = static_cast(allocator_->Malloc(GetStateSetSize())); + state0_.template Reserve(regex_.stateCount_); + state1_.template Reserve(regex_.stateCount_); + } + + ~GenericRegexSearch() + { + Allocator::Free(stateSet_); + RAPIDJSON_DELETE(ownAllocator_); + } + + template + bool Match(InputStream &is) + { + return SearchWithAnchoring(is, true, true); + } + + bool Match(const Ch *s) + { + GenericStringStream is(s); + return Match(is); + } + + template + bool Search(InputStream &is) + { + return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_); + } + + bool Search(const Ch *s) + { + GenericStringStream is(s); + return Search(is); + } + + private: + typedef typename RegexType::State State; + typedef typename RegexType::Range Range; + + template + bool SearchWithAnchoring(InputStream &is, bool anchorBegin, bool anchorEnd) + { + DecodedStream ds(is); + + state0_.Clear(); + Stack *current = &state0_, *next = &state1_; + const size_t stateSetSize = GetStateSetSize(); + std::memset(stateSet_, 0, stateSetSize); + + bool matched = AddState(*current, regex_.root_); + unsigned codepoint = 0; + while (!current->Empty() && (codepoint = ds.Take()) != 0) + { + std::memset(stateSet_, 0, stateSetSize); + next->Clear(); + matched = false; + for (const SizeType *s = current->template Bottom(); s != current->template End(); ++s) + { + const State &sr = regex_.GetState(*s); + if (sr.codepoint == codepoint || + sr.codepoint == RegexType::kAnyCharacterClass || + (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) + { + matched = AddState(*next, sr.out) || matched; + if (!anchorEnd && matched) + return true; + } + if (!anchorBegin) + AddState(*next, regex_.root_); + } + internal::Swap(current, next); + } + + return matched; + } + + size_t GetStateSetSize() const + { + return (regex_.stateCount_ + 31) / 32 * 4; + } + + // Return whether the added states is a match state + bool AddState(Stack &l, SizeType index) + { + RAPIDJSON_ASSERT(index != kRegexInvalidState); + + const State &s = regex_.GetState(index); + if (s.out1 != kRegexInvalidState) // Split + { + bool matched = AddState(l, s.out); + return AddState(l, s.out1) || matched; + } + else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) + { + stateSet_[index >> 5] |= (1u << (index & 31)); + *l.template PushUnsafe() = index; + } + return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. + } + + bool MatchRange(SizeType rangeIndex, unsigned codepoint) const + { + bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0; + while (rangeIndex != kRegexInvalidRange) + { + const Range &r = regex_.GetRange(rangeIndex); + if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end) + return yes; + rangeIndex = r.next; + } + return !yes; + } + + const RegexType ®ex_; + Allocator *allocator_; + Allocator *ownAllocator_; + Stack state0_; + Stack state1_; + uint32_t *stateSet_; + }; + + typedef GenericRegex > Regex; + typedef GenericRegexSearch RegexSearch; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_REGEX_H_ diff --git a/contrib/world_builder/include/rapidjson/internal/stack.h.bak b/contrib/world_builder/include/rapidjson/internal/stack.h.bak new file mode 100644 index 00000000000..8d64a7a451c --- /dev/null +++ b/contrib/world_builder/include/rapidjson/internal/stack.h.bak @@ -0,0 +1,277 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_STACK_H_ +#define RAPIDJSON_INTERNAL_STACK_H_ + +#include "../allocators.h" +#include "swap.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal +{ + +/////////////////////////////////////////////////////////////////////////////// +// Stack + +//! A type-unsafe stack for storing different types of data. + /*! \tparam Allocator Allocator for allocating stack memory. + */ + template + class Stack + { + public: + // Optimization note: Do not allocate memory for stack_ in constructor. + // Do it lazily when first Push() -> Expand() -> Resize(). + Stack(Allocator *allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) + { + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Stack(Stack &&rhs) + : allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + stack_(rhs.stack_), + stackTop_(rhs.stackTop_), + stackEnd_(rhs.stackEnd_), + initialCapacity_(rhs.initialCapacity_) + { + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.stack_ = 0; + rhs.stackTop_ = 0; + rhs.stackEnd_ = 0; + rhs.initialCapacity_ = 0; + } +#endif + + ~Stack() + { + Destroy(); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Stack &operator=(Stack&& rhs) + { + if (&rhs != this) + { + Destroy(); + + allocator_ = rhs.allocator_; + ownAllocator_ = rhs.ownAllocator_; + stack_ = rhs.stack_; + stackTop_ = rhs.stackTop_; + stackEnd_ = rhs.stackEnd_; + initialCapacity_ = rhs.initialCapacity_; + + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.stack_ = 0; + rhs.stackTop_ = 0; + rhs.stackEnd_ = 0; + rhs.initialCapacity_ = 0; + } + return *this; + } +#endif + + void Swap(Stack &rhs) RAPIDJSON_NOEXCEPT + { + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(stack_, rhs.stack_); + internal::Swap(stackTop_, rhs.stackTop_); + internal::Swap(stackEnd_, rhs.stackEnd_); + internal::Swap(initialCapacity_, rhs.initialCapacity_); + } + + void Clear() + { + stackTop_ = stack_; + } + + void ShrinkToFit() + { + if (Empty()) + { + // If the stack is empty, completely deallocate the memory. + Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc) + stack_ = 0; + stackTop_ = 0; + stackEnd_ = 0; + } + else + Resize(GetSize()); + } + + // Optimization note: try to minimize the size of this function for force inline. + // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. + template + RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) + { + // Expand the stack if needed + if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) + Expand(count); + } + + template + RAPIDJSON_FORCEINLINE T *Push(size_t count = 1) + { + Reserve(count); + return PushUnsafe(count); + } + + template + RAPIDJSON_FORCEINLINE T *PushUnsafe(size_t count = 1) + { + RAPIDJSON_ASSERT(stackTop_); + RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); + T *ret = reinterpret_cast(stackTop_); + stackTop_ += sizeof(T) * count; + return ret; + } + + template + T *Pop(size_t count) + { + RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); + stackTop_ -= count * sizeof(T); + return reinterpret_cast(stackTop_); + } + + template + T *Top() + { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return reinterpret_cast(stackTop_ - sizeof(T)); + } + + template + const T *Top() const + { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return reinterpret_cast(stackTop_ - sizeof(T)); + } + + template + T *End() + { + return reinterpret_cast(stackTop_); + } + + template + const T *End() const + { + return reinterpret_cast(stackTop_); + } + + template + T *Bottom() + { + return reinterpret_cast(stack_); + } + + template + const T *Bottom() const + { + return reinterpret_cast(stack_); + } + + bool HasAllocator() const + { + return allocator_ != 0; + } + + Allocator &GetAllocator() + { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } + + bool Empty() const + { + return stackTop_ == stack_; + } + size_t GetSize() const + { + return static_cast(stackTop_ - stack_); + } + size_t GetCapacity() const + { + return static_cast(stackEnd_ - stack_); + } + + private: + template + void Expand(size_t count) + { + // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. + size_t newCapacity; + if (stack_ == 0) + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + newCapacity = initialCapacity_; + } + else + { + newCapacity = GetCapacity(); + newCapacity += (newCapacity + 1) / 2; + } + size_t newSize = GetSize() + sizeof(T) * count; + if (newCapacity < newSize) + newCapacity = newSize; + + Resize(newCapacity); + } + + void Resize(size_t newCapacity) + { + const size_t size = GetSize(); // Backup the current size + stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); + stackTop_ = stack_ + size; + stackEnd_ = stack_ + newCapacity; + } + + void Destroy() + { + Allocator::Free(stack_); + RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack + } + + // Prohibit copy constructor & assignment operator. + Stack(const Stack &); + Stack &operator=(const Stack &); + + Allocator *allocator_; + Allocator *ownAllocator_; + char *stack_; + char *stackTop_; + char *stackEnd_; + size_t initialCapacity_; + }; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_STACK_H_ diff --git a/contrib/world_builder/include/rapidjson/internal/strfunc.h.bak b/contrib/world_builder/include/rapidjson/internal/strfunc.h.bak new file mode 100644 index 00000000000..c6a36d50f69 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/internal/strfunc.h.bak @@ -0,0 +1,75 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ +#define RAPIDJSON_INTERNAL_STRFUNC_H_ + +#include "../stream.h" +#include + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal +{ + +//! Custom strlen() which works on different character types. + /*! \tparam Ch Character type (e.g. char, wchar_t, short) + \param s Null-terminated input string. + \return Number of characters in the string. + \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. + */ + template + inline SizeType StrLen(const Ch *s) + { + RAPIDJSON_ASSERT(s != 0); + const Ch *p = s; + while (*p) ++p; + return SizeType(p - s); + } + + template <> + inline SizeType StrLen(const char *s) + { + return SizeType(std::strlen(s)); + } + + template <> + inline SizeType StrLen(const wchar_t *s) + { + return SizeType(std::wcslen(s)); + } + +//! Returns number of code points in a encoded string. + template + bool CountStringCodePoint(const typename Encoding::Ch *s, SizeType length, SizeType *outCount) + { + RAPIDJSON_ASSERT(s != 0); + RAPIDJSON_ASSERT(outCount != 0); + GenericStringStream is(s); + const typename Encoding::Ch *end = s + length; + SizeType count = 0; + while (is.src_ < end) + { + unsigned codepoint; + if (!Encoding::Decode(is, &codepoint)) + return false; + count++; + } + *outCount = count; + return true; + } + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ diff --git a/contrib/world_builder/include/rapidjson/internal/strtod.h.bak b/contrib/world_builder/include/rapidjson/internal/strtod.h.bak new file mode 100644 index 00000000000..b98760f7345 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/internal/strtod.h.bak @@ -0,0 +1,317 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_STRTOD_ +#define RAPIDJSON_STRTOD_ + +#include "ieee754.h" +#include "biginteger.h" +#include "diyfp.h" +#include "pow10.h" +#include +#include + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal +{ + + inline double FastPath(double significand, int exp) + { + if (exp < -308) + return 0.0; + else if (exp >= 0) + return significand * internal::Pow10(exp); + else + return significand / internal::Pow10(-exp); + } + + inline double StrtodNormalPrecision(double d, int p) + { + if (p < -308) + { + // Prevent expSum < -308, making Pow10(p) = 0 + d = FastPath(d, -308); + d = FastPath(d, p + 308); + } + else + d = FastPath(d, p); + return d; + } + + template + inline T Min3(T a, T b, T c) + { + T m = a; + if (m > b) m = b; + if (m > c) m = c; + return m; + } + + inline int CheckWithinHalfULP(double b, const BigInteger &d, int dExp) + { + const Double db(b); + const uint64_t bInt = db.IntegerSignificand(); + const int bExp = db.IntegerExponent(); + const int hExp = bExp - 1; + + int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; + + // Adjust for decimal exponent + if (dExp >= 0) + { + dS_Exp2 += dExp; + dS_Exp5 += dExp; + } + else + { + bS_Exp2 -= dExp; + bS_Exp5 -= dExp; + hS_Exp2 -= dExp; + hS_Exp5 -= dExp; + } + + // Adjust for binary exponent + if (bExp >= 0) + bS_Exp2 += bExp; + else + { + dS_Exp2 -= bExp; + hS_Exp2 -= bExp; + } + + // Adjust for half ulp exponent + if (hExp >= 0) + hS_Exp2 += hExp; + else + { + dS_Exp2 -= hExp; + bS_Exp2 -= hExp; + } + + // Remove common power of two factor from all three scaled values + int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); + dS_Exp2 -= common_Exp2; + bS_Exp2 -= common_Exp2; + hS_Exp2 -= common_Exp2; + + BigInteger dS = d; + dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); + + BigInteger bS(bInt); + bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); + + BigInteger hS(1); + hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); + + BigInteger delta(0); + dS.Difference(bS, &delta); + + return delta.Compare(hS); + } + + inline bool StrtodFast(double d, int p, double *result) + { + // Use fast path for string-to-double conversion if possible + // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + if (p > 22 && p < 22 + 16) + { + // Fast Path Cases In Disguise + d *= internal::Pow10(p - 22); + p = 22; + } + + if (p >= -22 && p <= 22 && d <= 9007199254740991.0) // 2^53 - 1 + { + *result = FastPath(d, p); + return true; + } + else + return false; + } + +// Compute an approximation and see if it is within 1/2 ULP + inline bool StrtodDiyFp(const char *decimals, int dLen, int dExp, double *result) + { + uint64_t significand = 0; + int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 + for (; i < dLen; i++) + { + if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || + (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) + break; + significand = significand * 10u + static_cast(decimals[i] - '0'); + } + + if (i < dLen && decimals[i] >= '5') // Rounding + significand++; + + int remaining = dLen - i; + const int kUlpShift = 3; + const int kUlp = 1 << kUlpShift; + int64_t error = (remaining == 0) ? 0 : kUlp / 2; + + DiyFp v(significand, 0); + v = v.Normalize(); + error <<= -v.e; + + dExp += remaining; + + int actualExp; + DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); + if (actualExp != dExp) + { + static const DiyFp kPow10[] = + { + DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1 + DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2 + DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3 + DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4 + DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5 + DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6 + DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7 + }; + int adjustment = dExp - actualExp; + RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8); + v = v * kPow10[adjustment - 1]; + if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit + error += kUlp / 2; + } + + v = v * cachedPower; + + error += kUlp + (error == 0 ? 0 : 1); + + const int oldExp = v.e; + v = v.Normalize(); + error <<= oldExp - v.e; + + const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); + int precisionSize = 64 - effectiveSignificandSize; + if (precisionSize + kUlpShift >= 64) + { + int scaleExp = (precisionSize + kUlpShift) - 63; + v.f >>= scaleExp; + v.e += scaleExp; + error = (error >> scaleExp) + 1 + kUlp; + precisionSize -= scaleExp; + } + + DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); + const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; + const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; + if (precisionBits >= halfWay + static_cast(error)) + { + rounded.f++; + if (rounded.f & (DiyFp::kDpHiddenBit << 1)) // rounding overflows mantissa (issue #340) + { + rounded.f >>= 1; + rounded.e++; + } + } + + *result = rounded.ToDouble(); + + return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); + } + + inline double StrtodBigInteger(double approx, const char *decimals, int dLen, int dExp) + { + RAPIDJSON_ASSERT(dLen >= 0); + const BigInteger dInt(decimals, static_cast(dLen)); + Double a(approx); + int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); + if (cmp < 0) + return a.Value(); // within half ULP + else if (cmp == 0) + { + // Round towards even + if (a.Significand() & 1) + return a.NextPositiveDouble(); + else + return a.Value(); + } + else // adjustment + return a.NextPositiveDouble(); + } + + inline double StrtodFullPrecision(double d, int p, const char *decimals, size_t length, size_t decimalPosition, int exp) + { + RAPIDJSON_ASSERT(d >= 0.0); + RAPIDJSON_ASSERT(length >= 1); + + double result = 0.0; + if (StrtodFast(d, p, &result)) + return result; + + RAPIDJSON_ASSERT(length <= INT_MAX); + int dLen = static_cast(length); + + RAPIDJSON_ASSERT(length >= decimalPosition); + RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX); + int dExpAdjust = static_cast(length - decimalPosition); + + RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust); + int dExp = exp - dExpAdjust; + + // Make sure length+dExp does not overflow + RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen); + + // Trim leading zeros + while (dLen > 0 && *decimals == '0') + { + dLen--; + decimals++; + } + + // Trim trailing zeros + while (dLen > 0 && decimals[dLen - 1] == '0') + { + dLen--; + dExp++; + } + + if (dLen == 0) // Buffer only contains zeros. + { + return 0.0; + } + + // Trim right-most digits + const int kMaxDecimalDigit = 767 + 1; + if (dLen > kMaxDecimalDigit) + { + dExp += dLen - kMaxDecimalDigit; + dLen = kMaxDecimalDigit; + } + + // If too small, underflow to zero. + // Any x <= 10^-324 is interpreted as zero. + if (dLen + dExp <= -324) + return 0.0; + + // If too large, overflow to infinity. + // Any x >= 10^309 is interpreted as +infinity. + if (dLen + dExp > 309) + return std::numeric_limits::infinity(); + + if (StrtodDiyFp(decimals, dLen, dExp, &result)) + return result; + + // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison + return StrtodBigInteger(result, decimals, dLen, dExp); + } + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STRTOD_ diff --git a/contrib/world_builder/include/rapidjson/internal/swap.h.bak b/contrib/world_builder/include/rapidjson/internal/swap.h.bak new file mode 100644 index 00000000000..dfb1f19e77e --- /dev/null +++ b/contrib/world_builder/include/rapidjson/internal/swap.h.bak @@ -0,0 +1,48 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_SWAP_H_ +#define RAPIDJSON_INTERNAL_SWAP_H_ + +#include "../rapidjson.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal +{ + +//! Custom swap() to avoid dependency on C++ header + /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. + \note This has the same semantics as std::swap(). + */ + template + inline void Swap(T &a, T &b) RAPIDJSON_NOEXCEPT + { + T tmp = a; + a = b; + b = tmp; + } + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_SWAP_H_ diff --git a/contrib/world_builder/include/rapidjson/istreamwrapper.h.bak b/contrib/world_builder/include/rapidjson/istreamwrapper.h.bak new file mode 100644 index 00000000000..f3b83b6858f --- /dev/null +++ b/contrib/world_builder/include/rapidjson/istreamwrapper.h.bak @@ -0,0 +1,137 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ +#define RAPIDJSON_ISTREAMWRAPPER_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::istringstream + - \c std::stringstream + - \c std::wistringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wifstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_istream. +*/ + +template +class BasicIStreamWrapper +{ + public: + typedef typename StreamType::char_type Ch; + BasicIStreamWrapper(StreamType &stream) : stream_(stream), count_(), peekBuffer_() {} + + Ch Peek() const + { + typename StreamType::int_type c = stream_.peek(); + return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : static_cast('\0'); + } + + Ch Take() + { + typename StreamType::int_type c = stream_.get(); + if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) + { + count_++; + return static_cast(c); + } + else + return '\0'; + } + + // tellg() may return -1 when failed. So we count by ourself. + size_t Tell() const + { + return count_; + } + + Ch *PutBegin() + { + RAPIDJSON_ASSERT(false); + return 0; + } + void Put(Ch) + { + RAPIDJSON_ASSERT(false); + } + void Flush() + { + RAPIDJSON_ASSERT(false); + } + size_t PutEnd(Ch *) + { + RAPIDJSON_ASSERT(false); + return 0; + } + + // For encoding detection only. + const Ch *Peek4() const + { + RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. + int i; + bool hasError = false; + for (i = 0; i < 4; ++i) + { + typename StreamType::int_type c = stream_.get(); + if (c == StreamType::traits_type::eof()) + { + hasError = true; + stream_.clear(); + break; + } + peekBuffer_[i] = static_cast(c); + } + for (--i; i >= 0; --i) + stream_.putback(peekBuffer_[i]); + return !hasError ? peekBuffer_ : 0; + } + + private: + BasicIStreamWrapper(const BasicIStreamWrapper &); + BasicIStreamWrapper &operator=(const BasicIStreamWrapper &); + + StreamType &stream_; + size_t count_; //!< Number of characters read. Note: + mutable Ch peekBuffer_[4]; +}; + +typedef BasicIStreamWrapper IStreamWrapper; +typedef BasicIStreamWrapper WIStreamWrapper; + +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ISTREAMWRAPPER_H_ diff --git a/contrib/world_builder/include/rapidjson/latexwriter.h.bak b/contrib/world_builder/include/rapidjson/latexwriter.h.bak new file mode 100644 index 00000000000..85c07e958ad --- /dev/null +++ b/contrib/world_builder/include/rapidjson/latexwriter.h.bak @@ -0,0 +1,468 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_LATEXWRITER_H_ +#define RAPIDJSON_LATEXWRITER_H_ + +#include "writer.h" + +#include +#include +#include + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + + +//! Writer with indentation and spacing. +/*! + \tparam OutputStream Type of output os. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam StackAllocator Type of allocator for allocating memory of stack. +*/ +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> +class LatexWriter : public Writer +{ + public: + typedef Writer Base; + typedef typename Base::Ch Ch; + + //! Constructor + /*! \param os Output stream. + \param allocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + explicit LatexWriter(OutputStream &os, StackAllocator *allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(os, allocator, levelDepth) + { + level_type.resize(0); + array_number.resize(0); + path.resize(0); + } + + + explicit LatexWriter(StackAllocator *allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(allocator, levelDepth) + { + level_type.resize(0); + array_number.resize(0); + path.resize(0); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + LatexWriter(LatexWriter &&rhs) : + Base(std::forward(rhs)) + { + level_type.resize(0); + array_number.resize(0); + path.resize(0); + } +#endif + + /*! @name Implementation of Handler + \see Handler + */ + //@{ + + bool Null() + { + return Base::EndValue(Base::WriteNull()); + } + bool Bool(bool b) + { + Base::EndValue(Base::WriteBool(b)); + Base::os_->Put('\n'); + return true; + } + bool Int(int i) + { + Base::EndValue(Base::WriteInt(i)); + Base::os_->Put('\n'); + return true; + } + bool Uint(unsigned u) + { + Base::EndValue(Base::WriteUint(u)); + Base::os_->Put('\n'); + return true; + } + bool Int64(int64_t i64) + { + Base::EndValue(Base::WriteInt64(i64)); + Base::os_->Put('\n'); + return true; + } + bool Uint64(uint64_t u64) + { + Base::EndValue(Base::WriteUint64(u64)); + Base::os_->Put('\n'); + return true; + } + bool Double(double d) + { + Base::EndValue(Base::WriteDouble(d)); + Base::os_->Put('\n'); + return true; + } + + bool RawNumber(const Ch *str, SizeType length, bool /*copy = false*/) + { + RAPIDJSON_ASSERT(str != 0); + Base::EndValue(Base::WriteString(str, length, false)); + Base::os_->Put('\n'); + return true; + } + + bool String(const Ch *str, SizeType length, bool /*copy = false*/) + { + RAPIDJSON_ASSERT(str != 0); + if (small_array == true) + { + if (first_small_array == true) + first_small_array = false; + else + { + Base::os_->Put(','); + Base::os_->Put(' '); + } + } + Base::EndValue(Base::WriteString(str, length, false)); + + if (small_array == false) + Base::os_->Put('\n'); + return true; + } + +#if RAPIDJSON_HAS_STDSTRING + bool String(const std::basic_string &str) + { + return String(str.data(), SizeType(str.size())); + } +#endif + + bool StartObject() + { + std::string begin = ""; + if (level_type.size() != 0 && level_type.back() == 1) + { + // this is a properties starting, so first clear all the itemize + // the lvel_type.push_back(1) has already been done by the key: properties + for (unsigned int i = 0; i < itemize_open; ++i) + { + begin += "\\end{itemize}"; + } + itemize_open = 0; + if (skip_next_push_back == false) + { + if (section_level <= 2) + begin += "\\section{(" + std::to_string(section_level) + ") " + get_path() + "}"; + else if (section_level <= 5) + begin += "\\subsection{(" + std::to_string(section_level) + ") " + get_path() + "}"; + else if (section_level <= 8) + begin += "\\subsubsection{(" + std::to_string(section_level) + ") " + get_path() + "}"; + else + begin += "\\paragraph{(" + std::to_string(section_level) + ") " + get_path() + "}"; + + open_new_itemize = true; + level_type.push_back(0); + } + else + { + skip_next_push_back = false; + } + } + else if (level_type.size() != 0 && level_type.back() == 2) + { + // this is a array starting, so first clear all the itemize + // the lvel_type.push_back(1) has already been done by the key: properties + for (unsigned int i = 0; i < itemize_open; ++i) + { + begin += "\\end{itemize}"; + } + itemize_open = 0; + unsigned int number = array_number.back() + 1; + array_number.back() = number; + path.push_back(std::to_string(array_number.back())); + level_type.push_back(0); + // have arrrays (/oneOf/1) as new section level + section_level++; + + if (section_level <= 2) + begin += "\\section{(" + std::to_string(section_level) + ") " + get_path() + "}"; + else if (section_level <= 5) + begin += "\\subsection{(" + std::to_string(section_level) + ") " + get_path() + "}"; + else if (section_level <= 8) + begin += "\\subsubsection{(" + std::to_string(section_level) + ") " + get_path() + "}"; + else + begin += "\\paragraph{(" + std::to_string(section_level) + ") " + get_path() + "}"; + + open_new_itemize = true; + } + else + { + for (unsigned int i = 0; i < itemize_open; ++i) + { + begin += "\\end{itemize}"; + } + itemize_open = 0; + + //begin += "C"; + if (section_level <= 2) + begin += "\\section{(" + std::to_string(section_level) + ") " + get_path() + "}"; + else if (section_level <= 5) + begin += "\\subsection{(" + std::to_string(section_level) + ") " + get_path() + "}"; + else if (section_level <= 8) + begin += "\\subsubsection{(" + std::to_string(section_level) + ") " + get_path() + "}"; + else + begin += "\\paragraph{(" + std::to_string(section_level) + ") " + get_path() + "}"; + + open_new_itemize = true; + if (level_type.size() > 0 && (level_type.back() != 3 || level_type.size() == 0)) + level_type.push_back(0); + } + + Base::WriteString(begin.c_str(), static_cast(begin.size()), false); + Base::os_->Put('\n'); + + return true; + } + + bool Key(const Ch *str, SizeType /*length*/, bool /*copy = false*/) + { + std::string item = ""; + + + std::string key(str); + if (key == "properties") + { + if (open_new_itemize == true) + { + item += "\\begin{itemize}[leftmargin=" + std::to_string(section_level) + "em]"; + itemize_open++; + } + level_type.push_back(1); + skip_next_push_back = true; + } + else if (key == "oneOf") + { + level_type.push_back(2); + path.push_back(key); + } + else if (key == "items") + { + if (open_new_itemize == true) + { + item += "\\begin{itemize}[leftmargin=" + std::to_string(section_level) + "em]"; + itemize_open++; + } + section_level++; + level_type.push_back(3); + path.push_back(key); + } + else if (level_type.size() > 0 && level_type.back() == 1) + { + // the level just below properties, these are the sections + // add to the path + + section_level++; + path.push_back(key); + } + else + { + if (open_new_itemize == true) + { + item += "\\begin{itemize}[leftmargin=" + std::to_string(section_level) + "em]"; + itemize_open++; + + } + item += "\\item {\\bf " + std::string(str) + "}: "; + } + + open_new_itemize = false; + Base::WriteString(item.c_str(), static_cast(item.length()), false); + + return true; + } + +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string &str) + { + return Key(str.data(), SizeType(str.size())); + } +#endif + + bool EndObject(SizeType /*memberCount = 0*/) + { + std::string end = ""; + if (itemize_open > 0) + { + end = "\\end{itemize}"; + itemize_open--; + } + itemize_open = 0; + // If this assert fails it could be an indicator that + // the world builder library is not fuly linked to the + // appllication. + if (level_type.size() > 0 && (level_type.back() == 0 || level_type.back() == 3)) + section_level = section_level > 0 ? section_level-1 : 0; + + + if (level_type.size() > 0 && path.size() > 0 && + ( level_type.back() == 3 || level_type.back() == 0)) + { + path.pop_back(); + } + + if (level_type.size() > 0) + level_type.pop_back(); + + Base::WriteString(end.c_str(), static_cast(end.length()), false); + + return true; + } + + bool StartArray() + { + std::string begin = ""; + if (level_type.size() != 0 && level_type.back() == 2) + { + // this is a properties starting, so first clear all the itemize + // the lvel_type.push_back(1) has already been done by the key: properties + for (unsigned int i = 0; i < itemize_open; ++i) + { + begin += "\\end{itemize}"; + } + itemize_open = 0; + + open_new_itemize = true; + array_number.push_back(0); + } + else + { + begin = "["; + small_array = true; + first_small_array = true; + } + + Base::WriteString(begin.c_str(), static_cast(begin.size()), false); + + if (small_array == false) + Base::os_->Put('\n'); + + return true; + } + + bool EndArray(SizeType /*memberCount = 0*/) + { + std::string end = ""; + if (level_type.size() != 0 && level_type.back() == 2) + { + array_number.pop_back(); + level_type.pop_back(); + + if (path.size() > 0) + path.pop_back(); + } + else + { + end = "]"; + small_array = false; + } + + Base::WriteString(end.c_str(), static_cast(end.size()), false); + + return true; + } + + //@} + + /*! @name Convenience extensions */ + //@{ + + //! Simpler but slower overload. + bool String(const Ch *str) + { + return String(str, internal::StrLen(str)); + } + bool Key(const Ch *str) + { + return Key(str, internal::StrLen(str)); + } + + //@} + + //! Write a raw JSON value. + /*! + For user to write a stringified JSON as a value. + + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. + \param length Length of the json. + \param type Type of the root of json. + \note When using LatexWriter::RawValue(), the result json may not be indented correctly. + */ + bool RawValue(const Ch *json, size_t length, Type /*type*/) + { + RAPIDJSON_ASSERT(json != 0); + return Base::EndValue(Base::WriteRawValue(json, length)); + } + + protected: + + std::string get_path() + { + std::string return_path; + for (auto string : path) + { + return_path += "/" + string; + } + return return_path == "" ? "/" : return_path; + } + + unsigned int itemize_open = 0; + std::vector level_type; + std::vector array_number; + bool skip_next_push_back = false; + bool small_array = false; + bool first_small_array = false; + bool open_new_itemize = false; + unsigned int section_level = 0; + + private: + std::vector path; + // Prohibit copy constructor & assignment operator. + LatexWriter(const LatexWriter &); + LatexWriter &operator=(const LatexWriter &); +}; + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/contrib/world_builder/include/rapidjson/memorybuffer.h.bak b/contrib/world_builder/include/rapidjson/memorybuffer.h.bak new file mode 100644 index 00000000000..f77b612f24e --- /dev/null +++ b/contrib/world_builder/include/rapidjson/memorybuffer.h.bak @@ -0,0 +1,91 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_MEMORYBUFFER_H_ +#define RAPIDJSON_MEMORYBUFFER_H_ + +#include "stream.h" +#include "internal/stack.h" + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory output byte stream. +/*! + This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. + + It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. + + Differences between MemoryBuffer and StringBuffer: + 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. + 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. + + \tparam Allocator type for allocating memory buffer. + \note implements Stream concept +*/ +template +struct GenericMemoryBuffer +{ + typedef char Ch; // byte + + GenericMemoryBuffer(Allocator *allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + + void Put(Ch c) + { + *stack_.template Push() = c; + } + void Flush() {} + + void Clear() + { + stack_.Clear(); + } + void ShrinkToFit() + { + stack_.ShrinkToFit(); + } + Ch *Push(size_t count) + { + return stack_.template Push(count); + } + void Pop(size_t count) + { + stack_.template Pop(count); + } + + const Ch *GetBuffer() const + { + return stack_.template Bottom(); + } + + size_t GetSize() const + { + return stack_.GetSize(); + } + + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; +}; + +typedef GenericMemoryBuffer<> MemoryBuffer; + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(MemoryBuffer &memoryBuffer, char c, size_t n) +{ + std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); +} + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/contrib/world_builder/include/rapidjson/memorystream.h.bak b/contrib/world_builder/include/rapidjson/memorystream.h.bak new file mode 100644 index 00000000000..68000d9938a --- /dev/null +++ b/contrib/world_builder/include/rapidjson/memorystream.h.bak @@ -0,0 +1,96 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_MEMORYSTREAM_H_ +#define RAPIDJSON_MEMORYSTREAM_H_ + +#include "stream.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory input byte stream. +/*! + This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. + + It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. + + Differences between MemoryStream and StringStream: + 1. StringStream has encoding but MemoryStream is a byte stream. + 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. + 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). + \note implements Stream concept +*/ +struct MemoryStream +{ + typedef char Ch; // byte + + MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} + + Ch Peek() const + { + return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; + } + Ch Take() + { + return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; + } + size_t Tell() const + { + return static_cast(src_ - begin_); + } + + Ch *PutBegin() + { + RAPIDJSON_ASSERT(false); + return 0; + } + void Put(Ch) + { + RAPIDJSON_ASSERT(false); + } + void Flush() + { + RAPIDJSON_ASSERT(false); + } + size_t PutEnd(Ch *) + { + RAPIDJSON_ASSERT(false); + return 0; + } + + // For encoding detection only. + const Ch *Peek4() const + { + return Tell() + 4 <= size_ ? src_ : 0; + } + + const Ch *src_; //!< Current read position. + const Ch *begin_; //!< Original head of the string. + const Ch *end_; //!< End of stream. + size_t size_; //!< Size of the stream. +}; + +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/contrib/world_builder/include/rapidjson/msinttypes/inttypes.h.bak b/contrib/world_builder/include/rapidjson/msinttypes/inttypes.h.bak new file mode 100644 index 00000000000..502d4bfe1e0 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/msinttypes/inttypes.h.bak @@ -0,0 +1,320 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +// The above software in this distribution may have been modified by +// THL A29 Limited ("Tencent Modifications"). +// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. +namespace rapidjson +{ +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// miloyip: VC supports inttypes.h since VC2013 +#if _MSC_VER >= 1800 +#include +#else + +// 7.8 Format conversion of integer types + + typedef struct + { + intmax_t quot; + intmax_t rem; + } imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 // [ +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else // _WIN64 ][ +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif // _WIN64 ] + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 // [ +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else // _WIN64 ][ +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif // _WIN64 ] + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ + static +#else // STATIC_IMAXDIV ][ + _inline +#endif // STATIC_IMAXDIV ] + imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) + { + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) + { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; + } + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + +#endif // _MSC_VER >= 1800 + +#endif // _MSC_INTTYPES_H_ ] +} \ No newline at end of file diff --git a/contrib/world_builder/include/rapidjson/msinttypes/stdint.h.bak b/contrib/world_builder/include/rapidjson/msinttypes/stdint.h.bak new file mode 100644 index 00000000000..421edf64459 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/msinttypes/stdint.h.bak @@ -0,0 +1,300 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +// The above software in this distribution may have been modified by +// THL A29 Limited ("Tencent Modifications"). +// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. +#if _MSC_VER >= 1600 // [ +#include + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +#undef INT8_C +#undef INT16_C +#undef INT32_C +#undef INT64_C +#undef UINT8_C +#undef UINT16_C +#undef UINT32_C +#undef UINT64_C + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#else // ] _MSC_VER >= 1700 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we have to wrap include with 'extern "C++" {}' +// or compiler would give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#if defined(__cplusplus) && !defined(_M_ARM) +extern "C" { +#endif +# include +#if defined(__cplusplus) && !defined(_M_ARM) +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#else +typedef signed __int8 int8_t; +typedef signed __int16 int16_t; +typedef signed __int32 int32_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ +typedef signed __int64 intptr_t; +typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ +typedef _W64 signed int intptr_t; +typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] diff --git a/contrib/world_builder/include/rapidjson/mystwriter.h.bak b/contrib/world_builder/include/rapidjson/mystwriter.h.bak new file mode 100644 index 00000000000..b684ddaf12b --- /dev/null +++ b/contrib/world_builder/include/rapidjson/mystwriter.h.bak @@ -0,0 +1,528 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_MYSTWRITER_H_ +#define RAPIDJSON_MYSTWRITER_H_ + +#include "writer.h" + +#include "assert.h" + +#include +#include +#include +#include + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +#define MAX_PATH_LEVEL 25 + +//! Writer with indentation and spacing. +/*! + \tparam OutputStream Type of output os. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam StackAllocator Type of allocator for allocating memory of stack. +*/ +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> +class MySTWriter : public Writer +{ + public: + typedef Writer Base; + typedef typename Base::Ch Ch; + + //! Constructor + /*! \param os Output stream. + \param allocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + explicit MySTWriter(OutputStream &os, bool _make_open = false, StackAllocator *allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(os, allocator, levelDepth) + { + make_open = _make_open; + level_type.resize(0); + array_number.resize(0); + path.resize(0); + } + + + explicit MySTWriter(StackAllocator *allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(allocator, levelDepth) + { + level_type.resize(0); + array_number.resize(0); + path.resize(0); + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + MySTWriter(MySTWriter &&rhs) : + Base(std::forward(rhs)) + { + level_type.resize(0); + array_number.resize(0); + path.resize(0); + } +#endif + + /*! @name Implementation of Handler + \see Handler + */ + //@{ + + bool Null() + { + return Base::EndValue(Base::WriteNull()); + } + bool Bool(bool b) + { + Base::EndValue(Base::WriteBool(b)); + Base::os_->Put('\n'); + return true; + } + bool Int(int i) + { + Base::EndValue(Base::WriteInt(i)); + Base::os_->Put('\n'); + return true; + } + bool Uint(unsigned u) + { + Base::EndValue(Base::WriteUint(u)); + Base::os_->Put('\n'); + return true; + } + bool Int64(int64_t i64) + { + Base::EndValue(Base::WriteInt64(i64)); + Base::os_->Put('\n'); + return true; + } + bool Uint64(uint64_t u64) + { + Base::EndValue(Base::WriteUint64(u64)); + Base::os_->Put('\n'); + return true; + } + bool Double(double d) + { + Base::EndValue(Base::WriteDouble(d)); + Base::os_->Put('\n'); + return true; + } + + bool RawNumber(const Ch *str, SizeType length, bool /*copy = false*/) + { + RAPIDJSON_ASSERT(str != 0); + Base::EndValue(Base::WriteString(str, length, false)); + Base::os_->Put('\n'); + return true; + } + + bool String(const Ch *str, SizeType length, bool /*copy = false*/) + { + RAPIDJSON_ASSERT(str != 0); + if (small_array == true) + { + if (first_small_array == true) + first_small_array = false; + else + { + Base::os_->Put(','); + Base::os_->Put(' '); + } + } + Base::EndValue(Base::WriteString(str, length, false)); + + if (small_array == false) + Base::os_->Put('\n'); + return true; + } + +#if RAPIDJSON_HAS_STDSTRING + bool String(const std::basic_string &str) + { + return String(str.data(), SizeType(str.size())); + } +#endif + + bool StartObject() + { + bool wrote_dropdown = false; + std::string begin = ""; + if (level_type.size() != 0 && level_type.back() == 1) + { + // this is a properties starting, so first clear all the itemize + // the lvel_type.push_back(1) has already been done by the key: properties + + if (skip_next_push_back == false) + { + for (size_t level =MAX_PATH_LEVEL-path.size(); level != 0; level--) + { + begin += ":"; + } + begin += "{dropdown} " + get_path(); + + wrote_dropdown = true; + level_type.push_back(0); + } + else + { + skip_next_push_back = false; + } + } + else if (level_type.size() != 0 && level_type.back() == 2) + { + unsigned int number = array_number.back() + 1; + array_number.back() = number; + path.push_back(std::to_string(array_number.back())); + level_type.push_back(0); + + for (size_t level =MAX_PATH_LEVEL-path.size(); level != 0; level--) + { + begin += ":"; + } + begin += "{dropdown} " + get_path(); + + + wrote_dropdown = true; + } + else if (level_type.size() != 0 && level_type.back() == 5) + { + unsigned int number = array_number.back() + 1; + array_number.back() = number; + path.push_back(std::to_string(array_number.back())); + level_type.push_back(0); + + for (size_t level =MAX_PATH_LEVEL-path.size(); level != 0; level--) + { + begin += ":"; + } + begin += "{dropdown} " + get_path(); + + + wrote_dropdown = true; + } + else + { + for (size_t level =MAX_PATH_LEVEL-path.size(); level != 0; level--) + { + begin += ":"; + } + begin += "{dropdown} " + get_path(); + + + wrote_dropdown = true; + if (level_type.size() > 0 && (level_type.back() != 3 || level_type.size() == 0)) + level_type.push_back(0); + } + + Base::WriteString(begin.c_str(), static_cast(begin.size()), false); + + Base::os_->Put('\n'); + if (level_type.size() == 0 && !make_open) + { + std::string string_open = ":open:"; + Base::WriteString(string_open.c_str(), static_cast(string_open.size()), false); + Base::os_->Put('\n'); + } + + if (wrote_dropdown) + { + if (make_open) + { + std::string open = ":open:"; + Base::WriteString(open.c_str(), static_cast(open.size()), false); + Base::os_->Put('\n'); + std::string name = ":name: open" + get_path_underscore() + ""; + Base::WriteString(name.c_str(), static_cast(name.size()), false); + Base::os_->Put('\n'); + Base::os_->Put('\n'); + } + else + { + std::string name = ":name: closed" + get_path_underscore() + ""; + Base::WriteString(name.c_str(), static_cast(name.size()), false); + Base::os_->Put('\n'); + Base::os_->Put('\n'); + } + } + + return true; + } + + bool Key(const Ch *str, SizeType /*length*/, bool /*copy = false*/) + { + std::string item = ""; + + + std::string key(str); + if (key == "properties") + { + level_type.push_back(1); + skip_next_push_back = true; + } + else if (key == "oneOf") + { + level_type.push_back(2); + path.push_back(key); + } + else if (key == "items") + { + level_type.push_back(3); + path.push_back(key); + } + else if (key == "enum" || key == "required" ) + { + level_type.push_back(4); + item += "- **" + std::string(str) + "**:"; + } + else if (key == "anyOf") + { + level_type.push_back(5); + path.push_back(key); + } + else if (level_type.size() > 0 && (level_type.back() == 1 || level_type.back() == 2 || level_type.back() == 5)) + { + // the level just below properties, these are the sections + // add to the path + path.push_back(key); + } + else + { + item += "- **" + std::string(str) + "**:"; + } + + Base::WriteString(item.c_str(), static_cast(item.length()), false); + + return true; + } + +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string &str) + { + return Key(str.data(), SizeType(str.size())); + } +#endif + + bool EndObject(SizeType /*memberCount = 0*/) + { + std::string end = ""; + + // If this assert fails it could be an indicator that + // the world builder library is not fuly linked to the + // appllication. + + if (level_type.size() > 0 && path.size() > 0 && + ( level_type.back() == 3 || level_type.back() == 0)) + { + + for (size_t level =MAX_PATH_LEVEL-path.size(); level != 0; level--) + { + WBAssert(path.size() < MAX_PATH_LEVEL, "EA: path size is larger than 90: " << path.size() << ", level = " << level); + end += ':'; + } + + path.pop_back(); + } + + if (level_type.size() > 0) + { + level_type.pop_back(); + } + + Base::WriteString(end.c_str(), static_cast(end.length()), false); + + Base::os_->Put('\n'); + Base::os_->Put('\n'); + return true; + } + + bool StartArray() + { + bool wrote_dropdown = false; + std::string begin = ""; + if (level_type.size() != 0 && (level_type.back() == 2|| level_type.back() == 3|| level_type.back() == 5 )) + { + //begin += "level type" + std::to_string(level_type.back()); + // this is a properties starting, so first clear all the itemize + // the lvel_type.push_back(1) has already been done by the key: properties + + for (size_t level = MAX_PATH_LEVEL-path.size(); level != 0; level--) + { + WBAssert(path.size() < MAX_PATH_LEVEL, "SA: path size is larger than 90: " << path.size() << ", level = " << level); + begin += ":"; + } + begin += "{dropdown} " + get_path(); + + wrote_dropdown = true; + array_number.push_back(0); + } + else + { + begin += "["; + small_array = true; + first_small_array = true; + } + + Base::WriteString(begin.c_str(), static_cast(begin.size()), false); + + if (small_array == false) + Base::os_->Put('\n'); + + + if (wrote_dropdown) + { + if (make_open) + { + std::string open = ":open:"; + Base::WriteString(open.c_str(), static_cast(open.size()), false); + Base::os_->Put('\n'); + std::string name = ":name: open" + get_path_underscore() + ""; + Base::WriteString(name.c_str(), static_cast(name.size()), false); + Base::os_->Put('\n'); + Base::os_->Put('\n'); + } + else + { + std::string name = ":name: closed" + get_path_underscore() + ""; + Base::WriteString(name.c_str(), static_cast(name.size()), false); + Base::os_->Put('\n'); + Base::os_->Put('\n'); + } + } + return true; + } + + bool EndArray(SizeType /*memberCount = 0*/) + { + std::string end = ""; + if (level_type.size() != 0 && (level_type.back() == 1 || level_type.back() == 2 || level_type.back() == 3 || level_type.back() == 5)) + { + array_number.pop_back(); + level_type.pop_back(); + + if (path.size() > 0) + path.pop_back(); + } + else + { + + end = "]"; + + small_array = false; + + if (level_type.size() > 0 && (level_type.back() == 4))// || level_type.back() == 0)) + { + level_type.pop_back(); + } + } + + Base::WriteString(end.c_str(), static_cast(end.size()), false); + + Base::os_->Put('\n'); + return true; + } + + //@} + + /*! @name Convenience extensions */ + //@{ + + //! Simpler but slower overload. + bool String(const Ch *str) + { + return String(str, internal::StrLen(str)); + } + bool Key(const Ch *str) + { + return Key(str, internal::StrLen(str)); + } + + //@} + + //! Write a raw JSON value. + /*! + For user to write a stringified JSON as a value. + + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. + \param length Length of the json. + \param type Type of the root of json. + \note When using MySTWriter::RawValue(), the result json may not be indented correctly. + */ + bool RawValue(const Ch *json, size_t length, Type /*type*/) + { + RAPIDJSON_ASSERT(json != 0); + return Base::EndValue(Base::WriteRawValue(json, length)); + } + + protected: + + std::string get_path() + { + std::string return_path; + for (auto string : path) + { + return_path += "/" + string; + } + return return_path == "" ? "/" : return_path; + } + + std::string get_path_underscore() + { + std::string return_path; + for (auto string : path) + { + return_path += "_" + string; + } + const char space = ' '; + const char dash = '-'; + std::replace(return_path.begin(), return_path.end(), space, dash); + return return_path == "" ? "_" : return_path; + } + + std::vector level_type; + std::vector array_number; + bool make_open = false; + bool skip_next_push_back = false; + bool small_array = false; + bool first_small_array = false; + + private: + std::vector path; + // Prohibit copy constructor & assignment operator. + MySTWriter(const MySTWriter &); + MySTWriter &operator=(const MySTWriter &); +}; + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/contrib/world_builder/include/rapidjson/ostreamwrapper.h.bak b/contrib/world_builder/include/rapidjson/ostreamwrapper.h.bak new file mode 100644 index 00000000000..70cb06ba940 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/ostreamwrapper.h.bak @@ -0,0 +1,104 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_OSTREAMWRAPPER_H_ +#define RAPIDJSON_OSTREAMWRAPPER_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::ostringstream + - \c std::stringstream + - \c std::wpstringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wofstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_ostream. +*/ + +template +class BasicOStreamWrapper +{ + public: + typedef typename StreamType::char_type Ch; + BasicOStreamWrapper(StreamType &stream) : stream_(stream) {} + + void Put(Ch c) + { + stream_.put(c); + } + + void Flush() + { + stream_.flush(); + } + + // Not implemented + char Peek() const + { + RAPIDJSON_ASSERT(false); + return 0; + } + char Take() + { + RAPIDJSON_ASSERT(false); + return 0; + } + size_t Tell() const + { + RAPIDJSON_ASSERT(false); + return 0; + } + char *PutBegin() + { + RAPIDJSON_ASSERT(false); + return 0; + } + size_t PutEnd(char *) + { + RAPIDJSON_ASSERT(false); + return 0; + } + + private: + BasicOStreamWrapper(const BasicOStreamWrapper &); + BasicOStreamWrapper &operator=(const BasicOStreamWrapper &); + + StreamType &stream_; +}; + +typedef BasicOStreamWrapper OStreamWrapper; +typedef BasicOStreamWrapper WOStreamWrapper; + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_OSTREAMWRAPPER_H_ diff --git a/contrib/world_builder/include/rapidjson/pointer.h.bak b/contrib/world_builder/include/rapidjson/pointer.h.bak new file mode 100644 index 00000000000..f2dee09185e --- /dev/null +++ b/contrib/world_builder/include/rapidjson/pointer.h.bak @@ -0,0 +1,1532 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_POINTER_H_ +#define RAPIDJSON_POINTER_H_ + +#include "document.h" +#include "internal/itoa.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +//RAPIDJSON_DIAG_OFF(switch -enum) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token + +//! Error code of parsing. +/*! \ingroup RAPIDJSON_ERRORS + \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode +*/ +enum PointerParseErrorCode +{ + kPointerParseErrorNone = 0, //!< The parse is successful + + kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' + kPointerParseErrorInvalidEscape, //!< Invalid escape + kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment + kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericPointer + +//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. +/*! + This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" + (https://tools.ietf.org/html/rfc6901). + + A JSON pointer is for identifying a specific value in a JSON document + (GenericDocument). It can simplify coding of DOM tree manipulation, because it + can access multiple-level depth of DOM tree with single API call. + + After it parses a string representation (e.g. "/foo/0" or URI fragment + representation (e.g. "#/foo/0") into its internal representation (tokens), + it can be used to resolve a specific value in multiple documents, or sub-tree + of documents. + + Contrary to GenericValue, Pointer can be copy constructed and copy assigned. + Apart from assignment, a Pointer cannot be modified after construction. + + Although Pointer is very convenient, please aware that constructing Pointer + involves parsing and dynamic memory allocation. A special constructor with user- + supplied tokens eliminates these. + + GenericPointer depends on GenericDocument and GenericValue. + + \tparam ValueType The value type of the DOM tree. E.g. GenericValue > + \tparam Allocator The allocator type for allocating memory for internal representation. + + \note GenericPointer uses same encoding of ValueType. + However, Allocator of GenericPointer is independent of Allocator of Value. +*/ +template +class GenericPointer +{ + public: + typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value + typedef typename ValueType::Ch Ch; //!< Character type from Value + + //! A token is the basic units of internal representation. + /*! + A JSON pointer string representation "/foo/123" is parsed to two tokens: + "foo" and 123. 123 will be represented in both numeric form and string form. + They are resolved according to the actual value type (object or array). + + For token that are not numbers, or the numeric value is out of bound + (greater than limits of SizeType), they are only treated as string form + (i.e. the token's index will be equal to kPointerInvalidIndex). + + This struct is public so that user can create a Pointer without parsing and + allocation, using a special constructor. + */ + struct Token + { + const Ch *name; //!< Name of the token. It has null character at the end but it can contain null character. + SizeType length; //!< Length of the name. + SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. + }; + + //!@name Constructors and destructor. + //@{ + + //! Default constructor. + GenericPointer(Allocator *allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} + + //! Constructor that parses a string or URI fragment representation. + /*! + \param source A null-terminated, string or URI fragment representation of JSON pointer. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + */ + explicit GenericPointer(const Ch *source, Allocator *allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) + { + Parse(source, internal::StrLen(source)); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Constructor that parses a string or URI fragment representation. + /*! + \param source A string or URI fragment representation of JSON pointer. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. + */ + explicit GenericPointer(const std::basic_string &source, Allocator *allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) + { + Parse(source.c_str(), source.size()); + } +#endif + + //! Constructor that parses a string or URI fragment representation, with length of the source string. + /*! + \param source A string or URI fragment representation of JSON pointer. + \param length Length of source. + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. + \note Slightly faster than the overload without length. + */ + GenericPointer(const Ch *source, size_t length, Allocator *allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) + { + Parse(source, length); + } + + //! Constructor with user-supplied tokens. + /*! + This constructor let user supplies const array of tokens. + This prevents the parsing process and eliminates allocation. + This is preferred for memory constrained environments. + + \param tokens An constant array of tokens representing the JSON pointer. + \param tokenCount Number of tokens. + + \b Example + \code + #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } + #define INDEX(i) { #i, sizeof(#i) - 1, i } + + static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; + static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); + // Equivalent to static const Pointer p("/foo/123"); + + #undef NAME + #undef INDEX + \endcode + */ + GenericPointer(const Token *tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} + + //! Copy constructor. + GenericPointer(const GenericPointer &rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) + { + *this = rhs; + } + + //! Copy constructor. + GenericPointer(const GenericPointer &rhs, Allocator *allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) + { + *this = rhs; + } + + //! Destructor. + ~GenericPointer() + { + if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. + Allocator::Free(tokens_); + RAPIDJSON_DELETE(ownAllocator_); + } + + //! Assignment operator. + GenericPointer &operator=(const GenericPointer &rhs) + { + if (this != &rhs) + { + // Do not delete ownAllcator + if (nameBuffer_) + Allocator::Free(tokens_); + + tokenCount_ = rhs.tokenCount_; + parseErrorOffset_ = rhs.parseErrorOffset_; + parseErrorCode_ = rhs.parseErrorCode_; + + if (rhs.nameBuffer_) + CopyFromRaw(rhs); // Normally parsed tokens. + else + { + tokens_ = rhs.tokens_; // User supplied const tokens. + nameBuffer_ = 0; + } + } + return *this; + } + + //@} + + //!@name Append token + //@{ + + //! Append a token and return a new Pointer + /*! + \param token Token to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const Token &token, Allocator *allocator = 0) const + { + GenericPointer r; + r.allocator_ = allocator; + Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); + std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); + r.tokens_[tokenCount_].name = p; + r.tokens_[tokenCount_].length = token.length; + r.tokens_[tokenCount_].index = token.index; + return r; + } + + //! Append a name token with length, and return a new Pointer + /*! + \param name Name to be appended. + \param length Length of name. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const Ch *name, SizeType length, Allocator *allocator = 0) const + { + Token token = { name, length, kPointerInvalidIndex }; + return Append(token, allocator); + } + + //! Append a name token without length, and return a new Pointer + /*! + \param name Name (const Ch*) to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) + Append(T *name, Allocator *allocator = 0) const + { + return Append(name, internal::StrLen(name), allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Append a name token, and return a new Pointer + /*! + \param name Name to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const std::basic_string &name, Allocator *allocator = 0) const + { + return Append(name.c_str(), static_cast(name.size()), allocator); + } +#endif + + //! Append a index token, and return a new Pointer + /*! + \param index Index to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(SizeType index, Allocator *allocator = 0) const + { + char buffer[21]; + char *end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); + SizeType length = static_cast(end - buffer); + buffer[length] = '\0'; + + if (sizeof(Ch) == 1) + { + Token token = { reinterpret_cast(buffer), length, index }; + return Append(token, allocator); + } + else + { + Ch name[21]; + for (size_t i = 0; i <= length; i++) + name[i] = static_cast(buffer[i]); + Token token = { name, length, index }; + return Append(token, allocator); + } + } + + //! Append a token by value, and return a new Pointer + /*! + \param token token to be appended. + \param allocator Allocator for the newly return Pointer. + \return A new Pointer with appended token. + */ + GenericPointer Append(const ValueType &token, Allocator *allocator = 0) const + { + if (token.IsString()) + return Append(token.GetString(), token.GetStringLength(), allocator); + else + { + RAPIDJSON_ASSERT(token.IsUint64()); + RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); + return Append(static_cast(token.GetUint64()), allocator); + } + } + + //!@name Handling Parse Error + //@{ + + //! Check whether this is a valid pointer. + bool IsValid() const + { + return parseErrorCode_ == kPointerParseErrorNone; + } + + //! Get the parsing error offset in code unit. + size_t GetParseErrorOffset() const + { + return parseErrorOffset_; + } + + //! Get the parsing error code. + PointerParseErrorCode GetParseErrorCode() const + { + return parseErrorCode_; + } + + //@} + + //! Get the allocator of this pointer. + Allocator &GetAllocator() + { + return *allocator_; + } + + //!@name Tokens + //@{ + + //! Get the token array (const version only). + const Token *GetTokens() const + { + return tokens_; + } + + //! Get the number of tokens. + size_t GetTokenCount() const + { + return tokenCount_; + } + + //@} + + //!@name Equality/inequality operators + //@{ + + //! Equality operator. + /*! + \note When any pointers are invalid, always returns false. + */ + bool operator==(const GenericPointer &rhs) const + { + if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) + return false; + + for (size_t i = 0; i < tokenCount_; i++) + { + if (tokens_[i].index != rhs.tokens_[i].index || + tokens_[i].length != rhs.tokens_[i].length || + (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) + { + return false; + } + } + + return true; + } + + //! Inequality operator. + /*! + \note When any pointers are invalid, always returns true. + */ + bool operator!=(const GenericPointer &rhs) const + { + return !(*this == rhs); + } + + //@} + + //!@name Stringify + //@{ + + //! Stringify the pointer into string representation. + /*! + \tparam OutputStream Type of output stream. + \param os The output stream. + */ + template + bool Stringify(OutputStream &os) const + { + return Stringify(os); + } + + //! Stringify the pointer into URI fragment representation. + /*! + \tparam OutputStream Type of output stream. + \param os The output stream. + */ + template + bool StringifyUriFragment(OutputStream &os) const + { + return Stringify(os); + } + + //@} + + //!@name Create value + //@{ + + //! Create a value in a subtree. + /*! + If the value is not exist, it creates all parent values and a JSON Null value. + So it always succeed and return the newly created or existing value. + + Remind that it may change types of parents according to tokens, so it + potentially removes previously stored values. For example, if a document + was an array, and "/foo" is used to create a value, then the document + will be changed to an object, and all existing array elements are lost. + + \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \param alreadyExist If non-null, it stores whether the resolved value is already exist. + \return The resolved newly created (a JSON Null value), or already exists value. + */ + ValueType &Create(ValueType &root, typename ValueType::AllocatorType &allocator, bool *alreadyExist = 0) const + { + RAPIDJSON_ASSERT(IsValid()); + ValueType *v = &root; + bool exist = true; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) + { + if (v->IsArray() && t->name[0] == '-' && t->length == 1) + { + v->PushBack(ValueType().Move(), allocator); + v = &((*v)[v->Size() - 1]); + exist = false; + } + else + { + if (t->index == kPointerInvalidIndex) // must be object name + { + if (!v->IsObject()) + v->SetObject(); // Change to Object + } + else // object name or array index + { + if (!v->IsArray() && !v->IsObject()) + v->SetArray(); // Change to Array + } + + if (v->IsArray()) + { + if (t->index >= v->Size()) + { + v->Reserve(t->index + 1, allocator); + while (t->index >= v->Size()) + v->PushBack(ValueType().Move(), allocator); + exist = false; + } + v = &((*v)[t->index]); + } + else + { + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + if (m == v->MemberEnd()) + { + v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); + v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end + exist = false; + } + else + v = &m->value; + } + } + } + + if (alreadyExist) + *alreadyExist = exist; + + return *v; + } + + //! Creates a value in a document. + /*! + \param document A document to be resolved. + \param alreadyExist If non-null, it stores whether the resolved value is already exist. + \return The resolved newly created, or already exists value. + */ + template + ValueType &Create(GenericDocument &document, bool *alreadyExist = 0) const + { + return Create(document, document.GetAllocator(), alreadyExist); + } + + //@} + + //!@name Query value + //@{ + + //! Query a value in a subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. + \return Pointer to the value if it can be resolved. Otherwise null. + + \note + There are only 3 situations when a value cannot be resolved: + 1. A value in the path is not an array nor object. + 2. An object value does not contain the token. + 3. A token is out of range of an array value. + + Use unresolvedTokenIndex to retrieve the token index. + */ + ValueType *Get(ValueType &root, size_t *unresolvedTokenIndex = 0) const + { + RAPIDJSON_ASSERT(IsValid()); + ValueType *v = &root; + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) + { + switch (v->GetType()) + { + case kObjectType: + { + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + if (m == v->MemberEnd()) + break; + v = &m->value; + } + continue; + case kArrayType: + if (t->index == kPointerInvalidIndex || t->index >= v->Size()) + break; + v = &((*v)[t->index]); + continue; + default: + break; + } + + // Error: unresolved token + if (unresolvedTokenIndex) + *unresolvedTokenIndex = static_cast(t - tokens_); + return 0; + } + return v; + } + + //! Query a const value in a const subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \return Pointer to the value if it can be resolved. Otherwise null. + */ + const ValueType *Get(const ValueType &root, size_t *unresolvedTokenIndex = 0) const + { + return Get(const_cast(root), unresolvedTokenIndex); + } + + //@} + + //!@name Query a value with default + //@{ + + //! Query a value in a subtree with default value. + /*! + Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. + So that this function always succeed. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param defaultValue Default value to be cloned if the value was not exists. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType &GetWithDefault(ValueType &root, const ValueType &defaultValue, typename ValueType::AllocatorType &allocator) const + { + bool alreadyExist; + ValueType &v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); + } + + //! Query a value in a subtree with default null-terminated string. + ValueType &GetWithDefault(ValueType &root, const Ch *defaultValue, typename ValueType::AllocatorType &allocator) const + { + bool alreadyExist; + ValueType &v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.SetString(defaultValue, allocator); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Query a value in a subtree with default std::basic_string. + ValueType &GetWithDefault(ValueType &root, const std::basic_string &defaultValue, typename ValueType::AllocatorType &allocator) const + { + bool alreadyExist; + ValueType &v = Create(root, allocator, &alreadyExist); + return alreadyExist ? v : v.SetString(defaultValue, allocator); + } +#endif + + //! Query a value in a subtree with default primitive value. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType &)) + GetWithDefault(ValueType &root, T defaultValue, typename ValueType::AllocatorType &allocator) const + { + return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); + } + + //! Query a value in a document with default value. + template + ValueType &GetWithDefault(GenericDocument &document, const ValueType &defaultValue) const + { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + + //! Query a value in a document with default null-terminated string. + template + ValueType &GetWithDefault(GenericDocument &document, const Ch *defaultValue) const + { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Query a value in a document with default std::basic_string. + template + ValueType &GetWithDefault(GenericDocument &document, const std::basic_string &defaultValue) const + { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } +#endif + + //! Query a value in a document with default primitive value. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType &)) + GetWithDefault(GenericDocument &document, T defaultValue) const + { + return GetWithDefault(document, defaultValue, document.GetAllocator()); + } + + //@} + + //!@name Set a value + //@{ + + //! Set a value in a subtree, with move semantics. + /*! + It creates all parents if they are not exist or types are different to the tokens. + So this function always succeeds but potentially remove existing values. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param value Value to be set. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType &Set(ValueType &root, ValueType &value, typename ValueType::AllocatorType &allocator) const + { + return Create(root, allocator) = value; + } + + //! Set a value in a subtree, with copy semantics. + ValueType &Set(ValueType &root, const ValueType &value, typename ValueType::AllocatorType &allocator) const + { + return Create(root, allocator).CopyFrom(value, allocator); + } + + //! Set a null-terminated string in a subtree. + ValueType &Set(ValueType &root, const Ch *value, typename ValueType::AllocatorType &allocator) const + { + return Create(root, allocator) = ValueType(value, allocator).Move(); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Set a std::basic_string in a subtree. + ValueType &Set(ValueType &root, const std::basic_string &value, typename ValueType::AllocatorType &allocator) const + { + return Create(root, allocator) = ValueType(value, allocator).Move(); + } +#endif + + //! Set a primitive value in a subtree. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType &)) + Set(ValueType &root, T value, typename ValueType::AllocatorType &allocator) const + { + return Create(root, allocator) = ValueType(value).Move(); + } + + //! Set a value in a document, with move semantics. + template + ValueType &Set(GenericDocument &document, ValueType &value) const + { + return Create(document) = value; + } + + //! Set a value in a document, with copy semantics. + template + ValueType &Set(GenericDocument &document, const ValueType &value) const + { + return Create(document).CopyFrom(value, document.GetAllocator()); + } + + //! Set a null-terminated string in a document. + template + ValueType &Set(GenericDocument &document, const Ch *value) const + { + return Create(document) = ValueType(value, document.GetAllocator()).Move(); + } + +#if RAPIDJSON_HAS_STDSTRING + //! Sets a std::basic_string in a document. + template + ValueType &Set(GenericDocument &document, const std::basic_string &value) const + { + return Create(document) = ValueType(value, document.GetAllocator()).Move(); + } +#endif + + //! Set a primitive value in a document. + /*! + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + */ + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType &)) + Set(GenericDocument &document, T value) const + { + return Create(document) = value; + } + + //@} + + //!@name Swap a value + //@{ + + //! Swap a value with a value in a subtree. + /*! + It creates all parents if they are not exist or types are different to the tokens. + So this function always succeeds but potentially remove existing values. + + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param value Value to be swapped. + \param allocator Allocator for creating the values if the specified value or its parents are not exist. + \see Create() + */ + ValueType &Swap(ValueType &root, ValueType &value, typename ValueType::AllocatorType &allocator) const + { + return Create(root, allocator).Swap(value); + } + + //! Swap a value with a value in a document. + template + ValueType &Swap(GenericDocument &document, ValueType &value) const + { + return Create(document).Swap(value); + } + + //@} + + //! Erase a value in a subtree. + /*! + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \return Whether the resolved value is found and erased. + + \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. + */ + bool Erase(ValueType &root) const + { + RAPIDJSON_ASSERT(IsValid()); + if (tokenCount_ == 0) // Cannot erase the root + return false; + + ValueType *v = &root; + const Token *last = tokens_ + (tokenCount_ - 1); + for (const Token *t = tokens_; t != last; ++t) + { + switch (v->GetType()) + { + case kObjectType: + { + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + if (m == v->MemberEnd()) + return false; + v = &m->value; + } + break; + case kArrayType: + if (t->index == kPointerInvalidIndex || t->index >= v->Size()) + return false; + v = &((*v)[t->index]); + break; + default: + return false; + } + } + + switch (v->GetType()) + { + case kObjectType: + return v->EraseMember(GenericStringRef(last->name, last->length)); + case kArrayType: + if (last->index == kPointerInvalidIndex || last->index >= v->Size()) + return false; + v->Erase(v->Begin() + last->index); + return true; + default: + return false; + } + } + + private: + //! Clone the content from rhs to this. + /*! + \param rhs Source pointer. + \param extraToken Extra tokens to be allocated. + \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. + \return Start of non-occupied name buffer, for storing extra names. + */ + Ch *CopyFromRaw(const GenericPointer &rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) + { + if (!allocator_) // allocator is independently owned. + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens + for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) + nameBufferSize += t->length; + + tokenCount_ = rhs.tokenCount_ + extraToken; + tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); + nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); + if (rhs.tokenCount_ > 0) + { + std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); + } + if (nameBufferSize > 0) + { + std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); + } + + // Adjust pointers to name buffer + std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; + for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) + t->name += diff; + + return nameBuffer_ + nameBufferSize; + } + + //! Check whether a character should be percent-encoded. + /*! + According to RFC 3986 2.3 Unreserved Characters. + \param c The character (code unit) to be tested. + */ + bool NeedPercentEncode(Ch c) const + { + return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); + } + + //! Parse a JSON String or its URI fragment representation into tokens. +#ifndef __clang__ // -Wdocumentation + /*! + \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. + \param length Length of the source string. + \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. + */ +#endif + void Parse(const Ch *source, size_t length) + { + RAPIDJSON_ASSERT(source != NULL); + RAPIDJSON_ASSERT(nameBuffer_ == 0); + RAPIDJSON_ASSERT(tokens_ == 0); + + // Create own allocator if user did not supply. + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + // Count number of '/' as tokenCount + tokenCount_ = 0; + for (const Ch *s = source; s != source + length; s++) + if (*s == '/') + tokenCount_++; + + Token *token = tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); + Ch *name = nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); + size_t i = 0; + + // Detect if it is a URI fragment + bool uriFragment = false; + if (source[i] == '#') + { + uriFragment = true; + i++; + } + + if (i != length && source[i] != '/') + { + parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; + goto error; + } + + while (i < length) + { + RAPIDJSON_ASSERT(source[i] == '/'); + i++; // consumes '/' + + token->name = name; + bool isNumber = true; + + while (i < length && source[i] != '/') + { + Ch c = source[i]; + if (uriFragment) + { + // Decoding percent-encoding for URI fragment + if (c == '%') + { + PercentDecodeStream is(&source[i], source + length); + GenericInsituStringStream os(name); + Ch *begin = os.PutBegin(); + if (!Transcoder, EncodingType>().Validate(is, os) || !is.IsValid()) + { + parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; + goto error; + } + size_t len = os.PutEnd(begin); + i += is.Tell() - 1; + if (len == 1) + c = *name; + else + { + name += len; + isNumber = false; + i++; + continue; + } + } + else if (NeedPercentEncode(c)) + { + parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; + goto error; + } + } + + i++; + + // Escaping "~0" -> '~', "~1" -> '/' + if (c == '~') + { + if (i < length) + { + c = source[i]; + if (c == '0') c = '~'; + else if (c == '1') c = '/'; + else + { + parseErrorCode_ = kPointerParseErrorInvalidEscape; + goto error; + } + i++; + } + else + { + parseErrorCode_ = kPointerParseErrorInvalidEscape; + goto error; + } + } + + // First check for index: all of characters are digit + if (c < '0' || c > '9') + isNumber = false; + + *name++ = c; + } + token->length = static_cast(name - token->name); + if (token->length == 0) + isNumber = false; + *name++ = '\0'; // Null terminator + + // Second check for index: more than one digit cannot have leading zero + if (isNumber && token->length > 1 && token->name[0] == '0') + isNumber = false; + + // String to SizeType conversion + SizeType n = 0; + if (isNumber) + { + for (size_t j = 0; j < token->length; j++) + { + SizeType m = n * 10 + static_cast(token->name[j] - '0'); + if (m < n) // overflow detection + { + isNumber = false; + break; + } + n = m; + } + } + + token->index = isNumber ? n : kPointerInvalidIndex; + token++; + } + + RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer + parseErrorCode_ = kPointerParseErrorNone; + return; + + error: + Allocator::Free(tokens_); + nameBuffer_ = 0; + tokens_ = 0; + tokenCount_ = 0; + parseErrorOffset_ = i; + return; + } + + //! Stringify to string or URI fragment representation. + /*! + \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. + \tparam OutputStream type of output stream. + \param os The output stream. + */ + template + bool Stringify(OutputStream &os) const + { + RAPIDJSON_ASSERT(IsValid()); + + if (uriFragment) + os.Put('#'); + + for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) + { + os.Put('/'); + for (size_t j = 0; j < t->length; j++) + { + Ch c = t->name[j]; + if (c == '~') + { + os.Put('~'); + os.Put('0'); + } + else if (c == '/') + { + os.Put('~'); + os.Put('1'); + } + else if (uriFragment && NeedPercentEncode(c)) + { + // Transcode to UTF8 sequence + GenericStringStream source(&t->name[j]); + PercentEncodeStream target(os); + if (!Transcoder >().Validate(source, target)) + return false; + j += source.Tell() - 1; + } + else + os.Put(c); + } + } + return true; + } + + //! A helper stream for decoding a percent-encoded sequence into code unit. + /*! + This stream decodes %XY triplet into code unit (0-255). + If it encounters invalid characters, it sets output code unit as 0 and + mark invalid, and to be checked by IsValid(). + */ + class PercentDecodeStream + { + public: + typedef typename ValueType::Ch Ch; + + //! Constructor + /*! + \param source Start of the stream + \param end Past-the-end of the stream. + */ + PercentDecodeStream(const Ch *source, const Ch *end) : src_(source), head_(source), end_(end), valid_(true) {} + + Ch Take() + { + if (*src_ != '%' || src_ + 3 > end_) // %XY triplet + { + valid_ = false; + return 0; + } + src_++; + Ch c = 0; + for (int j = 0; j < 2; j++) + { + c = static_cast(c << 4); + Ch h = *src_; + if (h >= '0' && h <= '9') c = static_cast(c + h - '0'); + else if (h >= 'A' && h <= 'F') c = static_cast(c + h - 'A' + 10); + else if (h >= 'a' && h <= 'f') c = static_cast(c + h - 'a' + 10); + else + { + valid_ = false; + return 0; + } + src_++; + } + return c; + } + + size_t Tell() const + { + return static_cast(src_ - head_); + } + bool IsValid() const + { + return valid_; + } + + private: + const Ch *src_; //!< Current read position. + const Ch *head_; //!< Original head of the string. + const Ch *end_; //!< Past-the-end position. + bool valid_; //!< Whether the parsing is valid. + }; + + //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. + template + class PercentEncodeStream + { + public: + PercentEncodeStream(OutputStream &os) : os_(os) {} + void Put(char c) // UTF-8 must be byte + { + unsigned char u = static_cast(c); + static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + os_.Put('%'); + os_.Put(static_cast(hexDigits[u >> 4])); + os_.Put(static_cast(hexDigits[u & 15])); + } + private: + OutputStream &os_; + }; + + Allocator *allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. + Allocator *ownAllocator_; //!< Allocator owned by this Pointer. + Ch *nameBuffer_; //!< A buffer containing all names in tokens. + Token *tokens_; //!< A list of tokens. + size_t tokenCount_; //!< Number of tokens in tokens_. + size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. + PointerParseErrorCode parseErrorCode_; //!< Parsing error code. +}; + +//! GenericPointer for Value (UTF-8, default allocator). +typedef GenericPointer Pointer; + +//!@name Helper functions for GenericPointer +//@{ + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType &CreateValueByPointer(T &root, const GenericPointer &pointer, typename T::AllocatorType &a) +{ + return pointer.Create(root, a); +} + +template +typename T::ValueType &CreateValueByPointer(T &root, const CharType(&source)[N], typename T::AllocatorType &a) +{ + return GenericPointer(source, N - 1).Create(root, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType &CreateValueByPointer(DocumentType &document, const GenericPointer &pointer) +{ + return pointer.Create(document); +} + +template +typename DocumentType::ValueType &CreateValueByPointer(DocumentType &document, const CharType(&source)[N]) +{ + return GenericPointer(source, N - 1).Create(document); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType *GetValueByPointer(T &root, const GenericPointer &pointer, size_t *unresolvedTokenIndex = 0) +{ + return pointer.Get(root, unresolvedTokenIndex); +} + +template +const typename T::ValueType *GetValueByPointer(const T &root, const GenericPointer &pointer, size_t *unresolvedTokenIndex = 0) +{ + return pointer.Get(root, unresolvedTokenIndex); +} + +template +typename T::ValueType *GetValueByPointer(T &root, const CharType (&source)[N], size_t *unresolvedTokenIndex = 0) +{ + return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); +} + +template +const typename T::ValueType *GetValueByPointer(const T &root, const CharType(&source)[N], size_t *unresolvedTokenIndex = 0) +{ + return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType &GetValueByPointerWithDefault(T &root, const GenericPointer &pointer, const typename T::ValueType &defaultValue, typename T::AllocatorType &a) +{ + return pointer.GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType &GetValueByPointerWithDefault(T &root, const GenericPointer &pointer, const typename T::Ch *defaultValue, typename T::AllocatorType &a) +{ + return pointer.GetWithDefault(root, defaultValue, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType &GetValueByPointerWithDefault(T &root, const GenericPointer &pointer, const std::basic_string &defaultValue, typename T::AllocatorType &a) +{ + return pointer.GetWithDefault(root, defaultValue, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType &)) +GetValueByPointerWithDefault(T &root, const GenericPointer &pointer, T2 defaultValue, typename T::AllocatorType &a) +{ + return pointer.GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType &GetValueByPointerWithDefault(T &root, const CharType(&source)[N], const typename T::ValueType &defaultValue, typename T::AllocatorType &a) +{ + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +template +typename T::ValueType &GetValueByPointerWithDefault(T &root, const CharType(&source)[N], const typename T::Ch *defaultValue, typename T::AllocatorType &a) +{ + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType &GetValueByPointerWithDefault(T &root, const CharType(&source)[N], const std::basic_string &defaultValue, typename T::AllocatorType &a) +{ + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType &)) +GetValueByPointerWithDefault(T &root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType &a) +{ + return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType &GetValueByPointerWithDefault(DocumentType &document, const GenericPointer &pointer, const typename DocumentType::ValueType &defaultValue) +{ + return pointer.GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType &GetValueByPointerWithDefault(DocumentType &document, const GenericPointer &pointer, const typename DocumentType::Ch *defaultValue) +{ + return pointer.GetWithDefault(document, defaultValue); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType &GetValueByPointerWithDefault(DocumentType &document, const GenericPointer &pointer, const std::basic_string &defaultValue) +{ + return pointer.GetWithDefault(document, defaultValue); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType &)) +GetValueByPointerWithDefault(DocumentType &document, const GenericPointer &pointer, T2 defaultValue) +{ + return pointer.GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType &GetValueByPointerWithDefault(DocumentType &document, const CharType(&source)[N], const typename DocumentType::ValueType &defaultValue) +{ + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +template +typename DocumentType::ValueType &GetValueByPointerWithDefault(DocumentType &document, const CharType(&source)[N], const typename DocumentType::Ch *defaultValue) +{ + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType &GetValueByPointerWithDefault(DocumentType &document, const CharType(&source)[N], const std::basic_string &defaultValue) +{ + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType &)) +GetValueByPointerWithDefault(DocumentType &document, const CharType(&source)[N], T2 defaultValue) +{ + return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType &SetValueByPointer(T &root, const GenericPointer &pointer, typename T::ValueType &value, typename T::AllocatorType &a) +{ + return pointer.Set(root, value, a); +} + +template +typename T::ValueType &SetValueByPointer(T &root, const GenericPointer &pointer, const typename T::ValueType &value, typename T::AllocatorType &a) +{ + return pointer.Set(root, value, a); +} + +template +typename T::ValueType &SetValueByPointer(T &root, const GenericPointer &pointer, const typename T::Ch *value, typename T::AllocatorType &a) +{ + return pointer.Set(root, value, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType &SetValueByPointer(T &root, const GenericPointer &pointer, const std::basic_string &value, typename T::AllocatorType &a) +{ + return pointer.Set(root, value, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType &)) +SetValueByPointer(T &root, const GenericPointer &pointer, T2 value, typename T::AllocatorType &a) +{ + return pointer.Set(root, value, a); +} + +template +typename T::ValueType &SetValueByPointer(T &root, const CharType(&source)[N], typename T::ValueType &value, typename T::AllocatorType &a) +{ + return GenericPointer(source, N - 1).Set(root, value, a); +} + +template +typename T::ValueType &SetValueByPointer(T &root, const CharType(&source)[N], const typename T::ValueType &value, typename T::AllocatorType &a) +{ + return GenericPointer(source, N - 1).Set(root, value, a); +} + +template +typename T::ValueType &SetValueByPointer(T &root, const CharType(&source)[N], const typename T::Ch *value, typename T::AllocatorType &a) +{ + return GenericPointer(source, N - 1).Set(root, value, a); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename T::ValueType &SetValueByPointer(T &root, const CharType(&source)[N], const std::basic_string &value, typename T::AllocatorType &a) +{ + return GenericPointer(source, N - 1).Set(root, value, a); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType &)) +SetValueByPointer(T &root, const CharType(&source)[N], T2 value, typename T::AllocatorType &a) +{ + return GenericPointer(source, N - 1).Set(root, value, a); +} + +// No allocator parameter + +template +typename DocumentType::ValueType &SetValueByPointer(DocumentType &document, const GenericPointer &pointer, typename DocumentType::ValueType &value) +{ + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType &SetValueByPointer(DocumentType &document, const GenericPointer &pointer, const typename DocumentType::ValueType &value) +{ + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType &SetValueByPointer(DocumentType &document, const GenericPointer &pointer, const typename DocumentType::Ch *value) +{ + return pointer.Set(document, value); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType &SetValueByPointer(DocumentType &document, const GenericPointer &pointer, const std::basic_string &value) +{ + return pointer.Set(document, value); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType &)) +SetValueByPointer(DocumentType &document, const GenericPointer &pointer, T2 value) +{ + return pointer.Set(document, value); +} + +template +typename DocumentType::ValueType &SetValueByPointer(DocumentType &document, const CharType(&source)[N], typename DocumentType::ValueType &value) +{ + return GenericPointer(source, N - 1).Set(document, value); +} + +template +typename DocumentType::ValueType &SetValueByPointer(DocumentType &document, const CharType(&source)[N], const typename DocumentType::ValueType &value) +{ + return GenericPointer(source, N - 1).Set(document, value); +} + +template +typename DocumentType::ValueType &SetValueByPointer(DocumentType &document, const CharType(&source)[N], const typename DocumentType::Ch *value) +{ + return GenericPointer(source, N - 1).Set(document, value); +} + +#if RAPIDJSON_HAS_STDSTRING +template +typename DocumentType::ValueType &SetValueByPointer(DocumentType &document, const CharType(&source)[N], const std::basic_string &value) +{ + return GenericPointer(source, N - 1).Set(document, value); +} +#endif + +template +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType &)) +SetValueByPointer(DocumentType &document, const CharType(&source)[N], T2 value) +{ + return GenericPointer(source, N - 1).Set(document, value); +} + +////////////////////////////////////////////////////////////////////////////// + +template +typename T::ValueType &SwapValueByPointer(T &root, const GenericPointer &pointer, typename T::ValueType &value, typename T::AllocatorType &a) +{ + return pointer.Swap(root, value, a); +} + +template +typename T::ValueType &SwapValueByPointer(T &root, const CharType(&source)[N], typename T::ValueType &value, typename T::AllocatorType &a) +{ + return GenericPointer(source, N - 1).Swap(root, value, a); +} + +template +typename DocumentType::ValueType &SwapValueByPointer(DocumentType &document, const GenericPointer &pointer, typename DocumentType::ValueType &value) +{ + return pointer.Swap(document, value); +} + +template +typename DocumentType::ValueType &SwapValueByPointer(DocumentType &document, const CharType(&source)[N], typename DocumentType::ValueType &value) +{ + return GenericPointer(source, N - 1).Swap(document, value); +} + +////////////////////////////////////////////////////////////////////////////// + +template +bool EraseValueByPointer(T &root, const GenericPointer &pointer) +{ + return pointer.Erase(root); +} + +template +bool EraseValueByPointer(T &root, const CharType(&source)[N]) +{ + return GenericPointer(source, N - 1).Erase(root); +} + +//@} + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_POINTER_H_ diff --git a/contrib/world_builder/include/rapidjson/prettywriter.h.bak b/contrib/world_builder/include/rapidjson/prettywriter.h.bak new file mode 100644 index 00000000000..ea658987976 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/prettywriter.h.bak @@ -0,0 +1,340 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_PRETTYWRITER_H_ +#define RAPIDJSON_PRETTYWRITER_H_ + +#include "writer.h" + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Combination of PrettyWriter format flags. +/*! \see PrettyWriter::SetFormatOptions + */ +enum PrettyFormatOptions +{ + kFormatDefault = 0, //!< Default pretty formatting. + kFormatSingleLineArray = 1 //!< Format arrays on a single line. +}; + +//! Writer with indentation and spacing. +/*! + \tparam OutputStream Type of output os. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam StackAllocator Type of allocator for allocating memory of stack. +*/ +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> +class PrettyWriter : public Writer +{ + public: + typedef Writer Base; + typedef typename Base::Ch Ch; + + //! Constructor + /*! \param os Output stream. + \param allocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + explicit PrettyWriter(OutputStream &os, StackAllocator *allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} + + + explicit PrettyWriter(StackAllocator *allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + PrettyWriter(PrettyWriter &&rhs) : + Base(std::forward(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {} +#endif + + //! Set custom indentation. + /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). + \param indentCharCount Number of indent characters for each indentation level. + \note The default indentation is 4 spaces. + */ + PrettyWriter &SetIndent(Ch indentChar, unsigned indentCharCount) + { + RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); + indentChar_ = indentChar; + indentCharCount_ = indentCharCount; + return *this; + } + + //! Set pretty writer formatting options. + /*! \param options Formatting options. + */ + PrettyWriter &SetFormatOptions(PrettyFormatOptions options) + { + formatOptions_ = options; + return *this; + } + + /*! @name Implementation of Handler + \see Handler + */ + //@{ + + bool Null() + { + PrettyPrefix(kNullType); + return Base::EndValue(Base::WriteNull()); + } + bool Bool(bool b) + { + PrettyPrefix(b ? kTrueType : kFalseType); + return Base::EndValue(Base::WriteBool(b)); + } + bool Int(int i) + { + PrettyPrefix(kNumberType); + return Base::EndValue(Base::WriteInt(i)); + } + bool Uint(unsigned u) + { + PrettyPrefix(kNumberType); + return Base::EndValue(Base::WriteUint(u)); + } + bool Int64(int64_t i64) + { + PrettyPrefix(kNumberType); + return Base::EndValue(Base::WriteInt64(i64)); + } + bool Uint64(uint64_t u64) + { + PrettyPrefix(kNumberType); + return Base::EndValue(Base::WriteUint64(u64)); + } + bool Double(double d) + { + PrettyPrefix(kNumberType); + return Base::EndValue(Base::WriteDouble(d)); + } + + bool RawNumber(const Ch *str, SizeType length, bool copy = false) + { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + PrettyPrefix(kNumberType); + return Base::EndValue(Base::WriteString(str, length)); + } + + bool String(const Ch *str, SizeType length, bool copy = false) + { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + PrettyPrefix(kStringType); + return Base::EndValue(Base::WriteString(str, length)); + } + +#if RAPIDJSON_HAS_STDSTRING + bool String(const std::basic_string &str) + { + return String(str.data(), SizeType(str.size())); + } +#endif + + bool StartObject() + { + PrettyPrefix(kObjectType); + new (Base::level_stack_.template Push()) typename Base::Level(false); + return Base::WriteStartObject(); + } + + bool Key(const Ch *str, SizeType length, bool copy = false) + { + return String(str, length, copy); + } + +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string &str) + { + return Key(str.data(), SizeType(str.size())); + } +#endif + + bool EndObject(SizeType memberCount = 0) + { + (void)memberCount; + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object + RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value + + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + + if (!empty) + { + Base::os_->Put('\n'); + WriteIndent(); + } + bool ret = Base::EndValue(Base::WriteEndObject()); + (void)ret; + RAPIDJSON_ASSERT(ret == true); + if (Base::level_stack_.Empty()) // end of json text + Base::Flush(); + return true; + } + + bool StartArray() + { + PrettyPrefix(kArrayType); + new (Base::level_stack_.template Push()) typename Base::Level(true); + return Base::WriteStartArray(); + } + + bool EndArray(SizeType memberCount = 0) + { + (void)memberCount; + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); + RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + + if (!empty && !(formatOptions_ & kFormatSingleLineArray)) + { + Base::os_->Put('\n'); + WriteIndent(); + } + bool ret = Base::EndValue(Base::WriteEndArray()); + (void)ret; + RAPIDJSON_ASSERT(ret == true); + if (Base::level_stack_.Empty()) // end of json text + Base::Flush(); + return true; + } + + //@} + + /*! @name Convenience extensions */ + //@{ + + //! Simpler but slower overload. + bool String(const Ch *str) + { + return String(str, internal::StrLen(str)); + } + bool Key(const Ch *str) + { + return Key(str, internal::StrLen(str)); + } + + //@} + + //! Write a raw JSON value. + /*! + For user to write a stringified JSON as a value. + + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. + \param length Length of the json. + \param type Type of the root of json. + \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. + */ + bool RawValue(const Ch *json, size_t length, Type type) + { + RAPIDJSON_ASSERT(json != 0); + PrettyPrefix(type); + return Base::EndValue(Base::WriteRawValue(json, length)); + } + + protected: + void PrettyPrefix(Type type) + { + (void)type; + if (Base::level_stack_.GetSize() != 0) // this value is not at root + { + typename Base::Level *level = Base::level_stack_.template Top(); + + if (level->inArray) + { + if (level->valueCount > 0) + { + Base::os_->Put(','); // add comma if it is not the first element in array + if (formatOptions_ & kFormatSingleLineArray) + Base::os_->Put(' '); + } + + if (!(formatOptions_ & kFormatSingleLineArray)) + { + Base::os_->Put('\n'); + WriteIndent(); + } + } + else // in object + { + if (level->valueCount > 0) + { + if (level->valueCount % 2 == 0) + { + Base::os_->Put(','); + Base::os_->Put('\n'); + } + else + { + Base::os_->Put(':'); + Base::os_->Put(' '); + } + } + else + Base::os_->Put('\n'); + + if (level->valueCount % 2 == 0) + WriteIndent(); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else + { + RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. + Base::hasRoot_ = true; + } + } + + void WriteIndent() + { + size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; + PutN(*Base::os_, static_cast(indentChar_), count); + } + + Ch indentChar_; + unsigned indentCharCount_; + PrettyFormatOptions formatOptions_; + + private: + // Prohibit copy constructor & assignment operator. + PrettyWriter(const PrettyWriter &); + PrettyWriter &operator=(const PrettyWriter &); +}; + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/contrib/world_builder/include/rapidjson/rapidjson.h.bak b/contrib/world_builder/include/rapidjson/rapidjson.h.bak new file mode 100644 index 00000000000..d857baeea34 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/rapidjson.h.bak @@ -0,0 +1,660 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_RAPIDJSON_H_ +#define RAPIDJSON_RAPIDJSON_H_ + +/*!\file rapidjson.h + \brief common definitions and configuration + + \see RAPIDJSON_CONFIG + */ + +/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration + \brief Configuration macros for library features + + Some RapidJSON features are configurable to adapt the library to a wide + variety of platforms, environments and usage scenarios. Most of the + features can be configured in terms of overridden or predefined + preprocessor macros at compile-time. + + Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. + + \note These macros should be given on the compiler command-line + (where applicable) to avoid inconsistent values when compiling + different translation units of a single application. + */ + +#include // malloc(), realloc(), free(), size_t +#include // memset(), memcpy(), memmove(), memcmp() + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_VERSION_STRING +// +// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. +// + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +// token stringification +#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) +#define RAPIDJSON_DO_STRINGIFY(x) #x + +// token concatenation +#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) +#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) +#define RAPIDJSON_DO_JOIN2(X, Y) X##Y +//!@endcond + +/*! \def RAPIDJSON_MAJOR_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Major version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_MINOR_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Minor version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_PATCH_VERSION + \ingroup RAPIDJSON_CONFIG + \brief Patch version of RapidJSON in integer. +*/ +/*! \def RAPIDJSON_VERSION_STRING + \ingroup RAPIDJSON_CONFIG + \brief Version of RapidJSON in ".." string format. +*/ +#define RAPIDJSON_MAJOR_VERSION 1 +#define RAPIDJSON_MINOR_VERSION 1 +#define RAPIDJSON_PATCH_VERSION 0 +#define RAPIDJSON_VERSION_STRING \ + RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NAMESPACE_(BEGIN|END) +/*! \def RAPIDJSON_NAMESPACE + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace + + In order to avoid symbol clashes and/or "One Definition Rule" errors + between multiple inclusions of (different versions of) RapidJSON in + a single binary, users can customize the name of the main RapidJSON + namespace. + + In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE + to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple + levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref + RAPIDJSON_NAMESPACE_END need to be defined as well: + + \code + // in some .cpp file + #define RAPIDJSON_NAMESPACE my::rapidjson + #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { + #define RAPIDJSON_NAMESPACE_END } } + #include "rapidjson/..." + \endcode + + \see rapidjson + */ +/*! \def RAPIDJSON_NAMESPACE_BEGIN + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace (opening expression) + \see RAPIDJSON_NAMESPACE +*/ +/*! \def RAPIDJSON_NAMESPACE_END + \ingroup RAPIDJSON_CONFIG + \brief provide custom rapidjson namespace (closing expression) + \see RAPIDJSON_NAMESPACE +*/ +#ifndef RAPIDJSON_NAMESPACE +#define RAPIDJSON_NAMESPACE rapidjson +#endif +#ifndef RAPIDJSON_NAMESPACE_BEGIN +#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { +#endif +#ifndef RAPIDJSON_NAMESPACE_END +#define RAPIDJSON_NAMESPACE_END } +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_HAS_STDSTRING + +#ifndef RAPIDJSON_HAS_STDSTRING +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation +#else +#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default +#endif +/*! \def RAPIDJSON_HAS_STDSTRING + \ingroup RAPIDJSON_CONFIG + \brief Enable RapidJSON support for \c std::string + + By defining this preprocessor symbol to \c 1, several convenience functions for using + \ref rapidjson::GenericValue with \c std::string are enabled, especially + for construction and comparison. + + \hideinitializer +*/ +#endif // !defined(RAPIDJSON_HAS_STDSTRING) + +#if RAPIDJSON_HAS_STDSTRING +#include +#endif // RAPIDJSON_HAS_STDSTRING + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NO_INT64DEFINE + +/*! \def RAPIDJSON_NO_INT64DEFINE + \ingroup RAPIDJSON_CONFIG + \brief Use external 64-bit integer types. + + RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types + to be available at global scope. + + If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to + prevent RapidJSON from defining its own types. +*/ +#ifndef RAPIDJSON_NO_INT64DEFINE +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 +#include "msinttypes/stdint.h" +#include "msinttypes/inttypes.h" +#else +// Other compilers should have this. +#include +#include +#endif +//!@endcond +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_NO_INT64DEFINE +#endif +#endif // RAPIDJSON_NO_INT64TYPEDEF + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_FORCEINLINE + +#ifndef RAPIDJSON_FORCEINLINE +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#if defined(_MSC_VER) && defined(NDEBUG) +#define RAPIDJSON_FORCEINLINE __forceinline +#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) +#define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) +#else +#define RAPIDJSON_FORCEINLINE +#endif +//!@endcond +#endif // RAPIDJSON_FORCEINLINE + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ENDIAN +#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine +#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine + +//! Endianness of the machine. +/*! + \def RAPIDJSON_ENDIAN + \ingroup RAPIDJSON_CONFIG + + GCC 4.6 provided macro for detecting endianness of the target machine. But other + compilers may not have this. User can define RAPIDJSON_ENDIAN to either + \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. + + Default detection implemented with reference to + \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html + \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp +*/ +#ifndef RAPIDJSON_ENDIAN +// Detect with GCC 4.6's macro +# ifdef __BYTE_ORDER__ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# else +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. +# endif // __BYTE_ORDER__ +// Detect with GLIBC's endian.h +# elif defined(__GLIBC__) +# include +# if (__BYTE_ORDER == __LITTLE_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif (__BYTE_ORDER == __BIG_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# else +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. +# endif // __GLIBC__ +// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro +# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +// Detect with architecture macros +# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(RAPIDJSON_DOXYGEN_RUNNING) +# define RAPIDJSON_ENDIAN +# else +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. +# endif +#endif // RAPIDJSON_ENDIAN + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_64BIT + +//! Whether using 64-bit architecture +#ifndef RAPIDJSON_64BIT +#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) +#define RAPIDJSON_64BIT 1 +#else +#define RAPIDJSON_64BIT 0 +#endif +#endif // RAPIDJSON_64BIT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ALIGN + +//! Data alignment of the machine. +/*! \ingroup RAPIDJSON_CONFIG + \param x pointer to align + + Some machines require strict data alignment. The default is 8 bytes. + User can customize by defining the RAPIDJSON_ALIGN function macro. +*/ +#ifndef RAPIDJSON_ALIGN +#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_UINT64_C2 + +//! Construct a 64-bit literal by a pair of 32-bit integer. +/*! + 64-bit literal with or without ULL suffix is prone to compiler warnings. + UINT64_C() is C macro which cause compilation problems. + Use this macro to define 64-bit constants by a pair of 32-bit integer. +*/ +#ifndef RAPIDJSON_UINT64_C2 +#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_48BITPOINTER_OPTIMIZATION + +//! Use only lower 48-bit address for some pointers. +/*! + \ingroup RAPIDJSON_CONFIG + + This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address. + The higher 16-bit can be used for storing other data. + \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture. +*/ +#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 +#else +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 +#endif +#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION + +#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 +#if RAPIDJSON_64BIT != 1 +#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 +#endif +#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast((reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast(reinterpret_cast(x)))) +#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast(reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) +#else +#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) +#define RAPIDJSON_GETPOINTER(type, p) (p) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD + +/*! \def RAPIDJSON_SIMD + \ingroup RAPIDJSON_CONFIG + \brief Enable SSE2/SSE4.2/Neon optimization. + + RapidJSON supports optimized implementations for some parsing operations + based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel + or ARM compatible processors. + + To enable these optimizations, three different symbols can be defined; + \code + // Enable SSE2 optimization. + #define RAPIDJSON_SSE2 + + // Enable SSE4.2 optimization. + #define RAPIDJSON_SSE42 + \endcode + + // Enable ARM Neon optimization. + #define RAPIDJSON_NEON + \endcode + + \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined. + + If any of these symbols is defined, RapidJSON defines the macro + \c RAPIDJSON_SIMD to indicate the availability of the optimized code. +*/ +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ + || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) +#define RAPIDJSON_SIMD +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NO_SIZETYPEDEFINE + +#ifndef RAPIDJSON_NO_SIZETYPEDEFINE +/*! \def RAPIDJSON_NO_SIZETYPEDEFINE + \ingroup RAPIDJSON_CONFIG + \brief User-provided \c SizeType definition. + + In order to avoid using 32-bit size types for indexing strings and arrays, + define this preprocessor symbol and provide the type rapidjson::SizeType + before including RapidJSON: + \code + #define RAPIDJSON_NO_SIZETYPEDEFINE + namespace rapidjson { typedef ::std::size_t SizeType; } + #include "rapidjson/..." + \endcode + + \see rapidjson::SizeType +*/ +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_NO_SIZETYPEDEFINE +#endif +RAPIDJSON_NAMESPACE_BEGIN +//! Size type (for string lengths, array sizes, etc.) +/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, + instead of using \c size_t. Users may override the SizeType by defining + \ref RAPIDJSON_NO_SIZETYPEDEFINE. +*/ +typedef unsigned SizeType; +RAPIDJSON_NAMESPACE_END +#endif + +// always import std::size_t to rapidjson namespace +RAPIDJSON_NAMESPACE_BEGIN +using std::size_t; +RAPIDJSON_NAMESPACE_END + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_ASSERT + +//! Assertion. +/*! \ingroup RAPIDJSON_CONFIG + By default, rapidjson uses C \c assert() for internal assertions. + User can override it by defining RAPIDJSON_ASSERT(x) macro. + + \note Parsing errors are handled and can be customized by the + \ref RAPIDJSON_ERRORS APIs. +*/ +#ifndef RAPIDJSON_ASSERT +#include "world_builder/assert.h" +#define RAPIDJSON_ASSERT(x) WBAssertThrow(x, "RapidJSON error.") +#endif // RAPIDJSON_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_STATIC_ASSERT + +// Prefer C++11 static_assert, if available +#ifndef RAPIDJSON_STATIC_ASSERT +#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) +#define RAPIDJSON_STATIC_ASSERT(x) \ + static_assert(x, RAPIDJSON_STRINGIFY(x)) +#endif // C++11 +#endif // RAPIDJSON_STATIC_ASSERT + +// Adopt C++03 implementation from boost +#ifndef RAPIDJSON_STATIC_ASSERT +#ifndef __clang__ +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#endif +RAPIDJSON_NAMESPACE_BEGIN +template struct STATIC_ASSERTION_FAILURE; +template <> struct STATIC_ASSERTION_FAILURE +{ + enum { value = 1 }; +}; +template struct StaticAssertTest {}; +RAPIDJSON_NAMESPACE_END + +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) +#else +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif +#ifndef __clang__ +//!@endcond +#endif + +/*! \def RAPIDJSON_STATIC_ASSERT + \brief (Internal) macro to check for conditions at compile-time + \param x compile-time condition + \hideinitializer + */ +#define RAPIDJSON_STATIC_ASSERT(x) \ + typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ + sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ + RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif // RAPIDJSON_STATIC_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY + +//! Compiler branching hint for expression with high probability to be true. +/*! + \ingroup RAPIDJSON_CONFIG + \param x Boolean expression likely to be true. +*/ +#ifndef RAPIDJSON_LIKELY +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) +#else +#define RAPIDJSON_LIKELY(x) (x) +#endif +#endif + +//! Compiler branching hint for expression with low probability to be true. +/*! + \ingroup RAPIDJSON_CONFIG + \param x Boolean expression unlikely to be true. +*/ +#ifndef RAPIDJSON_UNLIKELY +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define RAPIDJSON_UNLIKELY(x) (x) +#endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Helpers + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN + +#define RAPIDJSON_MULTILINEMACRO_BEGIN do { +#define RAPIDJSON_MULTILINEMACRO_END \ + } while((void)0, 0) + +// adopted from Boost +#define RAPIDJSON_VERSION_CODE(x,y,z) \ + (((x)*100000) + ((y)*100) + (z)) + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF + +#if defined(__GNUC__) +#define RAPIDJSON_GNUC \ + RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) +#endif + +#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) + +#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) +#define RAPIDJSON_DIAG_OFF(x) \ + RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) + +// push/pop support in Clang and GCC>=4.6 +#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) +#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) +#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) +#else // GCC >= 4.2, < 4.6 +#define RAPIDJSON_DIAG_PUSH /* ignored */ +#define RAPIDJSON_DIAG_POP /* ignored */ +#endif + +#elif defined(_MSC_VER) + +// pragma (MSVC specific) +#define RAPIDJSON_PRAGMA(x) __pragma(x) +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) + +#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) +#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) +#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) + +#else + +#define RAPIDJSON_DIAG_OFF(x) /* ignored */ +#define RAPIDJSON_DIAG_PUSH /* ignored */ +#define RAPIDJSON_DIAG_POP /* ignored */ + +#endif // RAPIDJSON_DIAG_* + +/////////////////////////////////////////////////////////////////////////////// +// C++11 features + +#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS +#if defined(__clang__) +#if __has_feature(cxx_rvalue_references) && \ + (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#else +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 +#endif +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1600) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) + +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#else +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 +#endif +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + +#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT +#if defined(__clang__) +#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1900) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 +#else +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 +#endif +#endif +#if RAPIDJSON_HAS_CXX11_NOEXCEPT +#define RAPIDJSON_NOEXCEPT noexcept +#else +#define RAPIDJSON_NOEXCEPT /* noexcept */ +#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT + +// no automatic detection, yet +#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS +#if (defined(_MSC_VER) && _MSC_VER >= 1700) +#define RAPIDJSON_HAS_CXX11_TYPETRAITS 1 +#else +#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 +#endif +#endif + +#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR +#if defined(__clang__) +#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1700) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 +#else +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 +#endif +#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR + +//!@endcond + +//! Assertion (in non-throwing contexts). +/*! \ingroup RAPIDJSON_CONFIG + Some functions provide a \c noexcept guarantee, if the compiler supports it. + In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to + throw an exception. This macro adds a separate customization point for + such cases. + + Defaults to C \c assert() (as \ref RAPIDJSON_ASSERT), if \c noexcept is + supported, and to \ref RAPIDJSON_ASSERT otherwise. +*/ + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NOEXCEPT_ASSERT + +#ifdef RAPIDJSON_ASSERT_THROWS +#if RAPIDJSON_HAS_CXX11_NOEXCEPT +#define RAPIDJSON_NOEXCEPT_ASSERT(x) +#else +#include +#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x) +#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT +#else +#include +#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x) +#endif // RAPIDJSON_ASSERT_THROWS + +/////////////////////////////////////////////////////////////////////////////// +// new/delete + +#ifndef RAPIDJSON_NEW +///! customization point for global \c new +#define RAPIDJSON_NEW(TypeName) new TypeName +#endif +#ifndef RAPIDJSON_DELETE +///! customization point for global \c delete +#define RAPIDJSON_DELETE(x) delete x +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Type + +/*! \namespace rapidjson + \brief main RapidJSON namespace + \see RAPIDJSON_NAMESPACE +*/ +RAPIDJSON_NAMESPACE_BEGIN + +//! Type of JSON value +enum Type +{ + kNullType = 0, //!< null + kFalseType = 1, //!< false + kTrueType = 2, //!< true + kObjectType = 3, //!< object + kArrayType = 4, //!< array + kStringType = 5, //!< string + kNumberType = 6 //!< number +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/contrib/world_builder/include/rapidjson/reader.h.bak b/contrib/world_builder/include/rapidjson/reader.h.bak new file mode 100644 index 00000000000..064a3e56ba8 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/reader.h.bak @@ -0,0 +1,2574 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_READER_H_ +#define RAPIDJSON_READER_H_ + +/*! \file reader.h */ + +#include "allocators.h" +#include "stream.h" +#include "encodedstream.h" +#include "internal/meta.h" +#include "internal/stack.h" +#include "internal/strtod.h" +#include + +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) +#include +#pragma intrinsic(_BitScanForward) +#endif +#ifdef RAPIDJSON_SSE42 +#include +#elif defined(RAPIDJSON_SSE2) +#include +#elif defined(RAPIDJSON_NEON) +#include +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(old-style-cast) +RAPIDJSON_DIAG_OFF(padded) +//RAPIDJSON_DIAG_OFF(switch -enum) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +RAPIDJSON_DIAG_OFF(4702) // unreachable code +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define RAPIDJSON_NOTHING /* deliberately empty */ +#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ + RAPIDJSON_MULTILINEMACRO_END +#endif +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) +//!@endcond + +/*! \def RAPIDJSON_PARSE_ERROR_NORETURN + \ingroup RAPIDJSON_ERRORS + \brief Macro to indicate a parse error. + \param parseErrorCode \ref rapidjson::ParseErrorCode of the error + \param offset position of the error in JSON input (\c size_t) + + This macros can be used as a customization point for the internal + error handling mechanism of RapidJSON. + + A common usage model is to throw an exception instead of requiring the + caller to explicitly check the \ref rapidjson::GenericReader::Parse's + return value: + + \code + #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ + throw ParseException(parseErrorCode, #parseErrorCode, offset) + + #include // std::runtime_error + #include "rapidjson/error/error.h" // rapidjson::ParseResult + + struct ParseException : std::runtime_error, rapidjson::ParseResult { + ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) + : std::runtime_error(msg), ParseResult(code, offset) {} + }; + + #include "rapidjson/reader.h" + \endcode + + \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse + */ +#ifndef RAPIDJSON_PARSE_ERROR_NORETURN +#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ + SetParseError(parseErrorCode, offset); \ + RAPIDJSON_MULTILINEMACRO_END +#endif + +/*! \def RAPIDJSON_PARSE_ERROR + \ingroup RAPIDJSON_ERRORS + \brief (Internal) macro to indicate and handle a parse error. + \param parseErrorCode \ref rapidjson::ParseErrorCode of the error + \param offset position of the error in JSON input (\c size_t) + + Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. + + \see RAPIDJSON_PARSE_ERROR_NORETURN + \hideinitializer + */ +#ifndef RAPIDJSON_PARSE_ERROR +#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ + RAPIDJSON_MULTILINEMACRO_BEGIN \ + RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ + RAPIDJSON_MULTILINEMACRO_END +#endif + +#include "error/error.h" // ParseErrorCode, ParseResult + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// ParseFlag + +/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG + \brief User-defined kParseDefaultFlags definition. + + User can define this as any \c ParseFlag combinations. +*/ +#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS +#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags +#endif + +//! Combination of parseFlags +/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream + */ +enum ParseFlag +{ + kParseNoFlags = 0, //!< No flags are set. + kParseInsituFlag = 1, //!< In-situ(destructive) parsing. + kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. + kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. + kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. + kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). + kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. + kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. + kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. + kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. + kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS +}; + +/////////////////////////////////////////////////////////////////////////////// +// Handler + +/*! \class rapidjson::Handler + \brief Concept for receiving events from GenericReader upon parsing. + The functions return true if no error occurs. If they return false, + the event publisher should terminate the process. +\code +concept Handler { + typename Ch; + + bool Null(); + bool Bool(bool b); + bool Int(int i); + bool Uint(unsigned i); + bool Int64(int64_t i); + bool Uint64(uint64_t i); + bool Double(double d); + /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) + bool RawNumber(const Ch* str, SizeType length, bool copy); + bool String(const Ch* str, SizeType length, bool copy); + bool StartObject(); + bool Key(const Ch* str, SizeType length, bool copy); + bool EndObject(SizeType memberCount); + bool StartArray(); + bool EndArray(SizeType elementCount); +}; +\endcode +*/ +/////////////////////////////////////////////////////////////////////////////// +// BaseReaderHandler + +//! Default implementation of Handler. +/*! This can be used as base class of any reader handler. + \note implements Handler concept +*/ +template, typename Derived = void> +struct BaseReaderHandler +{ + typedef typename Encoding::Ch Ch; + + typedef typename internal::SelectIf, BaseReaderHandler, Derived>::Type Override; + + bool Default() + { + return true; + } + bool Null() + { + return static_cast(*this).Default(); + } + bool Bool(bool) + { + return static_cast(*this).Default(); + } + bool Int(int) + { + return static_cast(*this).Default(); + } + bool Uint(unsigned) + { + return static_cast(*this).Default(); + } + bool Int64(int64_t) + { + return static_cast(*this).Default(); + } + bool Uint64(uint64_t) + { + return static_cast(*this).Default(); + } + bool Double(double) + { + return static_cast(*this).Default(); + } + /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) + bool RawNumber(const Ch *str, SizeType len, bool copy) + { + return static_cast(*this).String(str, len, copy); + } + bool String(const Ch *, SizeType, bool) + { + return static_cast(*this).Default(); + } + bool StartObject() + { + return static_cast(*this).Default(); + } + bool Key(const Ch *str, SizeType len, bool copy) + { + return static_cast(*this).String(str, len, copy); + } + bool EndObject(SizeType) + { + return static_cast(*this).Default(); + } + bool StartArray() + { + return static_cast(*this).Default(); + } + bool EndArray(SizeType) + { + return static_cast(*this).Default(); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// StreamLocalCopy + +namespace internal +{ + + template::copyOptimization> + class StreamLocalCopy; + +//! Do copy optimization. + template + class StreamLocalCopy + { + public: + StreamLocalCopy(Stream &original) : s(original), original_(original) {} + ~StreamLocalCopy() + { + original_ = s; + } + + Stream s; + + private: + StreamLocalCopy &operator=(const StreamLocalCopy &) /* = delete */; + + Stream &original_; + }; + +//! Keep reference. + template + class StreamLocalCopy + { + public: + StreamLocalCopy(Stream &original) : s(original) {} + + Stream &s; + + private: + StreamLocalCopy &operator=(const StreamLocalCopy &) /* = delete */; + }; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// SkipWhitespace + +//! Skip the JSON white spaces in a stream. +/*! \param is A input stream for skipping white spaces. + \note This function has SSE2/SSE4.2 specialization. +*/ +template +void SkipWhitespace(InputStream &is) +{ + internal::StreamLocalCopy copy(is); + InputStream &s(copy.s); + + typename InputStream::Ch c; + while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t') + s.Take(); +} + +inline const char *SkipWhitespace(const char *p, const char *end) +{ + while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + return p; +} + +#ifdef RAPIDJSON_SSE42 +//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char *p) +{ + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char *nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // The rest of string using SIMD + static const char whitespace[16] = " \n\r\t"; + const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); + + for (;; p += 16) + { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); + if (r != 16) // some of characters is non-whitespace + return p + r; + } +} + +inline const char *SkipWhitespace_SIMD(const char *p, const char *end) +{ + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + // The middle of string using SIMD + static const char whitespace[16] = " \n\r\t"; + const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); + + for (; p <= end - 16; p += 16) + { + const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); + if (r != 16) // some of characters is non-whitespace + return p + r; + } + + return SkipWhitespace(p, end); +} + +#elif defined(RAPIDJSON_SSE2) + +//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char *p) +{ + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char *nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // The rest of string +#define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; +#undef C16 + + const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); + const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); + const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); + const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); + + for (;; p += 16) + { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = static_cast(~_mm_movemask_epi8(x)); + if (r != 0) // some of characters may be non-whitespace + { +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } +} + +inline const char *SkipWhitespace_SIMD(const char *p, const char *end) +{ + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + // The rest of string +#define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; +#undef C16 + + const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); + const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); + const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); + const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); + + for (; p <= end - 16; p += 16) + { + const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = static_cast(~_mm_movemask_epi8(x)); + if (r != 0) // some of characters may be non-whitespace + { +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } + + return SkipWhitespace(p, end); +} + +#elif defined(RAPIDJSON_NEON) + +//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char *p) +{ + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char *nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (;; p += 16) + { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) + { + if (high != 0) + { + int lz =__builtin_clzll(high);; + return p + 8 + (lz >> 3); + } + } + else + { + int lz = __builtin_clzll(low);; + return p + (lz >> 3); + } + } +} + +inline const char *SkipWhitespace_SIMD(const char *p, const char *end) +{ + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (; p <= end - 16; p += 16) + { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) + { + if (high != 0) + { + int lz = __builtin_clzll(high); + return p + 8 + (lz >> 3); + } + } + else + { + int lz = __builtin_clzll(low); + return p + (lz >> 3); + } + } + + return SkipWhitespace(p, end); +} + +#endif // RAPIDJSON_NEON + +#ifdef RAPIDJSON_SIMD +//! Template function specialization for InsituStringStream +template<> inline void SkipWhitespace(InsituStringStream &is) +{ + is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); +} + +//! Template function specialization for StringStream +template<> inline void SkipWhitespace(StringStream &is) +{ + is.src_ = SkipWhitespace_SIMD(is.src_); +} + +template<> inline void SkipWhitespace(EncodedInputStream, MemoryStream> &is) +{ + is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_); +} +#endif // RAPIDJSON_SIMD + +/////////////////////////////////////////////////////////////////////////////// +// GenericReader + +//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. +/*! GenericReader parses JSON text from a stream, and send events synchronously to an + object implementing Handler concept. + + It needs to allocate a stack for storing a single decoded string during + non-destructive parsing. + + For in-situ parsing, the decoded string is directly written to the source + text string, no temporary buffer is required. + + A GenericReader object can be reused for parsing multiple JSON text. + + \tparam SourceEncoding Encoding of the input stream. + \tparam TargetEncoding Encoding of the parse output. + \tparam StackAllocator Allocator type for stack. +*/ +template +class GenericReader +{ + public: + typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type + + //! Constructor. + /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) + \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) + */ + GenericReader(StackAllocator *stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : + stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {} + + //! Parse JSON text. + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept. + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult Parse(InputStream &is, Handler &handler) + { + if (parseFlags & kParseIterativeFlag) + return IterativeParse(is, handler); + + parseResult_.Clear(); + + ClearStackOnExit scope(*this); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) + { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + else + { + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (!(parseFlags & kParseStopWhenDoneFlag)) + { + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + + if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) + { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + } + } + + return parseResult_; + } + + //! Parse JSON text (with \ref kParseDefaultFlags) + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult Parse(InputStream &is, Handler &handler) + { + return Parse(is, handler); + } + + //! Initialize JSON text token-by-token parsing + /*! + */ + void IterativeParseInit() + { + parseResult_.Clear(); + state_ = IterativeParsingStartState; + } + + //! Parse one token from JSON text + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + bool IterativeParseNext(InputStream &is, Handler &handler) + { + while (RAPIDJSON_LIKELY(is.Peek() != '\0')) + { + SkipWhitespaceAndComments(is); + + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state_, t); + IterativeParsingState d = Transit(state_, t, n, is, handler); + + // If we've finished or hit an error... + if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) + { + // Report errors. + if (d == IterativeParsingErrorState) + { + HandleError(state_, is); + return false; + } + + // Transition to the finish state. + RAPIDJSON_ASSERT(d == IterativeParsingFinishState); + state_ = d; + + // If StopWhenDone is not set... + if (!(parseFlags & kParseStopWhenDoneFlag)) + { + // ... and extra non-whitespace data is found... + SkipWhitespaceAndComments(is); + if (is.Peek() != '\0') + { + // ... this is considered an error. + HandleError(state_, is); + return false; + } + } + + // Success! We are done! + return true; + } + + // Transition to the new state. + state_ = d; + + // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now. + if (!IsIterativeParsingDelimiterState(n)) + return true; + } + + // We reached the end of file. + stack_.Clear(); + + if (state_ != IterativeParsingFinishState) + { + HandleError(state_, is); + return false; + } + + return true; + } + + //! Check if token-by-token parsing JSON text is complete + /*! \return Whether the JSON has been fully decoded. + */ + RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const + { + return IsIterativeParsingCompleteState(state_); + } + + //! Whether a parse error has occurred in the last parsing. + bool HasParseError() const + { + return parseResult_.IsError(); + } + + //! Get the \ref ParseErrorCode of last parsing. + ParseErrorCode GetParseErrorCode() const + { + return parseResult_.Code(); + } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorOffset() const + { + return parseResult_.Offset(); + } + + protected: + void SetParseError(ParseErrorCode code, size_t offset) + { + parseResult_.Set(code, offset); + } + + private: + // Prohibit copy constructor & assignment operator. + GenericReader(const GenericReader &); + GenericReader &operator=(const GenericReader &); + + void ClearStack() + { + stack_.Clear(); + } + + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit + { + explicit ClearStackOnExit(GenericReader &r) : r_(r) {} + ~ClearStackOnExit() + { + r_.ClearStack(); + } + private: + GenericReader &r_; + ClearStackOnExit(const ClearStackOnExit &); + ClearStackOnExit &operator=(const ClearStackOnExit &); + }; + + template + void SkipWhitespaceAndComments(InputStream &is) + { + SkipWhitespace(is); + + if (parseFlags & kParseCommentsFlag) + { + while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) + { + if (Consume(is, '*')) + { + while (true) + { + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + else if (Consume(is, '*')) + { + if (Consume(is, '/')) + break; + } + else + is.Take(); + } + } + else if (RAPIDJSON_LIKELY(Consume(is, '/'))) + while (is.Peek() != '\0' && is.Take() != '\n') {} + else + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + + SkipWhitespace(is); + } + } + } + + // Parse object: { string : value, ... } + template + void ParseObject(InputStream &is, Handler &handler) + { + RAPIDJSON_ASSERT(is.Peek() == '{'); + is.Take(); // Skip '{' + + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, '}')) + { + if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + + for (SizeType memberCount = 0;;) + { + if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); + + ParseString(is, handler, true); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (RAPIDJSON_UNLIKELY(!Consume(is, ':'))) + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ++memberCount; + + switch (is.Peek()) + { + case ',': + is.Take(); + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + break; + case '}': + is.Take(); + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + default: + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); + break; // This useless break is only for making warning and coverage happy + } + + if (parseFlags & kParseTrailingCommasFlag) + { + if (is.Peek() == '}') + { + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + is.Take(); + return; + } + } + } + } + + // Parse array: [ value, ... ] + template + void ParseArray(InputStream &is, Handler &handler) + { + RAPIDJSON_ASSERT(is.Peek() == '['); + is.Take(); // Skip '[' + + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, ']')) + { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + + for (SizeType elementCount = 0;;) + { + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + ++elementCount; + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, ',')) + { + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + } + else if (Consume(is, ']')) + { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + + if (parseFlags & kParseTrailingCommasFlag) + { + if (is.Peek() == ']') + { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + is.Take(); + return; + } + } + } + } + + template + void ParseNull(InputStream &is, Handler &handler) + { + RAPIDJSON_ASSERT(is.Peek() == 'n'); + is.Take(); + + if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) + { + if (RAPIDJSON_UNLIKELY(!handler.Null())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + void ParseTrue(InputStream &is, Handler &handler) + { + RAPIDJSON_ASSERT(is.Peek() == 't'); + is.Take(); + + if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) + { + if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + void ParseFalse(InputStream &is, Handler &handler) + { + RAPIDJSON_ASSERT(is.Peek() == 'f'); + is.Take(); + + if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) + { + if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + RAPIDJSON_FORCEINLINE static bool Consume(InputStream &is, typename InputStream::Ch expect) + { + if (RAPIDJSON_LIKELY(is.Peek() == expect)) + { + is.Take(); + return true; + } + else + return false; + } + + // Helper function to parse four hexadecimal digits in \uXXXX in ParseString(). + template + unsigned ParseHex4(InputStream &is, size_t escapeOffset) + { + unsigned codepoint = 0; + for (int i = 0; i < 4; i++) + { + Ch c = is.Peek(); + codepoint <<= 4; + codepoint += static_cast(c); + if (c >= '0' && c <= '9') + codepoint -= '0'; + else if (c >= 'A' && c <= 'F') + codepoint -= 'A' - 10; + else if (c >= 'a' && c <= 'f') + codepoint -= 'a' - 10; + else + { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); + } + is.Take(); + } + return codepoint; + } + + template + class StackStream + { + public: + typedef CharType Ch; + + StackStream(internal::Stack &stack) : stack_(stack), length_(0) {} + RAPIDJSON_FORCEINLINE void Put(Ch c) + { + *stack_.template Push() = c; + ++length_; + } + + RAPIDJSON_FORCEINLINE void *Push(SizeType count) + { + length_ += count; + return stack_.template Push(count); + } + + size_t Length() const + { + return length_; + } + + Ch *Pop() + { + return stack_.template Pop(length_); + } + + private: + StackStream(const StackStream &); + StackStream &operator=(const StackStream &); + + internal::Stack &stack_; + SizeType length_; + }; + + // Parse string and generate String event. Different code paths for kParseInsituFlag. + template + void ParseString(InputStream &is, Handler &handler, bool isKey = false) + { + internal::StreamLocalCopy copy(is); + InputStream &s(copy.s); + + RAPIDJSON_ASSERT(s.Peek() == '\"'); + s.Take(); // Skip '\"' + + bool success = false; + if (parseFlags & kParseInsituFlag) + { + typename InputStream::Ch *head = s.PutBegin(); + ParseStringToStream(s, s); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + size_t length = s.PutEnd(head) - 1; + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + const typename TargetEncoding::Ch *const str = reinterpret_cast(head); + success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); + } + else + { + StackStream stackStream(stack_); + ParseStringToStream(s, stackStream); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + SizeType length = static_cast(stackStream.Length()) - 1; + const typename TargetEncoding::Ch *const str = stackStream.Pop(); + success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); + } + if (RAPIDJSON_UNLIKELY(!success)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + } + + // Parse string to an output is + // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. + template + RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream &is, OutputStream &os) + { +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + static const char escape[256] = + { + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', + Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, + 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, + 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 + }; +#undef Z16 +//!@endcond + + for (;;) + { + // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation. + if (!(parseFlags & kParseValidateEncodingFlag)) + ScanCopyUnescapedString(is, os); + + Ch c = is.Peek(); + if (RAPIDJSON_UNLIKELY(c == '\\')) // Escape + { + size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset + is.Take(); + Ch e = is.Peek(); + if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) + { + is.Take(); + os.Put(static_cast(escape[static_cast(e)])); + } + else if (RAPIDJSON_LIKELY(e == 'u')) // Unicode + { + is.Take(); + unsigned codepoint = ParseHex4(is, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) + { + // Handle UTF-16 surrogate pair + if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + unsigned codepoint2 = ParseHex4(is, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; + } + TEncoding::Encode(os, codepoint); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); + } + else if (RAPIDJSON_UNLIKELY(c == '"')) // Closing double quote + { + is.Take(); + os.Put('\0'); // null-terminate the string + return; + } + else if (RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + { + if (c == '\0') + RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); + else + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); + } + else + { + size_t offset = is.Tell(); + if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? + !Transcoder::Validate(is, os) : + !Transcoder::Transcode(is, os)))) + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); + } + } + } + + template + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream &, OutputStream &) + { + // Do nothing for generic version + } + +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream &is, StackStream &os) + { + const char *p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char *nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) + { + is.src_ = p; + return; + } + else + os.Put(*p++); + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16) + { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) // some of characters is escaped + { + SizeType length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + if (length != 0) + { + char *q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + + p += length; + } + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); + } + + is.src_ = p; + } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream &is, InsituStringStream &os) + { + RAPIDJSON_ASSERT(&is == &os); + (void)os; + + if (is.src_ == is.dst_) + { + SkipUnescapedString(is); + return; + } + + char *p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char *nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) + { + is.src_ = p; + is.dst_ = q; + return; + } + else + *q++ = *p++; + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16, q += 16) + { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) // some of characters is escaped + { + size_t length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + for (const char *pend = p + length; p != pend; ) + *q++ = *p++; + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); + } + + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream &is) + { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char *p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char *nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) + { + is.src_ = is.dst_ = p; + return; + } + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16) + { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) // some of characters is escaped + { + size_t length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + p += length; + break; + } + } + + is.src_ = is.dst_ = p; + } +#elif defined(RAPIDJSON_NEON) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream &is, StackStream &os) + { + const char *p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char *nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) + { + is.src_ = p; + return; + } + else + os.Put(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) + { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) + { + if (high != 0) + { + unsigned lz = (unsigned)__builtin_clzll(high);; + length = 8 + (lz >> 3); + escaped = true; + } + } + else + { + unsigned lz = (unsigned)__builtin_clzll(low);; + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) // some of characters is escaped + { + if (length != 0) + { + char *q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + + p += length; + } + break; + } + vst1q_u8(reinterpret_cast(os.Push(16)), s); + } + + is.src_ = p; + } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream &is, InsituStringStream &os) + { + RAPIDJSON_ASSERT(&is == &os); + (void)os; + + if (is.src_ == is.dst_) + { + SkipUnescapedString(is); + return; + } + + char *p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char *nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) + { + is.src_ = p; + is.dst_ = q; + return; + } + else + *q++ = *p++; + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16, q += 16) + { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) + { + if (high != 0) + { + unsigned lz = (unsigned)__builtin_clzll(high); + length = 8 + (lz >> 3); + escaped = true; + } + } + else + { + unsigned lz = (unsigned)__builtin_clzll(low); + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) // some of characters is escaped + { + for (const char *pend = p + length; p != pend; ) + { + *q++ = *p++; + } + break; + } + vst1q_u8(reinterpret_cast(q), s); + } + + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream &is) + { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char *p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char *nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) + { + is.src_ = is.dst_ = p; + return; + } + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) + { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) + { + if (high != 0) + { + int lz = __builtin_clzll(high); + p += 8 + (lz >> 3); + break; + } + } + else + { + int lz = __builtin_clzll(low); + p += lz >> 3; + break; + } + } + + is.src_ = is.dst_ = p; + } +#endif // RAPIDJSON_NEON + + template + class NumberStream; + + template + class NumberStream + { + public: + typedef typename InputStream::Ch Ch; + + NumberStream(GenericReader &reader, InputStream &s) : is(s) + { + (void)reader; + } + + RAPIDJSON_FORCEINLINE Ch Peek() const + { + return is.Peek(); + } + RAPIDJSON_FORCEINLINE Ch TakePush() + { + return is.Take(); + } + RAPIDJSON_FORCEINLINE Ch Take() + { + return is.Take(); + } + RAPIDJSON_FORCEINLINE void Push(char) {} + + size_t Tell() + { + return is.Tell(); + } + size_t Length() + { + return 0; + } + const char *Pop() + { + return 0; + } + + protected: + NumberStream &operator=(const NumberStream &); + + InputStream &is; + }; + + template + class NumberStream : public NumberStream + { + typedef NumberStream Base; + public: + NumberStream(GenericReader &reader, InputStream &is) : Base(reader, is), stackStream(reader.stack_) {} + + RAPIDJSON_FORCEINLINE Ch TakePush() + { + stackStream.Put(static_cast(Base::is.Peek())); + return Base::is.Take(); + } + + RAPIDJSON_FORCEINLINE void Push(char c) + { + stackStream.Put(c); + } + + size_t Length() + { + return stackStream.Length(); + } + + const char *Pop() + { + stackStream.Put('\0'); + return stackStream.Pop(); + } + + private: + StackStream stackStream; + }; + + template + class NumberStream : public NumberStream + { + typedef NumberStream Base; + public: + NumberStream(GenericReader &reader, InputStream &is) : Base(reader, is) {} + + RAPIDJSON_FORCEINLINE Ch Take() + { + return Base::TakePush(); + } + }; + + template + void ParseNumber(InputStream &is, Handler &handler) + { + internal::StreamLocalCopy copy(is); + NumberStream s(*this, copy.s); + + size_t startOffset = s.Tell(); + double d = 0.0; + bool useNanOrInf = false; + + // Parse minus + bool minus = Consume(s, '-'); + + // Parse int: zero / ( digit1-9 *DIGIT ) + unsigned i = 0; + uint64_t i64 = 0; + bool use64bit = false; + int significandDigit = 0; + if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) + { + i = 0; + s.TakePush(); + } + else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) + { + i = static_cast(s.TakePush() - '0'); + + if (minus) + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) + { + if (RAPIDJSON_UNLIKELY(i >= 214748364)) // 2^31 = 2147483648 + { + if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) + { + i64 = i; + use64bit = true; + break; + } + } + i = i * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + else + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) + { + if (RAPIDJSON_UNLIKELY(i >= 429496729)) // 2^32 - 1 = 4294967295 + { + if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) + { + i64 = i; + use64bit = true; + break; + } + } + i = i * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + } + // Parse NaN or Infinity here + else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) + { + if (Consume(s, 'N')) + { + if (Consume(s, 'a') && Consume(s, 'N')) + { + d = std::numeric_limits::quiet_NaN(); + useNanOrInf = true; + } + } + else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) + { + if (Consume(s, 'n') && Consume(s, 'f')) + { + d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); + useNanOrInf = true; + + if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') + && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) + { + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + } + } + + if (RAPIDJSON_UNLIKELY(!useNanOrInf)) + { + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + + // Parse 64bit int + bool useDouble = false; + if (use64bit) + { + if (minus) + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) + { + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) + { + d = static_cast(i64); + useDouble = true; + break; + } + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + else + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) + { + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) + { + d = static_cast(i64); + useDouble = true; + break; + } + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + significandDigit++; + } + } + + // Force double for big integer + if (useDouble) + { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) + { + d = d * 10 + (s.TakePush() - '0'); + } + } + + // Parse frac = decimal-point 1*DIGIT + int expFrac = 0; + size_t decimalPosition; + if (Consume(s, '.')) + { + decimalPosition = s.Length(); + + if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); + + if (!useDouble) + { +#if RAPIDJSON_64BIT + // Use i64 to store significand in 64-bit architecture + if (!use64bit) + i64 = i; + + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) + { + if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path + break; + else + { + i64 = i64 * 10 + static_cast(s.TakePush() - '0'); + --expFrac; + if (i64 != 0) + significandDigit++; + } + } + + d = static_cast(i64); +#else + // Use double to store significand in 32-bit architecture + d = static_cast(use64bit ? i64 : i); +#endif + useDouble = true; + } + + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) + { + if (significandDigit < 17) + { + d = d * 10.0 + (s.TakePush() - '0'); + --expFrac; + if (RAPIDJSON_LIKELY(d > 0.0)) + significandDigit++; + } + else + s.TakePush(); + } + } + else + decimalPosition = s.Length(); // decimal position at the end of integer. + + // Parse exp = e [ minus / plus ] 1*DIGIT + int exp = 0; + if (Consume(s, 'e') || Consume(s, 'E')) + { + if (!useDouble) + { + d = static_cast(use64bit ? i64 : i); + useDouble = true; + } + + bool expMinus = false; + if (Consume(s, '+')) + ; + else if (Consume(s, '-')) + expMinus = true; + + if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) + { + exp = static_cast(s.Take() - '0'); + if (expMinus) + { + // (exp + expFrac) must not underflow int => we're detecting when -exp gets + // dangerously close to INT_MIN (a pessimistic next digit 9 would push it into + // underflow territory): + // + // -(exp * 10 + 9) + expFrac >= INT_MIN + // <=> exp <= (expFrac - INT_MIN - 9) / 10 + RAPIDJSON_ASSERT(expFrac <= 0); + int maxExp = (expFrac + 2147483639) / 10; + + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) + { + exp = exp * 10 + static_cast(s.Take() - '0'); + if (RAPIDJSON_UNLIKELY(exp > maxExp)) + { + while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent + s.Take(); + } + } + } + else // positive exp + { + int maxExp = 308 - expFrac; + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) + { + exp = exp * 10 + static_cast(s.Take() - '0'); + if (RAPIDJSON_UNLIKELY(exp > maxExp)) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); + } + } + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); + + if (expMinus) + exp = -exp; + } + + // Finish parsing, call event according to the type of number. + bool cont = true; + + if (parseFlags & kParseNumbersAsStringsFlag) + { + if (parseFlags & kParseInsituFlag) + { + s.Pop(); // Pop stack no matter if it will be used or not. + typename InputStream::Ch *head = is.PutBegin(); + const size_t length = s.Tell() - startOffset; + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + // unable to insert the \0 character here, it will erase the comma after this number + const typename TargetEncoding::Ch *const str = reinterpret_cast(head); + cont = handler.RawNumber(str, SizeType(length), false); + } + else + { + SizeType numCharsToCopy = static_cast(s.Length()); + StringStream srcStream(s.Pop()); + StackStream dstStream(stack_); + while (numCharsToCopy--) + { + Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); + } + dstStream.Put('\0'); + const typename TargetEncoding::Ch *str = dstStream.Pop(); + const SizeType length = static_cast(dstStream.Length()) - 1; + cont = handler.RawNumber(str, SizeType(length), true); + } + } + else + { + size_t length = s.Length(); + const char *decimal = s.Pop(); // Pop stack no matter if it will be used or not. + + if (useDouble) + { + int p = exp + expFrac; + if (parseFlags & kParseFullPrecisionFlag) + d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); + else + d = internal::StrtodNormalPrecision(d, p); + + // Use > max, instead of == inf, to fix bogus warning -Wfloat-equal + if (d > (std::numeric_limits::max)()) + { + // Overflow + // TODO: internal::StrtodX should report overflow (or underflow) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); + } + + cont = handler.Double(minus ? -d : d); + } + else if (useNanOrInf) + { + cont = handler.Double(d); + } + else + { + if (use64bit) + { + if (minus) + cont = handler.Int64(static_cast(~i64 + 1)); + else + cont = handler.Uint64(i64); + } + else + { + if (minus) + cont = handler.Int(static_cast(~i + 1)); + else + cont = handler.Uint(i); + } + } + } + if (RAPIDJSON_UNLIKELY(!cont)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); + } + + // Parse any JSON value + template + void ParseValue(InputStream &is, Handler &handler) + { + switch (is.Peek()) + { + case 'n': + ParseNull (is, handler); + break; + case 't': + ParseTrue (is, handler); + break; + case 'f': + ParseFalse (is, handler); + break; + case '"': + ParseString(is, handler); + break; + case '{': + ParseObject(is, handler); + break; + case '[': + ParseArray (is, handler); + break; + default : + ParseNumber(is, handler); + break; + + } + } + + // Iterative Parsing + + // States + enum IterativeParsingState + { + IterativeParsingFinishState = 0, // sink states at top + IterativeParsingErrorState, // sink states at top + IterativeParsingStartState, + + // Object states + IterativeParsingObjectInitialState, + IterativeParsingMemberKeyState, + IterativeParsingMemberValueState, + IterativeParsingObjectFinishState, + + // Array states + IterativeParsingArrayInitialState, + IterativeParsingElementState, + IterativeParsingArrayFinishState, + + // Single value state + IterativeParsingValueState, + + // Delimiter states (at bottom) + IterativeParsingElementDelimiterState, + IterativeParsingMemberDelimiterState, + IterativeParsingKeyValueDelimiterState, + + cIterativeParsingStateCount + }; + + // Tokens + enum Token + { + LeftBracketToken = 0, + RightBracketToken, + + LeftCurlyBracketToken, + RightCurlyBracketToken, + + CommaToken, + ColonToken, + + StringToken, + FalseToken, + TrueToken, + NullToken, + NumberToken, + + kTokenCount + }; + + RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const + { + +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#define N NumberToken +#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N + // Maps from ASCII to Token + static const unsigned char tokenMap[256] = + { + N16, // 00~0F + N16, // 10~1F + N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F + N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F + N16, // 40~4F + N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F + N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F + N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F + N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF + }; +#undef N +#undef N16 +//!@endcond + + if (sizeof(Ch) == 1 || static_cast(c) < 256) + return static_cast(tokenMap[static_cast(c)]); + else + return NumberToken; + } + + RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const + { + // current state x one lookahead token -> new state + static const char G[cIterativeParsingStateCount][kTokenCount] = + { + // Finish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Error(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Start + { + IterativeParsingArrayInitialState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingValueState, // String + IterativeParsingValueState, // False + IterativeParsingValueState, // True + IterativeParsingValueState, // Null + IterativeParsingValueState // Number + }, + // ObjectInitial + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // MemberKey + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingKeyValueDelimiterState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // MemberValue + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingMemberDelimiterState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // ObjectFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // ArrayInitial + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // Element + { + IterativeParsingErrorState, // Left bracket + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingElementDelimiterState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // ArrayFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Single Value (sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // ElementDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // MemberDelimiter + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // KeyValueDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberValueState, // String + IterativeParsingMemberValueState, // False + IterativeParsingMemberValueState, // True + IterativeParsingMemberValueState, // Null + IterativeParsingMemberValueState // Number + }, + }; // End of G + + return static_cast(G[state][token]); + } + + // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). + // May return a new state on state pop. + template + RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream &is, Handler &handler) + { + (void)token; + + switch (dst) + { + case IterativeParsingErrorState: + return dst; + + case IterativeParsingObjectInitialState: + case IterativeParsingArrayInitialState: + { + // Push the state(Element or MemeberValue) if we are nested in another array or value of member. + // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. + IterativeParsingState n = src; + if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) + n = IterativeParsingElementState; + else if (src == IterativeParsingKeyValueDelimiterState) + n = IterativeParsingMemberValueState; + // Push current state. + *stack_.template Push(1) = n; + // Initialize and push the member/element count. + *stack_.template Push(1) = 0; + // Call handler + bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); + // On handler short circuits the parsing. + if (!hr) + { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else + { + is.Take(); + return dst; + } + } + + case IterativeParsingMemberKeyState: + ParseString(is, handler, true); + if (HasParseError()) + return IterativeParsingErrorState; + else + return dst; + + case IterativeParsingKeyValueDelimiterState: + RAPIDJSON_ASSERT(token == ColonToken); + is.Take(); + return dst; + + case IterativeParsingMemberValueState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) + { + return IterativeParsingErrorState; + } + return dst; + + case IterativeParsingElementState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) + { + return IterativeParsingErrorState; + } + return dst; + + case IterativeParsingMemberDelimiterState: + case IterativeParsingElementDelimiterState: + is.Take(); + // Update member/element count. + *stack_.template Top() = *stack_.template Top() + 1; + return dst; + + case IterativeParsingObjectFinishState: + { + // Transit from delimiter is only allowed when trailing commas are enabled + if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) + { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); + return IterativeParsingErrorState; + } + // Get member count. + SizeType c = *stack_.template Pop(1); + // If the object is not empty, count the last member. + if (src == IterativeParsingMemberValueState) + ++c; + // Restore the state. + IterativeParsingState n = static_cast(*stack_.template Pop(1)); + // Transit to Finish state if this is the topmost scope. + if (n == IterativeParsingStartState) + n = IterativeParsingFinishState; + // Call handler + bool hr = handler.EndObject(c); + // On handler short circuits the parsing. + if (!hr) + { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else + { + is.Take(); + return n; + } + } + + case IterativeParsingArrayFinishState: + { + // Transit from delimiter is only allowed when trailing commas are enabled + if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) + { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); + return IterativeParsingErrorState; + } + // Get element count. + SizeType c = *stack_.template Pop(1); + // If the array is not empty, count the last element. + if (src == IterativeParsingElementState) + ++c; + // Restore the state. + IterativeParsingState n = static_cast(*stack_.template Pop(1)); + // Transit to Finish state if this is the topmost scope. + if (n == IterativeParsingStartState) + n = IterativeParsingFinishState; + // Call handler + bool hr = handler.EndArray(c); + // On handler short circuits the parsing. + if (!hr) + { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else + { + is.Take(); + return n; + } + } + + default: + // This branch is for IterativeParsingValueState actually. + // Use `default:` rather than + // `case IterativeParsingValueState:` is for code coverage. + + // The IterativeParsingStartState is not enumerated in this switch-case. + // It is impossible for that case. And it can be caught by following assertion. + + // The IterativeParsingFinishState is not enumerated in this switch-case either. + // It is a "derivative" state which cannot triggered from Predict() directly. + // Therefore it cannot happen here. And it can be caught by following assertion. + RAPIDJSON_ASSERT(dst == IterativeParsingValueState); + + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) + { + return IterativeParsingErrorState; + } + return IterativeParsingFinishState; + } + } + + template + void HandleError(IterativeParsingState src, InputStream &is) + { + if (HasParseError()) + { + // Error flag has been set. + return; + } + + switch (src) + { + case IterativeParsingStartState: + RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); + return; + case IterativeParsingFinishState: + RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); + return; + case IterativeParsingObjectInitialState: + case IterativeParsingMemberDelimiterState: + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); + return; + case IterativeParsingMemberKeyState: + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); + return; + case IterativeParsingMemberValueState: + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); + return; + case IterativeParsingKeyValueDelimiterState: + case IterativeParsingArrayInitialState: + case IterativeParsingElementDelimiterState: + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + return; + default: + RAPIDJSON_ASSERT(src == IterativeParsingElementState); + RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + return; + } + } + + RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const + { + return s >= IterativeParsingElementDelimiterState; + } + + RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const + { + return s <= IterativeParsingErrorState; + } + + template + ParseResult IterativeParse(InputStream &is, Handler &handler) + { + parseResult_.Clear(); + ClearStackOnExit scope(*this); + IterativeParsingState state = IterativeParsingStartState; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + while (is.Peek() != '\0') + { + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state, t); + IterativeParsingState d = Transit(state, t, n, is, handler); + + if (d == IterativeParsingErrorState) + { + HandleError(state, is); + break; + } + + state = d; + + // Do not further consume streams if a root JSON has been parsed. + if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) + break; + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + + // Handle the end of file. + if (state != IterativeParsingFinishState) + HandleError(state, is); + + return parseResult_; + } + + static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. + internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. + ParseResult parseResult_; + IterativeParsingState state_; +}; // class GenericReader + +//! Reader with UTF8 encoding and default allocator. +typedef GenericReader, UTF8<> > Reader; + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + + +#ifdef __GNUC__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_READER_H_ diff --git a/contrib/world_builder/include/rapidjson/schema.h.bak b/contrib/world_builder/include/rapidjson/schema.h.bak new file mode 100644 index 00000000000..66a90b3a44e --- /dev/null +++ b/contrib/world_builder/include/rapidjson/schema.h.bak @@ -0,0 +1,2927 @@ +// Tencent is pleased to support the open source community by making RapidJSON available-> +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License-> You may obtain a copy of the License at +// +// http://opensource->org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied-> See the License for the +// specific language governing permissions and limitations under the License-> + +#ifndef RAPIDJSON_SCHEMA_H_ +#define RAPIDJSON_SCHEMA_H_ + +#include "document.h" +#include "pointer.h" +#include "stringbuffer.h" +#include // abs, floor + +#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 +#else +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 +#endif + +#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) +#define RAPIDJSON_SCHEMA_USE_STDREGEX 1 +#else +#define RAPIDJSON_SCHEMA_USE_STDREGEX 0 +#endif + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX +#include "internal/regex.h" +#elif RAPIDJSON_SCHEMA_USE_STDREGEX +#include +#endif + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX +#define RAPIDJSON_SCHEMA_HAS_REGEX 1 +#else +#define RAPIDJSON_SCHEMA_HAS_REGEX 0 +#endif + +#ifndef RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_VERBOSE 0 +#endif + +#if RAPIDJSON_SCHEMA_VERBOSE +#include "stringbuffer.h" +#endif + +RAPIDJSON_DIAG_PUSH + +#if defined(__GNUC__) +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_OFF(weak-vtables) +RAPIDJSON_DIAG_OFF(exit-time-destructors) +RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) +RAPIDJSON_DIAG_OFF(variadic-macros) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Verbose Utilities + +#if RAPIDJSON_SCHEMA_VERBOSE + +namespace internal +{ + + inline void PrintInvalidKeyword(const char *keyword) + { + printf("Fail keyword: %s\n", keyword); + } + + inline void PrintInvalidKeyword(const wchar_t *keyword) + { + wprintf(L"Fail keyword: %ls\n", keyword); + } + + inline void PrintInvalidDocument(const char *document) + { + printf("Fail document: %s\n\n", document); + } + + inline void PrintInvalidDocument(const wchar_t *document) + { + wprintf(L"Fail document: %ls\n\n", document); + } + + inline void PrintValidatorPointers(unsigned depth, const char *s, const char *d) + { + printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); + } + + inline void PrintValidatorPointers(unsigned depth, const wchar_t *s, const wchar_t *d) + { + wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); + } + +} // namespace internal + +#endif // RAPIDJSON_SCHEMA_VERBOSE + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_INVALID_KEYWORD_RETURN + +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) +#else +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) +#endif + +#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\ + RAPIDJSON_MULTILINEMACRO_BEGIN\ + context.invalidKeyword = keyword.GetString();\ + RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\ + return false;\ + RAPIDJSON_MULTILINEMACRO_END + +/////////////////////////////////////////////////////////////////////////////// +// Forward declarations + +template +class GenericSchemaDocument; + +namespace internal +{ + + template + class Schema; + +/////////////////////////////////////////////////////////////////////////////// +// ISchemaValidator + + class ISchemaValidator + { + public: + virtual ~ISchemaValidator() {} + virtual bool IsValid() const = 0; + }; + +/////////////////////////////////////////////////////////////////////////////// +// ISchemaStateFactory + + template + class ISchemaStateFactory + { + public: + virtual ~ISchemaStateFactory() {} + virtual ISchemaValidator *CreateSchemaValidator(const SchemaType &) = 0; + virtual void DestroySchemaValidator(ISchemaValidator *validator) = 0; + virtual void *CreateHasher() = 0; + virtual uint64_t GetHashCode(void *hasher) = 0; + virtual void DestroryHasher(void *hasher) = 0; + virtual void *MallocState(size_t size) = 0; + virtual void FreeState(void *p) = 0; + }; + +/////////////////////////////////////////////////////////////////////////////// +// IValidationErrorHandler + + template + class IValidationErrorHandler + { + public: + typedef typename SchemaType::Ch Ch; + typedef typename SchemaType::SValue SValue; + + virtual ~IValidationErrorHandler() {} + + virtual void NotMultipleOf(int64_t actual, const SValue &expected) = 0; + virtual void NotMultipleOf(uint64_t actual, const SValue &expected) = 0; + virtual void NotMultipleOf(double actual, const SValue &expected) = 0; + virtual void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive) = 0; + virtual void AboveMaximum(uint64_t actual, const SValue &expected, bool exclusive) = 0; + virtual void AboveMaximum(double actual, const SValue &expected, bool exclusive) = 0; + virtual void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive) = 0; + virtual void BelowMinimum(uint64_t actual, const SValue &expected, bool exclusive) = 0; + virtual void BelowMinimum(double actual, const SValue &expected, bool exclusive) = 0; + + virtual void TooLong(const Ch *str, SizeType length, SizeType expected) = 0; + virtual void TooShort(const Ch *str, SizeType length, SizeType expected) = 0; + virtual void DoesNotMatch(const Ch *str, SizeType length) = 0; + + virtual void DisallowedItem(SizeType index) = 0; + virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0; + virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0; + virtual void DuplicateItems(SizeType index1, SizeType index2) = 0; + + virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0; + virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0; + virtual void StartMissingProperties() = 0; + virtual void AddMissingProperty(const SValue &name) = 0; + virtual bool EndMissingProperties() = 0; + virtual void PropertyViolations(ISchemaValidator **subvalidators, SizeType count) = 0; + virtual void DisallowedProperty(const Ch *name, SizeType length) = 0; + + virtual void StartDependencyErrors() = 0; + virtual void StartMissingDependentProperties() = 0; + virtual void AddMissingDependentProperty(const SValue &targetName) = 0; + virtual void EndMissingDependentProperties(const SValue &sourceName) = 0; + virtual void AddDependencySchemaError(const SValue &souceName, ISchemaValidator *subvalidator) = 0; + virtual bool EndDependencyErrors() = 0; + + virtual void DisallowedValue() = 0; + virtual void StartDisallowedType() = 0; + virtual void AddExpectedType(const typename SchemaType::ValueType &expectedType) = 0; + virtual void EndDisallowedType(const typename SchemaType::ValueType &actualType) = 0; + virtual void NotAllOf(ISchemaValidator **subvalidators, SizeType count) = 0; + virtual void NoneOf(ISchemaValidator **subvalidators, SizeType count) = 0; + virtual void NotOneOf(ISchemaValidator **subvalidators, SizeType count) = 0; + virtual void Disallowed() = 0; + }; + + +/////////////////////////////////////////////////////////////////////////////// +// Hasher + +// For comparison of compound value + template + class Hasher + { + public: + typedef typename Encoding::Ch Ch; + + Hasher(Allocator *allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} + + bool Null() + { + return WriteType(kNullType); + } + bool Bool(bool b) + { + return WriteType(b ? kTrueType : kFalseType); + } + bool Int(int i) + { + Number n; + n.u.i = i; + n.d = static_cast(i); + return WriteNumber(n); + } + bool Uint(unsigned u) + { + Number n; + n.u.u = u; + n.d = static_cast(u); + return WriteNumber(n); + } + bool Int64(int64_t i) + { + Number n; + n.u.i = i; + n.d = static_cast(i); + return WriteNumber(n); + } + bool Uint64(uint64_t u) + { + Number n; + n.u.u = u; + n.d = static_cast(u); + return WriteNumber(n); + } + bool Double(double d) + { + Number n; + if (d < 0) n.u.i = static_cast(d); + else n.u.u = static_cast(d); + n.d = d; + return WriteNumber(n); + } + + bool RawNumber(const Ch *str, SizeType len, bool) + { + WriteBuffer(kNumberType, str, len * sizeof(Ch)); + return true; + } + + bool String(const Ch *str, SizeType len, bool) + { + WriteBuffer(kStringType, str, len * sizeof(Ch)); + return true; + } + + bool StartObject() + { + return true; + } + bool Key(const Ch *str, SizeType len, bool copy) + { + return String(str, len, copy); + } + bool EndObject(SizeType memberCount) + { + uint64_t h = Hash(0, kObjectType); + uint64_t *kv = stack_.template Pop(memberCount * 2); + for (SizeType i = 0; i < memberCount; i++) + h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive + *stack_.template Push() = h; + return true; + } + + bool StartArray() + { + return true; + } + bool EndArray(SizeType elementCount) + { + uint64_t h = Hash(0, kArrayType); + uint64_t *e = stack_.template Pop(elementCount); + for (SizeType i = 0; i < elementCount; i++) + h = Hash(h, e[i]); // Use hash to achieve element order sensitive + *stack_.template Push() = h; + return true; + } + + bool IsValid() const + { + return stack_.GetSize() == sizeof(uint64_t); + } + + uint64_t GetHashCode() const + { + RAPIDJSON_ASSERT(IsValid()); + return *stack_.template Top(); + } + + private: + static const size_t kDefaultSize = 256; + struct Number + { + union U + { + uint64_t u; + int64_t i; + } u; + double d; + }; + + bool WriteType(Type type) + { + return WriteBuffer(type, 0, 0); + } + + bool WriteNumber(const Number &n) + { + return WriteBuffer(kNumberType, &n, sizeof(n)); + } + + bool WriteBuffer(Type type, const void *data, size_t len) + { + // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ + uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); + const unsigned char *d = static_cast(data); + for (size_t i = 0; i < len; i++) + h = Hash(h, d[i]); + *stack_.template Push() = h; + return true; + } + + static uint64_t Hash(uint64_t h, uint64_t d) + { + static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); + h ^= d; + h *= kPrime; + return h; + } + + Stack stack_; + }; + +/////////////////////////////////////////////////////////////////////////////// +// SchemaValidationContext + + template + struct SchemaValidationContext + { + typedef Schema SchemaType; + typedef ISchemaStateFactory SchemaValidatorFactoryType; + typedef IValidationErrorHandler ErrorHandlerType; + typedef typename SchemaType::ValueType ValueType; + typedef typename ValueType::Ch Ch; + + enum PatternValidatorType + { + kPatternValidatorOnly, + kPatternValidatorWithProperty, + kPatternValidatorWithAdditionalProperty + }; + + SchemaValidationContext(SchemaValidatorFactoryType &f, ErrorHandlerType &eh, const SchemaType *s) : + factory(f), + error_handler(eh), + schema(s), + valueSchema(), + invalidKeyword(), + hasher(), + arrayElementHashCodes(), + validators(), + validatorCount(), + patternPropertiesValidators(), + patternPropertiesValidatorCount(), + patternPropertiesSchemas(), + patternPropertiesSchemaCount(), + valuePatternValidatorType(kPatternValidatorOnly), + propertyExist(), + inArray(false), + valueUniqueness(false), + arrayUniqueness(false) + { + } + + ~SchemaValidationContext() + { + if (hasher) + factory.DestroryHasher(hasher); + if (validators) + { + for (SizeType i = 0; i < validatorCount; i++) + factory.DestroySchemaValidator(validators[i]); + factory.FreeState(validators); + } + if (patternPropertiesValidators) + { + for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) + factory.DestroySchemaValidator(patternPropertiesValidators[i]); + factory.FreeState(patternPropertiesValidators); + } + if (patternPropertiesSchemas) + factory.FreeState(patternPropertiesSchemas); + if (propertyExist) + factory.FreeState(propertyExist); + } + + SchemaValidatorFactoryType &factory; + ErrorHandlerType &error_handler; + const SchemaType *schema; + const SchemaType *valueSchema; + const Ch *invalidKeyword; + void *hasher; // Only validator access + void *arrayElementHashCodes; // Only validator access this + ISchemaValidator **validators; + SizeType validatorCount; + ISchemaValidator **patternPropertiesValidators; + SizeType patternPropertiesValidatorCount; + const SchemaType **patternPropertiesSchemas; + SizeType patternPropertiesSchemaCount; + PatternValidatorType valuePatternValidatorType; + PatternValidatorType objectPatternValidatorType; + SizeType arrayElementIndex; + bool *propertyExist; + bool inArray; + bool valueUniqueness; + bool arrayUniqueness; + }; + +/////////////////////////////////////////////////////////////////////////////// +// Schema + + template + class Schema + { + public: + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename SchemaDocumentType::AllocatorType AllocatorType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef SchemaValidationContext Context; + typedef Schema SchemaType; + typedef GenericValue SValue; + typedef IValidationErrorHandler ErrorHandler; + friend class GenericSchemaDocument; + + Schema(SchemaDocumentType *schemaDocument, const PointerType &p, const ValueType &value, const ValueType &document, AllocatorType *allocator) : + allocator_(allocator), + uri_(schemaDocument->GetURI(), *allocator), + pointer_(p), + typeless_(schemaDocument->GetTypeless()), + enum_(), + enumCount_(), + not_(), + type_((1 << kTotalSchemaType) - 1), // typeless + validatorCount_(), + notValidatorIndex_(), + properties_(), + additionalPropertiesSchema_(), + patternProperties_(), + patternPropertyCount_(), + propertyCount_(), + minProperties_(), + maxProperties_(SizeType(~0)), + additionalProperties_(true), + hasDependencies_(), + hasRequired_(), + hasSchemaDependencies_(), + additionalItemsSchema_(), + itemsList_(), + itemsTuple_(), + itemsTupleCount_(), + minItems_(), + maxItems_(SizeType(~0)), + additionalItems_(true), + uniqueItems_(false), + pattern_(), + minLength_(0), + maxLength_(~SizeType(0)), + exclusiveMinimum_(false), + exclusiveMaximum_(false), + defaultValueLength_(0) + { + typedef typename ValueType::ConstValueIterator ConstValueIterator; + typedef typename ValueType::ConstMemberIterator ConstMemberIterator; + + if (!value.IsObject()) + return; + + if (const ValueType *v = GetMember(value, GetTypeString())) + { + type_ = 0; + if (v->IsString()) + AddType(*v); + else if (v->IsArray()) + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) + AddType(*itr); + } + + if (const ValueType *v = GetMember(value, GetEnumString())) + if (v->IsArray() && v->Size() > 0) + { + enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) + { + typedef Hasher > EnumHasherType; + char buffer[256u + 24]; + MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); + EnumHasherType h(&hasherAllocator, 256); + itr->Accept(h); + enum_[enumCount_++] = h.GetHashCode(); + } + } + + if (schemaDocument) + { + AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); + AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); + AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); + } + + if (const ValueType *v = GetMember(value, GetNotString())) + { + schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); + notValidatorIndex_ = validatorCount_; + validatorCount_++; + } + + // Object + + const ValueType *properties = GetMember(value, GetPropertiesString()); + const ValueType *required = GetMember(value, GetRequiredString()); + const ValueType *dependencies = GetMember(value, GetDependenciesString()); + { + // Gather properties from properties/required/dependencies + SValue allProperties(kArrayType); + + if (properties && properties->IsObject()) + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) + AddUniqueElement(allProperties, itr->name); + + if (required && required->IsArray()) + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) + if (itr->IsString()) + AddUniqueElement(allProperties, *itr); + + if (dependencies && dependencies->IsObject()) + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) + { + AddUniqueElement(allProperties, itr->name); + if (itr->value.IsArray()) + for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) + if (i->IsString()) + AddUniqueElement(allProperties, *i); + } + + if (allProperties.Size() > 0) + { + propertyCount_ = allProperties.Size(); + properties_ = static_cast(allocator_->Malloc(sizeof(Property) * propertyCount_)); + for (SizeType i = 0; i < propertyCount_; i++) + { + new (&properties_[i]) Property(); + properties_[i].name = allProperties[i]; + properties_[i].schema = typeless_; + } + } + } + + if (properties && properties->IsObject()) + { + PointerType q = p.Append(GetPropertiesString(), allocator_); + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) + { + SizeType index; + if (FindPropertyIndex(itr->name, &index)) + schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document); + } + } + + if (const ValueType *v = GetMember(value, GetPatternPropertiesString())) + { + PointerType q = p.Append(GetPatternPropertiesString(), allocator_); + patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); + patternPropertyCount_ = 0; + + for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) + { + new (&patternProperties_[patternPropertyCount_]) PatternProperty(); + patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); + schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document); + patternPropertyCount_++; + } + } + + if (required && required->IsArray()) + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) + if (itr->IsString()) + { + SizeType index; + if (FindPropertyIndex(*itr, &index)) + { + properties_[index].required = true; + hasRequired_ = true; + } + } + + if (dependencies && dependencies->IsObject()) + { + PointerType q = p.Append(GetDependenciesString(), allocator_); + hasDependencies_ = true; + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) + { + SizeType sourceIndex = 0; + if (FindPropertyIndex(itr->name, &sourceIndex)) + { + if (itr->value.IsArray()) + { + properties_[sourceIndex].dependencies = static_cast(allocator_->Malloc(sizeof(bool) * propertyCount_)); + std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); + for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) + { + SizeType targetIndex = 0; + if (FindPropertyIndex(*targetItr, &targetIndex)) + properties_[sourceIndex].dependencies[targetIndex] = true; + } + } + else if (itr->value.IsObject()) + { + hasSchemaDependencies_ = true; + schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); + properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; + validatorCount_++; + } + } + } + } + + if (const ValueType *v = GetMember(value, GetAdditionalPropertiesString())) + { + if (v->IsBool()) + additionalProperties_ = v->GetBool(); + else if (v->IsObject()) + schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); + } + + AssignIfExist(minProperties_, value, GetMinPropertiesString()); + AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); + + // Array + if (const ValueType *v = GetMember(value, GetItemsString())) + { + PointerType q = p.Append(GetItemsString(), allocator_); + if (v->IsObject()) // List validation + schemaDocument->CreateSchema(&itemsList_, q, *v, document); + else if (v->IsArray()) // Tuple validation + { + itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema *) * v->Size())); + SizeType index = 0; + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) + schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document); + } + } + + AssignIfExist(minItems_, value, GetMinItemsString()); + AssignIfExist(maxItems_, value, GetMaxItemsString()); + + if (const ValueType *v = GetMember(value, GetAdditionalItemsString())) + { + if (v->IsBool()) + additionalItems_ = v->GetBool(); + else if (v->IsObject()) + schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); + } + + AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); + + // String + AssignIfExist(minLength_, value, GetMinLengthString()); + AssignIfExist(maxLength_, value, GetMaxLengthString()); + + if (const ValueType *v = GetMember(value, GetPatternString())) + pattern_ = CreatePattern(*v); + + // Number + if (const ValueType *v = GetMember(value, GetMinimumString())) + if (v->IsNumber()) + minimum_.CopyFrom(*v, *allocator_); + + if (const ValueType *v = GetMember(value, GetMaximumString())) + if (v->IsNumber()) + maximum_.CopyFrom(*v, *allocator_); + + AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); + AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); + + if (const ValueType *v = GetMember(value, GetMultipleOfString())) + if (v->IsNumber() && v->GetDouble() > 0.0) + multipleOf_.CopyFrom(*v, *allocator_); + + // Default + if (const ValueType *v = GetMember(value, GetDefaultValueString())) + if (v->IsString()) + defaultValueLength_ = v->GetStringLength(); + + } + + ~Schema() + { + AllocatorType::Free(enum_); + if (properties_) + { + for (SizeType i = 0; i < propertyCount_; i++) + properties_[i].~Property(); + AllocatorType::Free(properties_); + } + if (patternProperties_) + { + for (SizeType i = 0; i < patternPropertyCount_; i++) + patternProperties_[i].~PatternProperty(); + AllocatorType::Free(patternProperties_); + } + AllocatorType::Free(itemsTuple_); +#if RAPIDJSON_SCHEMA_HAS_REGEX + if (pattern_) + { + pattern_->~RegexType(); + AllocatorType::Free(pattern_); + } +#endif + } + + const SValue &GetURI() const + { + return uri_; + } + + const PointerType &GetPointer() const + { + return pointer_; + } + + bool BeginValue(Context &context) const + { + if (context.inArray) + { + if (uniqueItems_) + context.valueUniqueness = true; + + if (itemsList_) + context.valueSchema = itemsList_; + else if (itemsTuple_) + { + if (context.arrayElementIndex < itemsTupleCount_) + context.valueSchema = itemsTuple_[context.arrayElementIndex]; + else if (additionalItemsSchema_) + context.valueSchema = additionalItemsSchema_; + else if (additionalItems_) + context.valueSchema = typeless_; + else + { + context.error_handler.DisallowedItem(context.arrayElementIndex); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); + } + } + else + context.valueSchema = typeless_; + + context.arrayElementIndex++; + } + return true; + } + + RAPIDJSON_FORCEINLINE bool EndValue(Context &context) const + { + if (context.patternPropertiesValidatorCount > 0) + { + bool otherValid = false; + SizeType count = context.patternPropertiesValidatorCount; + if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) + otherValid = context.patternPropertiesValidators[--count]->IsValid(); + + bool patternValid = true; + for (SizeType i = 0; i < count; i++) + if (!context.patternPropertiesValidators[i]->IsValid()) + { + patternValid = false; + break; + } + + if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) + { + if (!patternValid) + { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + } + else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) + { + if (!patternValid || !otherValid) + { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + } + else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty) + { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + } + + if (enum_) + { + const uint64_t h = context.factory.GetHashCode(context.hasher); + for (SizeType i = 0; i < enumCount_; i++) + if (enum_[i] == h) + goto foundEnum; + context.error_handler.DisallowedValue(); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); + foundEnum: + ; + } + + if (allOf_.schemas) + for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) + if (!context.validators[i]->IsValid()) + { + context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString()); + } + + if (anyOf_.schemas) + { + for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) + if (context.validators[i]->IsValid()) + goto foundAny; + context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); + foundAny: + ; + } + + if (oneOf_.schemas) + { + bool oneValid = false; + for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) + if (context.validators[i]->IsValid()) + { + if (oneValid) + { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); + } + else + oneValid = true; + } + if (!oneValid) + { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); + } + } + + if (not_ && context.validators[notValidatorIndex_]->IsValid()) + { + context.error_handler.Disallowed(); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); + } + + return true; + } + + bool Null(Context &context) const + { + if (!(type_ & (1 << kNullSchemaType))) + { + DisallowedType(context, GetNullString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + return CreateParallelValidator(context); + } + + bool Bool(Context &context, bool) const + { + if (!(type_ & (1 << kBooleanSchemaType))) + { + DisallowedType(context, GetBooleanString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + return CreateParallelValidator(context); + } + + bool Int(Context &context, int i) const + { + if (!CheckInt(context, i)) + return false; + return CreateParallelValidator(context); + } + + bool Uint(Context &context, unsigned u) const + { + if (!CheckUint(context, u)) + return false; + return CreateParallelValidator(context); + } + + bool Int64(Context &context, int64_t i) const + { + if (!CheckInt(context, i)) + return false; + return CreateParallelValidator(context); + } + + bool Uint64(Context &context, uint64_t u) const + { + if (!CheckUint(context, u)) + return false; + return CreateParallelValidator(context); + } + + bool Double(Context &context, double d) const + { + if (!(type_ & (1 << kNumberSchemaType))) + { + DisallowedType(context, GetNumberString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) + return false; + + if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) + return false; + + if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) + return false; + + return CreateParallelValidator(context); + } + + bool String(Context &context, const Ch *str, SizeType length, bool) const + { + if (!(type_ & (1 << kStringSchemaType))) + { + DisallowedType(context, GetStringString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (minLength_ != 0 || maxLength_ != SizeType(~0)) + { + SizeType count; + if (internal::CountStringCodePoint(str, length, &count)) + { + if (count < minLength_) + { + context.error_handler.TooShort(str, length, minLength_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); + } + if (count > maxLength_) + { + context.error_handler.TooLong(str, length, maxLength_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); + } + } + } + + if (pattern_ && !IsPatternMatch(pattern_, str, length)) + { + context.error_handler.DoesNotMatch(str, length); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); + } + + return CreateParallelValidator(context); + } + + bool StartObject(Context &context) const + { + if (!(type_ & (1 << kObjectSchemaType))) + { + DisallowedType(context, GetObjectString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (hasDependencies_ || hasRequired_) + { + context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); + std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); + } + + if (patternProperties_) // pre-allocate schema array + { + SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType + context.patternPropertiesSchemas = static_cast(context.factory.MallocState(sizeof(const SchemaType *) * count)); + context.patternPropertiesSchemaCount = 0; + std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType *) * count); + } + + return CreateParallelValidator(context); + } + + bool Key(Context &context, const Ch *str, SizeType len, bool) const + { + if (patternProperties_) + { + context.patternPropertiesSchemaCount = 0; + for (SizeType i = 0; i < patternPropertyCount_; i++) + if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) + { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; + context.valueSchema = typeless_; + } + } + + SizeType index; + if (FindPropertyIndex(ValueType(str, len).Move(), &index)) + { + if (context.patternPropertiesSchemaCount > 0) + { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; + context.valueSchema = typeless_; + context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; + } + else + context.valueSchema = properties_[index].schema; + + if (context.propertyExist) + context.propertyExist[index] = true; + + return true; + } + + if (additionalPropertiesSchema_) + { + if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) + { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; + context.valueSchema = typeless_; + context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; + } + else + context.valueSchema = additionalPropertiesSchema_; + return true; + } + else if (additionalProperties_) + { + context.valueSchema = typeless_; + return true; + } + + if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties + { + context.error_handler.DisallowedProperty(str, len); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); + } + + return true; + } + + bool EndObject(Context &context, SizeType memberCount) const + { + if (hasRequired_) + { + context.error_handler.StartMissingProperties(); + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].required && !context.propertyExist[index]) + if (properties_[index].schema->defaultValueLength_ == 0 ) + context.error_handler.AddMissingProperty(properties_[index].name); + if (context.error_handler.EndMissingProperties()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); + } + + if (memberCount < minProperties_) + { + context.error_handler.TooFewProperties(memberCount, minProperties_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); + } + + if (memberCount > maxProperties_) + { + context.error_handler.TooManyProperties(memberCount, maxProperties_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); + } + + if (hasDependencies_) + { + context.error_handler.StartDependencyErrors(); + for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) + { + const Property &source = properties_[sourceIndex]; + if (context.propertyExist[sourceIndex]) + { + if (source.dependencies) + { + context.error_handler.StartMissingDependentProperties(); + for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) + if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex]) + context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name); + context.error_handler.EndMissingDependentProperties(source.name); + } + else if (source.dependenciesSchema) + { + ISchemaValidator *dependenciesValidator = context.validators[source.dependenciesValidatorIndex]; + if (!dependenciesValidator->IsValid()) + context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator); + } + } + } + if (context.error_handler.EndDependencyErrors()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); + } + + return true; + } + + bool StartArray(Context &context) const + { + if (!(type_ & (1 << kArraySchemaType))) + { + DisallowedType(context, GetArrayString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + context.arrayElementIndex = 0; + context.inArray = true; + + return CreateParallelValidator(context); + } + + bool EndArray(Context &context, SizeType elementCount) const + { + context.inArray = false; + + if (elementCount < minItems_) + { + context.error_handler.TooFewItems(elementCount, minItems_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); + } + + if (elementCount > maxItems_) + { + context.error_handler.TooManyItems(elementCount, maxItems_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); + } + + return true; + } + + // Generate functions for string literal according to Ch +#define RAPIDJSON_STRING_(name, ...) \ + static const ValueType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const ValueType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1));\ + return v;\ + } + + RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') + RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') + RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') + RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') + RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') + RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') + RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') + RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') + RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') + RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') + RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') + RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') + RAPIDJSON_STRING_(Not, 'n', 'o', 't') + RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') + RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') + RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') + RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') + RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') + RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') + RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't') + +#undef RAPIDJSON_STRING_ + + private: + enum SchemaValueType + { + kNullSchemaType, + kBooleanSchemaType, + kObjectSchemaType, + kArraySchemaType, + kStringSchemaType, + kNumberSchemaType, + kIntegerSchemaType, + kTotalSchemaType + }; + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + typedef internal::GenericRegex RegexType; +#elif RAPIDJSON_SCHEMA_USE_STDREGEX + typedef std::basic_regex RegexType; +#else + typedef char RegexType; +#endif + + struct SchemaArray + { + SchemaArray() : schemas(), count() {} + ~SchemaArray() + { + AllocatorType::Free(schemas); + } + const SchemaType **schemas; + SizeType begin; // begin index of context.validators + SizeType count; + }; + + template + void AddUniqueElement(V1 &a, const V2 &v) + { + for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) + if (*itr == v) + return; + V1 c(v, *allocator_); + a.PushBack(c, *allocator_); + } + + static const ValueType *GetMember(const ValueType &value, const ValueType &name) + { + typename ValueType::ConstMemberIterator itr = value.FindMember(name); + return itr != value.MemberEnd() ? &(itr->value) : 0; + } + + static void AssignIfExist(bool &out, const ValueType &value, const ValueType &name) + { + if (const ValueType *v = GetMember(value, name)) + if (v->IsBool()) + out = v->GetBool(); + } + + static void AssignIfExist(SizeType &out, const ValueType &value, const ValueType &name) + { + if (const ValueType *v = GetMember(value, name)) + if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) + out = static_cast(v->GetUint64()); + } + + void AssignIfExist(SchemaArray &out, SchemaDocumentType &schemaDocument, const PointerType &p, const ValueType &value, const ValueType &name, const ValueType &document) + { + if (const ValueType *v = GetMember(value, name)) + { + if (v->IsArray() && v->Size() > 0) + { + PointerType q = p.Append(name, allocator_); + out.count = v->Size(); + out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema *))); + memset(out.schemas, 0, sizeof(Schema *)* out.count); + for (SizeType i = 0; i < out.count; i++) + schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document); + out.begin = validatorCount_; + validatorCount_ += out.count; + } + } + } + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + template + RegexType *CreatePattern(const ValueType &value) + { + if (value.IsString()) + { + RegexType *r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_); + if (!r->IsValid()) + { + r->~RegexType(); + AllocatorType::Free(r); + r = 0; + } + return r; + } + return 0; + } + + static bool IsPatternMatch(const RegexType *pattern, const Ch *str, SizeType) + { + GenericRegexSearch rs(*pattern); + return rs.Search(str); + } +#elif RAPIDJSON_SCHEMA_USE_STDREGEX + template + RegexType *CreatePattern(const ValueType &value) + { + if (value.IsString()) + try + { + return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); + } + catch (const std::regex_error &) + { + } + return 0; + } + + static bool IsPatternMatch(const RegexType *pattern, const Ch *str, SizeType length) + { + std::match_results r; + return std::regex_search(str, str + length, r, *pattern); + } +#else + template + RegexType *CreatePattern(const ValueType &) + { + return 0; + } + + static bool IsPatternMatch(const RegexType *, const Ch *, SizeType) + { + return true; + } +#endif // RAPIDJSON_SCHEMA_USE_STDREGEX + + void AddType(const ValueType &type) + { + if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; + else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; + else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; + else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; + else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; + else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; + else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); + } + + bool CreateParallelValidator(Context &context) const + { + if (enum_ || context.arrayUniqueness) + context.hasher = context.factory.CreateHasher(); + + if (validatorCount_) + { + RAPIDJSON_ASSERT(context.validators == 0); + context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator *) * validatorCount_)); + context.validatorCount = validatorCount_; + + if (allOf_.schemas) + CreateSchemaValidators(context, allOf_); + + if (anyOf_.schemas) + CreateSchemaValidators(context, anyOf_); + + if (oneOf_.schemas) + CreateSchemaValidators(context, oneOf_); + + if (not_) + context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_); + + if (hasSchemaDependencies_) + { + for (SizeType i = 0; i < propertyCount_; i++) + if (properties_[i].dependenciesSchema) + context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema); + } + } + + return true; + } + + void CreateSchemaValidators(Context &context, const SchemaArray &schemas) const + { + for (SizeType i = 0; i < schemas.count; i++) + context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]); + } + + // O(n) + bool FindPropertyIndex(const ValueType &name, SizeType *outIndex) const + { + SizeType len = name.GetStringLength(); + const Ch *str = name.GetString(); + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].name.GetStringLength() == len && + (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) + { + *outIndex = index; + return true; + } + return false; + } + + bool CheckInt(Context &context, int64_t i) const + { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) + { + DisallowedType(context, GetIntegerString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (!minimum_.IsNull()) + { + if (minimum_.IsInt64()) + { + if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) + { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + } + else if (minimum_.IsUint64()) + { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() + } + else if (!CheckDoubleMinimum(context, static_cast(i))) + return false; + } + + if (!maximum_.IsNull()) + { + if (maximum_.IsInt64()) + { + if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) + { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + } + else if (maximum_.IsUint64()) { } + /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() + else if (!CheckDoubleMaximum(context, static_cast(i))) + return false; + } + + if (!multipleOf_.IsNull()) + { + if (multipleOf_.IsUint64()) + { + if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) + { + context.error_handler.NotMultipleOf(i, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + } + else if (!CheckDoubleMultipleOf(context, static_cast(i))) + return false; + } + + return true; + } + + bool CheckUint(Context &context, uint64_t i) const + { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) + { + DisallowedType(context, GetIntegerString()); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } + + if (!minimum_.IsNull()) + { + if (minimum_.IsUint64()) + { + if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) + { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + } + else if (minimum_.IsInt64()) + /* do nothing */; // i >= 0 > minimum.Getint64() + else if (!CheckDoubleMinimum(context, static_cast(i))) + return false; + } + + if (!maximum_.IsNull()) + { + if (maximum_.IsUint64()) + { + if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) + { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + } + else if (maximum_.IsInt64()) + { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ + } + else if (!CheckDoubleMaximum(context, static_cast(i))) + return false; + } + + if (!multipleOf_.IsNull()) + { + if (multipleOf_.IsUint64()) + { + if (i % multipleOf_.GetUint64() != 0) + { + context.error_handler.NotMultipleOf(i, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + } + else if (!CheckDoubleMultipleOf(context, static_cast(i))) + return false; + } + + return true; + } + + bool CheckDoubleMinimum(Context &context, double d) const + { + if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) + { + context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + return true; + } + + bool CheckDoubleMaximum(Context &context, double d) const + { + if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) + { + context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + return true; + } + + bool CheckDoubleMultipleOf(Context &context, double d) const + { + double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); + double q = std::floor(a / b); + double r = a - q * b; + if (r > 0.0) + { + context.error_handler.NotMultipleOf(d, multipleOf_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + return true; + } + + void DisallowedType(Context &context, const ValueType &actualType) const + { + ErrorHandler &eh = context.error_handler; + eh.StartDisallowedType(); + + if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString()); + if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString()); + if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString()); + if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString()); + if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString()); + + if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString()); + else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString()); + + eh.EndDisallowedType(actualType); + } + + struct Property + { + Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} + ~Property() + { + AllocatorType::Free(dependencies); + } + SValue name; + const SchemaType *schema; + const SchemaType *dependenciesSchema; + SizeType dependenciesValidatorIndex; + bool *dependencies; + bool required; + }; + + struct PatternProperty + { + PatternProperty() : schema(), pattern() {} + ~PatternProperty() + { + if (pattern) + { + pattern->~RegexType(); + AllocatorType::Free(pattern); + } + } + const SchemaType *schema; + RegexType *pattern; + }; + + AllocatorType *allocator_; + SValue uri_; + PointerType pointer_; + const SchemaType *typeless_; + uint64_t *enum_; + SizeType enumCount_; + SchemaArray allOf_; + SchemaArray anyOf_; + SchemaArray oneOf_; + const SchemaType *not_; + unsigned type_; // bitmask of kSchemaType + SizeType validatorCount_; + SizeType notValidatorIndex_; + + Property *properties_; + const SchemaType *additionalPropertiesSchema_; + PatternProperty *patternProperties_; + SizeType patternPropertyCount_; + SizeType propertyCount_; + SizeType minProperties_; + SizeType maxProperties_; + bool additionalProperties_; + bool hasDependencies_; + bool hasRequired_; + bool hasSchemaDependencies_; + + const SchemaType *additionalItemsSchema_; + const SchemaType *itemsList_; + const SchemaType **itemsTuple_; + SizeType itemsTupleCount_; + SizeType minItems_; + SizeType maxItems_; + bool additionalItems_; + bool uniqueItems_; + + RegexType *pattern_; + SizeType minLength_; + SizeType maxLength_; + + SValue minimum_; + SValue maximum_; + SValue multipleOf_; + bool exclusiveMinimum_; + bool exclusiveMaximum_; + + SizeType defaultValueLength_; + }; + + template + struct TokenHelper + { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack &documentStack, SizeType index) + { + *documentStack.template Push() = '/'; + char buffer[21]; + size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); + for (size_t i = 0; i < length; i++) + *documentStack.template Push() = static_cast(buffer[i]); + } + }; + +// Partial specialized version for char to prevent buffer copying. + template + struct TokenHelper + { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack &documentStack, SizeType index) + { + if (sizeof(SizeType) == 4) + { + char *buffer = documentStack.template Push(1 + 10); // '/' + uint + *buffer++ = '/'; + const char *end = internal::u32toa(index, buffer); + documentStack.template Pop(static_cast(10 - (end - buffer))); + } + else + { + char *buffer = documentStack.template Push(1 + 20); // '/' + uint64 + *buffer++ = '/'; + const char *end = internal::u64toa(index, buffer); + documentStack.template Pop(static_cast(20 - (end - buffer))); + } + } + }; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// IGenericRemoteSchemaDocumentProvider + +template +class IGenericRemoteSchemaDocumentProvider +{ + public: + typedef typename SchemaDocumentType::Ch Ch; + + virtual ~IGenericRemoteSchemaDocumentProvider() {} + virtual const SchemaDocumentType *GetRemoteDocument(const Ch *uri, SizeType length) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericSchemaDocument + +//! JSON schema document. +/*! + A JSON schema document is a compiled version of a JSON schema. + It is basically a tree of internal::Schema. + + \note This is an immutable class (i.e. its instance cannot be modified after construction). + \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. + \tparam Allocator Allocator type for allocating memory of this document. +*/ +template +class GenericSchemaDocument +{ + public: + typedef ValueT ValueType; + typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; + typedef Allocator AllocatorType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef internal::Schema SchemaType; + typedef GenericPointer PointerType; + typedef GenericValue URIType; + friend class internal::Schema; + template + friend class GenericSchemaValidator; + + //! Constructor. + /*! + Compile a JSON document into schema document. + + \param document A JSON document as source. + \param uri The base URI of this schema document for purposes of violation reporting. + \param uriLength Length of \c name, in code points. + \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. + \param allocator An optional allocator instance for allocating memory. Can be null. + */ + explicit GenericSchemaDocument(const ValueType &document, const Ch *uri = 0, SizeType uriLength = 0, + IRemoteSchemaDocumentProviderType *remoteProvider = 0, Allocator *allocator = 0) : + remoteProvider_(remoteProvider), + allocator_(allocator), + ownAllocator_(), + root_(), + typeless_(), + schemaMap_(allocator, kInitialSchemaMapSize), + schemaRef_(allocator, kInitialSchemaRefSize) + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + Ch noUri[1] = {0}; + uri_.SetString(uri ? uri : noUri, uriLength, *allocator_); + + typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); + new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_); + + // Generate root schema, it will call CreateSchema() to create sub-schemas, + // And call AddRefSchema() if there are $ref. + CreateSchemaRecursive(&root_, PointerType(), document, document); + + // Resolve $ref + while (!schemaRef_.Empty()) + { + SchemaRefEntry *refEntry = schemaRef_.template Pop(1); + if (const SchemaType *s = GetSchema(refEntry->target)) + { + if (refEntry->schema) + *refEntry->schema = s; + + // Create entry in map if not exist + if (!GetSchema(refEntry->source)) + { + new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false, allocator_); + } + } + else if (refEntry->schema) + *refEntry->schema = typeless_; + + refEntry->~SchemaRefEntry(); + } + + RAPIDJSON_ASSERT(root_ != 0); + + schemaRef_.ShrinkToFit(); // Deallocate all memory for ref + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericSchemaDocument(GenericSchemaDocument &&rhs) RAPIDJSON_NOEXCEPT : + remoteProvider_(rhs.remoteProvider_), + allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + root_(rhs.root_), + typeless_(rhs.typeless_), + schemaMap_(std::move(rhs.schemaMap_)), + schemaRef_(std::move(rhs.schemaRef_)), + uri_(std::move(rhs.uri_)) + { + rhs.remoteProvider_ = 0; + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.typeless_ = 0; + } +#endif + + //! Destructor + ~GenericSchemaDocument() + { + while (!schemaMap_.Empty()) + schemaMap_.template Pop(1)->~SchemaEntry(); + + if (typeless_) + { + typeless_->~SchemaType(); + Allocator::Free(typeless_); + } + + RAPIDJSON_DELETE(ownAllocator_); + } + + const URIType &GetURI() const + { + return uri_; + } + + //! Get the root schema. + const SchemaType &GetRoot() const + { + return *root_; + } + + private: + //! Prohibit copying + GenericSchemaDocument(const GenericSchemaDocument &); + //! Prohibit assignment + GenericSchemaDocument &operator=(const GenericSchemaDocument &); + + struct SchemaRefEntry + { + SchemaRefEntry(const PointerType &s, const PointerType &t, const SchemaType **outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} + PointerType source; + PointerType target; + const SchemaType **schema; + }; + + struct SchemaEntry + { + SchemaEntry(const PointerType &p, SchemaType *s, bool o, Allocator *allocator) : pointer(p, allocator), schema(s), owned(o) {} + ~SchemaEntry() + { + if (owned) + { + schema->~SchemaType(); + Allocator::Free(schema); + } + } + PointerType pointer; + SchemaType *schema; + bool owned; + }; + + void CreateSchemaRecursive(const SchemaType **schema, const PointerType &pointer, const ValueType &v, const ValueType &document) + { + if (schema) + *schema = typeless_; + + if (v.GetType() == kObjectType) + { + const SchemaType *s = GetSchema(pointer); + if (!s) + CreateSchema(schema, pointer, v, document); + + for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) + CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); + } + else if (v.GetType() == kArrayType) + for (SizeType i = 0; i < v.Size(); i++) + CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); + } + + void CreateSchema(const SchemaType **schema, const PointerType &pointer, const ValueType &v, const ValueType &document) + { + RAPIDJSON_ASSERT(pointer.IsValid()); + if (v.IsObject()) + { + if (!HandleRefSchema(pointer, schema, v, document)) + { + SchemaType *s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_); + new (schemaMap_.template Push()) SchemaEntry(pointer, s, true, allocator_); + if (schema) + *schema = s; + } + } + } + + bool HandleRefSchema(const PointerType &source, const SchemaType **schema, const ValueType &v, const ValueType &document) + { + static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' }; + static const ValueType kRefValue(kRefString, 4); + + typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue); + if (itr == v.MemberEnd()) + return false; + + if (itr->value.IsString()) + { + SizeType len = itr->value.GetStringLength(); + if (len > 0) + { + const Ch *s = itr->value.GetString(); + SizeType i = 0; + while (i < len && s[i] != '#') // Find the first # + i++; + + if (i > 0) // Remote reference, resolve immediately + { + if (remoteProvider_) + { + if (const GenericSchemaDocument *remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) + { + PointerType pointer(&s[i], len - i, allocator_); + if (pointer.IsValid()) + { + if (const SchemaType *sc = remoteDocument->GetSchema(pointer)) + { + if (schema) + *schema = sc; + new (schemaMap_.template Push()) SchemaEntry(source, const_cast(sc), false, allocator_); + return true; + } + } + } + } + } + else if (s[i] == '#') // Local reference, defer resolution + { + PointerType pointer(&s[i], len - i, allocator_); + if (pointer.IsValid()) + { + if (const ValueType *nv = pointer.Get(document)) + if (HandleRefSchema(source, schema, *nv, document)) + return true; + + new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema, allocator_); + return true; + } + } + } + } + return false; + } + + const SchemaType *GetSchema(const PointerType &pointer) const + { + for (const SchemaEntry *target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) + if (pointer == target->pointer) + return target->schema; + return 0; + } + + PointerType GetPointer(const SchemaType *schema) const + { + for (const SchemaEntry *target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) + if (schema == target->schema) + return target->pointer; + return PointerType(); + } + + const SchemaType *GetTypeless() const + { + return typeless_; + } + + static const size_t kInitialSchemaMapSize = 64; + static const size_t kInitialSchemaRefSize = 64; + + IRemoteSchemaDocumentProviderType *remoteProvider_; + Allocator *allocator_; + Allocator *ownAllocator_; + const SchemaType *root_; //!< Root schema. + SchemaType *typeless_; + internal::Stack schemaMap_; // Stores created Pointer -> Schemas + internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref + URIType uri_; +}; + +//! GenericSchemaDocument using Value type. +typedef GenericSchemaDocument SchemaDocument; +//! IGenericRemoteSchemaDocumentProvider using SchemaDocument. +typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; + +/////////////////////////////////////////////////////////////////////////////// +// GenericSchemaValidator + +//! JSON Schema Validator. +/*! + A SAX style JSON schema validator. + It uses a \c GenericSchemaDocument to validate SAX events. + It delegates the incoming SAX events to an output handler. + The default output handler does nothing. + It can be reused multiple times by calling \c Reset(). + + \tparam SchemaDocumentType Type of schema document. + \tparam OutputHandler Type of output handler. Default handler does nothing. + \tparam StateAllocator Allocator for storing the internal validation states. +*/ +template < + typename SchemaDocumentType, + typename OutputHandler = BaseReaderHandler, + typename StateAllocator = CrtAllocator> +class GenericSchemaValidator : + public internal::ISchemaStateFactory, + public internal::ISchemaValidator, + public internal::IValidationErrorHandler +{ + public: + typedef typename SchemaDocumentType::SchemaType SchemaType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename SchemaType::EncodingType EncodingType; + typedef typename SchemaType::SValue SValue; + typedef typename EncodingType::Ch Ch; + typedef GenericStringRef StringRefType; + typedef GenericValue ValueType; + + //! Constructor without output handler. + /*! + \param schemaDocument The schema document to conform to. + \param allocator Optional allocator for storing internal validation states. + \param schemaStackCapacity Optional initial capacity of schema path stack. + \param documentStackCapacity Optional initial capacity of document path stack. + */ + GenericSchemaValidator( + const SchemaDocumentType &schemaDocument, + StateAllocator *allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(schemaDocument.GetRoot()), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(0) +#endif + { + } + + //! Constructor with output handler. + /*! + \param schemaDocument The schema document to conform to. + \param allocator Optional allocator for storing internal validation states. + \param schemaStackCapacity Optional initial capacity of schema path stack. + \param documentStackCapacity Optional initial capacity of document path stack. + */ + GenericSchemaValidator( + const SchemaDocumentType &schemaDocument, + OutputHandler &outputHandler, + StateAllocator *allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(schemaDocument.GetRoot()), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(&outputHandler), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(0) +#endif + { + } + + //! Destructor. + ~GenericSchemaValidator() + { + Reset(); + RAPIDJSON_DELETE(ownStateAllocator_); + } + + //! Reset the internal states. + void Reset() + { + while (!schemaStack_.Empty()) + PopSchema(); + documentStack_.Clear(); + error_.SetObject(); + currentError_.SetNull(); + missingDependents_.SetNull(); + valid_ = true; + } + + //! Checks whether the current state is valid. + // Implementation of ISchemaValidator + bool IsValid() const override final + { + return valid_; + } + + //! Gets the error object. + ValueType &GetError() + { + return error_; + } + const ValueType &GetError() const + { + return error_; + } + + //! Gets the JSON pointer pointed to the invalid schema. + PointerType GetInvalidSchemaPointer() const + { + return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer(); + } + + //! Gets the keyword of invalid schema. + const Ch *GetInvalidSchemaKeyword() const + { + return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword; + } + + //! Gets the JSON pointer pointed to the invalid value. + PointerType GetInvalidDocumentPointer() const + { + if (documentStack_.Empty()) + { + return PointerType(); + } + else + { + return PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); + } + } + + void NotMultipleOf(int64_t actual, const SValue &expected) override final + { + AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected); + } + void NotMultipleOf(uint64_t actual, const SValue &expected) override final + { + AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected); + } + void NotMultipleOf(double actual, const SValue &expected) override final + { + AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected); + } + void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive) override final + { + AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void AboveMaximum(uint64_t actual, const SValue &expected, bool exclusive) override final + { + AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void AboveMaximum(double actual, const SValue &expected, bool exclusive) override final + { + AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive) override final + { + AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + void BelowMinimum(uint64_t actual, const SValue &expected, bool exclusive) override final + { + AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + void BelowMinimum(double actual, const SValue &expected, bool exclusive) override final + { + AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + + void TooLong(const Ch *str, SizeType length, SizeType expected) override final + { + AddNumberError(SchemaType::GetMaxLengthString(), + ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); + } + void TooShort(const Ch *str, SizeType length, SizeType expected) override final + { + AddNumberError(SchemaType::GetMinLengthString(), + ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); + } + void DoesNotMatch(const Ch *str, SizeType length) override final + { + currentError_.SetObject(); + currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator()); + AddCurrentError(SchemaType::GetPatternString()); + } + + void DisallowedItem(SizeType index) override final + { + currentError_.SetObject(); + currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator()); + AddCurrentError(SchemaType::GetAdditionalItemsString(), true); + } + void TooFewItems(SizeType actualCount, SizeType expectedCount) override final + { + AddNumberError(SchemaType::GetMinItemsString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void TooManyItems(SizeType actualCount, SizeType expectedCount) override final + { + AddNumberError(SchemaType::GetMaxItemsString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void DuplicateItems(SizeType index1, SizeType index2) override final + { + ValueType duplicates(kArrayType); + duplicates.PushBack(index1, GetStateAllocator()); + duplicates.PushBack(index2, GetStateAllocator()); + currentError_.SetObject(); + currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator()); + AddCurrentError(SchemaType::GetUniqueItemsString(), true); + } + + void TooManyProperties(SizeType actualCount, SizeType expectedCount) override final + { + AddNumberError(SchemaType::GetMaxPropertiesString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void TooFewProperties(SizeType actualCount, SizeType expectedCount) override final + { + AddNumberError(SchemaType::GetMinPropertiesString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void StartMissingProperties() override final + { + currentError_.SetArray(); + } + void AddMissingProperty(const SValue &name) override final + { + currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator()); + } + bool EndMissingProperties() override final + { + if (currentError_.Empty()) + return false; + ValueType error(kObjectType); + error.AddMember(GetMissingString(), currentError_, GetStateAllocator()); + currentError_ = error; + AddCurrentError(SchemaType::GetRequiredString()); + return true; + } + void PropertyViolations(ISchemaValidator **subvalidators, SizeType count) override final + { + for (SizeType i = 0; i < count; ++i) + MergeError(static_cast(subvalidators[i])->GetError()); + } + void DisallowedProperty(const Ch *name, SizeType length) override final + { + currentError_.SetObject(); + currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator()); + AddCurrentError(SchemaType::GetAdditionalPropertiesString(), true); + } + + void StartDependencyErrors() override final + { + currentError_.SetObject(); + } + void StartMissingDependentProperties() override final + { + missingDependents_.SetArray(); + } + void AddMissingDependentProperty(const SValue &targetName) override final + { + missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator()); + } + void EndMissingDependentProperties(const SValue &sourceName) override final + { + if (!missingDependents_.Empty()) + currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), + missingDependents_, GetStateAllocator()); + } + void AddDependencySchemaError(const SValue &sourceName, ISchemaValidator *subvalidator) override final + { + currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), + static_cast(subvalidator)->GetError(), GetStateAllocator()); + } + bool EndDependencyErrors() override final + { + if (currentError_.ObjectEmpty()) + return false; + ValueType error(kObjectType); + error.AddMember(GetErrorsString(), currentError_, GetStateAllocator()); + currentError_ = error; + AddCurrentError(SchemaType::GetDependenciesString()); + return true; + } + + void DisallowedValue() override final + { + currentError_.SetObject(); + AddCurrentError(SchemaType::GetEnumString()); + } + void StartDisallowedType() override final + { + currentError_.SetArray(); + } + void AddExpectedType(const typename SchemaType::ValueType &expectedType) override final + { + currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator()); + } + void EndDisallowedType(const typename SchemaType::ValueType &actualType) override final + { + ValueType error(kObjectType); + error.AddMember(GetExpectedString(), currentError_, GetStateAllocator()); + error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator()); + currentError_ = error; + AddCurrentError(SchemaType::GetTypeString()); + } + void NotAllOf(ISchemaValidator **subvalidators, SizeType count) override final + { + for (SizeType i = 0; i < count; ++i) + { + MergeError(static_cast(subvalidators[i])->GetError()); + } + } + void NoneOf(ISchemaValidator **subvalidators, SizeType count) override final + { + AddErrorArray(SchemaType::GetAnyOfString(), subvalidators, count); + } + void NotOneOf(ISchemaValidator **subvalidators, SizeType count) override final + { + AddErrorArray(SchemaType::GetOneOfString(), subvalidators, count); + } + void Disallowed() override final + { + currentError_.SetObject(); + AddCurrentError(SchemaType::GetNotString()); + } + +#define RAPIDJSON_STRING_(name, ...) \ + static const StringRefType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const StringRefType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1)); \ + return v;\ + } + + RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f') + RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f') + RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd') + RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l') + RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd') + RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g') + RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's') + RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's') + +#undef RAPIDJSON_STRING_ + +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ + RAPIDJSON_MULTILINEMACRO_BEGIN\ + *documentStack_.template Push() = '\0';\ + documentStack_.template Pop(1);\ + internal::PrintInvalidDocument(documentStack_.template Bottom());\ + RAPIDJSON_MULTILINEMACRO_END +#else +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() +#endif + +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ + if (!valid_) return false; \ + if (!BeginValue() || !CurrentSchema().method arg1) {\ + RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ + return valid_ = false;\ + } + +#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ + for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ + if (context->hasher)\ + static_cast(context->hasher)->method arg2;\ + if (context->validators)\ + for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ + static_cast(context->validators[i_])->method arg2;\ + if (context->patternPropertiesValidators)\ + for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ + static_cast(context->patternPropertiesValidators[i_])->method arg2;\ + } + +#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ + return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2) + +#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ + RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ + RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) + + bool Null() + { + RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); + } + bool Bool(bool b) + { + RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); + } + bool Int(int i) + { + RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); + } + bool Uint(unsigned u) + { + RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); + } + bool Int64(int64_t i) + { + RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); + } + bool Uint64(uint64_t u) + { + RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); + } + bool Double(double d) + { + RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); + } + bool RawNumber(const Ch *str, SizeType length, bool copy) + { + RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); + } + bool String(const Ch *str, SizeType length, bool copy) + { + RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); + } + + bool StartObject() + { + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); + return valid_ = !outputHandler_ || outputHandler_->StartObject(); + } + + bool Key(const Ch *str, SizeType len, bool copy) + { + if (!valid_) return false; + AppendToken(str, len); + if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); + return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); + } + + bool EndObject(SizeType memberCount) + { + if (!valid_) return false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); + if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); + } + + bool StartArray() + { + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); + return valid_ = !outputHandler_ || outputHandler_->StartArray(); + } + + bool EndArray(SizeType elementCount) + { + if (!valid_) return false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); + if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); + } + +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ +#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ +#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ + + // Implementation of ISchemaStateFactory + ISchemaValidator *CreateSchemaValidator(const SchemaType &root) override final + { + return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom(), documentStack_.GetSize(), +#if RAPIDJSON_SCHEMA_VERBOSE + depth_ + 1, +#endif + &GetStateAllocator()); + } + + void DestroySchemaValidator(ISchemaValidator *validator) override final + { + GenericSchemaValidator *v = static_cast(validator); + v->~GenericSchemaValidator(); + StateAllocator::Free(v); + } + + void *CreateHasher() override final + { + return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); + } + + uint64_t GetHashCode(void *hasher) override final + { + return static_cast(hasher)->GetHashCode(); + } + + void DestroryHasher(void *hasher) override final + { + HasherType *h = static_cast(hasher); + h->~HasherType(); + StateAllocator::Free(h); + } + + void *MallocState(size_t size) override final + { + return GetStateAllocator().Malloc(size); + } + + void FreeState(void *p) override final + { + StateAllocator::Free(p); + } + + private: + typedef typename SchemaType::Context Context; + typedef GenericValue, StateAllocator> HashCodeArray; + typedef internal::Hasher HasherType; + + GenericSchemaValidator( + const SchemaDocumentType &schemaDocument, + const SchemaType &root, + const char *basePath, size_t basePathSize, +#if RAPIDJSON_SCHEMA_VERBOSE + unsigned depth, +#endif + StateAllocator *allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(root), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(depth) +#endif + { + if (basePath && basePathSize) + memcpy(documentStack_.template Push(basePathSize), basePath, basePathSize); + } + + StateAllocator &GetStateAllocator() + { + if (!stateAllocator_) + stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)(); + return *stateAllocator_; + } + + bool BeginValue() + { + if (schemaStack_.Empty()) + PushSchema(root_); + else + { + if (CurrentContext().inArray) + internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); + + if (!CurrentSchema().BeginValue(CurrentContext())) + return false; + + SizeType count = CurrentContext().patternPropertiesSchemaCount; + const SchemaType **sa = CurrentContext().patternPropertiesSchemas; + typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; + bool valueUniqueness = CurrentContext().valueUniqueness; + RAPIDJSON_ASSERT(CurrentContext().valueSchema); + PushSchema(*CurrentContext().valueSchema); + + if (count > 0) + { + CurrentContext().objectPatternValidatorType = patternValidatorType; + ISchemaValidator ** &va = CurrentContext().patternPropertiesValidators; + SizeType &validatorCount = CurrentContext().patternPropertiesValidatorCount; + va = static_cast(MallocState(sizeof(ISchemaValidator *) * count)); + for (SizeType i = 0; i < count; i++) + va[validatorCount++] = CreateSchemaValidator(*sa[i]); + } + + CurrentContext().arrayUniqueness = valueUniqueness; + } + return true; + } + + bool EndValue() + { + if (!CurrentSchema().EndValue(CurrentContext())) + return false; + +#if RAPIDJSON_SCHEMA_VERBOSE + GenericStringBuffer sb; + schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); + + *documentStack_.template Push() = '\0'; + documentStack_.template Pop(1); + internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom()); +#endif + + uint64_t h = CurrentContext().arrayUniqueness ? static_cast(CurrentContext().hasher)->GetHashCode() : 0; + + PopSchema(); + + if (!schemaStack_.Empty()) + { + Context &context = CurrentContext(); + if (context.valueUniqueness) + { + HashCodeArray *a = static_cast(context.arrayElementHashCodes); + if (!a) + CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); + for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) + if (itr->GetUint64() == h) + { + DuplicateItems(static_cast(itr - a->Begin()), a->Size()); + RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString()); + } + a->PushBack(h, GetStateAllocator()); + } + } + + // Remove the last token of document pointer + while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/') + ; + + return true; + } + + void AppendToken(const Ch *str, SizeType len) + { + documentStack_.template Reserve(1 + len * 2); // worst case all characters are escaped as two characters + *documentStack_.template PushUnsafe() = '/'; + for (SizeType i = 0; i < len; i++) + { + if (str[i] == '~') + { + *documentStack_.template PushUnsafe() = '~'; + *documentStack_.template PushUnsafe() = '0'; + } + else if (str[i] == '/') + { + *documentStack_.template PushUnsafe() = '~'; + *documentStack_.template PushUnsafe() = '1'; + } + else + *documentStack_.template PushUnsafe() = str[i]; + } + } + + RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType &schema) + { + new (schemaStack_.template Push()) Context(*this, *this, &schema); + } + + RAPIDJSON_FORCEINLINE void PopSchema() + { + Context *c = schemaStack_.template Pop(1); + if (HashCodeArray *a = static_cast(c->arrayElementHashCodes)) + { + a->~HashCodeArray(); + StateAllocator::Free(a); + } + c->~Context(); + } + + void AddErrorLocation(ValueType &result, bool parent) + { + GenericStringBuffer sb; + PointerType instancePointer = GetInvalidDocumentPointer(); + ((parent && instancePointer.GetTokenCount() > 0) + ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1) + : instancePointer).StringifyUriFragment(sb); + ValueType instanceRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), + GetStateAllocator()); + result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator()); + sb.Clear(); + memcpy(sb.Push(CurrentSchema().GetURI().GetStringLength()), + CurrentSchema().GetURI().GetString(), + CurrentSchema().GetURI().GetStringLength() * sizeof(Ch)); + GetInvalidSchemaPointer().StringifyUriFragment(sb); + ValueType schemaRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), + GetStateAllocator()); + result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator()); + } + + void AddError(ValueType &keyword, ValueType &error) + { + typename ValueType::MemberIterator member = error_.FindMember(keyword); + if (member == error_.MemberEnd()) + error_.AddMember(keyword, error, GetStateAllocator()); + else + { + if (member->value.IsObject()) + { + ValueType errors(kArrayType); + errors.PushBack(member->value, GetStateAllocator()); + member->value = errors; + } + member->value.PushBack(error, GetStateAllocator()); + } + } + + void AddCurrentError(const typename SchemaType::ValueType &keyword, bool parent = false) + { + AddErrorLocation(currentError_, parent); + AddError(ValueType(keyword, GetStateAllocator(), false).Move(), currentError_); + } + + void MergeError(ValueType &other) + { + for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) + { + AddError(it->name, it->value); + } + } + + void AddNumberError(const typename SchemaType::ValueType &keyword, ValueType &actual, const SValue &expected, + const typename SchemaType::ValueType& (*exclusive)() = 0) + { + currentError_.SetObject(); + currentError_.AddMember(GetActualString(), actual, GetStateAllocator()); + currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator()); + if (exclusive) + currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator()); + AddCurrentError(keyword); + } + + void AddErrorArray(const typename SchemaType::ValueType &keyword, + ISchemaValidator **subvalidators, SizeType count) + { + ValueType errors(kArrayType); + for (SizeType i = 0; i < count; ++i) + errors.PushBack(static_cast(subvalidators[i])->GetError(), GetStateAllocator()); + currentError_.SetObject(); + currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator()); + AddCurrentError(keyword); + } + + const SchemaType &CurrentSchema() const + { + return *schemaStack_.template Top()->schema; + } + Context &CurrentContext() + { + return *schemaStack_.template Top(); + } + const Context &CurrentContext() const + { + return *schemaStack_.template Top(); + } + + static const size_t kDefaultSchemaStackCapacity = 1024; + static const size_t kDefaultDocumentStackCapacity = 256; + const SchemaDocumentType *schemaDocument_; + const SchemaType &root_; + StateAllocator *stateAllocator_; + StateAllocator *ownStateAllocator_; + internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) + internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) + OutputHandler *outputHandler_; + ValueType error_; + ValueType currentError_; + ValueType missingDependents_; + bool valid_; +#if RAPIDJSON_SCHEMA_VERBOSE + unsigned depth_; +#endif +}; + +typedef GenericSchemaValidator SchemaValidator; + +/////////////////////////////////////////////////////////////////////////////// +// SchemaValidatingReader + +//! A helper class for parsing with validation. +/*! + This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). + + \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept. + \tparam SourceEncoding Encoding of the input stream. + \tparam SchemaDocumentType Type of schema document. + \tparam StackAllocator Allocator type for stack. +*/ +template < + unsigned parseFlags, + typename InputStream, + typename SourceEncoding, + typename SchemaDocumentType = SchemaDocument, + typename StackAllocator = CrtAllocator> +class SchemaValidatingReader +{ + public: + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename InputStream::Ch Ch; + typedef GenericValue ValueType; + + //! Constructor + /*! + \param is Input stream. + \param sd Schema document. + */ + SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), error_(kObjectType), isValid_(true) {} + + template + bool operator()(Handler &handler) + { + GenericReader reader; + GenericSchemaValidator validator(sd_, handler); + parseResult_ = reader.template Parse(is_, validator); + + isValid_ = validator.IsValid(); + if (isValid_) + { + invalidSchemaPointer_ = PointerType(); + invalidSchemaKeyword_ = 0; + invalidDocumentPointer_ = PointerType(); + error_.SetObject(); + } + else + { + invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); + invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); + invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); + error_.CopyFrom(validator.GetError(), allocator_); + } + + return parseResult_; + } + + const ParseResult &GetParseResult() const + { + return parseResult_; + } + bool IsValid() const + { + return isValid_; + } + const PointerType &GetInvalidSchemaPointer() const + { + return invalidSchemaPointer_; + } + const Ch *GetInvalidSchemaKeyword() const + { + return invalidSchemaKeyword_; + } + const PointerType &GetInvalidDocumentPointer() const + { + return invalidDocumentPointer_; + } + const ValueType &GetError() const + { + return error_; + } + + private: + InputStream &is_; + const SchemaDocumentType &sd_; + + ParseResult parseResult_; + PointerType invalidSchemaPointer_; + const Ch *invalidSchemaKeyword_; + PointerType invalidDocumentPointer_; + StackAllocator allocator_; + ValueType error_; + bool isValid_; +}; + +RAPIDJSON_NAMESPACE_END +RAPIDJSON_DIAG_POP + +#endif // RAPIDJSON_SCHEMA_H_ diff --git a/contrib/world_builder/include/rapidjson/stream.h.bak b/contrib/world_builder/include/rapidjson/stream.h.bak new file mode 100644 index 00000000000..adf4ed30cff --- /dev/null +++ b/contrib/world_builder/include/rapidjson/stream.h.bak @@ -0,0 +1,312 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#include "rapidjson.h" + +#ifndef RAPIDJSON_STREAM_H_ +#define RAPIDJSON_STREAM_H_ + +#include "encodings.h" + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Stream + +/*! \class rapidjson::Stream + \brief Concept for reading and writing characters. + + For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). + + For write-only stream, only need to implement Put() and Flush(). + +\code +concept Stream { + typename Ch; //!< Character type of the stream. + + //! Read the current character from stream without moving the read cursor. + Ch Peek() const; + + //! Read the current character from stream and moving the read cursor to next character. + Ch Take(); + + //! Get the current read cursor. + //! \return Number of characters read from start. + size_t Tell(); + + //! Begin writing operation at the current read pointer. + //! \return The begin writer pointer. + Ch* PutBegin(); + + //! Write a character. + void Put(Ch c); + + //! Flush the buffer. + void Flush(); + + //! End the writing operation. + //! \param begin The begin write pointer returned by PutBegin(). + //! \return Number of characters written. + size_t PutEnd(Ch* begin); +} +\endcode +*/ + +//! Provides additional information for stream. +/*! + By using traits pattern, this type provides a default configuration for stream. + For custom stream, this type can be specialized for other configuration. + See TEST(Reader, CustomStringStream) in readertest.cpp for example. +*/ +template +struct StreamTraits +{ + //! Whether to make local copy of stream for optimization during parsing. + /*! + By default, for safety, streams do not use local copy optimization. + Stream that can be copied fast should specialize this, like StreamTraits. + */ + enum { copyOptimization = 0 }; +}; + +//! Reserve n characters for writing to a stream. +template +inline void PutReserve(Stream &stream, size_t count) +{ + (void)stream; + (void)count; +} + +//! Write character to a stream, presuming buffer is reserved. +template +inline void PutUnsafe(Stream &stream, typename Stream::Ch c) +{ + stream.Put(c); +} + +//! Put N copies of a character to a stream. +template +inline void PutN(Stream &stream, Ch c, size_t n) +{ + PutReserve(stream, n); + for (size_t i = 0; i < n; i++) + PutUnsafe(stream, c); +} + +/////////////////////////////////////////////////////////////////////////////// +// GenericStreamWrapper + +//! A Stream Wrapper +/*! \tThis string stream is a wrapper for any stream by just forwarding any + \treceived message to the origin stream. + \note implements Stream concept +*/ + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +template > +class GenericStreamWrapper +{ + public: + typedef typename Encoding::Ch Ch; + GenericStreamWrapper(InputStream &is): is_(is) {} + + Ch Peek() const + { + return is_.Peek(); + } + Ch Take() + { + return is_.Take(); + } + size_t Tell() + { + return is_.Tell(); + } + Ch *PutBegin() + { + return is_.PutBegin(); + } + void Put(Ch ch) + { + is_.Put(ch); + } + void Flush() + { + is_.Flush(); + } + size_t PutEnd(Ch *ch) + { + return is_.PutEnd(ch); + } + + // wrapper for MemoryStream + const Ch *Peek4() const + { + return is_.Peek4(); + } + + // wrapper for AutoUTFInputStream + UTFType GetType() const + { + return is_.GetType(); + } + bool HasBOM() const + { + return is_.HasBOM(); + } + + protected: + InputStream &is_; +}; + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_POP +#endif + +/////////////////////////////////////////////////////////////////////////////// +// StringStream + +//! Read-only string stream. +/*! \note implements Stream concept +*/ +template +struct GenericStringStream +{ + typedef typename Encoding::Ch Ch; + + GenericStringStream(const Ch *src) : src_(src), head_(src) {} + + Ch Peek() const + { + return *src_; + } + Ch Take() + { + return *src_++; + } + size_t Tell() const + { + return static_cast(src_ - head_); + } + + Ch *PutBegin() + { + RAPIDJSON_ASSERT(false); + return 0; + } + void Put(Ch) + { + RAPIDJSON_ASSERT(false); + } + void Flush() + { + RAPIDJSON_ASSERT(false); + } + size_t PutEnd(Ch *) + { + RAPIDJSON_ASSERT(false); + return 0; + } + + const Ch *src_; //!< Current read position. + const Ch *head_; //!< Original head of the string. +}; + +template +struct StreamTraits > +{ + enum { copyOptimization = 1 }; +}; + +//! String stream with UTF8 encoding. +typedef GenericStringStream > StringStream; + +/////////////////////////////////////////////////////////////////////////////// +// InsituStringStream + +//! A read-write string stream. +/*! This string stream is particularly designed for in-situ parsing. + \note implements Stream concept +*/ +template +struct GenericInsituStringStream +{ + typedef typename Encoding::Ch Ch; + + GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} + + // Read + Ch Peek() + { + return *src_; + } + Ch Take() + { + return *src_++; + } + size_t Tell() + { + return static_cast(src_ - head_); + } + + // Write + void Put(Ch c) + { + RAPIDJSON_ASSERT(dst_ != 0); + *dst_++ = c; + } + + Ch *PutBegin() + { + return dst_ = src_; + } + size_t PutEnd(Ch *begin) + { + return static_cast(dst_ - begin); + } + void Flush() {} + + Ch *Push(size_t count) + { + Ch *begin = dst_; + dst_ += count; + return begin; + } + void Pop(size_t count) + { + dst_ -= count; + } + + Ch *src_; + Ch *dst_; + Ch *head_; +}; + +template +struct StreamTraits > +{ + enum { copyOptimization = 1 }; +}; + +//! Insitu string stream with UTF8 encoding. +typedef GenericInsituStringStream > InsituStringStream; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STREAM_H_ diff --git a/contrib/world_builder/include/rapidjson/stringbuffer.h.bak b/contrib/world_builder/include/rapidjson/stringbuffer.h.bak new file mode 100644 index 00000000000..1e917796e4c --- /dev/null +++ b/contrib/world_builder/include/rapidjson/stringbuffer.h.bak @@ -0,0 +1,155 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_STRINGBUFFER_H_ +#define RAPIDJSON_STRINGBUFFER_H_ + +#include "stream.h" +#include "internal/stack.h" + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS +#include // std::move +#endif + +#include "internal/stack.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Represents an in-memory output stream. +/*! + \tparam Encoding Encoding of the stream. + \tparam Allocator type for allocating memory buffer. + \note implements Stream concept +*/ +template +class GenericStringBuffer +{ + public: + typedef typename Encoding::Ch Ch; + + GenericStringBuffer(Allocator *allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericStringBuffer(GenericStringBuffer &&rhs) : stack_(std::move(rhs.stack_)) {} + GenericStringBuffer &operator=(GenericStringBuffer&& rhs) + { + if (&rhs != this) + stack_ = std::move(rhs.stack_); + return *this; + } +#endif + + void Put(Ch c) + { + *stack_.template Push() = c; + } + void PutUnsafe(Ch c) + { + *stack_.template PushUnsafe() = c; + } + void Flush() {} + + void Clear() + { + stack_.Clear(); + } + void ShrinkToFit() + { + // Push and pop a null terminator. This is safe. + *stack_.template Push() = '\0'; + stack_.ShrinkToFit(); + stack_.template Pop(1); + } + + void Reserve(size_t count) + { + stack_.template Reserve(count); + } + Ch *Push(size_t count) + { + return stack_.template Push(count); + } + Ch *PushUnsafe(size_t count) + { + return stack_.template PushUnsafe(count); + } + void Pop(size_t count) + { + stack_.template Pop(count); + } + + const Ch *GetString() const + { + // Push and pop a null terminator. This is safe. + *stack_.template Push() = '\0'; + stack_.template Pop(1); + + return stack_.template Bottom(); + } + + //! Get the size of string in bytes in the string buffer. + size_t GetSize() const + { + return stack_.GetSize(); + } + + //! Get the length of string in Ch in the string buffer. + size_t GetLength() const + { + return stack_.GetSize() / sizeof(Ch); + } + + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; + + private: + // Prohibit copy constructor & assignment operator. + GenericStringBuffer(const GenericStringBuffer &); + GenericStringBuffer &operator=(const GenericStringBuffer &); +}; + +//! String buffer with UTF8 encoding +typedef GenericStringBuffer > StringBuffer; + +template +inline void PutReserve(GenericStringBuffer &stream, size_t count) +{ + stream.Reserve(count); +} + +template +inline void PutUnsafe(GenericStringBuffer &stream, typename Encoding::Ch c) +{ + stream.PutUnsafe(c); +} + +//! Implement specialized version of PutN() with memset() for better performance. +template<> +inline void PutN(GenericStringBuffer > &stream, char c, size_t n) +{ + std::memset(stream.stack_.Push(n), c, n * sizeof(c)); +} + +RAPIDJSON_NAMESPACE_END + +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_STRINGBUFFER_H_ diff --git a/contrib/world_builder/include/rapidjson/writer.h.bak b/contrib/world_builder/include/rapidjson/writer.h.bak new file mode 100644 index 00000000000..815dfcdde83 --- /dev/null +++ b/contrib/world_builder/include/rapidjson/writer.h.bak @@ -0,0 +1,867 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_WRITER_H_ +#define RAPIDJSON_WRITER_H_ + +#include "stream.h" +#include "internal/meta.h" +#include "internal/stack.h" +#include "internal/strfunc.h" +#include "internal/dtoa.h" +#include "internal/itoa.h" +#include "stringbuffer.h" +#include // placement new + +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) +#include +#pragma intrinsic(_BitScanForward) +#endif +#ifdef RAPIDJSON_SSE42 +#include +#elif defined(RAPIDJSON_SSE2) +#include +#elif defined(RAPIDJSON_NEON) +#include +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(c++98-compat) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// WriteFlag + +/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG + \brief User-defined kWriteDefaultFlags definition. + + User can define this as any \c WriteFlag combinations. +*/ +#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS +#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags +#endif + +//! Combination of writeFlags +enum WriteFlag +{ + kWriteNoFlags = 0, //!< No flags are set. + kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. + kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. + kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS +}; + +//! JSON writer +/*! Writer implements the concept Handler. + It generates JSON text by events to an output os. + + User may programmatically calls the functions of a writer to generate JSON text. + + On the other side, a writer can also be passed to objects that generates events, + + for example Reader::Parse() and Document::Accept(). + + \tparam OutputStream Type of output stream. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam StackAllocator Type of allocator for allocating memory of stack. + \note implements Handler concept +*/ +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> +class Writer +{ + public: + typedef typename SourceEncoding::Ch Ch; + + static const int kDefaultMaxDecimalPlaces = 324; + + //! Constructor + /*! \param os Output stream. + \param stackAllocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + explicit + Writer(OutputStream &os, StackAllocator *stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(&os), level_stack_(stackAllocator, levelDepth *sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} + + explicit + Writer(StackAllocator *allocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(0), level_stack_(allocator, levelDepth *sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Writer(Writer &&rhs) : + os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) + { + rhs.os_ = 0; + } +#endif + + //! Reset the writer with a new stream. + /*! + This function reset the writer with a new stream and default settings, + in order to make a Writer object reusable for output multiple JSONs. + + \param os New output stream. + \code + Writer writer(os1); + writer.StartObject(); + // ... + writer.EndObject(); + + writer.Reset(os2); + writer.StartObject(); + // ... + writer.EndObject(); + \endcode + */ + void Reset(OutputStream &os) + { + os_ = &os; + hasRoot_ = false; + level_stack_.Clear(); + } + + //! Checks whether the output is a complete JSON. + /*! + A complete JSON has a complete root object or array. + */ + bool IsComplete() const + { + return hasRoot_ && level_stack_.Empty(); + } + + int GetMaxDecimalPlaces() const + { + return maxDecimalPlaces_; + } + + //! Sets the maximum number of decimal places for double output. + /*! + This setting truncates the output with specified number of decimal places. + + For example, + + \code + writer.SetMaxDecimalPlaces(3); + writer.StartArray(); + writer.Double(0.12345); // "0.123" + writer.Double(0.0001); // "0.0" + writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent) + writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent) + writer.EndArray(); + \endcode + + The default setting does not truncate any decimal places. You can restore to this setting by calling + \code + writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); + \endcode + */ + void SetMaxDecimalPlaces(int maxDecimalPlaces) + { + maxDecimalPlaces_ = maxDecimalPlaces; + } + + /*!@name Implementation of Handler + \see Handler + */ + //@{ + + bool Null() + { + Prefix(kNullType); + return EndValue(WriteNull()); + } + bool Bool(bool b) + { + Prefix(b ? kTrueType : kFalseType); + return EndValue(WriteBool(b)); + } + bool Int(int i) + { + Prefix(kNumberType); + return EndValue(WriteInt(i)); + } + bool Uint(unsigned u) + { + Prefix(kNumberType); + return EndValue(WriteUint(u)); + } + bool Int64(int64_t i64) + { + Prefix(kNumberType); + return EndValue(WriteInt64(i64)); + } + bool Uint64(uint64_t u64) + { + Prefix(kNumberType); + return EndValue(WriteUint64(u64)); + } + + //! Writes the given \c double value to the stream + /*! + \param d The value to be written. + \return Whether it is succeed. + */ + bool Double(double d) + { + Prefix(kNumberType); + return EndValue(WriteDouble(d)); + } + + bool RawNumber(const Ch *str, SizeType length, bool copy = false) + { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + Prefix(kNumberType); + return EndValue(WriteString(str, length)); + } + + bool String(const Ch *str, SizeType length, bool copy = false) + { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + Prefix(kStringType); + return EndValue(WriteString(str, length)); + } + +#if RAPIDJSON_HAS_STDSTRING + bool String(const std::basic_string &str) + { + return String(str.data(), SizeType(str.size())); + } +#endif + + bool StartObject() + { + Prefix(kObjectType); + new (level_stack_.template Push()) Level(false); + return WriteStartObject(); + } + + bool Key(const Ch *str, SizeType length, bool copy = false) + { + return String(str, length, copy); + } + +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string &str) + { + return Key(str.data(), SizeType(str.size())); + } +#endif + + bool EndObject(SizeType memberCount = 0) + { + (void)memberCount; + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object + RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value + level_stack_.template Pop(1); + return EndValue(WriteEndObject()); + } + + bool StartArray() + { + Prefix(kArrayType); + new (level_stack_.template Push()) Level(true); + return WriteStartArray(); + } + + bool EndArray(SizeType elementCount = 0) + { + (void)elementCount; + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); + RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); + level_stack_.template Pop(1); + return EndValue(WriteEndArray()); + } + //@} + + /*! @name Convenience extensions */ + //@{ + + //! Simpler but slower overload. + bool String(const Ch *const &str) + { + return String(str, internal::StrLen(str)); + } + bool Key(const Ch *const &str) + { + return Key(str, internal::StrLen(str)); + } + + //@} + + //! Write a raw JSON value. + /*! + For user to write a stringified JSON as a value. + + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. + \param length Length of the json. + \param type Type of the root of json. + */ + bool RawValue(const Ch *json, size_t length, Type type) + { + RAPIDJSON_ASSERT(json != 0); + Prefix(type); + return EndValue(WriteRawValue(json, length)); + } + + //! Flush the output stream. + /*! + Allows the user to flush the output stream immediately. + */ + void Flush() + { + os_->Flush(); + } + + protected: + //! Information for each nested level + struct Level + { + Level(bool inArray_) : valueCount(0), inArray(inArray_) {} + size_t valueCount; //!< number of values in this level + bool inArray; //!< true if in array, otherwise in object + }; + + static const size_t kDefaultLevelDepth = 32; + + bool WriteNull() + { + PutReserve(*os_, 4); + PutUnsafe(*os_, 'n'); + PutUnsafe(*os_, 'u'); + PutUnsafe(*os_, 'l'); + PutUnsafe(*os_, 'l'); + return true; + } + + bool WriteBool(bool b) + { + if (b) + { + PutReserve(*os_, 4); + PutUnsafe(*os_, 't'); + PutUnsafe(*os_, 'r'); + PutUnsafe(*os_, 'u'); + PutUnsafe(*os_, 'e'); + } + else + { + PutReserve(*os_, 5); + PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'a'); + PutUnsafe(*os_, 'l'); + PutUnsafe(*os_, 's'); + PutUnsafe(*os_, 'e'); + } + return true; + } + + bool WriteInt(int i) + { + char buffer[11]; + const char *end = internal::i32toa(i, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (const char *p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteUint(unsigned u) + { + char buffer[10]; + const char *end = internal::u32toa(u, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (const char *p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteInt64(int64_t i64) + { + char buffer[21]; + const char *end = internal::i64toa(i64, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (const char *p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteUint64(uint64_t u64) + { + char buffer[20]; + char *end = internal::u64toa(u64, buffer); + PutReserve(*os_, static_cast(end - buffer)); + for (char *p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteDouble(double d) + { + if (internal::Double(d).IsNanOrInf()) + { + if (!(writeFlags & kWriteNanAndInfFlag)) + return false; + if (internal::Double(d).IsNan()) + { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); + PutUnsafe(*os_, 'a'); + PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) + { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); + PutUnsafe(*os_, 'n'); + PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); + PutUnsafe(*os_, 'n'); + PutUnsafe(*os_, 'i'); + PutUnsafe(*os_, 't'); + PutUnsafe(*os_, 'y'); + return true; + } + + char buffer[25]; + char *end = internal::dtoa(d, buffer, maxDecimalPlaces_); + PutReserve(*os_, static_cast(end - buffer)); + for (char *p = buffer; p != end; ++p) + PutUnsafe(*os_, static_cast(*p)); + return true; + } + + bool WriteString(const Ch *str, SizeType length, bool quotes = true) + { + static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + static const char escape[256] = + { +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 + 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 + Z16, Z16, // 30~4F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF +#undef Z16 + }; + + if (quotes) + { + if (TargetEncoding::supportUnicode) + PutReserve(*os_, 2 + length * 6); // "\uxxxx..." + else + PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." + } + else + { + if (TargetEncoding::supportUnicode) + PutReserve(*os_, length * 6); // "\uxxxx..." + else + PutReserve(*os_, length * 12); // "\uxxxx\uyyyy..." + } + + if (quotes) + PutUnsafe(*os_, '\"'); + GenericStringStream is(str); + while (ScanWriteUnescapedString(is, length)) + { + const Ch c = is.Peek(); + if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) + { + // Unicode escaping + unsigned codepoint; + if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) + return false; + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, 'u'); + if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) + { + PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); + } + else + { + RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); + // Surrogate pair + unsigned s = codepoint - 0x010000; + unsigned lead = (s >> 10) + 0xD800; + unsigned trail = (s & 0x3FF) + 0xDC00; + PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(lead ) & 15]); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, 'u'); + PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(trail ) & 15]); + } + } + else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) + { + is.Take(); + if (quotes) + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, static_cast(escape[static_cast(c)])); + if (escape[static_cast(c)] == 'u') + { + PutUnsafe(*os_, '0'); + PutUnsafe(*os_, '0'); + PutUnsafe(*os_, hexDigits[static_cast(c) >> 4]); + PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); + } + } + else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + Transcoder::Validate(is, *os_) : + Transcoder::TranscodeUnsafe(is, *os_)))) + return false; + } + if (quotes) + PutUnsafe(*os_, '\"'); + return true; + } + + bool ScanWriteUnescapedString(GenericStringStream &is, size_t length) + { + return RAPIDJSON_LIKELY(is.Tell() < length); + } + + bool WriteStartObject() + { + os_->Put('{'); + return true; + } + bool WriteEndObject() + { + os_->Put('}'); + return true; + } + bool WriteStartArray() + { + os_->Put('['); + return true; + } + bool WriteEndArray() + { + os_->Put(']'); + return true; + } + + bool WriteRawValue(const Ch *json, size_t length) + { + PutReserve(*os_, length); + GenericStringStream is(json); + while (RAPIDJSON_LIKELY(is.Tell() < length)) + { + RAPIDJSON_ASSERT(is.Peek() != '\0'); + if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + Transcoder::Validate(is, *os_) : + Transcoder::TranscodeUnsafe(is, *os_)))) + return false; + } + return true; + } + + void Prefix(Type type) + { + (void)type; + if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) // this value is not at root + { + Level *level = level_stack_.template Top(); + if (level->valueCount > 0) + { + if (level->inArray) + os_->Put(','); // add comma if it is not the first element in array + else // in object + os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else + { + RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. + hasRoot_ = true; + } + } + + // Flush the value if it is the top level one. + bool EndValue(bool ret) + { + if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text + Flush(); + return ret; + } + + OutputStream *os_; + internal::Stack level_stack_; + int maxDecimalPlaces_; + bool hasRoot_; + + private: + // Prohibit copy constructor & assignment operator. + Writer(const Writer &); + Writer &operator=(const Writer &); +}; + +// Full specialization for StringStream to prevent memory copying + +template<> +inline bool Writer::WriteInt(int i) +{ + char *buffer = os_->Push(11); + const char *end = internal::i32toa(i, buffer); + os_->Pop(static_cast(11 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteUint(unsigned u) +{ + char *buffer = os_->Push(10); + const char *end = internal::u32toa(u, buffer); + os_->Pop(static_cast(10 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteInt64(int64_t i64) +{ + char *buffer = os_->Push(21); + const char *end = internal::i64toa(i64, buffer); + os_->Pop(static_cast(21 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteUint64(uint64_t u) +{ + char *buffer = os_->Push(20); + const char *end = internal::u64toa(u, buffer); + os_->Pop(static_cast(20 - (end - buffer))); + return true; +} + +template<> +inline bool Writer::WriteDouble(double d) +{ + if (internal::Double(d).IsNanOrInf()) + { + // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). + if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) + return false; + if (internal::Double(d).IsNan()) + { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); + PutUnsafe(*os_, 'a'); + PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) + { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); + PutUnsafe(*os_, 'n'); + PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); + PutUnsafe(*os_, 'n'); + PutUnsafe(*os_, 'i'); + PutUnsafe(*os_, 't'); + PutUnsafe(*os_, 'y'); + return true; + } + + char *buffer = os_->Push(25); + char *end = internal::dtoa(d, buffer, maxDecimalPlaces_); + os_->Pop(static_cast(25 - (end - buffer))); + return true; +} + +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream &is, size_t length) +{ + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); + + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; + + const char *p = is.src_; + const char *end = is.head_ + length; + const char *nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + const char *endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); + if (nextAligned > end) + return true; + + while (p != nextAligned) + if (*p < 0x20 || *p == '\"' || *p == '\\') + { + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); + } + else + os_->PutUnsafe(*p++); + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (; p != endAligned; p += 16) + { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) // some of characters is escaped + { + SizeType len; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + len = offset; +#else + len = static_cast(__builtin_ffs(r) - 1); +#endif + char *q = reinterpret_cast(os_->PushUnsafe(len)); + for (size_t i = 0; i < len; i++) + q[i] = p[i]; + + p += len; + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); + } + + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); +} +#elif defined(RAPIDJSON_NEON) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream &is, size_t length) +{ + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); + + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; + + const char *p = is.src_; + const char *end = is.head_ + length; + const char *nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + const char *endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); + if (nextAligned > end) + return true; + + while (p != nextAligned) + if (*p < 0x20 || *p == '\"' || *p == '\\') + { + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); + } + else + os_->PutUnsafe(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (; p != endAligned; p += 16) + { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType len = 0; + bool escaped = false; + if (low == 0) + { + if (high != 0) + { + unsigned lz = (unsigned)__builtin_clzll(high); + len = 8 + (lz >> 3); + escaped = true; + } + } + else + { + unsigned lz = (unsigned)__builtin_clzll(low); + len = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) // some of characters is escaped + { + char *q = reinterpret_cast(os_->PushUnsafe(len)); + for (size_t i = 0; i < len; i++) + q[i] = p[i]; + + p += len; + break; + } + vst1q_u8(reinterpret_cast(os_->PushUnsafe(16)), s); + } + + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); +} +#endif // RAPIDJSON_NEON + +RAPIDJSON_NAMESPACE_END + +#if defined(_MSC_VER) || defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/contrib/world_builder/include/visualization/main.h.bak b/contrib/world_builder/include/visualization/main.h.bak new file mode 100644 index 00000000000..de5685a9a84 --- /dev/null +++ b/contrib/world_builder/include/visualization/main.h.bak @@ -0,0 +1,39 @@ +/* + Copyright (C) 2020 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_VISUALIZATION_MAIN_H_ +#define WORLD_BUILDER_VISUALIZATION_MAIN_H_ + +#include +#include + +void project_on_sphere(double, double &, double &, double &); + +void lay_points(double x1, double y1, double z1, + double x2, double y2, double z2, + double x3, double y3, double z3, + double x4, double y4, double z4, + std::vector &x, std::vector &y, std::vector &z, + std::vector &hull, size_t level); + +std::vector get_command_line_options_vector(int argc, char **argv); + +bool find_command_line_option(char **begin, char **end, const std::string &option); + +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/assert.h.bak b/contrib/world_builder/include/world_builder/assert.h.bak new file mode 100644 index 00000000000..c0b563cfd07 --- /dev/null +++ b/contrib/world_builder/include/world_builder/assert.h.bak @@ -0,0 +1,63 @@ +/* + 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 . +*/ +#ifndef WORLD_BUILDER_ASSERT_H_ +#define WORLD_BUILDER_ASSERT_H_ + +#include + +namespace WorldBuilder +{ +#ifndef NDEBUG +# define WBAssert(condition, message) \ + do { \ + if (! (condition)) { \ + std::stringstream smessage; \ + smessage << "Assert `" #condition "` failed in " << __FILE__ \ + << " at line " << __LINE__ << ": " << message << std::endl << std::endl << "Error not recoverable, aborting program."; \ + throw std::runtime_error(smessage.str()); \ + } \ + } while (false) +#else +# define WBAssert(condition, message) do { } while (false) +#endif + +# define WBAssertThrow(condition, message) \ + do { \ + if (! (condition)) { \ + std::stringstream smessage; \ + smessage << "AssertThrow `" #condition "` failed in " << __FILE__ \ + << " at line " << __LINE__ << ": " << message << std::endl << std::endl << "Error not recoverable, aborting program."; \ + throw std::runtime_error(smessage.str()); \ + } \ + } while (false) + + +# define WBAssertThrowExc(condition, exc, message) \ + do { \ + if (! (condition)) { \ + exc \ + std::stringstream smessage; \ + smessage << "AssertThrow `" #condition "` failed in " << __FILE__ \ + << " at line " << __LINE__ << ": " << message << std::endl; \ + throw std::runtime_error(smessage.str()); \ + } \ + } while (false) +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/bounding_box.h.bak b/contrib/world_builder/include/world_builder/bounding_box.h.bak new file mode 100644 index 00000000000..808c15cb8f0 --- /dev/null +++ b/contrib/world_builder/include/world_builder/bounding_box.h.bak @@ -0,0 +1,513 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2017 - 2021 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, 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.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE.md at +// the top level directory of deal.II. +// +// --------------------------------------------------------------------- + +#ifndef WORLD_BUILDER_BOUNDING_BOX_H +#define WORLD_BUILDER_BOUNDING_BOX_H + + +#include "assert.h" +#include "point.h" + +#include + + +namespace WorldBuilder +{ + + + /** + * A class that represents a box of arbitrary dimension spacedim and + * with sides parallel to the coordinate axes, that is, a region + * @f[ + * [x_0^L, x_0^U] \times ... \times [x_{spacedim-1}^L, x_{spacedim-1}^U], + * @f] + * where $(x_0^L , ..., x_{spacedim-1}^L)$ and $(x_0^U , ..., x_{spacedim-1}^U)$ + * denote the two vertices (bottom left and top right) which are used to + * represent the box. The quantities $x_k^L$ and $x_k^U$ denote the "lower" + * and "upper" bounds of values that are within the box for each coordinate + * direction $k$. + * + * Geometrically, a bounding box is thus: + * - 1D: a segment (represented by its vertices in the proper order) + * - 2D: a rectangle (represented by the vertices V at bottom left, top right) + * @code + * .--------V + * | | + * V--------. + * @endcode + * + * - 3D: a cuboid (in which case the two vertices V follow the convention and + * are not owned by the same face) + * @code + * .------V + * / /| + * .------. | + * | | / + * | |/ + * V------. + * @endcode + * + * Bounding boxes are, for example, useful in parallel distributed meshes to + * give a general description of the owners of each portion of the mesh. More + * generally, bounding boxes are often used to roughly describe a region of + * space in which an object is contained; if a candidate point is not within + * the bounding box (a test that is cheap to execute), then it is not necessary + * to perform an expensive test whether the candidate point is in fact inside + * the object itself. Bounding boxes are therefore often used as a first, + * cheap rejection test before more detailed checks. As such, bounding boxes + * serve many of the same purposes as the + * [convex hull](https://en.wikipedia.org/wiki/Convex_hull), for which it is + * also relatively straightforward to compute whether a point is inside or + * outside, though not quite as cheap as for the bounding box. + * + * Taking the cross section of a BoundingBox orthogonal to a given + * direction gives a box in one dimension lower: BoundingBox. + * In 3D, the 2 coordinates of the cross section of BoundingBox<3> can be + * ordered in 2 different ways. That is, if we take the cross section orthogonal + * to the y direction we could either order a 3D-coordinate into a + * 2D-coordinate as $(x,z)$ or as $(z,x)$. This class uses the second + * convention, corresponding to the coordinates being ordered cyclicly + * $x \rightarrow y \rightarrow z \rightarrow x \rightarrow ... $ + * To be precise, if we take a cross section: + * + * | Orthogonal to | Cross section coordinates ordered as | + * |:-------------:|:------------------------------------:| + * | x | (y, z) | + * | y | (z, x) | + * | z | (x, y) | + * + * This is according to the convention set by the function + * coordinate_to_one_dim_higher. + * + * @note The majority of this class is copied from the deal.II library. + */ + template + class BoundingBox + { + public: + /** + * Standard constructor. Creates an object that corresponds to a + * box that corresponds to the entire space, i.e. a degenerate + * box with end points at minus and plus infinity. + */ + BoundingBox(); + + /** + * Standard constructor for non-empty boxes: it uses a pair of points + * which describe the box: one for the bottom and one for the top + * corner. + */ + BoundingBox(const std::pair, Point> + &boundary_points); + + /** + * Construct the bounding box that encloses all the points in the given + * container. + * + * The constructor supports any Container that provides begin() and end() + * iterators to Point elements. + */ + template + BoundingBox(const Container &points); + + /** + * Return a reference to the boundary_points + */ + std::pair, Point> &get_boundary_points(); + + /** + * Return a const reference to the boundary_points + */ + const std::pair, Point> &get_boundary_points() const; + + /** + * Test for equality. + */ + bool + operator==(const BoundingBox &box) const; + + /** + * Test for inequality. + */ + bool + operator!=(const BoundingBox &box) const; + + /** + * Enlarge the current object so that it contains @p other_bbox . + * If the current object already contains @p other_bbox then it is not changed + * by this function. + */ + void + merge_with(const BoundingBox &other_bbox); + + /** + * Return true if the point is inside the Bounding Box, false otherwise. The + * parameter @p tolerance is a factor by which the bounding box is enlarged + * relative to the dimensions of the bounding box in order to determine in a + * numerically robust way whether the point is inside. + * + * This function is a wrapper for the function point_inside_implementation + * to also test point+2pi is the longtiude is smaller then zero and point-2pi + * if the longitude is larger than zero. + */ + bool + point_inside( + const Point &p, + const double tolerance = std::numeric_limits::epsilon()) const; + + /** + * Increase (or decrease) the size of the bounding box by the given amount. + * After calling this method, the lower left corner of the bounding box will + * have each coordinate decreased by @p amount, and the upper right corner + * of the bounding box will have each coordinate increased by @p amount. + * + * If you call this method with a negative number, and one of the axes of the + * original bounding box is smaller than amount/2, the method will trigger + * an assertion. + */ + void + extend(const double amount); + + /** + * Compute the volume (i.e. the dim-dimensional measure) of the BoundingBox. + */ + double + volume() const; + + /** + * Returns the point in the center of the box. + */ + Point + center() const; + + /** + * Returns the side length of the box in @p direction. + */ + double + side_length(const unsigned int direction) const; + + /** + * Return the lower bound of the box in @p direction. + */ + double + lower_bound(const unsigned int direction) const; + + /** + * Return the upper bound of the box in @p direction. + */ + double + upper_bound(const unsigned int direction) const; + + private: + /** + * Return true if the point is inside the Bounding Box, false otherwise. The + * parameter @p tolerance is a factor by which the bounding box is enlarged + * relative to the dimensions of the bounding box in order to determine in a + * numerically robust way whether the point is inside. + * + * This function is supposed to be only used by the point_inside function. + */ + bool + point_inside_implementation( + const Point &p, + const double tolerance = std::numeric_limits::epsilon()) const; + + std::pair, Point> boundary_points; + + }; + + + /*------------------------ Inline functions: BoundingBox --------------------*/ + +#ifndef DOXYGEN + + + template <> + inline BoundingBox<2>::BoundingBox() + : + boundary_points ({{ + -std::numeric_limits::max(), + -std::numeric_limits::max(), + cartesian + }, + { + +std::numeric_limits::max(), + +std::numeric_limits::max(), + cartesian + } + }) + {} + + template <> + inline BoundingBox<3>::BoundingBox() + : + boundary_points ({{ + -std::numeric_limits::max(), + -std::numeric_limits::max(), + -std::numeric_limits::max(), + cartesian + }, + { + +std::numeric_limits::max(), + +std::numeric_limits::max(), + +std::numeric_limits::max(), + cartesian + } + }) + {} + + + + template + inline BoundingBox::BoundingBox( + const std::pair, Point> + &boundary_points_) + : + boundary_points (boundary_points_) + { + // We check the Bounding Box is not degenerate + for (unsigned int i = 0; i < spacedim; ++i) + WBAssert(boundary_points.first[i] <= boundary_points.second[i], + "Bounding Box can't be created: the points' " + "order should be bottom left, top right!"); + } + + + + template + template + inline BoundingBox::BoundingBox(const Container &points) + { + // Use the default constructor in case points is empty instead of setting + // things to +oo and -oo + if (points.size() > 0) + { + auto &min = boundary_points.first; + auto &max = boundary_points.second; + std::fill(min.begin_raw(), + min.end_raw(), + std::numeric_limits::infinity()); + std::fill(max.begin_raw(), + max.end_raw(), + -std::numeric_limits::infinity()); + + for (const Point &point : points) + for (unsigned int d = 0; d < spacedim; ++d) + { + min[d] = std::min(min[d], point[d]); + max[d] = std::max(max[d], point[d]); + } + } + } + + + + template + inline std::pair, Point> &BoundingBox::get_boundary_points() + { + return this->boundary_points; + } + + + + template + inline const std::pair, Point> &BoundingBox::get_boundary_points() const + { + return this->boundary_points; + } + + + + template + inline bool + BoundingBox:: + operator==(const BoundingBox &box) const + { + return boundary_points == box.boundary_points; + } + + + + template + inline bool + BoundingBox:: + operator!=(const BoundingBox &box) const + { + return boundary_points != box.boundary_points; + } + + + + template + inline void + BoundingBox::extend(const double amount) + { + for (unsigned int d = 0; d < spacedim; ++d) + { + boundary_points.first[d] -= amount; + boundary_points.second[d] += amount; + WBAssert(boundary_points.first[d] <= boundary_points.second[d], + "Bounding Box can't be shrunk this much: the points' " + "order should remain bottom left, top right."); + } + } + + + template + inline + bool + BoundingBox::point_inside(const Point &point, + const double tolerance) const + { + WBAssert(boundary_points.first.get_coordinate_system() == point.get_coordinate_system(), + "Cannot compare two points which represent different coordinate systems."); + WBAssert(boundary_points.second.get_coordinate_system() == point.get_coordinate_system(), + "Cannot compare two points which represent different coordinate systems."); + + if (point.get_coordinate_system() == CoordinateSystem::spherical) + { + Point other_point = point; + if (spacedim == 2) + { + other_point[0] += point[0] < 0 ? 2.0 * Consts::PI : -2.0 * Consts::PI; + } + else + { + // spacedim == 3 (rad,long,lat) + other_point[1] += point[1] < 0 ? 2.0 * Consts::PI : -2.0 * Consts::PI; + } + + return (point_inside_implementation(point, tolerance) || + point_inside_implementation(other_point, tolerance)); + } + + return point_inside_implementation(point, tolerance); + + } + + template + inline + bool + BoundingBox::point_inside_implementation(const Point &p, + const double tolerance) const + { + WBAssert(boundary_points.first.get_coordinate_system() == p.get_coordinate_system(), + "Cannot compare two points which represent different coordinate systems."); + WBAssert(boundary_points.second.get_coordinate_system() == p.get_coordinate_system(), + "Cannot compare two points which represent different coordinate systems."); + + for (unsigned int i = 0; i < spacedim; ++i) + { + // Bottom left-top right convention: the point is outside if it's smaller + // than the first or bigger than the second boundary point The bounding + // box is defined as a closed set + if ((p[i] < this->boundary_points.first[i] - + tolerance * std::abs(this->boundary_points.second[i] - + this->boundary_points.first[i])) || + (p[i] > this->boundary_points.second[i] + + tolerance * std::abs(this->boundary_points.second[i] - + this->boundary_points.first[i]))) + return false; + } + return true; + } + + + + template + inline + void + BoundingBox::merge_with( + const BoundingBox &other_bbox) + { + for (unsigned int i = 0; i < spacedim; ++i) + { + this->boundary_points.first[i] = + std::min(this->boundary_points.first[i], + other_bbox.boundary_points.first[i]); + this->boundary_points.second[i] = + std::max(this->boundary_points.second[i], + other_bbox.boundary_points.second[i]); + } + } + + + + template + double + BoundingBox::volume() const + { + double vol = 1.0; + for (unsigned int i = 0; i < spacedim; ++i) + vol *= (this->boundary_points.second[i] - this->boundary_points.first[i]); + return vol; + } + + + + template + inline + double + BoundingBox::lower_bound(const unsigned int direction) const + { + WBAssert(direction, spacedim); + + return boundary_points.first[direction]; + } + + + + template + inline + double + BoundingBox::upper_bound(const unsigned int direction) const + { + WBAssert(direction, spacedim); + + return boundary_points.second[direction]; + } + + + + template + Point + BoundingBox::center() const + { + Point point = boundary_points.first; // initialize to inherit coordinate system + for (unsigned int i = 0; i < spacedim; ++i) + point[i] = .5 * (boundary_points.first[i] + boundary_points.second[i]); + + return point; + } + + + + template + inline + double + BoundingBox::side_length(const unsigned int direction) const + { + WBAssert(direction < spacedim, "Invalid index"); + + return boundary_points.second[direction] - boundary_points.first[direction]; + } + + +#endif // DOXYGEN + +} + + +#endif diff --git a/contrib/world_builder/include/world_builder/consts.h.bak b/contrib/world_builder/include/world_builder/consts.h.bak new file mode 100644 index 00000000000..56d01f284a5 --- /dev/null +++ b/contrib/world_builder/include/world_builder/consts.h.bak @@ -0,0 +1,35 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_GLOBAL_H +#define WORLD_BUILDER_GLOBAL_H + +#include +#include + +namespace WorldBuilder +{ + namespace Consts + { + constexpr double PI = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066; + } // namespace Consts + +} + +#endif diff --git a/contrib/world_builder/include/world_builder/coordinate_system.h.bak b/contrib/world_builder/include/world_builder/coordinate_system.h.bak new file mode 100644 index 00000000000..f60195abff5 --- /dev/null +++ b/contrib/world_builder/include/world_builder/coordinate_system.h.bak @@ -0,0 +1,68 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_COORDINATE_SYSTEM_H +#define WORLD_BUILDER_COORDINATE_SYSTEM_H + +namespace WorldBuilder +{ + /** + * This enum lists available coordinate systems that can be used for the + * function variables. Allowed values are 'cartesian', 'spherical'. + * 'spherical' coordinates follow: r, phi (2D) or r, phi, theta (3D); where + * r is radius, phi is longitude, and theta is the polar angle (colatitude). + */ + enum CoordinateSystem + { + cartesian, + spherical, + invalid + }; + + /** + * There are three ways to look at what should happen when the user gives an + * angle to go down in a sphere. The first one is the easiest, which is just + * to tread the system as a Cartesian system. This means taking the angle + * with the surface tangential at the starting point at the surface + * everywhere. The advantage is that it is very intuitive and easy to + * predict what geometry should be produced. This option is called + * 'angle_at_starting_point_with_surface'. The other end member is that + * going down with an angle in a sphere should mean that it always goes down + * with a constant angle relative to the surface tangential at that + * longitude and latitude. This means a the geometry would a a logarithmic + * spiral. This option is called 'continuous_angle_with_surface'. Because it + * is currently to time consuming to implement this option with all the + * required features, there is an option which approximates this behavior, + * by using the option 'angle_at_starting_point_with_surface'. This option + * uses the surface tangential at the beginning of every segment. This means + * that in the limit of segments going to length zero, this option produces + * exactly the same geometry as 'continuous_angle_with_surface'. + */ + enum DepthMethod + { + angle_at_starting_point_with_surface, + angle_at_begin_segment_with_surface, + angle_at_begin_segment_applied_to_end_segment_with_surface, + continuous_angle_with_surface, + none + }; +} // namespace WorldBuilder + +#endif + diff --git a/contrib/world_builder/include/world_builder/coordinate_systems/cartesian.h.bak b/contrib/world_builder/include/world_builder/coordinate_systems/cartesian.h.bak new file mode 100644 index 00000000000..cb196e4b8c4 --- /dev/null +++ b/contrib/world_builder/include/world_builder/coordinate_systems/cartesian.h.bak @@ -0,0 +1,114 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_COORDINATE_SYSTEMS_CARTESIAN_H +#define WORLD_BUILDER_COORDINATE_SYSTEMS_CARTESIAN_H + +#include "world_builder/coordinate_systems/interface.h" + +namespace WorldBuilder +{ + + namespace CoordinateSystems + { + /** + * Register header file + */ + //WB_REGISTER_COORDINATE_SYSTEM_HEADER(Cartesian) + + + /** + * This implements a Cartesian geometry model.The Cartesian geometry model + * doesn't do anything with the coordinates, but is needed to have a common + * interface for all the geometry models. + */ + class Cartesian final : public Interface + { + public: + /** + * constructor + */ + Cartesian(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Cartesian() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns what the natural coordinate system for this Coordinate System is. + */ + CoordinateSystem natural_coordinate_system() const override final; + + /** + * Returns what method should be used to go down with an angle into + * the domain. + * \sa DepthMethod + */ + DepthMethod depth_method() const override final; + + /** + * Takes the Cartesian points (x,z or x,y,z) and returns standardized + * coordinates which are most 'natural' to the geometry model. For a box + * this will be (x,z) in 2d or (x,y,z) in 3d, and for a spheroid geometry + * model it will be (radius, longitude) in 2d and (radius, longitude, + * latitude) in 3d. + */ + std::array cartesian_to_natural_coordinates(const std::array &position) const override final; + + /** + * Undoes the action of cartesian_to_natural_coordinates, and turns the + * coordinate system which is most 'natural' to the geometry model into + * Cartesian coordinates. + */ + std::array natural_to_cartesian_coordinates(const std::array &position) const override final; + + + /** + * Computes the distance between two points which are on the same depth. + * The input is two 3d points at that depth. It is implemented as the + */ + double distance_between_points_at_same_depth(const Point<3> &point_1, const Point<3> &point_2) const override final; + + /** + * Returns the max model depth. This always returns infinity for Cartesian + * models. + */ + virtual + double max_model_depth() const override final; + + private: + + }; + } // namespace CoordinateSystems +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/coordinate_systems/interface.h.bak b/contrib/world_builder/include/world_builder/coordinate_systems/interface.h.bak new file mode 100644 index 00000000000..d8147fe0d4c --- /dev/null +++ b/contrib/world_builder/include/world_builder/coordinate_systems/interface.h.bak @@ -0,0 +1,184 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_COORDINATE_SYSTEMS_INTERFACE_H +#define WORLD_BUILDER_COORDINATE_SYSTEMS_INTERFACE_H + +#include "world_builder/coordinate_systems/interface.h" + +#include "world_builder/coordinate_system.h" +#include "world_builder/parameters.h" +#include "world_builder/types/string.h" + + +namespace WorldBuilder +{ + class World; + + namespace CoordinateSystems + { + + class ObjectFactory; + + /** + * This class is an interface for the specific coordinate systems. + */ + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + /** + * Returns what the natural coordinate system for this geometry model is. + */ + virtual + CoordinateSystem natural_coordinate_system() const = 0; + + /** + * Returns what method should be used to go down with an angle into + * the domain. + * \sa DepthMethod + */ + virtual + DepthMethod depth_method() const = 0; + + /** + * Takes the Cartesian points (x,z or x,y,z) and returns standardized + * coordinates which are most 'natural' to the geometry model. For a box + * this will be (x,z) in 2d or (x,y,z) in 3d, and for a spheroid geometry + * model it will be (radius, longitude) in 2d and (radius, longitude, + * latitude) in 3d. + */ + virtual + std::array cartesian_to_natural_coordinates(const std::array &position) const = 0; + + /** + * Undoes the action of cartesian_to_natural_coordinates, and turns the + * coordinate system which is most 'natural' to the geometry model into + * Cartesian coordinates. + */ + virtual + std::array natural_to_cartesian_coordinates(const std::array &position) const = 0; + + /** + * Computes the distance between two points which are on the same depth. + * The input is two 3d points at that depth. + */ + virtual + double distance_between_points_at_same_depth(const Point<3> &point_1, const Point<3> &point_2) const = 0; + + /** + * Returns the max model depth. This should be the infinity for Cartesian + * models and the radius in spherical models. + */ + virtual + double max_model_depth() const = 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); + + 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_COORDINATE_SYSTEM(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 CoordinateSystems +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/coordinate_systems/invalid.h.bak b/contrib/world_builder/include/world_builder/coordinate_systems/invalid.h.bak new file mode 100644 index 00000000000..481929abdf3 --- /dev/null +++ b/contrib/world_builder/include/world_builder/coordinate_systems/invalid.h.bak @@ -0,0 +1,110 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_COORDINATE_SYSTEMS_INVALID_H +#define WORLD_BUILDER_COORDINATE_SYSTEMS_INVALID_H + +#include "world_builder/coordinate_systems/interface.h" +#include "world_builder/nan.h" + + +namespace WorldBuilder +{ + + namespace CoordinateSystems + { + /** + * This implements a Invalid geometry model.The Invalid geometry model + * doesn't do anything with the coordinates, but is needed to have a common + * interface for all the geometry models. + */ + class Invalid final : public Interface + { + public: + /** + * constructor + */ + Invalid(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Invalid() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns what the natural coordinate system for this Coordinate System is. + */ + CoordinateSystem natural_coordinate_system() const override final; + + /** + * Returns what method should be used to go down with an angle into + * the domain. + * \sa DepthMethod + */ + DepthMethod depth_method() const override final; + + /** + * Takes the Invalid points (x,z or x,y,z) and returns standardized + * coordinates which are most 'natural' to the geometry model. For a box + * this will be (x,z) in 2d or (x,y,z) in 3d, and for a spheroid geometry + * model it will be (radius, longitude) in 2d and (radius, longitude, + * latitude) in 3d. + */ + std::array cartesian_to_natural_coordinates(const std::array &position) const override final; + + /** + * Undoes the action of invalid_to_natural_coordinates, and turns the + * coordinate system which is most 'natural' to the geometry model into + * Invalid coordinates. + */ + std::array natural_to_cartesian_coordinates(const std::array &position) const override final; + + + /** + * Computes the distance between two points which are on the same depth. + * The input is two 3d points at that depth. It is implemented as the + */ + double distance_between_points_at_same_depth(const Point<3> &point_1, const Point<3> &point_2) const override final; + + /** + * Returns the max model depth. This always returns infinity for Invalid + * models. + */ + virtual + double max_model_depth() const override final; + + private: + + }; + } // namespace CoordinateSystems +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/coordinate_systems/spherical.h.bak b/contrib/world_builder/include/world_builder/coordinate_systems/spherical.h.bak new file mode 100644 index 00000000000..6fe89645e40 --- /dev/null +++ b/contrib/world_builder/include/world_builder/coordinate_systems/spherical.h.bak @@ -0,0 +1,130 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_COORDINATE_SYSTEMS_SPHERICAL_H +#define WORLD_BUILDER_COORDINATE_SYSTEMS_SPHERICAL_H + +#include "world_builder/coordinate_systems/interface.h" + +#include + +namespace WorldBuilder +{ + + namespace CoordinateSystems + { + /** + * Register header file + */ + //WB_REGISTER_COORDINATE_SYSTEM_HEADER(Spherical) + + /** + * This implements a Spherical geometry model.The Cartesian geometry model + * doesn't do anything with the coordinates, but is needed to have a common + * interface for all the geometry models. + */ + class Spherical final : public Interface + { + public: + /** + * constructor + */ + Spherical(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Spherical() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns what the natural coordinate system for this Coordinate System is. + */ + CoordinateSystem natural_coordinate_system() const override final; + + /** + * Returns what method should be used to go down with an angle into + * the domain. + * \sa DepthMethod + */ + DepthMethod depth_method() const override final; + + /** + * Takes the Cartesian points (x,z or x,y,z) and returns standardized + * coordinates which are most 'natural' to the geometry model. For a box + * this will be (x,z) in 2d or (x,y,z) in 3d, and for a spheroid geometry + * model it will be (radius, longitude) in 2d and (radius, longitude, + * latitude) in 3d. + */ + std::array cartesian_to_natural_coordinates(const std::array &position) const override final; + + /** + * Undoes the action of cartesian_to_natural_coordinates, and turns the + * coordinate system which is most 'natural' to the geometry model into + * Cartesian coordinates. + */ + std::array natural_to_cartesian_coordinates(const std::array &position) const override final; + + + /** + * Computes the distance between two points which are on the same depth. + * The input is two 2d points at that depth. The distance is returned + * in meters. To compute this distance from spherical coordinates the + * radius is multiplied with the central angle. The central angle is + * compute in the most accurate way given on wikipedia + * (https://en.wikipedia.org/wiki/Great-circle_distance), through a + * special case of the Vincenty formula for an ellipsoid with equal + * major and minor axes (https://doi.org/10.1179/sre.1975.23.176.88). + */ + double distance_between_points_at_same_depth(const Point<3> &point_1, const Point<3> &point_2) const override final; + + /** + * Returns the max model depth. This returns the radius in spherical + * models. + */ + virtual + double max_model_depth() const override final; + + /** + * What depth method the spherical coordinates use. + */ + DepthMethod used_depth_method; + + private: + /** + * The maximum depth of the model. In the spherical case that is equal to the + * radius of the sphere. + */ + double radius_sphere; + }; + } // namespace CoordinateSystems +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/deprecate.h.bak b/contrib/world_builder/include/world_builder/deprecate.h.bak new file mode 100644 index 00000000000..2c7296ce4db --- /dev/null +++ b/contrib/world_builder/include/world_builder/deprecate.h.bak @@ -0,0 +1,13 @@ +// if deprecated is supported, which is definitely C++14, but some compilers support it before C++14. +// Once the world builder switches to C++14 this can be simplified. +#if defined(__has_cpp_attribute) +#if __has_cpp_attribute(deprecated) +#define DEPRECATED(msg, func) [[deprecated(msg)]] func +#endif +#else +#if defined(__GNUC__) || defined(__clang__) +#define DEPRECATED(msg, func) func __attribute__ ((deprecated(msg))) +#elif defined(_MSC_VER) +#define DEPRECATED(msg, func) __declspec(deprecated(msg)) func +#endif +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/features/continental_plate.h.bak b/contrib/world_builder/include/world_builder/features/continental_plate.h.bak new file mode 100644 index 00000000000..ac3f55111ad --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/continental_plate.h.bak @@ -0,0 +1,162 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_H +#define WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_H + + +#include "world_builder/features/interface.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + class Parameters; + class World; + + namespace Features + { + namespace ContinentalPlateModels + { + namespace Composition + { + class Interface; + } // namespace Composition + namespace Grains + { + class Interface; + } // namespace Grains + namespace Temperature + { + class Interface; + } // namespace Temperature + } // namespace ContinentalPlateModels + + /** + * This class represents a continental plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class ContinentalPlate final: public Interface + { + public: + /** + * constructor + */ + ContinentalPlate(WorldBuilder::World *world); + + /** + * Destructor + */ + ~ContinentalPlate() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, + const std::string &parent_name = "", + const std::vector &required_entries = {}); + + /** + * Produce a JSON snippet for the schema + */ + static + void make_snippet(Parameters &prm); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns different values at a single point in one go stored in a vector of doubles. + * + * The properties input decides what each entry means, and the output is generated in the + * same order as the properties input. The properties input consists of + * a 3D array, where the first entry identifies the property and the last two entries + * provide extra information about that property. + * + * Temperature is identified by 1 and no extra information is needed. So temperature + * input usually looks like {1,0,0}. A temperature query prodoces one entry in the output + * vector. + * + * Composition is identified by 2. This produces one + * value in the output. The second entry identifies the composition number and the third + * number is not used. So a commposition query asking about composition 1 looks like this: + * {2,1,0}. A composition query prodoces one entry in the output vector. + * + * Grains are identified by 2. The second entry is the grain composition number and the third + * entry is the number of grains. A query about the grains, where it asks about composition 1 + * (for example enstatite) and 500 grains, looks like this: {2,1,500}. + * A composition query prodoces n_grains*10 entries in the output vector. The first n_grains + * entries are the sizes of all the grains, and the other 9 entries are sets of rotation + * matrices. The rotation matrix entries are ordered [0][0],[0][1],[0][2],[1][0],[1][1],etc. + * + * The entries in output variable relates the index of the property to the index in the output. + */ + void + properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity, + const std::vector &entry_in_output, + std::vector &output) const override final; + + private: + /** + * A vector containing all the pointers to the temperature models. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > temperature_models; + + /** + * A vector containing all the pointers to the composition models. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > composition_models; + + /** + * A vector containing all the pointers to the grains models. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > grains_models; + + + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + + }; + + + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/continental_plate_models/composition/interface.h.bak b/contrib/world_builder/include/world_builder/features/continental_plate_models/composition/interface.h.bak new file mode 100644 index 00000000000..61e34188168 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/continental_plate_models/composition/interface.h.bak @@ -0,0 +1,164 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_COMPOSITION_INTERFACE_H +#define WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_COMPOSITION_INTERFACE_H + + +#include "world_builder/parameters.h" +#include "world_builder/objects/natural_coordinate.h" + +namespace WorldBuilder +{ + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as continental plate, oceanic plate and subduction zone. + */ + namespace Features + { + + namespace ContinentalPlateModels + { + namespace Composition + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm, const std::vector> &coordinates) = 0; + + + /** + * takes composition and position and returns a composition. + */ + virtual + double get_composition(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + std::string name; + + + + 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_FEATURE_CONTINENTAL_PLATE_COMPOSITION_MODEL(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 Composition + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/continental_plate_models/composition/random.h.bak b/contrib/world_builder/include/world_builder/features/continental_plate_models/composition/random.h.bak new file mode 100644 index 00000000000..5d7a9f40110 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/continental_plate_models/composition/random.h.bak @@ -0,0 +1,100 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_COMPOSITION_RANDOM_H +#define WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_COMPOSITION_RANDOM_H + + +#include "world_builder/features/continental_plate_models/composition/interface.h" +#include "world_builder/objects/surface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + namespace Features + { + using namespace FeatureUtilities; + namespace ContinentalPlateModels + { + namespace Composition + { + /** + * This class represents a continental plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Random final : public Interface + { + public: + /** + * constructor + */ + Random(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Random() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a composition based on the given position, depth in the model, + * gravity and current composition. + */ + double get_composition(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // Random composition submodule parameters + + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector compositions; + std::vector min_value; + std::vector max_value; + Operations operation; + + }; + } // namespace Composition + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/continental_plate_models/composition/uniform.h.bak b/contrib/world_builder/include/world_builder/features/continental_plate_models/composition/uniform.h.bak new file mode 100644 index 00000000000..f6540cf8227 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/continental_plate_models/composition/uniform.h.bak @@ -0,0 +1,99 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_COMPOSITION_UNIFORM_H +#define WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_COMPOSITION_UNIFORM_H + + +#include "world_builder/features/continental_plate_models/composition/interface.h" +#include "world_builder/objects/surface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + namespace Features + { + using namespace FeatureUtilities; + namespace ContinentalPlateModels + { + namespace Composition + { + /** + * This class represents a continental plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a composition based on the given position, depth in the model, + * gravity and current composition. + */ + double get_composition(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // uniform composition submodule parameters + + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector compositions; + std::vector fractions; + Operations operation; + + }; + } // namespace Composition + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/continental_plate_models/grains/interface.h.bak b/contrib/world_builder/include/world_builder/features/continental_plate_models/grains/interface.h.bak new file mode 100644 index 00000000000..20693855c07 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/continental_plate_models/grains/interface.h.bak @@ -0,0 +1,170 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_GRAINS_INTERFACE_H +#define WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_GRAINS_INTERFACE_H + + +#include "world_builder/grains.h" +#include "world_builder/parameters.h" +#include "world_builder/objects/natural_coordinate.h" + + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as continental plate, oceanic plate and subduction zone. + */ + namespace Features + { + + namespace ContinentalPlateModels + { + namespace Grains + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm, const std::vector> &coordinates) = 0; + + + /** + * takes composition and position and returns grains. + */ + virtual + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + std::string name; + + + + 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_FEATURE_CONTINENTAL_PLATE_GRAINS_MODEL(klass,name) \ + class klass##Factory : public ObjectFactory { \ + public: \ + klass##Factory() \ + { \ + Interface::registerType(#name, klass::declare_entries, this); \ + } \ + virtual std::unique_ptr create(World *world) override final { \ + return std::unique_ptr(new klass(world)); \ + } \ + }; \ + static klass##Factory global_##klass##Factory; + + } // namespace Grains + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/continental_plate_models/grains/random_uniform_distribution.h.bak b/contrib/world_builder/include/world_builder/features/continental_plate_models/grains/random_uniform_distribution.h.bak new file mode 100644 index 00000000000..dfa20197d28 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/continental_plate_models/grains/random_uniform_distribution.h.bak @@ -0,0 +1,115 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_H +#define WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_H + + +#include "world_builder/features/continental_plate_models/grains/interface.h" +#include "world_builder/objects/surface.h" + +namespace WorldBuilder +{ + class Parameters; + + namespace Features + { + namespace ContinentalPlateModels + { + namespace Grains + { + /** + * This class represents a continental plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + class RandomUniformDistribution final : public Interface + { + public: + /** + * constructor + */ + RandomUniformDistribution(WorldBuilder::World *world); + + /** + * Destructor + */ + ~RandomUniformDistribution() override final; + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const override final; + + private: + // uniform grains submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector grain_sizes; + std::vector normalize_grain_sizes; + }; + } // namespace Grains + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/continental_plate_models/grains/random_uniform_distribution_deflected.h.bak b/contrib/world_builder/include/world_builder/features/continental_plate_models/grains/random_uniform_distribution_deflected.h.bak new file mode 100644 index 00000000000..4e8cf717326 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/continental_plate_models/grains/random_uniform_distribution_deflected.h.bak @@ -0,0 +1,115 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_DEFLECTED_H +#define WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_DEFLECTED_H + + +#include "world_builder/features/continental_plate_models/grains/interface.h" +#include "world_builder/objects/surface.h" + +namespace WorldBuilder +{ + class Parameters; + + namespace Features + { + namespace ContinentalPlateModels + { + namespace Grains + { + /** + * This class represents a continental plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + class RandomUniformDistributionDeflected final : public Interface + { + public: + /** + * constructor + */ + RandomUniformDistributionDeflected(WorldBuilder::World *world); + + /** + * Destructor + */ + ~RandomUniformDistributionDeflected() override final; + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const override final; + + private: + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector grain_sizes; + std::vector normalize_grain_sizes; + std::vector deflections; + }; + } // namespace Grains + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/features/continental_plate_models/grains/uniform.h.bak b/contrib/world_builder/include/world_builder/features/continental_plate_models/grains/uniform.h.bak new file mode 100644 index 00000000000..6a054a9506e --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/continental_plate_models/grains/uniform.h.bak @@ -0,0 +1,113 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_GRAINS_UNIFORM_H +#define WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_GRAINS_UNIFORM_H + + +#include "world_builder/features/continental_plate_models/grains/interface.h" +#include "world_builder/objects/surface.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace ContinentalPlateModels + { + namespace Grains + { + /** + * This class represents a continental plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + 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 parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const override final; + + private: + // uniform grains submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector, 3>> rotation_matrices; + std::vector grain_sizes; + }; + } // namespace Grains + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/adiabatic.h.bak b/contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/adiabatic.h.bak new file mode 100644 index 00000000000..d8be4739f71 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/adiabatic.h.bak @@ -0,0 +1,113 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_TEMPERATURE_ADIABATIC_H +#define WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_TEMPERATURE_ADIABATIC_H + + +#include "world_builder/features/continental_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + + namespace Features + { + using namespace FeatureUtilities; + namespace ContinentalPlateModels + { + namespace Temperature + { + /** + * This class represents a continental plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Adiabatic final: public Interface + { + public: + /** + * constructor + */ + Adiabatic(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Adiabatic() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // adiabatic temperature submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + /** + * Todo + */ + double potential_mantle_temperature; + + + /** + * Todo + */ + double thermal_expansion_coefficient; + + /** + * Todo + */ + double specific_heat; + + Operations operation; + + }; + } // namespace Temperature + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/interface.h.bak b/contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/interface.h.bak new file mode 100644 index 00000000000..4bc2b1bac40 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/interface.h.bak @@ -0,0 +1,169 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_TEMPERATURE_INTERFACE_H +#define WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_TEMPERATURE_INTERFACE_H + + +#include "world_builder/parameters.h" +#include "world_builder/objects/natural_coordinate.h" + + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as continental plate, oceanic plate and subduction zone. + */ + namespace Features + { + + namespace ContinentalPlateModels + { + namespace Temperature + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm, const std::vector> &coordinates) = 0; + + + /** + * takes temperature and position and returns a temperature. + */ + virtual + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + /** + * The name of the feature type. + */ + std::string name; + + 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_FEATURE_CONTINENTAL_PLATE_TEMPERATURE_MODEL(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 Temperature + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/linear.h.bak b/contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/linear.h.bak new file mode 100644 index 00000000000..07a2a022ed6 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/linear.h.bak @@ -0,0 +1,99 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_TEMPERATURE_LINEAR_H +#define WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_TEMPERATURE_LINEAR_H + + +#include "world_builder/features/continental_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + + namespace Features + { + using namespace FeatureUtilities; + namespace ContinentalPlateModels + { + namespace Temperature + { + /** + * This class represents a continental plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Linear final: public Interface + { + public: + /** + * constructor + */ + Linear(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Linear() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // linear temperature submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + double top_temperature; + double bottom_temperature; + Operations operation; + + }; + } // namespace Temperature + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/uniform.h.bak b/contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/uniform.h.bak new file mode 100644 index 00000000000..bb70e04a21e --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/continental_plate_models/temperature/uniform.h.bak @@ -0,0 +1,98 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_TEMPERATURE_UNIFORM_H +#define WORLD_BUILDER_FEATURES_CONTINENTAL_PLATE_MODELS_TEMPERATURE_UNIFORM_H + + +#include "world_builder/features/continental_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + + namespace Features + { + using namespace FeatureUtilities; + namespace ContinentalPlateModels + { + namespace Temperature + { + /** + * This class represents a continental plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // uniform temperature submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + double temperature; + Operations operation; + + }; + } // namespace Temperature + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/fault.h.bak b/contrib/world_builder/include/world_builder/features/fault.h.bak new file mode 100644 index 00000000000..f8e98d11242 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/fault.h.bak @@ -0,0 +1,229 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_FAULT_H +#define WORLD_BUILDER_FEATURES_FAULT_H + + +#include "world_builder/features/fault_models/composition/interface.h" +#include "world_builder/features/fault_models/grains/interface.h" +#include "world_builder/features/fault_models/temperature/interface.h" +#include "world_builder/objects/segment.h" +#include "world_builder/bounding_box.h" +#include "world_builder/objects/distance_from_surface.h" + + +namespace WorldBuilder +{ + class Parameters; + class World; + + namespace Features + { + namespace FaultModels + { + namespace Composition + { + class Interface; + } // namespace Composition + namespace Grains + { + class Interface; + } // namespace Grains + namespace Temperature + { + class Interface; + } // namespace Temperature + } // namespace FaultModels + + /** + * This class represents a fault and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Fault final: public Interface + { + public: + /** + * constructor + */ + Fault(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Fault() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, + const std::string &parent_name = "", + const std::vector &required_entries = {}); + + /** + * Produce a JSON snippet for the schema + */ + static + void make_snippet(Parameters &prm); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Computes the bounding points for a BoundingBox object using two extreme points in all the surface + * coordinates and an additional buffer zone that accounts for the fault thickness and length. The first and second + * points correspond to the lower left and the upper right corners of the bounding box, respectively (see the + * documentation in include/bounding_box.h). + * For the spherical system, the buffer zone along the longitudal direction is calculated using the + * corresponding latitude points. + */ + const BoundingBox<2> &get_surface_bounding_box () const; + + /** + * Returns different values at a single point in one go stored in a vector of doubles. + * + * The properties input decides what each entry means, and the output is generated in the + * same order as the properties input. The properties input consists of + * a 3D array, where the first entry identifies the property and the last two entries + * provide extra information about that property. + * + * Temperature is identified by 1 and no extra information is needed. So temperature + * input usually looks like {1,0,0}. A temperature query prodoces one entry in the output + * vector. + * + * Composition is identified by 2. This produces one + * value in the output. The second entry identifies the composition number and the third + * number is not used. So a commposition query asking about composition 1 looks like this: + * {2,1,0}. A composition query prodoces one entry in the output vector. + * + * Grains are identified by 2. The second entry is the grain composition number and the third + * entry is the number of grains. A query about the grains, where it asks about composition 1 + * (for example enstatite) and 500 grains, looks like this: {2,1,500}. + * A composition query prodoces n_grains*10 entries in the output vector. The first n_grains + * entries are the sizes of all the grains, and the other 9 entries are sets of rotation + * matrices. The rotation matrix entries are ordered [0][0],[0][1],[0][2],[1][0],[1][1],etc. + * + * The entries in output variable relates the index of the property to the index in the output. + */ + void + properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity, + const std::vector &entry_in_output, + std::vector &output) const override final; + + /** + * Returns a PlaneDistances object that has the distance from and along a fault plane, + * calculated 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; + std::vector > default_grains_models; + + std::vector > default_segment_vector; + + std::vector< std::vector > > sections_segment_vector; + + // This vector stores segments to this coordinate/section. + //First used (raw) pointers to the segment relevant to this coordinate/section, + // but I do not trust it won't fail when memory is moved. So storing the all the data now. + std::vector > > segment_vector; + + // todo: the memory of this can be greatly improved by + // or using a plugin system for the submodules, or + // putting the variables in a union. Although the memory + // used by this program is in real cases expected to be + // insignificant compared to what a calling program may + // use, a smaller amount of memory used in here, could + // theoretically speed up the computation, because more + // relevant data could be stored in the cache. But this + // not a urgent problem, and would require testing. + + /** + * This variable stores the depth at which the fault + * starts. It makes this depth effectively the surface + * of the model for the fault. + */ + double starting_depth; + + /** + * The depth which below the fault may no longer + * be present. This can not only help setting up models with + * less effort, but can also improve performance, because + * the algorithm doesn't have to search in locations below + * this depth. + */ + double maximum_depth; + + /** + * Computee bounding points for a BoundingBox object using two extreme points in all the surface + * coordinates and an additional buffer zone that accounts for the fault thickness and length. The first and second + * points correspond to the lower left and the upper right corners of the bounding box, respectively (see the + * documentation in include/bounding_box.h). + * For the spherical system, the buffer zone along the longitudal direction is calculated using the + * corresponding latitude points. + */ + BoundingBox<2> surface_bounding_box; + + /** + * A point on the surface to which the fault dips. + */ + WorldBuilder::Point<2> reference_point; + + std::vector > fault_segment_lengths; + std::vector > > fault_segment_thickness; + std::vector > > fault_segment_top_truncation; + std::vector > > fault_segment_angles; + std::vector total_fault_length; + double maximum_total_fault_length; + double maximum_fault_thickness; + + double min_along_x; + double max_along_x; + double min_along_y; + double max_along_y; + double min_lat_cos_inv; + double max_lat_cos_inv; + double buffer_around_fault_cartesian; + + }; + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/fault_models/composition/interface.h.bak b/contrib/world_builder/include/world_builder/features/fault_models/composition/interface.h.bak new file mode 100644 index 00000000000..379f23198e7 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/fault_models/composition/interface.h.bak @@ -0,0 +1,172 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_FAULT_MODELS_COMPOSITION_INTERFACE_H +#define WORLD_BUILDER_FEATURES_FAULT_MODELS_COMPOSITION_INTERFACE_H + +#include "world_builder/grains.h" +#include "world_builder/parameters.h" +#include "world_builder/utilities.h" +#include "world_builder/features/feature_utilities.h" + +#include +#include + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as oceanic plate, oceanic plate and subduction zone. + */ + namespace Features + { + using namespace FeatureUtilities; + namespace FaultModels + { + namespace Composition + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + + /** + * takes composition and position and returns a composition. + */ + virtual + double get_composition(const Point<3> &position, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + std::string name; + + + + 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_FEATURE_FAULT_COMPOSITION_MODEL(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 Composition + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/fault_models/composition/smooth.h.bak b/contrib/world_builder/include/world_builder/features/fault_models/composition/smooth.h.bak new file mode 100644 index 00000000000..cf2797297a9 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/fault_models/composition/smooth.h.bak @@ -0,0 +1,97 @@ +/* + 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 . +*/ + +#ifndef _world_builder_features_fault_composition_smooth_h +#define _world_builder_features_fault_composition_smooth_h + +#include +#include +#include + + +namespace WorldBuilder +{ + namespace Features + { + using namespace FeatureUtilities; + namespace FaultModels + { + namespace Composition + { + /** + * This class represents a subducting plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Smooth: public Interface + { + public: + /** + * constructor + */ + Smooth(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Smooth(); + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a composition based on the given position, depth in the model, + * and current composition. + */ + double get_composition(const Point<3> &position, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + private: + // linear temperature submodule parameters + double min_distance; + double side_distance; + std::vector center_fraction; + // currently not using the side composition, but maybe useful if you want another composition towards the end + std::vector side_fraction; + std::vector compositions; + Operations operation; + + }; + } + } + } +} + +#endif diff --git a/contrib/world_builder/include/world_builder/features/fault_models/composition/uniform.h.bak b/contrib/world_builder/include/world_builder/features/fault_models/composition/uniform.h.bak new file mode 100644 index 00000000000..d4cf27758c6 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/fault_models/composition/uniform.h.bak @@ -0,0 +1,95 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_FAULT_MODELS_COMPOSITION_UNIFORM_H +#define WORLD_BUILDER_FEATURES_FAULT_MODELS_COMPOSITION_UNIFORM_H + + +#include "world_builder/features/fault_models/composition/interface.h" + + +namespace WorldBuilder +{ + + namespace Features + { + namespace FaultModels + { + namespace Composition + { + /** + * This class represents a subducting plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a composition based on the given position, depth in the model, + * gravity and current composition. + */ + double get_composition(const Point<3> &position, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + + private: + // uniform composition submodule parameters + double min_depth; + double max_depth; + std::vector compositions; + std::vector fractions; + Operations operation; + + }; + } // namespace Composition + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/fault_models/grains/interface.h.bak b/contrib/world_builder/include/world_builder/features/fault_models/grains/interface.h.bak new file mode 100644 index 00000000000..64fc61674bb --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/fault_models/grains/interface.h.bak @@ -0,0 +1,173 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_FAULT_MODELS_GRAINS_INTERFACE_H +#define WORLD_BUILDER_FEATURES_FAULT_MODELS_GRAINS_INTERFACE_H + +#include "world_builder/grains.h" +#include "world_builder/parameters.h" +#include "world_builder/utilities.h" +#include "world_builder/features/feature_utilities.h" + +#include +#include + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as oceanic plate, oceanic plate and subduction zone. + */ + namespace Features + { + using namespace FeatureUtilities; + namespace FaultModels + { + namespace Grains + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + + /** + * takes composition and position and returns a composition. + */ + virtual + WorldBuilder::grains + get_grains(const Point<3> &position, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + std::string name; + + + + 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_FEATURE_FAULT_GRAINS_MODEL(klass,name) \ + class klass##Factory : public ObjectFactory { \ + public: \ + klass##Factory() \ + { \ + Interface::registerType(#name, klass::declare_entries, this); \ + } \ + virtual std::unique_ptr create(World *world) override final { \ + return std::unique_ptr(new klass(world)); \ + } \ + }; \ + static klass##Factory global_##klass##Factory; + + } // namespace Grains + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/fault_models/grains/random_uniform_distribution.h.bak b/contrib/world_builder/include/world_builder/features/fault_models/grains/random_uniform_distribution.h.bak new file mode 100644 index 00000000000..67712d21156 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/fault_models/grains/random_uniform_distribution.h.bak @@ -0,0 +1,113 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_FAULT_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_H +#define WORLD_BUILDER_FEATURES_FAULT_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_H + + +#include "world_builder/features/fault_models/grains/interface.h" + +namespace WorldBuilder +{ + + namespace Features + { + using namespace FeatureUtilities; + namespace FaultModels + { + namespace Grains + { + /** + * This class represents a continental plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + class RandomUniformDistribution final: public Interface + { + public: + /** + * constructor + */ + RandomUniformDistribution(WorldBuilder::World *world); + + /** + * Destructor + */ + ~RandomUniformDistribution() override final; + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + private: + // uniform grains submodule parameters + double min_depth; + double max_depth; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector grain_sizes; + std::vector normalize_grain_sizes; + }; + } // namespace Grains + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/fault_models/grains/random_uniform_distribution_deflected.h.bak b/contrib/world_builder/include/world_builder/features/fault_models/grains/random_uniform_distribution_deflected.h.bak new file mode 100644 index 00000000000..82d2c683f07 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/fault_models/grains/random_uniform_distribution_deflected.h.bak @@ -0,0 +1,113 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_FAULT_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_DEFLECTED_H +#define WORLD_BUILDER_FEATURES_FAULT_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_DEFLECTED_H + + +#include "world_builder/features/fault_models/grains/interface.h" + +namespace WorldBuilder +{ + + namespace Features + { + using namespace FeatureUtilities; + namespace FaultModels + { + namespace Grains + { + /** + * This class represents a fault and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + class RandomUniformDistributionDeflected final: public Interface + { + public: + /** + * constructor + */ + RandomUniformDistributionDeflected(WorldBuilder::World *world); + + /** + * Destructor + */ + ~RandomUniformDistributionDeflected() override final; + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + private: + double min_depth; + double max_depth; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector grain_sizes; + std::vector normalize_grain_sizes; + std::vector deflections; + }; + } // namespace Grains + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/features/fault_models/grains/uniform.h.bak b/contrib/world_builder/include/world_builder/features/fault_models/grains/uniform.h.bak new file mode 100644 index 00000000000..d56b49a9ecf --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/fault_models/grains/uniform.h.bak @@ -0,0 +1,112 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_FAULT_MODELS_GRAINS_UNIFORM_H +#define WORLD_BUILDER_FEATURES_FAULT_MODELS_GRAINS_UNIFORM_H + + +#include "world_builder/features/fault_models/grains/interface.h" + +namespace WorldBuilder +{ + + namespace Features + { + namespace FaultModels + { + namespace Grains + { + /** + * This class represents a oceanic plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + 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 parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + private: + // uniform grains submodule parameters + double min_depth; + double max_depth; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector, 3>> rotation_matrices; + std::vector grain_sizes; + }; + } // namespace Grains + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/fault_models/temperature/adiabatic.h.bak b/contrib/world_builder/include/world_builder/features/fault_models/temperature/adiabatic.h.bak new file mode 100644 index 00000000000..0cf1e7a4686 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/fault_models/temperature/adiabatic.h.bak @@ -0,0 +1,110 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_FAULT_MODELS_TEMPERATURE_ADIABATIC_H +#define WORLD_BUILDER_FEATURES_FAULT_MODELS_TEMPERATURE_ADIABATIC_H + + +#include "world_builder/features/fault_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + + namespace Features + { + namespace FaultModels + { + namespace Temperature + { + /** + * This class represents a subducting plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Adiabatic final: public Interface + { + public: + /** + * constructor + */ + Adiabatic(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Adiabatic() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + + private: + // adiabatic temperature submodule parameters + double min_depth; + double max_depth; + /** + * Todo + */ + double potential_mantle_temperature; + + + /** + * Todo + */ + double thermal_expansion_coefficient; + + /** + * Todo + */ + double specific_heat; + + Operations operation; + + }; + } // namespace Temperature + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/fault_models/temperature/interface.h.bak b/contrib/world_builder/include/world_builder/features/fault_models/temperature/interface.h.bak new file mode 100644 index 00000000000..57a74886f30 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/fault_models/temperature/interface.h.bak @@ -0,0 +1,173 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_FAULT_MODELS_TEMPERATURE_INTERFACE_H +#define WORLD_BUILDER_FEATURES_FAULT_MODELS_TEMPERATURE_INTERFACE_H + +#include "world_builder/grains.h" +#include "world_builder/parameters.h" +#include "world_builder/utilities.h" +#include "world_builder/features/feature_utilities.h" + +#include +#include + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as oceanic plate, oceanic plate and subduction zone. + */ + namespace Features + { + using namespace FeatureUtilities; + namespace FaultModels + { + namespace Temperature + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + + /** + * takes temperature and position and returns a temperature. + */ + virtual + double get_temperature(const Point<3> &position, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + /** + * The name of the feature type. + */ + std::string name; + + 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_FEATURE_FAULT_TEMPERATURE_MODEL(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 Temperature + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/fault_models/temperature/linear.h.bak b/contrib/world_builder/include/world_builder/features/fault_models/temperature/linear.h.bak new file mode 100644 index 00000000000..d70b8c57c15 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/fault_models/temperature/linear.h.bak @@ -0,0 +1,95 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_FAULT_MODELS_TEMPERATURE_LINEAR_H +#define WORLD_BUILDER_FEATURES_FAULT_MODELS_TEMPERATURE_LINEAR_H + + +#include "world_builder/features/fault_models/temperature/interface.h" + + +namespace WorldBuilder +{ + + namespace Features + { + namespace FaultModels + { + namespace Temperature + { + /** + * This class represents a subducting plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Linear final: public Interface + { + public: + /** + * constructor + */ + Linear(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Linear() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + + private: + // linear temperature submodule parameters + double min_depth; + double max_depth; + double center_temperature; + double side_temperature; + Operations operation; + + }; + } // namespace Temperature + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/fault_models/temperature/uniform.h.bak b/contrib/world_builder/include/world_builder/features/fault_models/temperature/uniform.h.bak new file mode 100644 index 00000000000..2b42e9faa4d --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/fault_models/temperature/uniform.h.bak @@ -0,0 +1,95 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_FAULT_MODELS_TEMPERATURE_UNIFORM_H +#define WORLD_BUILDER_FEATURES_FAULT_MODELS_TEMPERATURE_UNIFORM_H + + +#include "world_builder/features/fault_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + + namespace Features + { + namespace FaultModels + { + namespace Temperature + { + /** + * This class represents a subducting plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + + private: + // uniform temperature submodule parameters + double min_depth; + double max_depth; + double temperature; + Operations operation; + + }; + } // namespace Temperature + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/feature_utilities.h.bak b/contrib/world_builder/include/world_builder/features/feature_utilities.h.bak new file mode 100644 index 00000000000..997eed98995 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/feature_utilities.h.bak @@ -0,0 +1,101 @@ +/* + 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 . +*/ + + +#ifndef WORLD_BUILDER_FEATURES_FEATURE_UTILITIES_H +#define WORLD_BUILDER_FEATURES_FEATURE_UTILITIES_H + +#include +#include + +#include "world_builder/assert.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace FeatureUtilities + { + enum class Operations + { + REPLACE,ADD,SUBTRACT,REPLACE_DEFINED_ONLY + }; + + /** + * transforms string operations into enums. + */ + Operations + string_operations_to_enum(const std::string &operation); + + + /** + * Applies different operations such as replace, add and subtract to the original values + */ + inline double + apply_operation(const Operations operation, + const double old_value, + const double new_value) + { + switch (operation) + { + case Operations::REPLACE: + case Operations::REPLACE_DEFINED_ONLY: + return new_value; + break; + + case Operations::ADD: + return old_value + new_value; + break; + + case Operations::SUBTRACT: + return old_value - new_value; + + default: + WBAssert(false,"Operation not found."); + } + + return std::numeric_limits::signaling_NaN(); + } + + /** + * A struct that is used to hold additional values based on the output of + * the function distance_point_from_curved_planes(). + */ + struct AdditionalParameters + { + // The total length of all the segments at the location of the plane. + double total_local_segment_length; + + // The local thickness of the segment at the location of the plane. + double local_thickness; + }; + + + /** + * Add a string to a vector of strings, if the exact string isn't already + * in the vector. Returns the location of the string in the final vector. + */ + size_t + add_vector_unique(std::vector &vector,const std::string &add_string); + + } // namespace Utilities + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/interface.h.bak b/contrib/world_builder/include/world_builder/features/interface.h.bak new file mode 100644 index 00000000000..a23a45c7592 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/interface.h.bak @@ -0,0 +1,228 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_INTERFACE_H +#define WORLD_BUILDER_FEATURES_INTERFACE_H + + +#include "world_builder/grains.h" +#include "world_builder/utilities.h" +#include "world_builder/objects/distance_from_surface.h" + +namespace WorldBuilder +{ + class World; + class Parameters; + + + namespace Features + { + class ObjectFactory; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as continental plate, oceanic plate and subduction zone. + */ + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * helper function to parse coordinates. + */ + void + get_coordinates(const std::string &name, + Parameters &prm, + const CoordinateSystem coordinate_system); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + + /** + * takes a set of properties and a position and return a new set of properties + */ + virtual + void properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity, + const std::vector &entry_in_output, + std::vector &output) const = 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 &, const std::vector &required_entries), + void ( *make_snippet)(Parameters &), + ObjectFactory *factory); + + std::string get_name() const + { + return name; + }; + + + /** + * 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); + + /** + * Returns a PlaneDistances object that has the distance from and along a feature plane, + * calculated 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. + */ + WorldBuilder::World *world; + + /** + * The name of the feature type. + */ + std::string name; + + /** + * The index of the tag for this feature. + * This corresponds to the index in the feature_tags variable which is store in the World. + */ + size_t tag_index; + + /** + * The type of interpolation used to get the line position between the points. + */ + WorldBuilder::Utilities::InterpolationType interpolation_type; + + /** + * number of original coordinates, before adding + * more automatically. + */ + std::size_t original_number_of_coordinates; + + /** + * The coordinates at the surface of the feature + */ + std::vector > coordinates; + + /** + * The x and y spline + */ + WorldBuilder::Objects::BezierCurve bezier_curve; + + + /** + * The name of the temperature submodule used by this feature. + */ + std::string temperature_submodule_name; + + /** + * The name of the composition submodule used by this feature. + */ + std::string composition_submodule_name; + + + private: + static std::map &get_factory_map() + { + static std::map factories; + return factories; + } + + static std::map& required_entries)> &get_declare_map() + { + static std::map& required_entries)> declares; + return declares; + } + + static std::map &get_snippet_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_FEATURE(klass,name) \ + class klass##Factory : public ObjectFactory { \ + public: \ + klass##Factory() \ + { \ + Interface::registerType(#name, klass::declare_entries, klass::make_snippet, this); \ + } \ + std::unique_ptr create(World *world) override final { \ + return std::unique_ptr(new klass(world)); \ + } \ + }; \ + static klass##Factory global_##klass##Factory; + + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/mantle_layer.h.bak b/contrib/world_builder/include/world_builder/features/mantle_layer.h.bak new file mode 100644 index 00000000000..39785617f47 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/mantle_layer.h.bak @@ -0,0 +1,161 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_MANTLE_LAYER_H +#define WORLD_BUILDER_FEATURES_MANTLE_LAYER_H + + +#include "world_builder/features/interface.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + class Parameters; + class World; + + namespace Features + { + namespace MantleLayerModels + { + namespace Composition + { + class Interface; + } // namespace Composition + namespace Grains + { + class Interface; + } // namespace Grains + namespace Temperature + { + class Interface; + } // namespace Temperature + } // namespace MantleLayerModels + + /** + * This class represents a mantle layer and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class MantleLayer final: public Interface + { + public: + /** + * constructor + */ + MantleLayer(WorldBuilder::World *world); + + /** + * Destructor + */ + ~MantleLayer() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, + const std::string &parent_name = "", + const std::vector &required_entries = {}); + + /** + * Produce a JSON snippet for the schema + */ + static + void make_snippet(Parameters &prm); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns different values at a single point in one go stored in a vector of doubles. + * + * The properties input decides what each entry means, and the output is generated in the + * same order as the properties input. The properties input consists of + * a 3D array, where the first entry identifies the property and the last two entries + * provide extra information about that property. + * + * Temperature is identified by 1 and no extra information is needed. So temperature + * input usually looks like {1,0,0}. A temperature query prodoces one entry in the output + * vector. + * + * Composition is identified by 2. This produces one + * value in the output. The second entry identifies the composition number and the third + * number is not used. So a commposition query asking about composition 1 looks like this: + * {2,1,0}. A composition query prodoces one entry in the output vector. + * + * Grains are identified by 2. The second entry is the grain composition number and the third + * entry is the number of grains. A query about the grains, where it asks about composition 1 + * (for example enstatite) and 500 grains, looks like this: {2,1,500}. + * A composition query prodoces n_grains*10 entries in the output vector. The first n_grains + * entries are the sizes of all the grains, and the other 9 entries are sets of rotation + * matrices. The rotation matrix entries are ordered [0][0],[0][1],[0][2],[1][0],[1][1],etc. + * + * The entries in output variable relates the index of the property to the index in the output. + */ + void + properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity, + const std::vector &entry_in_output, + std::vector &output) const override final; + + private: + /** + * A vector containing all the pointers to the temperature models. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > temperature_models; + + /** + * A vector containing all the pointers to the composition models. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > composition_models; + + /** + * A vector containing all the pointers to the grains models. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > grains_models; + + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + + }; + + + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/mantle_layer_models/composition/interface.h.bak b/contrib/world_builder/include/world_builder/features/mantle_layer_models/composition/interface.h.bak new file mode 100644 index 00000000000..280cc7471bf --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/mantle_layer_models/composition/interface.h.bak @@ -0,0 +1,168 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_COMPOSITION_INTERFACE_H +#define WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_COMPOSITION_INTERFACE_H + + +#include "world_builder/parameters.h" +#include "world_builder/objects/natural_coordinate.h" + + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as continental plate, oceanic plate and subduction zone. + */ + namespace Features + { + + namespace MantleLayerModels + { + namespace Composition + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm, const std::vector> &coordinates) = 0; + + + /** + * takes composition and position and returns a composition. + */ + virtual + double get_composition(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + std::string name; + + + + 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_FEATURE_MANTLE_LAYER_COMPOSITION_MODEL(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 Composition + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/mantle_layer_models/composition/uniform.h.bak b/contrib/world_builder/include/world_builder/features/mantle_layer_models/composition/uniform.h.bak new file mode 100644 index 00000000000..247125db618 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/mantle_layer_models/composition/uniform.h.bak @@ -0,0 +1,98 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_COMPOSITION_UNIFORM_H +#define WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_COMPOSITION_UNIFORM_H + + +#include "world_builder/features/mantle_layer_models/composition/interface.h" +#include "world_builder/objects/surface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + namespace Features + { + using namespace FeatureUtilities; + namespace MantleLayerModels + { + namespace Composition + { + /** + * This class represents a mantle layer and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a composition based on the given position, depth in the model, + * gravity and current composition. + */ + double get_composition(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // uniform composition submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector compositions; + std::vector fractions; + Operations operation; + + }; + } // namespace Composition + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/interface.h.bak b/contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/interface.h.bak new file mode 100644 index 00000000000..3d86a58fb16 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/interface.h.bak @@ -0,0 +1,170 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_GRAINS_INTERFACE_H +#define WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_GRAINS_INTERFACE_H + + +#include "world_builder/grains.h" +#include "world_builder/parameters.h" +#include "world_builder/objects/natural_coordinate.h" + + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as continental plate, oceanic plate and subduction zone. + */ + namespace Features + { + + namespace MantleLayerModels + { + namespace Grains + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm, const std::vector> &coordinates) = 0; + + + /** + * takes composition and position and returns grains. + */ + virtual + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + std::string name; + + + + 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_FEATURE_MANTLE_LAYER_GRAINS_MODEL(klass,name) \ + class klass##Factory : public ObjectFactory { \ + public: \ + klass##Factory() \ + { \ + Interface::registerType(#name, klass::declare_entries, this); \ + } \ + virtual std::unique_ptr create(World *world) override final { \ + return std::unique_ptr(new klass(world)); \ + } \ + }; \ + static klass##Factory global_##klass##Factory; + + } // namespace Grains + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/random_uniform_distribution.h.bak b/contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/random_uniform_distribution.h.bak new file mode 100644 index 00000000000..ac8476e3742 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/random_uniform_distribution.h.bak @@ -0,0 +1,114 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_H +#define WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_H + + +#include "world_builder/features/mantle_layer_models/grains/interface.h" +#include "world_builder/objects/surface.h" + +namespace WorldBuilder +{ + + namespace Features + { + namespace MantleLayerModels + { + namespace Grains + { + /** + * This class represents a continental plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + class RandomUniformDistribution final: public Interface + { + public: + /** + * constructor + */ + RandomUniformDistribution(WorldBuilder::World *world); + + /** + * Destructor + */ + ~RandomUniformDistribution() override final; + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const override final; + + private: + // uniform grains submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector grain_sizes; + std::vector normalize_grain_sizes; + }; + } // namespace Grains + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/random_uniform_distribution_deflected.h.bak b/contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/random_uniform_distribution_deflected.h.bak new file mode 100644 index 00000000000..4d0bd807be8 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/random_uniform_distribution_deflected.h.bak @@ -0,0 +1,114 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_DEFLECTED_H +#define WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_DEFLECTED_H + + +#include "world_builder/features/mantle_layer_models/grains/interface.h" +#include "world_builder/objects/surface.h" + +namespace WorldBuilder +{ + + namespace Features + { + namespace MantleLayerModels + { + namespace Grains + { + /** + * This class represents a mantle layer and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + class RandomUniformDistributionDeflected final: public Interface + { + public: + /** + * constructor + */ + RandomUniformDistributionDeflected(WorldBuilder::World *world); + + /** + * Destructor + */ + ~RandomUniformDistributionDeflected() override final; + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const override final; + + private: + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector grain_sizes; + std::vector normalize_grain_sizes; + std::vector deflections; + }; + } // namespace Grains + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/uniform.h.bak b/contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/uniform.h.bak new file mode 100644 index 00000000000..60b8cd87b96 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/mantle_layer_models/grains/uniform.h.bak @@ -0,0 +1,114 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_GRAINS_UNIFORM_H +#define WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_GRAINS_UNIFORM_H + + +#include "world_builder/features/mantle_layer_models/grains/interface.h" +#include "world_builder/objects/surface.h" + +namespace WorldBuilder +{ + + namespace Features + { + namespace MantleLayerModels + { + namespace Grains + { + /** + * This class represents a oceanic plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + 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 parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const override final; + + private: + // uniform grains submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector, 3>> rotation_matrices; + std::vector grain_sizes; + }; + } // namespace Grains + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/adiabatic.h.bak b/contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/adiabatic.h.bak new file mode 100644 index 00000000000..e281a0510e2 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/adiabatic.h.bak @@ -0,0 +1,113 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_TEMPERATURE_ADIABATIC_H +#define WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_TEMPERATURE_ADIABATIC_H + + +#include "world_builder/features/mantle_layer_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + + namespace Features + { + using namespace FeatureUtilities; + namespace MantleLayerModels + { + namespace Temperature + { + /** + * This class represents a mantle layer and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Adiabatic final: public Interface + { + public: + /** + * constructor + */ + Adiabatic(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Adiabatic() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // adiabatic temperature submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + /** + * Todo + */ + double potential_mantle_temperature; + + + /** + * Todo + */ + double thermal_expansion_coefficient; + + /** + * Todo + */ + double specific_heat; + + Operations operation; + + }; + } // namespace Temperature + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/interface.h.bak b/contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/interface.h.bak new file mode 100644 index 00000000000..cc4dc67b6bd --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/interface.h.bak @@ -0,0 +1,169 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_TEMPERATURE_INTERFACE_H +#define WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_TEMPERATURE_INTERFACE_H + + +#include "world_builder/parameters.h" +#include "world_builder/objects/natural_coordinate.h" + + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as continental plate, oceanic plate and subduction zone. + */ + namespace Features + { + + namespace MantleLayerModels + { + namespace Temperature + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm, const std::vector> &coordinates) = 0; + + + /** + * takes temperature and position and returns a temperature. + */ + virtual + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + /** + * The name of the feature type. + */ + std::string name; + + 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_FEATURE_MANTLE_LAYER_TEMPERATURE_MODEL(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 Temperature + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/linear.h.bak b/contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/linear.h.bak new file mode 100644 index 00000000000..df29e574412 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/linear.h.bak @@ -0,0 +1,98 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_TEMPERATURE_LINEAR_H +#define WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_TEMPERATURE_LINEAR_H + + +#include "world_builder/features/mantle_layer_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + namespace Features + { + using namespace FeatureUtilities; + namespace MantleLayerModels + { + namespace Temperature + { + /** + * This class represents a mantle layer and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Linear final: public Interface + { + public: + /** + * constructor + */ + Linear(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Linear() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // linear temperature submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + double top_temperature; + double bottom_temperature; + Operations operation; + + }; + } // namespace Temperature + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/uniform.h.bak b/contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/uniform.h.bak new file mode 100644 index 00000000000..beb7a69d9ab --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/mantle_layer_models/temperature/uniform.h.bak @@ -0,0 +1,97 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_TEMPERATURE_UNIFORM_H +#define WORLD_BUILDER_FEATURES_MANTLE_LAYER_MODELS_TEMPERATURE_UNIFORM_H + + +#include "world_builder/features/mantle_layer_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + namespace Features + { + using namespace FeatureUtilities; + namespace MantleLayerModels + { + namespace Temperature + { + /** + * This class represents a mantle layer and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // uniform temperature submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + double temperature; + Operations operation; + + }; + } // namespace Temperature + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate.h.bak new file mode 100644 index 00000000000..50ec29c9c66 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate.h.bak @@ -0,0 +1,158 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_H + + +#include "world_builder/features/interface.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + class Parameters; + class World; + + namespace Features + { + namespace OceanicPlateModels + { + namespace Composition + { + class Interface; + } // namespace Composition + namespace Grains + { + class Interface; + } // namespace Grains + namespace Temperature + { + class Interface; + } // namespace Temperature + } // namespace OceanicPlateModels + + /** + * This class represents a oceanic plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class OceanicPlate final: public Interface + { + public: + /** + * constructor + */ + OceanicPlate(WorldBuilder::World *world); + + /** + * Destructor + */ + ~OceanicPlate() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, + const std::string &parent_name = "", + const std::vector &required_entries = {}); + + /** + * Produce a JSON snippet for the schema + */ + static + void make_snippet(Parameters &prm); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns different values at a single point in one go stored in a vector of doubles. + * + * The properties input decides what each entry means, and the output is generated in the + * same order as the properties input. The properties input consists of + * a 3D array, where the first entry identifies the property and the last two entries + * provide extra information about that property. + * + * Temperature is identified by 1 and no extra information is needed. So temperature + * input usually looks like {1,0,0}. A temperature query prodoces one entry in the output + * vector. + * + * Composition is identified by 2. This produces one + * value in the output. The second entry identifies the composition number and the third + * number is not used. So a commposition query asking about composition 1 looks like this: + * {2,1,0}. A composition query prodoces one entry in the output vector. + * + * Grains are identified by 2. The second entry is the grain composition number and the third + * entry is the number of grains. A query about the grains, where it asks about composition 1 + * (for example enstatite) and 500 grains, looks like this: {2,1,500}. + * A composition query prodoces n_grains*10 entries in the output vector. The first n_grains + * entries are the sizes of all the grains, and the other 9 entries are sets of rotation + * matrices. The rotation matrix entries are ordered [0][0],[0][1],[0][2],[1][0],[1][1],etc. + * + * The entries in output variable relates the index of the property to the index in the output. + */ + void + properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity, + const std::vector &entry_in_output, + std::vector &output) const override final; + + private: + /** + * A vector containing all the pointers to the temperature models. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > temperature_models; + + /** + * A vector containing all the pointers to the composition models. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > composition_models; + + /** + * A vector containing all the pointers to the grains models. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > grains_models; + + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + }; + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/composition/interface.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/composition/interface.h.bak new file mode 100644 index 00000000000..afb2cdf25f4 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/composition/interface.h.bak @@ -0,0 +1,168 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_COMPOSITION_INTERFACE_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_COMPOSITION_INTERFACE_H + + +#include "world_builder/parameters.h" +#include "world_builder/objects/natural_coordinate.h" + + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as oceanic plate, oceanic plate and subduction zone. + */ + namespace Features + { + + namespace OceanicPlateModels + { + namespace Composition + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm, const std::vector> &coordinates) = 0; + + + /** + * takes composition and position and returns a composition. + */ + virtual + double get_composition(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + std::string name; + + + + 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_FEATURE_OCEANIC_PLATE_COMPOSITION_MODEL(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 Composition + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/composition/uniform.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/composition/uniform.h.bak new file mode 100644 index 00000000000..d4ffad6943f --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/composition/uniform.h.bak @@ -0,0 +1,98 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_COMPOSITION_UNIFORM_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_COMPOSITION_UNIFORM_H + + +#include "world_builder/features/oceanic_plate_models/composition/interface.h" +#include "world_builder/objects/surface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + namespace Features + { + using namespace FeatureUtilities; + namespace OceanicPlateModels + { + namespace Composition + { + /** + * This class represents a oceanic plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a composition based on the given position, depth in the model, + * gravity and current composition. + */ + double get_composition(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // uniform composition submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector compositions; + std::vector fractions; + Operations operation; + + }; + } // namespace Composition + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/interface.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/interface.h.bak new file mode 100644 index 00000000000..33cb8afaf05 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/interface.h.bak @@ -0,0 +1,166 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_GRAINS_INTERFACE_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_GRAINS_INTERFACE_H + + +#include "world_builder/grains.h" +#include "world_builder/parameters.h" +#include "world_builder/objects/natural_coordinate.h" + + +namespace WorldBuilder +{ + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as oceanic plate, oceanic plate and subduction zone. + */ + namespace Features + { + + namespace OceanicPlateModels + { + namespace Grains + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm, const std::vector> &coordinates) = 0; + + + /** + * takes composition and position and returns grains. + */ + virtual + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + std::string name; + + + + 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_FEATURE_OCEANIC_PLATE_GRAINS_MODEL(klass,name) \ + class klass##Factory : public ObjectFactory { \ + public: \ + klass##Factory() \ + { \ + Interface::registerType(#name, klass::declare_entries, this); \ + } \ + virtual std::unique_ptr create(World *world) override final { \ + return std::unique_ptr(new klass(world)); \ + } \ + }; \ + static klass##Factory global_##klass##Factory; + + } // namespace Grains + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution.h.bak new file mode 100644 index 00000000000..6b9604d0f2c --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution.h.bak @@ -0,0 +1,114 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_H + + +#include "world_builder/features/oceanic_plate_models/grains/interface.h" +#include "world_builder/objects/surface.h" + +namespace WorldBuilder +{ + + namespace Features + { + namespace OceanicPlateModels + { + namespace Grains + { + /** + * This class represents a continental plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + class RandomUniformDistribution final: public Interface + { + public: + /** + * constructor + */ + RandomUniformDistribution(WorldBuilder::World *world); + + /** + * Destructor + */ + ~RandomUniformDistribution() override final; + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const override final; + + private: + // uniform grains submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector grain_sizes; + std::vector normalize_grain_sizes; + }; + } // namespace Grains + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution_deflected.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution_deflected.h.bak new file mode 100644 index 00000000000..4a80945817d --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution_deflected.h.bak @@ -0,0 +1,114 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_DEFLECTED_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_DEFLECTED_H + + +#include "world_builder/features/oceanic_plate_models/grains/interface.h" +#include "world_builder/objects/surface.h" + +namespace WorldBuilder +{ + + namespace Features + { + namespace OceanicPlateModels + { + namespace Grains + { + /** + * This class represents a continental plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + class RandomUniformDistributionDeflected final: public Interface + { + public: + /** + * constructor + */ + RandomUniformDistributionDeflected(WorldBuilder::World *world); + + /** + * Destructor + */ + ~RandomUniformDistributionDeflected() override final; + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const override final; + + private: + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector grain_sizes; + std::vector normalize_grain_sizes; + std::vector deflections; + }; + } // namespace Grains + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/uniform.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/uniform.h.bak new file mode 100644 index 00000000000..ba08f845e69 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/grains/uniform.h.bak @@ -0,0 +1,114 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_GRAINS_UNIFORM_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_GRAINS_UNIFORM_H + + +#include "world_builder/features/oceanic_plate_models/grains/interface.h" +#include "world_builder/objects/surface.h" + +namespace WorldBuilder +{ + + namespace Features + { + namespace OceanicPlateModels + { + namespace Grains + { + /** + * This class represents a oceanic plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + 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 parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const override final; + + private: + // uniform grains submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector, 3>> rotation_matrices; + std::vector grain_sizes; + }; + } // namespace Grains + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/adiabatic.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/adiabatic.h.bak new file mode 100644 index 00000000000..9147f3b99fb --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/adiabatic.h.bak @@ -0,0 +1,112 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_ADIABATIC_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_ADIABATIC_H + + +#include "world_builder/features/oceanic_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + namespace Features + { + using namespace FeatureUtilities; + namespace OceanicPlateModels + { + namespace Temperature + { + /** + * This class represents a oceanic plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Adiabatic final: public Interface + { + public: + /** + * constructor + */ + Adiabatic(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Adiabatic() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // adiabatic temperature submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + /** + * Todo + */ + double potential_mantle_temperature; + + + /** + * Todo + */ + double thermal_expansion_coefficient; + + /** + * Todo + */ + double specific_heat; + + Operations operation; + + }; + } // namespace Temperature + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/half_space_model.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/half_space_model.h.bak new file mode 100644 index 00000000000..967134ec5c9 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/half_space_model.h.bak @@ -0,0 +1,103 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_HALF_SPACE_MODEL_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_HALF_SPACE_MODEL_H + + +#include "world_builder/features/oceanic_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + class Parameters; + class World; + + namespace Features + { + using namespace FeatureUtilities; + namespace OceanicPlateModels + { + namespace Temperature + { + /** + * This class represents a oceanic plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class HalfSpaceModel final: public Interface + { + public: + /** + * constructor + */ + HalfSpaceModel(WorldBuilder::World *world); + + /** + * Destructor + */ + ~HalfSpaceModel() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const override final; + + private: + // plate model temperature submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + double top_temperature; + double bottom_temperature; + std::pair,std::vector> spreading_velocities; + std::vector > > mid_oceanic_ridges; + std::vector> spreading_velocities_at_each_ridge_point; + Operations operation; + + }; + } // namespace Temperature + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/interface.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/interface.h.bak new file mode 100644 index 00000000000..5239b8570b5 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/interface.h.bak @@ -0,0 +1,169 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_INTERFACE_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_INTERFACE_H + + +#include "world_builder/parameters.h" +#include "world_builder/objects/natural_coordinate.h" + + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as oceanic plate, oceanic plate and subduction zone. + */ + namespace Features + { + + namespace OceanicPlateModels + { + namespace Temperature + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm, const std::vector> &coordinates) = 0; + + + /** + * takes temperature and position and returns a temperature. + */ + virtual + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + /** + * The name of the feature type. + */ + std::string name; + + 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_FEATURE_OCEANIC_PLATE_TEMPERATURE_MODEL(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 Temperature + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/linear.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/linear.h.bak new file mode 100644 index 00000000000..3044603f3af --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/linear.h.bak @@ -0,0 +1,98 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_LINEAR_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_LINEAR_H + + +#include "world_builder/features/oceanic_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + namespace Features + { + using namespace FeatureUtilities; + namespace OceanicPlateModels + { + namespace Temperature + { + /** + * This class represents a oceanic plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Linear final: public Interface + { + public: + /** + * constructor + */ + Linear(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Linear() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // linear temperature submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + double top_temperature; + double bottom_temperature; + Operations operation; + + }; + } // namespace Temperature + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/plate_model.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/plate_model.h.bak new file mode 100644 index 00000000000..ef381bd6f0a --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/plate_model.h.bak @@ -0,0 +1,107 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_PLATE_MODEL_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_PLATE_MODEL_H + + +#include "world_builder/features/oceanic_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + class Parameters; + class World; + + namespace Features + { + using namespace FeatureUtilities; + namespace OceanicPlateModels + { + namespace Temperature + { + /** + * This class represents a oceanic plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + * In this plugin, the temperature of the plate is derived from the plate model, + * featuring continuous cooling of a plate from a spreading ridge by both vertical + * and horizontal heat conduction. + */ + class PlateModel final: public Interface + { + public: + /** + * constructor + */ + PlateModel(WorldBuilder::World *world); + + /** + * Destructor + */ + ~PlateModel() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // plate model temperature submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + double top_temperature; + double bottom_temperature; + std::pair,std::vector> spreading_velocities; + std::vector > > mid_oceanic_ridges; + std::vector> spreading_velocities_at_each_ridge_point; + Operations operation; + + }; + } // namespace Temperature + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/plate_model_constant_age.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/plate_model_constant_age.h.bak new file mode 100644 index 00000000000..b73e6ebfc51 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/plate_model_constant_age.h.bak @@ -0,0 +1,105 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_PLATE_MODEL_CONSTANT_AGE_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_PLATE_MODEL_CONSTANT_AGE_H + + +#include "world_builder/features/oceanic_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + class Parameters; + class World; + + namespace Features + { + using namespace FeatureUtilities; + namespace OceanicPlateModels + { + namespace Temperature + { + /** + * This class represents a oceanic plate of constant age and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + * In this plugin, the temperature of the plate is derived from the plate model, + * featuring cooling of a plate from a ridge by vertical heat conduction, + * while the effects of horizontal heat conduction are ignored. + */ + class PlateModelConstantAge final: public Interface + { + public: + /** + * constructor + */ + PlateModelConstantAge(WorldBuilder::World *world); + + /** + * Destructor + */ + ~PlateModelConstantAge() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // plate model constant age temperature submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + double top_temperature; + double bottom_temperature; + double plate_age; + Operations operation; + + }; + } // namespace Temperature + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/uniform.h.bak b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/uniform.h.bak new file mode 100644 index 00000000000..031e3c3a004 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/oceanic_plate_models/temperature/uniform.h.bak @@ -0,0 +1,97 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_UNIFORM_H +#define WORLD_BUILDER_FEATURES_OCEANIC_PLATE_MODELS_TEMPERATURE_UNIFORM_H + + +#include "world_builder/features/oceanic_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + namespace Features + { + using namespace FeatureUtilities; + namespace OceanicPlateModels + { + namespace Temperature + { + /** + * This class represents a oceanic plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm, const std::vector> &coordinates) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // uniform temperature submodule parameters + double min_depth; + Objects::Surface min_depth_surface; + double max_depth; + Objects::Surface max_depth_surface; + double temperature; + Operations operation; + + }; + } // namespace Temperature + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/plume.h.bak b/contrib/world_builder/include/world_builder/features/plume.h.bak new file mode 100644 index 00000000000..cbd73cf8d4a --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/plume.h.bak @@ -0,0 +1,164 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_PLUME_H +#define WORLD_BUILDER_FEATURES_PLUME_H + + +#include "world_builder/features/interface.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + class Parameters; + class World; + + namespace Features + { + namespace PlumeModels + { + namespace Composition + { + class Interface; + } // namespace Composition + namespace Grains + { + class Interface; + } // namespace Grains + namespace Temperature + { + class Interface; + } // namespace Temperature + } // namespace PlumeModels + + /** + * This class represents a plume and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Plume final: public Interface + { + public: + /** + * constructor + */ + Plume(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Plume() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, + const std::string &parent_name = "", + const std::vector &required_entries = {}); + + /** + * Produce a JSON snippet for the schema + */ + static + void make_snippet(Parameters &prm); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns different values at a single point in one go stored in a vector of doubles. + * + * The properties input decides what each entry means, and the output is generated in the + * same order as the properties input. The properties input consists of + * a 3D array, where the first entry identifies the property and the last two entries + * provide extra information about that property. + * + * Temperature is identified by 1 and no extra information is needed. So temperature + * input usually looks like {1,0,0}. A temperature query prodoces one entry in the output + * vector. + * + * Composition is identified by 2. This produces one + * value in the output. The second entry identifies the composition number and the third + * number is not used. So a commposition query asking about composition 1 looks like this: + * {2,1,0}. A composition query produces one entry in the output vector. + * + * Grains are identified by 2. The second entry is the grain composition number and the third + * entry is the number of grains. A query about the grains, where it asks about composition 1 + * (for example enstatite) and 500 grains, looks like this: {2,1,500}. + * A composition query prodoces n_grains*10 entries in the output vector. The first n_grains + * entries are the sizes of all the grains, and the other 9 entries are sets of rotation + * matrices. The rotation matrix entries are ordered [0][0],[0][1],[0][2],[1][0],[1][1],etc. + * + * The entries in output variable relates the index of the property to the index in the output. + */ + void + properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity, + const std::vector &entry_in_output, + std::vector &output) const override final; + + private: + /** + * A vector containing all the pointers to the temperature models. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > temperature_models; + + /** + * A vector containing all the pointers to the composition models. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > composition_models; + + /** + * A vector containing all the pointers to the grains models. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > grains_models; + + + double min_depth; + double max_depth; + + std::vector depths; + std::vector semi_major_axis_lengths; + std::vector eccentricities; + std::vector rotation_angles; + }; + + + } // namespace Features +} // namespace WorldBuilder + +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/features/plume_models/composition/interface.h.bak b/contrib/world_builder/include/world_builder/features/plume_models/composition/interface.h.bak new file mode 100644 index 00000000000..ad34a427e22 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/plume_models/composition/interface.h.bak @@ -0,0 +1,164 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_PLUME_MODELS_COMPOSITION_INTERFACE_H +#define WORLD_BUILDER_FEATURES_PLUME_MODELS_COMPOSITION_INTERFACE_H + + +#include "world_builder/parameters.h" +#include "world_builder/objects/natural_coordinate.h" + +namespace WorldBuilder +{ + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as continental plate, oceanic plate and subduction zone. + */ + namespace Features + { + + namespace PlumeModels + { + namespace Composition + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + + /** + * takes composition and position and returns a composition. + */ + virtual + double get_composition(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + std::string name; + + + + 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_FEATURE_PLUME_COMPOSITION_MODEL(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 Composition + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/plume_models/composition/uniform.h.bak b/contrib/world_builder/include/world_builder/features/plume_models/composition/uniform.h.bak new file mode 100644 index 00000000000..209bd78c2d6 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/plume_models/composition/uniform.h.bak @@ -0,0 +1,97 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_PLUME_MODELS_COMPOSITION_UNIFORM_H +#define WORLD_BUILDER_FEATURES_PLUME_MODELS_COMPOSITION_UNIFORM_H + + +#include "world_builder/features/plume_models/composition/interface.h" +#include "world_builder/objects/surface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + namespace Features + { + using namespace FeatureUtilities; + namespace PlumeModels + { + namespace Composition + { + /** + * This class represents a plume and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a composition based on the given position, depth in the model, + * gravity and current composition. + */ + double get_composition(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth) const override final; + + + private: + // uniform composition submodule parameters + + double min_depth; + double max_depth; + std::vector compositions; + std::vector fractions; + Operations operation; + + }; + } // namespace Composition + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/plume_models/grains/interface.h.bak b/contrib/world_builder/include/world_builder/features/plume_models/grains/interface.h.bak new file mode 100644 index 00000000000..b18fbd11b17 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/plume_models/grains/interface.h.bak @@ -0,0 +1,170 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_PLUME_MODELS_GRAINS_INTERFACE_H +#define WORLD_BUILDER_FEATURES_PLUME_MODELS_GRAINS_INTERFACE_H + + +#include "world_builder/grains.h" +#include "world_builder/parameters.h" +#include "world_builder/objects/natural_coordinate.h" + + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as continental plate, oceanic plate and subduction zone. + */ + namespace Features + { + + namespace PlumeModels + { + namespace Grains + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + + /** + * takes composition and position and returns grains. + */ + virtual + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + std::string name; + + + + 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_FEATURE_PLUME_GRAINS_MODEL(klass,name) \ + class klass##Factory : public ObjectFactory { \ + public: \ + klass##Factory() \ + { \ + Interface::registerType(#name, klass::declare_entries, this); \ + } \ + virtual std::unique_ptr create(World *world) override final { \ + return std::unique_ptr(new klass(world)); \ + } \ + }; \ + static klass##Factory global_##klass##Factory; + + } // namespace Grains + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/plume_models/grains/uniform.h.bak b/contrib/world_builder/include/world_builder/features/plume_models/grains/uniform.h.bak new file mode 100644 index 00000000000..ad906fa95d3 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/plume_models/grains/uniform.h.bak @@ -0,0 +1,111 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_PLUME_MODELS_GRAINS_UNIFORM_H +#define WORLD_BUILDER_FEATURES_PLUME_MODELS_GRAINS_UNIFORM_H + + +#include "world_builder/features/plume_models/grains/interface.h" +#include "world_builder/objects/surface.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace PlumeModels + { + namespace Grains + { + /** + * This class represents a plume and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + 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 parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth) const override final; + + private: + // uniform grains submodule parameters + double min_depth; + double max_depth; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector, 3>> rotation_matrices; + std::vector grain_sizes; + }; + } // namespace Grains + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/plume_models/temperature/gaussian.h.bak b/contrib/world_builder/include/world_builder/features/plume_models/temperature/gaussian.h.bak new file mode 100644 index 00000000000..6dd80a0b8ee --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/plume_models/temperature/gaussian.h.bak @@ -0,0 +1,96 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_PLUME_MODELS_TEMPERATURE_GAUSSIAN_H +#define WORLD_BUILDER_FEATURES_PLUME_MODELS_TEMPERATURE_GAUSSIAN_H + + +#include "world_builder/features/plume_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + + namespace Features + { + using namespace FeatureUtilities; + namespace PlumeModels + { + namespace Temperature + { + /** + * This class represents a plume and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Gaussian final: public Interface + { + public: + /** + * constructor + */ + Gaussian(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Gaussian() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const double relative_distance_from_center) const override final; + + + private: + // Gaussian temperature submodule parameters + std::vector depths; + std::vector center_temperatures; + std::vector gaussian_sigmas; + Operations operation; + + }; + } // namespace Temperature + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/plume_models/temperature/interface.h.bak b/contrib/world_builder/include/world_builder/features/plume_models/temperature/interface.h.bak new file mode 100644 index 00000000000..8f4ba5dd579 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/plume_models/temperature/interface.h.bak @@ -0,0 +1,173 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_PLUME_MODELS_TEMPERATURE_INTERFACE_H +#define WORLD_BUILDER_FEATURES_PLUME_MODELS_TEMPERATURE_INTERFACE_H + + +#include "world_builder/parameters.h" +#include "world_builder/objects/natural_coordinate.h" + + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as continental plate, oceanic plate and subduction zone. + */ + namespace Features + { + + namespace PlumeModels + { + namespace Temperature + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + + /** + * takes temperature and position and returns a temperature. + * The relative distance from center gives the result of the ellipse + * equation, i.e., x^2/a^2 + y^2/b^2, i.e., it tells us how far we + * are between the center and margin of the ellipse. + */ + virtual + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const double relative_distance_from_center) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + /** + * The name of the feature type. + */ + std::string name; + + 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_FEATURE_PLUME_TEMPERATURE_MODEL(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 Temperature + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/features/plume_models/temperature/uniform.h.bak b/contrib/world_builder/include/world_builder/features/plume_models/temperature/uniform.h.bak new file mode 100644 index 00000000000..d6032cd8d66 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/plume_models/temperature/uniform.h.bak @@ -0,0 +1,98 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_PLUME_MODELS_TEMPERATURE_UNIFORM_H +#define WORLD_BUILDER_FEATURES_PLUME_MODELS_TEMPERATURE_UNIFORM_H + + +#include "world_builder/features/plume_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/objects/surface.h" + + +namespace WorldBuilder +{ + + namespace Features + { + using namespace FeatureUtilities; + namespace PlumeModels + { + namespace Temperature + { + /** + * This class represents a plume and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + * In this class, the temperature within the plume is uniform. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const double relative_distance_from_center) const override final; + + + private: + // uniform temperature submodule parameters + double min_depth; + double max_depth; + double temperature; + Operations operation; + + }; + } // namespace Temperature + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate.h.bak new file mode 100644 index 00000000000..2be2f50939e --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate.h.bak @@ -0,0 +1,230 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_H + + +#include "world_builder/features/subducting_plate_models/composition/interface.h" +#include "world_builder/features/subducting_plate_models/grains/interface.h" +#include "world_builder/features/subducting_plate_models/temperature/interface.h" +#include "world_builder/objects/segment.h" +#include "world_builder/bounding_box.h" +#include "world_builder/objects/distance_from_surface.h" + + +namespace WorldBuilder +{ + class Parameters; + class World; + + namespace Features + { + using namespace FeatureUtilities; + namespace SubductingPlateModels + { + namespace Composition + { + class Interface; + } // namespace Composition + namespace Grains + { + class Interface; + } // namespace Grains + namespace Temperature + { + class Interface; + } // namespace Temperature + } // namespace SubductingPlateModels + + /** + * This class represents a subducting plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class SubductingPlate final: public Interface + { + public: + /** + * constructor + */ + SubductingPlate(WorldBuilder::World *world); + + /** + * Destructor + */ + ~SubductingPlate() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, + const std::string &parent_name = "", + const std::vector &required_entries = {}); + + /** + * Produce a JSON snippet for the schema + */ + static + void make_snippet(Parameters &prm); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns the bounding points for a BoundingBox object using two extreme points in all the surface + * coordinates and an additional buffer zone that accounts for the fault thickness and length. The first and second + * points correspond to the lower left and the upper right corners of the bounding box, respectively (see the + * documentation in include/bounding_box.h). + * For the spherical system, the buffer zone along the longitudal direction is calculated using the + * corresponding latitude points. + */ + const BoundingBox<2> &get_surface_bounding_box () const; + + /** + * Returns different values at a single point in one go stored in a vector of doubles. + * + * The properties input decides what each entry means, and the output is generated in the + * same order as the properties input. The properties input consists of + * a 3D array, where the first entry identifies the property and the last two entries + * provide extra information about that property. + * + * Temperature is identified by 1 and no extra information is needed. So temperature + * input usually looks like {1,0,0}. A temperature query prodoces one entry in the output + * vector. + * + * Composition is identified by 2. This produces one + * value in the output. The second entry identifies the composition number and the third + * number is not used. So a commposition query asking about composition 1 looks like this: + * {2,1,0}. A composition query prodoces one entry in the output vector. + * + * Grains are identified by 2. The second entry is the grain composition number and the third + * entry is the number of grains. A query about the grains, where it asks about composition 1 + * (for example enstatite) and 500 grains, looks like this: {2,1,500}. + * A composition query prodoces n_grains*10 entries in the output vector. The first n_grains + * entries are the sizes of all the grains, and the other 9 entries are sets of rotation + * matrices. The rotation matrix entries are ordered [0][0],[0][1],[0][2],[1][0],[1][1],etc. + * + * The entries in output variable relates the index of the property to the index in the output. + */ + void + properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity, + 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, + * calculated 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; + std::vector > default_grains_models; + + std::vector > default_segment_vector; + + std::vector< std::vector > > sections_segment_vector; + + // This vector stores segments to this coordinate/section. + //First used (raw) pointers to the segment relevant to this coordinate/section, + // but I do not trust it won't fail when memory is moved. So storing the all the data now. + std::vector > > segment_vector; + + // todo: the memory of this can be greatly improved by + // or using a plugin system for the submodules, or + // putting the variables in a union. Although the memory + // used by this program is in real cases expected to be + // Insignificant compared to what a calling program may + // use, a smaller amount of memory used in here, could + // theoretically speed up the computation, because more + // relevant data could be stored in the cache. But this + // not a urgent problem, and would require testing. + + /** + * This variable stores the depth at which the subducting + * plate starts. It makes this depth effectively the surface + * of the model for the slab. + */ + double starting_depth; + + /** + * The depth which below the subducting plate may no longer + * be present. This can not only help setting up models with + * less effort, but can also improve performance, because + * the algorithm doesn't have to search in locations below + * this depth. + */ + double maximum_depth; + + /** + * Stores the bounding points for a BoundingBox object using two extreme points in all the surface + * coordinates and an additional buffer zone that accounts for the fault thickness and length. The first and second + * points correspond to the lower left and the upper right corners of the bounding box, respectively (see the + * documentation in include/bounding_box.h). + * For the spherical system, the buffer zone along the longitudal direction is calculated using the + * corresponding latitude points. + */ + BoundingBox<2> surface_bounding_box; + + /** + * A point on the surface to which the subducting plates subduct. + */ + Point<2> reference_point; + + std::vector > slab_segment_lengths; + std::vector > > slab_segment_thickness; + std::vector > > slab_segment_top_truncation; + std::vector > > slab_segment_angles; + std::vector total_slab_length; + double maximum_total_slab_length; + double maximum_slab_thickness; + + double min_along_x; + double max_along_x; + double min_along_y; + double max_along_y; + double min_lat_cos_inv; + double max_lat_cos_inv; + double buffer_around_slab_cartesian; + }; + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/composition/interface.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/composition/interface.h.bak new file mode 100644 index 00000000000..130ad43c0e0 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/composition/interface.h.bak @@ -0,0 +1,173 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_COMPOSITION_INTERFACE_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_COMPOSITION_INTERFACE_H + +#include "world_builder/grains.h" +#include "world_builder/parameters.h" +#include "world_builder/utilities.h" +#include "world_builder/features/feature_utilities.h" + +#include +#include + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as oceanic plate, oceanic plate and subduction zone. + */ + namespace Features + { + using namespace FeatureUtilities; + + namespace SubductingPlateModels + { + namespace Composition + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + + /** + * takes composition and position and returns a composition. + */ + virtual + double get_composition(const Point<3> &position, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + std::string name; + + + + 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_FEATURE_SUBDUCTING_PLATE_COMPOSITION_MODEL(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 Composition + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/composition/smooth.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/composition/smooth.h.bak new file mode 100644 index 00000000000..b6ff89a5fa8 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/composition/smooth.h.bak @@ -0,0 +1,98 @@ +/* + 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 . +*/ + +#ifndef _world_builder_features_subducting_plate_composition_smooth_h +#define _world_builder_features_subducting_plate_composition_smooth_h + +#include +#include +#include + + +namespace WorldBuilder +{ + namespace Features + { + using namespace FeatureUtilities; + namespace SubductingPlateModels + { + namespace Composition + { + /** + * This class represents a subducting plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Smooth: public Interface + { + public: + /** + * constructor + */ + Smooth(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Smooth(); + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a composition based on the given position, depth in the model, + * and current composition. + */ + double get_composition(const Point<3> &position, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + private: + // linear temperature submodule parameters + double min_distance; + double max_distance; + double side_distance; + std::vector top_fraction; + // currently not using the side composition, but maybe usefu if you want another composition towards the end + std::vector bottom_fraction; + std::vector compositions; + Operations operation; + + }; + } + } + } +} + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/composition/uniform.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/composition/uniform.h.bak new file mode 100644 index 00000000000..dd10cfb725d --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/composition/uniform.h.bak @@ -0,0 +1,95 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_COMPOSITION_UNIFORM_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_COMPOSITION_UNIFORM_H + + +#include "world_builder/features/subducting_plate_models/composition/interface.h" + + +namespace WorldBuilder +{ + + namespace Features + { + namespace SubductingPlateModels + { + namespace Composition + { + /** + * This class represents a subducting plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a composition based on the given position, depth in the model, + * gravity and current composition. + */ + double get_composition(const Point<3> &position, + const double depth, + const unsigned int composition_number, + double composition, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + + private: + // uniform composition submodule parameters + double min_depth; + double max_depth; + std::vector compositions; + std::vector fractions; + Operations operation; + + }; + } // namespace Composition + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/interface.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/interface.h.bak new file mode 100644 index 00000000000..82999be947f --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/interface.h.bak @@ -0,0 +1,173 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_GRAINS_INTERFACE_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_GRAINS_INTERFACE_H + +#include "world_builder/grains.h" +#include "world_builder/parameters.h" +#include "world_builder/utilities.h" +#include "world_builder/features/feature_utilities.h" + +#include +#include + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as oceanic plate, oceanic plate and subduction zone. + */ + namespace Features + { + using namespace FeatureUtilities; + namespace SubductingPlateModels + { + namespace Grains + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + + /** + * takes composition and position and returns a composition. + */ + virtual + WorldBuilder::grains + get_grains(const Point<3> &position, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + std::string name; + + + + 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_FEATURE_SUBDUCTING_PLATE_GRAINS_MODEL(klass,name) \ + class klass##Factory : public ObjectFactory { \ + public: \ + klass##Factory() \ + { \ + Interface::registerType(#name, klass::declare_entries, this); \ + } \ + virtual std::unique_ptr create(World *world) override final { \ + return std::unique_ptr(new klass(world)); \ + } \ + }; \ + static klass##Factory global_##klass##Factory; + + } // namespace Grains + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/random_uniform_distribution.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/random_uniform_distribution.h.bak new file mode 100644 index 00000000000..45f1e8f2395 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/random_uniform_distribution.h.bak @@ -0,0 +1,112 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_H + + +#include "world_builder/features/subducting_plate_models/grains/interface.h" + +namespace WorldBuilder +{ + + namespace Features + { + namespace SubductingPlateModels + { + namespace Grains + { + /** + * This class represents a continental plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + class RandomUniformDistribution final: public Interface + { + public: + /** + * constructor + */ + RandomUniformDistribution(WorldBuilder::World *world); + + /** + * Destructor + */ + ~RandomUniformDistribution() override final; + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + private: + // uniform grains submodule parameters + double min_depth; + double max_depth; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector grain_sizes; + std::vector normalize_grain_sizes; + }; + } // namespace Grains + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/random_uniform_distribution_deflected.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/random_uniform_distribution_deflected.h.bak new file mode 100644 index 00000000000..ddaada0be0b --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/random_uniform_distribution_deflected.h.bak @@ -0,0 +1,113 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_DEFLECTED_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_GRAINS_RANDOM_UNIFORM_DISTRIBUTION_DEFLECTED_H + + +#include "world_builder/features/subducting_plate_models/grains/interface.h" + +namespace WorldBuilder +{ + + namespace Features + { + namespace SubductingPlateModels + { + namespace Grains + { + /** + * This class represents a subducting plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + class RandomUniformDistributionDeflected final: public Interface + { + public: + /** + * constructor + */ + RandomUniformDistributionDeflected(WorldBuilder::World *world); + + /** + * Destructor + */ + ~RandomUniformDistributionDeflected() override final; + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + private: + double min_depth; + double max_depth; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector grain_sizes; + std::vector normalize_grain_sizes; + std::vector deflections; + + }; + } // namespace Grains + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/uniform.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/uniform.h.bak new file mode 100644 index 00000000000..7265453073a --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/grains/uniform.h.bak @@ -0,0 +1,112 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_GRAINS_UNIFORM_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_GRAINS_UNIFORM_H + + +#include "world_builder/features/subducting_plate_models/grains/interface.h" + +namespace WorldBuilder +{ + + namespace Features + { + namespace SubductingPlateModels + { + namespace Grains + { + /** + * This class represents a oceanic plate and can implement + * submodules for temperature and grains. These submodules determine + * what the returned temperature or grains of the temperature and grains + * functions of this class will be. + */ + 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 parameters + * class + */ + static void declare_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void declare_grain_size_model_entries( + Parameters &prm, const std::string &parent_name, + const std::vector &required_entries); + + /** + * declare and read in the world builder file into the parameters + * class + */ + static void + declare_fixed_size_model_entries(Parameters &prm, + const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters + * class + */ + void parse_entries(Parameters &prm) override final; + + /** + * Returns a grains based on the given position, composition (e.g. + * olivine and/or enstatite)depth in the model, gravity and current grains. + */ + WorldBuilder::grains + get_grains(const Point<3> &position, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + private: + // uniform grains submodule parameters + double min_depth; + double max_depth; + std::vector grains; + std::vector compositions; + std::string operation; + std::vector, 3>> rotation_matrices; + std::vector grain_sizes; + }; + } // namespace Grains + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/adiabatic.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/adiabatic.h.bak new file mode 100644 index 00000000000..9fb26e304ff --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/adiabatic.h.bak @@ -0,0 +1,110 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_TEMPERATURE_ADIABATIC_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_TEMPERATURE_ADIABATIC_H + + +#include "world_builder/features/subducting_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + + namespace Features + { + namespace SubductingPlateModels + { + namespace Temperature + { + /** + * This class represents a subducting plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Adiabatic final: public Interface + { + public: + /** + * constructor + */ + Adiabatic(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Adiabatic() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + + private: + // adiabatic temperature submodule parameters + double min_depth; + double max_depth; + /** + * Todo + */ + double potential_mantle_temperature; + + + /** + * Todo + */ + double thermal_expansion_coefficient; + + /** + * Todo + */ + double specific_heat; + + Operations operation; + + }; + } // namespace Temperature + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/interface.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/interface.h.bak new file mode 100644 index 00000000000..78bf056680e --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/interface.h.bak @@ -0,0 +1,174 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_TEMPERATURE_INTERFACE_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_TEMPERATURE_INTERFACE_H + +#include "world_builder/grains.h" +#include "world_builder/parameters.h" +#include "world_builder/utilities.h" +#include "world_builder/features/feature_utilities.h" + +#include +#include + +namespace WorldBuilder +{ + class World; + class Parameters; + template class Point; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as oceanic plate, oceanic plate and subduction zone. + */ + namespace Features + { + using namespace FeatureUtilities; + + namespace SubductingPlateModels + { + namespace Temperature + { + class ObjectFactory; + + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + + /** + * takes temperature and position and returns a temperature. + */ + virtual + double get_temperature(const Point<3> &position, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const = 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); + + /** + * Returns the name of the plugin + */ + std::string get_name() const + { + return name; + }; + + protected: + /** + * A pointer to the world class to retrieve variables. + */ + WorldBuilder::World *world; + + /** + * The name of the feature type. + */ + std::string name; + + 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_FEATURE_SUBDUCTING_PLATE_TEMPERATURE_MODEL(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 Temperature + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/linear.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/linear.h.bak new file mode 100644 index 00000000000..7484cf35fe8 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/linear.h.bak @@ -0,0 +1,96 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_TEMPERATURE_LINEAR_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_TEMPERATURE_LINEAR_H + + +#include "world_builder/features/subducting_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + + namespace Features + { + namespace SubductingPlateModels + { + namespace Temperature + { + /** + * This class represents a subducting plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class Linear final: public Interface + { + public: + /** + * constructor + */ + Linear(WorldBuilder::World *world); + + /** + * Destructor + */ + ~Linear() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + + private: + // linear temperature submodule parameters + double min_depth; + double max_depth; + double top_temperature; + double bottom_temperature; + Operations operation; + + }; + } // namespace Temperature + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/mass_conserving.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/mass_conserving.h.bak new file mode 100644 index 00000000000..38344fb90c1 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/mass_conserving.h.bak @@ -0,0 +1,143 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_TEMPERATURE_MASS_CONSERVING_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_TEMPERATURE_MASS_CONSERVING_H + + +#include "world_builder/features/subducting_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + + namespace Features + { + namespace SubductingPlateModels + { + namespace Temperature + { + /** + * This class represents a subducting plate temperature model. The temperature + * model uses the heat content (proportional to to thermal mass anomaly) to + * define a smooth temperature profile that conserves mass along the slab length. + * An empirical (linear) model is used to define how the minimum temperature + * increases with depth and how the location of the minimum temperature shifts + * into the slab interior. The slab is divided in to top and bottom parts, + * which meet at the location where the minimum temperature occurs in the slab. + * For the bottom slab the temperature is defined by a half-space cooling model. + * For the top of the slab the temperature is defined by one side of a 1D infinite + * space cooling model. The age of the overriding plate is used so the slab temperature + * at shallow depth smoothly transitions to the temperature of the overriding plate: + * this is not perfect, and is affected by the value of "top truncation" parameter + * subducting plate. Also note that the parameter "thickness" for the subducting plate + * segments needs to be defined but is not used. + * Note that the empirical model used to define how Tmin increases with depth + * and how the position of Tmin shift with depth is expected to change somewhat + * after better calibrating with further tests. + */ + class MassConserving final: public Interface + { + public: + /** + * constructor + */ + MassConserving(WorldBuilder::World *world); + + /** + * Destructor + */ + ~MassConserving() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + /** + * Returns a temperature based on the given heat content, temperatures, effective plate age, + * and adjusted distance to the coldest point in the slab. The temperature is formulated by + * the analytical solutions. + */ + double get_temperature_analytic(const double top_heat_content, + const double min_temperature, + const double background_temperature, + const double temperature_, + const double plate_velocity, + const double effective_plate_age, + const double adjusted_distance) const; + + + private: + // temperature submodule parameters + double min_depth; + double max_depth; + double density; + std::vector> subducting_velocities; + std::pair,std::vector> ridge_spreading_velocities; + std::vector> ridge_spreading_velocities_at_each_ridge_point; + double mantle_coupling_depth; + double forearc_cooling_factor; + double thermal_conductivity; + double thermal_expansion_coefficient; + double specific_heat; + double thermal_diffusivity; + double potential_mantle_temperature; + double surface_temperature; + double taper_distance; + bool adiabatic_heating; + std::vector>> mid_oceanic_ridges; + Operations operation; + enum ReferenceModelName + { + half_space_model, + plate_model + }; + ReferenceModelName reference_model_name; + const int plate_model_summation_number = 100; // for the plate model + bool apply_spline; + unsigned int spline_n_points; + }; + } // namespace Temperature + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/plate_model.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/plate_model.h.bak new file mode 100644 index 00000000000..b92f9e995a5 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/plate_model.h.bak @@ -0,0 +1,102 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_TEMPERATURE_PLATE_MODEL_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_TEMPERATURE_PLATE_MODEL_H + + +#include "world_builder/features/subducting_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + + namespace Features + { + namespace SubductingPlateModels + { + namespace Temperature + { + /** + * This class represents a subducting plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class PlateModel final: public Interface + { + public: + /** + * constructor + */ + PlateModel(WorldBuilder::World *world); + + /** + * Destructor + */ + ~PlateModel() override final; + + /** + * declare and read in the world builder file into the parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + + private: + // plate model temperature submodule parameters + double min_depth; + double max_depth; + double density; + double plate_velocity; + double thermal_conductivity; + double thermal_expansion_coefficient; + double specific_heat; + double potential_mantle_temperature; + double surface_temperature; + bool adiabatic_heating; + Operations operation; + + }; + } // namespace Temperature + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/uniform.h.bak b/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/uniform.h.bak new file mode 100644 index 00000000000..2abcc838346 --- /dev/null +++ b/contrib/world_builder/include/world_builder/features/subducting_plate_models/temperature/uniform.h.bak @@ -0,0 +1,95 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_TEMPERATURE_UNIFORM_H +#define WORLD_BUILDER_FEATURES_SUBDUCTING_PLATE_MODELS_TEMPERATURE_UNIFORM_H + + +#include "world_builder/features/subducting_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" + + +namespace WorldBuilder +{ + + namespace Features + { + namespace SubductingPlateModels + { + namespace Temperature + { + /** + * This class represents a subducting plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + /** + * Returns a temperature based on the given position, depth in the model, + * gravity and current temperature. + */ + double get_temperature(const Point<3> &position, + const double depth, + const double gravity, + double temperature, + const double feature_min_depth, + const double feature_max_depth, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const override final; + + + private: + // uniform temperature submodule parameters + double min_depth; + double max_depth; + double temperature; + Operations operation; + + }; + } // namespace Temperature + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/grains.h.bak b/contrib/world_builder/include/world_builder/grains.h.bak new file mode 100644 index 00000000000..eb47b2a12d2 --- /dev/null +++ b/contrib/world_builder/include/world_builder/grains.h.bak @@ -0,0 +1,68 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_GRAINS_H +#define WORLD_BUILDER_GRAINS_H + +#include +#include +#include + +namespace WorldBuilder +{ + /** + * This is a simple structure to store information about grains. + * The advantage of storing all grains in separate vectors, compared + * to having a vector of individual grains, is that the vectors can + * be empty if the information is not needed. + */ + struct grains + { + grains(); + + grains(const std::vector &vector, + const size_t number_of_grains, + const size_t start_entry = 0); + + void unroll_into(std::vector &vector, + const size_t start_entry = 0) const; + + // The sizes of the grains + std::vector sizes; + + // the rotation matrices of the latices of the grains. + // todo: convention. + std::vector,3> > rotation_matrices; + + friend std::ostream &operator<<(std::ostream &os, const grains &grains) + { + for (unsigned int i = 0; i < grains.sizes.size(); ++i) + { + os << i << ": s=" << grains.sizes[i] << ", R=" + << grains.rotation_matrices[i][0][0] << " " << grains.rotation_matrices[i][0][1] << " " << grains.rotation_matrices[i][0][2] << " " + << grains.rotation_matrices[i][1][0] << " " << grains.rotation_matrices[i][1][1] << " " << grains.rotation_matrices[i][1][2] << " " + << grains.rotation_matrices[i][2][0] << " " << grains.rotation_matrices[i][2][1] << " " << grains.rotation_matrices[i][2][2] << " "; + } + return os; + } + }; + +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/gravity_model/interface.h.bak b/contrib/world_builder/include/world_builder/gravity_model/interface.h.bak new file mode 100644 index 00000000000..79c20b01a24 --- /dev/null +++ b/contrib/world_builder/include/world_builder/gravity_model/interface.h.bak @@ -0,0 +1,149 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_GRAVITY_MODELS_INTERFACE_H +#define WORLD_BUILDER_GRAVITY_MODELS_INTERFACE_H + +#include "world_builder/gravity_model/interface.h" + +#include "world_builder/parameters.h" +#include "world_builder/types/string.h" + + +namespace WorldBuilder +{ + class World; + + namespace GravityModel + { + + class ObjectFactory; + + /** + * This class is an interface for the specific coordinate systems. + */ + class Interface + { + public: + /** + * constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * declare and read in the world builder file into the parameters 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 parameters class + */ + virtual + void parse_entries(Parameters &prm) = 0; + + /** + * Returns the gravity vector in a Cartesian coordinate system at a given position. + */ + virtual + Point<3> gravity_vector(Point<3> point) const = 0; + + /** + * Returns the norm of the gravity at a given position. + */ + virtual + double gravity_norm(Point<3> point) const = 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); + + 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_GRAVITY_MODEL(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 CoordinateSystems +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/gravity_model/uniform.h.bak b/contrib/world_builder/include/world_builder/gravity_model/uniform.h.bak new file mode 100644 index 00000000000..b3f5c29cc68 --- /dev/null +++ b/contrib/world_builder/include/world_builder/gravity_model/uniform.h.bak @@ -0,0 +1,96 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_COORDINATE_SYSTEMS_UNIFORM_H +#define WORLD_BUILDER_COORDINATE_SYSTEMS_UNIFORM_H + +#include "world_builder/gravity_model/interface.h" + +#include "world_builder/utilities.h" + + +namespace WorldBuilder +{ + + namespace GravityModel + { + /** + * Register header file + */ + //WB_REGISTER_COORDINATE_SYSTEM_HEADER(Uniform) + + + /** + * This implements a Uniform geometry model.The Uniform geometry model + * doesn't do anything with the coordinates, but is needed to have a common + * interface for all the geometry models. + */ + 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 parameters class + */ + static + void declare_entries(Parameters &prm, const std::string &parent_name = ""); + + /** + * declare and read in the world builder file into the parameters class + */ + void parse_entries(Parameters &prm) override final; + + + + /** + * Returns the gravity vector in a Cartesian coordinate system at a given position, + * which has a constant magitude for the whole domain. The vector points down in + * cartesian coordinates and to the center of the sphere in spherical coordinates. + */ + virtual + Point<3> gravity_vector(Point<3> point) const override final; + + /** + * Returns the norm of the gravity at a given position, which is a constant + * number for the whole domain. + */ + virtual + double gravity_norm(Point<3> point) const override final; + + private: + + /** + * The uniform gravity. + */ + double gravity_magnitude; + + }; + } // namespace CoordinateSystems +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/kd_tree.h.bak b/contrib/world_builder/include/world_builder/kd_tree.h.bak new file mode 100644 index 00000000000..1dcef34f0f0 --- /dev/null +++ b/contrib/world_builder/include/world_builder/kd_tree.h.bak @@ -0,0 +1,161 @@ +/* + 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 . +*/ + +#ifndef KD_TREE_H +#define KD_TREE_H + +#include +#include +#include +#include + +#include "world_builder/assert.h" +#include "world_builder/point.h" + +namespace WorldBuilder +{ + namespace KDTree + { + /** + * A struct to store an index for a point and the + * distance to that point. + */ + struct IndexDistance + { + size_t index; + double distance; + }; + + + /** + * A struct to store an index for a point and the + * distance to that point. + */ + struct IndexDistances + { + size_t min_index; + double min_distance; + std::vector vector; + }; + + /** + * Each item contains an index and an x and y coordinate + */ + struct Node + { + size_t index; + double x; + double y; + + Node(size_t index_, double x_, double y_) + : + index(index_), + x(x_), + y(y_) + {} + + + /** + * access index (const) + */ + inline + const double &operator[](const bool y_axis) const + { + WBAssert(std::fabs((y_axis ? y : x) - *(&x+y_axis)) < std::numeric_limits::epsilon(), + "Internal error: y_axis=" << y_axis << ", x=" << x << ", y=" << y <<", *(&x+y_axis)=" << *(&x+y_axis) + << ", ((bool)y_axis ? x : y) - *(&x+y_axis)=" << fabs((y_axis ? x : y) - *(&x+y_axis))); + return *(&x+y_axis); + } + }; + + class KDTree + { + public: + /** + * Constructor. + */ + KDTree() = default; + /** + * Constructor. Requires a list of Nodes. + */ + KDTree(const std::vector point_list); + + /** + * Create a tree based on the current information in the + * node vector. + */ + void create_tree(const size_t left, + const size_t right, + const bool x_axis); + + /** + * Return a reference to the vector containing the nodes. + */ + const std::vector &get_nodes() const; + + /** + * Returns the index of the closest point and the distance + * of that point to the check point. + */ + IndexDistance find_closest_point(const Point<2> &check_point) const; + + + + /** + * Returns the index of the closest point and the distance + * of that point to the check point. Stores the points searched + * through in a unsorted vector. + * Note: I can only guarantee that the point with the least distance + * is the closest point. The point in the list with the second/third/etc. + * smallest distance may or may not actually be the global point + * with the second/third/etc. smallest distance. It will most likely be a + * very good guess though. + */ + IndexDistances find_closest_points(const Point<2> &check_point) const; + + + private: + /** + * Returns the index of the closest point and the distance + * of that point to the check point. This function is used + * by find_closest_point to find the correct point. + */ + void find_closest_point_recursive(const Point<2> &check_point, + const size_t left, + const size_t right, + const bool y_axis, + IndexDistance &index_distance) const; + + + /** + * Returns the index of the closest point and the distance + * of that point to the check point. This function is used + * by find_closest_point to find the correct point. + */ + void find_closest_points_recursive(const Point<2> &check_point, + const size_t left, + const size_t right, + const bool y_axis, + IndexDistances &index_distances) const; + + std::vector nodes; + }; + } +} +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/nan.h.bak b/contrib/world_builder/include/world_builder/nan.h.bak new file mode 100644 index 00000000000..96916c783e5 --- /dev/null +++ b/contrib/world_builder/include/world_builder/nan.h.bak @@ -0,0 +1,50 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_NAN_H +#define WORLD_BUILDER_NAN_H + +#include + +namespace WorldBuilder +{ + namespace NaN + { + /** + * A double signaling NaN + */ + const double DQNAN = std::numeric_limits::quiet_NaN(); + + /** + * A unsigned int signaling NaN + */ + const unsigned int IQNAN = std::numeric_limits::quiet_NaN(); + /** + * A double signaling NaN + */ + const double DSNAN = std::numeric_limits::signaling_NaN(); + + /** + * A unsigned int signaling NaN + */ + const unsigned int ISNAN = std::numeric_limits::signaling_NaN(); + } // namespace NaN +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/objects/bezier_curve.h.bak b/contrib/world_builder/include/world_builder/objects/bezier_curve.h.bak new file mode 100644 index 00000000000..cc0868da52a --- /dev/null +++ b/contrib/world_builder/include/world_builder/objects/bezier_curve.h.bak @@ -0,0 +1,89 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_OBJECTS_BEZIER_CURVE_H +#define WORLD_BUILDER_OBJECTS_BEZIER_CURVE_H + +#include "world_builder/objects/closest_point_on_curve.h" +#include "world_builder/point.h" +#include +#include + +namespace WorldBuilder +{ + namespace Objects + { + + /** + * @brief Class for circle line/spline, including interpolation on it + * + */ + class BezierCurve + { + public: + /** + * @brief Construct a new Bezier Curve object + * + * @param p + * @param angle_constrains + */ + BezierCurve() = default; + + /** + * @brief Construct a new Bezier Curve object + * + * @param p + * @param angle_constrains + */ + BezierCurve(const std::vector > &p, const std::vector &angle_constrains = {}); + + /** + * @brief Finds the closest point on the curve. If the the closest point + * doesn't fall on the segment, return a point with x and y being nan. + * + * @param p + * @param verbose Whether this function should be outputting its Newton iteration + * to std::cout while running. This is very expensive, but useful for debugging + * purposes. + * @return ClosestPointOnCurve + */ + ClosestPointOnCurve closest_point_on_curve_segment(const Point<2> &p, const bool verbose = false) const; + + /** + * @brief + * + * @param i + * @param x + * @return Point<2> + */ + Point<2> operator()(const size_t i, const double x) const; + + private: + std::vector > points; + std::vector,2 > > control_points; + std::vector lengths; + std::vector angles; + + }; + } + +} + + +#endif diff --git a/contrib/world_builder/include/world_builder/objects/closest_point_on_curve.h.bak b/contrib/world_builder/include/world_builder/objects/closest_point_on_curve.h.bak new file mode 100644 index 00000000000..19377d61e39 --- /dev/null +++ b/contrib/world_builder/include/world_builder/objects/closest_point_on_curve.h.bak @@ -0,0 +1,56 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_OBJECTS_CLOSEST_POINT_ON_CURVE_H +#define WORLD_BUILDER_OBJECTS_CLOSEST_POINT_ON_CURVE_H + + +#include "world_builder/point.h" +#include "world_builder/nan.h" + +//using namespace WorldBuilder; + +namespace WorldBuilder +{ + namespace Objects + { + + + struct ClosestPointOnCurve + { + ClosestPointOnCurve() + : + distance(std::numeric_limits::infinity()), + parametric_fraction(NaN::DSNAN), + interpolation_fraction(NaN::DSNAN), + index(0), + point(Point<2>(NaN::DQNAN,NaN::DQNAN,CoordinateSystem::invalid)), + normal(Point<2>(NaN::DSNAN,NaN::DSNAN,CoordinateSystem::invalid)) + {} + + double distance; + double parametric_fraction; + double interpolation_fraction; + size_t index; + Point<2> point; + Point<2> normal; + }; + } +} +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/objects/distance_from_surface.h.bak b/contrib/world_builder/include/world_builder/objects/distance_from_surface.h.bak new file mode 100644 index 00000000000..d0b45d1dfc0 --- /dev/null +++ b/contrib/world_builder/include/world_builder/objects/distance_from_surface.h.bak @@ -0,0 +1,64 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_OBJECTS_DISTANCE_FROM_SURFACE_H +#define WORLD_BUILDER_OBJECTS_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() const; + + /** + * Function to get the distance along the surface + */ + double get_distance_along_surface() const; + + 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/contrib/world_builder/include/world_builder/objects/natural_coordinate.h.bak b/contrib/world_builder/include/world_builder/objects/natural_coordinate.h.bak new file mode 100644 index 00000000000..27f82163823 --- /dev/null +++ b/contrib/world_builder/include/world_builder/objects/natural_coordinate.h.bak @@ -0,0 +1,125 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_OBJECTS_NATURAL_COORDINATE_H +#define WORLD_BUILDER_OBJECTS_NATURAL_COORDINATE_H + +#include +#include "world_builder/point.h" +#include "world_builder/coordinate_systems/interface.h" + +namespace WorldBuilder +{ + namespace Objects + { + /* + * A class that represents a point in a chosen coordinate system. + */ + class NaturalCoordinate + { + public: + /** + * Constructor based on providing the geometry model as a pointer + */ + NaturalCoordinate(const std::array &position, + const ::WorldBuilder::CoordinateSystems::Interface &coordinate_system); + + /** + * Constructor based on providing the geometry model as a pointer + */ + NaturalCoordinate(const Point<3> &position, + const ::WorldBuilder::CoordinateSystems::Interface &coordinate_system); + + /** + * Returns the coordinates in the given coordinate system, which may + * not be Cartesian. + */ + const std::array &get_coordinates() const; + + /** + * The coordinate that represents the 'surface' directions in the + * chosen coordinate system. + */ + std::array get_surface_coordinates() const; + + /** + * The coordinate that represents the 'surface' directions in the + * chosen coordinate system. + */ + Point<2> get_surface_point() const; + + /** + * The coordinate that represents the 'depth' direction in the chosen + * coordinate system. + */ + double get_depth_coordinate() const; + + /** + * Return a reference to the coordinate that represents the 'depth' direction + * in the chosen coordinate system. + */ + double &get_ref_depth_coordinate(); + + /** + * get the coordinate system type of this coordinate. + */ + CoordinateSystem get_coordinate_system() const; + + private: + /** + * An enum which stores the coordinate system of this natural + * point + */ + CoordinateSystem coordinate_system; + + /** + * An array which stores the coordinates in the coordinates system + */ + std::array coordinates; + }; + + + inline + double + NaturalCoordinate::get_depth_coordinate() const + { + switch (coordinate_system) + { + case CoordinateSystem::cartesian: + { + return coordinates[2]; + break; + } + + case CoordinateSystem::spherical: + { + return coordinates[0]; + break; + } + + default: + WBAssertThrow (false, "Coordinate system not implemented."); + } + + return 0; + } + } +} + +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/objects/segment.h.bak b/contrib/world_builder/include/world_builder/objects/segment.h.bak new file mode 100644 index 00000000000..5b2b7319d91 --- /dev/null +++ b/contrib/world_builder/include/world_builder/objects/segment.h.bak @@ -0,0 +1,79 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_OBJECTS_SEGMENT_H +#define WORLD_BUILDER_OBJECTS_SEGMENT_H + + +#include "world_builder/types/plugin_system.h" + + +namespace WorldBuilder +{ + class Parameters; + + namespace Objects + { + + /** + * This class represents an actual segment + */ + template + class Segment + { + public: + + /** + * A constructor for the clone and set_entry function + */ + Segment(const double default_length, + const WorldBuilder::Point<2> &default_thickness, + const WorldBuilder::Point<2> &default_top_truncation, + const WorldBuilder::Point<2> &default_angle, + std::vector > temperature_systems, + std::vector > composition_systems, + std::vector > grains_systems); + + /** + * Copy constructor + */ + Segment(Segment const &other); + + /** + * Destructor + */ + ~Segment(); + + double value_length; + double default_length; + WorldBuilder::Point<2> value_thickness; + WorldBuilder::Point<2> value_top_truncation; + WorldBuilder::Point<2> value_angle; + std::vector > temperature_systems; + std::vector > composition_systems; + std::vector > grains_systems; + + protected: + private: + + }; + } // namespace Objects +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/objects/surface.h.bak b/contrib/world_builder/include/world_builder/objects/surface.h.bak new file mode 100644 index 00000000000..f55a862e040 --- /dev/null +++ b/contrib/world_builder/include/world_builder/objects/surface.h.bak @@ -0,0 +1,112 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_OBJECTS_SURFACE_H +#define WORLD_BUILDER_OBJECTS_SURFACE_H + +#include "world_builder/utilities.h" +#include "world_builder/kd_tree.h" + +namespace WorldBuilder +{ + namespace Objects + { + struct SurfaceValueInfo + { + size_t triangle_index; + double interpolated_value; + double interpolator_s; + double interpolator_t; + + SurfaceValueInfo( + size_t triangle_index_, + double interpolated_value_, + double interpolator_s_, + double interpolator_t_) + : + triangle_index(triangle_index_), + interpolated_value(interpolated_value_), + interpolator_s(interpolator_s_), + interpolator_t(interpolator_t_) {}; + + SurfaceValueInfo(double interpolated_value_) + : + triangle_index(NaN::IQNAN), + interpolated_value(interpolated_value_), + interpolator_s(NaN::DQNAN), + interpolator_t(NaN::DQNAN) {}; + }; + + class Surface + { + public: + /** + * Constructor to create an empty surface. + */ + Surface(); + + /** + * Constructor to create a surface from value at points object output. + */ + Surface(std::pair,std::vector> values_at_points); + + /** + * Returns the value of the surface at the check point. + */ + SurfaceValueInfo local_value(const Point<2> &check_point) const; + + /** + * Whether the surface is a constant value or not. This is used for optimalization. + */ + bool constant_value; + + /** + * The minimum value of all provided points. + */ + double minimum; + + /** + * The maximum value of all provided points. + */ + double maximum; + + /** + * The KD tree which stores the centroids of all triangles and an index to the triangle points + * and values stored in the triangles member variable. + */ + KDTree::KDTree tree; + + /** + * Stores the triangles as a list of three points. + */ + std::vector,3> > triangles; + + /** + * @brief Stores precomputed values + */ + std::vector > in_triangle_precomputed; + + private: + + }; + } + +} + +#endif \ No newline at end of file diff --git a/contrib/world_builder/include/world_builder/parameters.h.bak b/contrib/world_builder/include/world_builder/parameters.h.bak new file mode 100644 index 00000000000..8323d981830 --- /dev/null +++ b/contrib/world_builder/include/world_builder/parameters.h.bak @@ -0,0 +1,332 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_PARAMETERS_H +#define WORLD_BUILDER_PARAMETERS_H + +#include +#include +#include + +#include "rapidjson/schema.h" +#include "world_builder/point.h" +#include "world_builder/types/unsigned_int.h" + +namespace WorldBuilder +{ + namespace Types + { + class Interface; + template + class Point; + class Double; + class String; + class Segment; + class Array; + class Bool; + class UnsignedInt; + class Int; + } // namespace Types + + namespace Features + { + class Interface; + } // namespace Features + + namespace CoordinateSystems + { + class Interface; + } // namespace CoordinateSystems + + namespace GravityModel + { + class Interface; + } // namespace GravityModel + + class World; + + /** + * A class to hold all the parameters needed by the world builder. Internally + * it holds all values in the form of vectors of class Types. Values can be + * entered in two ways into this class. The first way is through the + * load_entry function which load the value from the provided world builder + * file. The second way is through the set_entry function, through which + * values can be directly entered into the parameter class. Values can be + * retrieved through the get functions which take the name of the value + * with which it was set. It is also required for bot loading, setting and + * getting values to do it in the correct subsection. Subsections can be + * entered with the enter_subsection function and left with the + * leave_subsection function. The current path can be retrieved through the + * function get_current_path() and get_current_path_without_arrays(). + */ + class Parameters + { + public: + /** + * Constructor + * \param world A reference to the World class + */ + Parameters(World &world); + + /** + * Destructor + */ + ~Parameters(); + + /** + * Initializes the parameter file + * \param filename A string with the path to the world builder file + * \param has_output_dir A bool indicating whether the world builder may write out information. + * \param output_dir A string with the path to the directory where it can output information if allowed by has_output_dir + */ + void initialize(std::string &filename, bool has_output_dir = false, const std::string &output_dir = ""); + + /** + * A generic get function to retrieve setting from the parameter file. + * Note that this is dependent on the current path/subsection which you are in. + * \param name The name of the entry to retrieved + * @see path + * @see enter_subsection() + * @see leave_subsection() + */ + template + T get(const std::string &name); + + /** + * A specialized version of get which can return vectors/arrays. + * \param name The name of the entry to retrieved + */ + template + std::vector get_vector(const std::string &name); + + std::vector> get_vector_or_double(const std::string &name); + + /** + * A specialized version of get which can return a value at points type. + * \param name The name of the entry to retrieved + * \param name additional points to be added to the list at either the default value or at the value of a single value array in the list + */ + std::pair,std::vector> + get(const std::string &name, + const std::vector > &addition_points = {}); + + /** + * A specialized version of get which can return a values at times type. + * \param name The name of the entry to retrieved + */ + std::pair,std::vector> get_value_at_array(const std::string &name); + + /** + * A specialized version of get which can return vectors/arrays. + * This version is designed for the plugin system. + * \param name The name of the entry to retrieved + */ + template + std::vector get_vector(const std::string &name, std::vector > &, std::vector > &, std::vector > &); + + /** + * A specialized version of get which can return unique pointers. + * \param name The name of the entry to retrieved + */ + template + std::unique_ptr get_unique_pointer(const std::string &name); + + /** + * A specialized version of get which can return unique pointers as an argument + * and returns a bool to indicate whether it was successful or not. + * Note that this function will erase all information in the vector. + * \param name The name of the entry to retrieved + * \param vector A vector of unique pointers. + */ + template + bool + get_unique_pointers(const std::string &name, std::vector > &vector); + + /** + * A specialized version of get which can return shared pointers as an argument + * and returns a bool to indicate whether it was successful or not. + * Note that this function will erase all information in the vector. + * \param name The name of the entry to retrieved + * \param vector A vector of shared pointers. + */ + template + bool + get_shared_pointers(const std::string &name, std::vector > & /*vector*/); + + /** + * Checks for the existence of an entry in the parameter file. + * Return true when an entry is specified and false when it is not. + * This is independent of whether an entry has been declared or not. + * The main intended usage is to check whether the user has provided + * the specified entry in the user supplied parameters file, since + * the get functions may use default values. + * \param name The name of the entry to be checked. + */ + bool + check_entry(const std::string &name) const; + + /** + * Declares the existence an entry in the parameters class. + * Default values are supplied by the type. + * \param name The name of the entry to be declared + * \param type The type of entry (e.g. Double, Array, etc.) + * \param documentation A string containing information about this parameter. + */ + void declare_entry(const std::string &name, + const Types::Interface &type, + const std::string &documentation); + + + /** + * This function is used to enter a subsection. It appends to the path + * variable. This action is revesed by the leave subsection function. + * \param name The name of the subsection to be entered. + * @see path + * @see leave_subsection() + */ + void enter_subsection(const std::string &name); + + /** + * This function is used to leave a subsection by removing the last + * element of the path variable. It reverses the action of the enter + * subsection function. + * @see path + * @see enter_subsection() + */ + void leave_subsection(); + + /** + * A utilities function for declaring plugin model entries. This always contains a model declaration entry with the plugin name. + * @param model_group_name The name of the model group which is declared. + * @param parent_name The name of the parent declaration group. + * @param declaration_map A map containing plugin names and plugin declaration functions + * @param required_entries A vector containing what entries should be required from the user. Default value is empty. + * @param extra_declarations A vector containing extra declarations common to all plugins in this group. Default value is empty. + */ + void + declare_model_entries(const std::string &model_group_name, + const std::string &parent_name, + const std::map &declare_map, + const std::vector &required_entries = {}, + const std::vector > &extra_declarations = {}); + + + /** + * A reference to the World class. This is needed to create the features. + */ + World &world; + + /** + * This variable stores what path separator is used in the property tree + * and in this class. + */ + const std::string path_separator = "."; + + /** + * This variable stores the path in a vector of strings. + * @see enter_subsection() + * @see leave_subsection() + */ + std::vector path; + + rapidjson::Document declarations; + rapidjson::Document parameters; + + + + + /** + * A vector containing all the pointers to the features. This vector is + * responsible for the features and has ownership over them. Therefore + * unique pointers are used. + * @see Features + */ + std::vector > features; + + /** + * A pointers to the corodinate system. This variable is responsible for + * the coordinate system and has ownership over it. Therefore a unique + * pointer are used. + * @see CoordinateSystem + */ + std::unique_ptr coordinate_system; + + /** + * A pointers to the gravity model. This variable is responsible for + * the gravity model and has ownership over it. Therefore a unique + * pointer are used. + * @see CoordinateSystem + */ + std::unique_ptr gravity_model; + + /** + * This function return the current path as stored in the path variable + * as a string in json pointer format. + * \return std::string + */ + std::string get_full_json_path(size_t max_size = std::numeric_limits::max()) const; + + /** + * todo: Warning: do not use before declarations is filled. + * This function return the current path as stored in the path variable + * as a string in json pointer format. + * \return std::string + */ + std::string get_full_json_schema_path() const; + + /** + * This function return the current path as stored in the path variable + * as a string. + * \return std::string + */ + //std::string get_full_path() const; + + /** + * This function return the current path as stored in the path variable + * as a string, but the arrays are striped. This is useful for working + * with the boost property tree. + * \return std::string + */ + //std::string get_full_path_without_arrays() const; + + private: + + + /** + * This is used for the get relative path functions. It stores how many + * top entries of the path should be ignored. + */ + size_t path_level; + + /** + * A function which returns the relative path, which is the full path + * minus the path_level top entries.. + * @see get_current_path() + */ + std::string get_relative_path() const; + + /** + * A function which returns the relative path, which is the full path + * minus the path_level top entries., without names for the arrays. + * @see get_current_path_without_arrays() + */ + std::string get_relative_path_without_arrays() const; + }; +} // namespace WorldBuilder +#endif diff --git a/contrib/world_builder/include/world_builder/point.h.bak b/contrib/world_builder/include/world_builder/point.h.bak new file mode 100644 index 00000000000..c3b0bca2d85 --- /dev/null +++ b/contrib/world_builder/include/world_builder/point.h.bak @@ -0,0 +1,473 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_POINT_H +#define WORLD_BUILDER_POINT_H +#include "nan.h" +#define _USE_MATH_DEFINES +#include +#include +#include +#include + +#include "world_builder/assert.h" +#include "world_builder/consts.h" +#include "world_builder/coordinate_system.h" + +namespace WorldBuilder +{ + + /** + * This namespace contains some faster but less accurate version of the + * trigonomic functions and a faster version of the fmod function. + */ + namespace FT + { + /** + * Fast version of the fmod function. + */ + inline double fmod(const double x, const double y) + { + if (y < 0.0 || y > 0.0) + { + const double x_div_y = x/y; + return (x_div_y-static_cast(x_div_y))*y; + } + return NaN::DQNAN; + } + + /** + * Fast sin function, accurate for values between 0 and pi. The implementation is + * based on discussion at https://stackoverflow.com/a/6104692. + * + * The accuracy seem good enough for most purposes. The unit test tests in steps + * of 0.01 from -4 pi to 4 pi and compares against the std sin function and the difference + * is always smaller than 1.2e-5. If the test is run with intervals of 0.001 then there + * are 12 entries which are (very slightly) above that (<3e-8) at angles of about + * -174, -6, 6 and 174. + * + */ + inline double fast_sin_d(const double angle) + { + constexpr double A = 4.0/(Consts::PI * Consts::PI); + constexpr double oneminPmin = 1.-0.1952403377008734-0.01915214119105392; + + const double y = A* angle * ( Consts::PI - angle ); + return y*( oneminPmin + y*( 0.1952403377008734 + y * 0.01915214119105392 ) ) ; + } + + /** + * Fast but less accurate sin function for any angle. + * Implemented by calling fast_sin_d with a mirrored x if needed to + * forfill the constrained of fast_sin_d to only have values between + * zero and pi. + */ + inline double sin(const double raw_angle) + { + const double angle = (raw_angle > -Consts::PI && raw_angle < Consts::PI) + ? + raw_angle + : + FT::fmod(raw_angle + std::copysign(Consts::PI,raw_angle), Consts::PI * 2.0) - std::copysign(Consts::PI,raw_angle); + + if (angle >= 0) + return fast_sin_d(angle); + return -fast_sin_d(-angle); + } + + /** + * Fast but less accurate cos function for any angle. + */ + inline double cos(const double angle) + { + return FT::sin((Consts::PI*0.5)-angle); + } + } // namespace FT + + + /** + * A class which stores 2d and 3d arrays of doubles (depending on the dimension), + * and the coordinate system which the coordinates can be used for. It also + * implements several operations such as the computation of the l2 norm and the + * dot product. + */ + template + class Point + { + public: + /** + * Constructor. Constructs a Point at (0,0) in 2d or (0,0,0) in 3d + * with a Cartesian coordinate system. + */ + inline + Point(CoordinateSystem coordinate_system_) + : + point(std::array()), + coordinate_system(coordinate_system_) + {} + + /** + * Constructor. Constructs a Point from a std::array and + * a coordinate system. + */ + inline + Point(const std::array &location, CoordinateSystem coordinate_system_) + : + point(location), + coordinate_system(coordinate_system_) + {} + + /** + * Constructor. Constructs a Point from an other Point and + * a coordinate system. + */ + inline + Point(const Point &location, CoordinateSystem coordinate_system_) + : + point(location.get_array()), + coordinate_system(coordinate_system_) + {} + + /** + * Constructor. Constructs a Point from an other Point. + */ + inline + Point(const Point &location) + : + point(location.get_array()), + coordinate_system(location.get_coordinate_system()) + {} + + /** + * Constructor. Constructs a 2d Point from two doubles and + * a coordinate system. + */ + Point(const double x, const double y, CoordinateSystem coordinate_system); + + /** + * Constructor. Constructs a 3d Point from three doubles and + * a coordinate system. + */ + Point(const double x, const double y, const double z, CoordinateSystem coordinate_system); + + /** + * Destructor + */ + inline + ~Point() = default; + + inline + Point &operator=(const Point &point_right) + { + point = point_right.point; + coordinate_system = point_right.coordinate_system; + return *this; + } + + /** + * dot product + */ + inline + double operator*(const Point &point_right) const + { + WBAssert(coordinate_system == point_right.get_coordinate_system(), + "Cannot take the dot product of two points which represent different coordinate systems."); + const std::array &array = point_right.get_array(); + double dot_product = 0; + for (unsigned int i = 0; i < dim; ++i) + dot_product += point[i] * array[i]; + return dot_product; + } + + + /** + * Multiply the vector with a scalar + */ + inline + Point operator*(const double scalar) const + { + // initialize the array to zero. + std::array array; + for (unsigned int i = 0; i < dim; ++i) + array[i] = point[i] * scalar; + return Point(array,coordinate_system); + } + + /** + * Divide the vector through a scalar + */ + inline + Point operator/(const double scalar) const + { + // initialize the array to zero. + std::array array; + const double one_over_scalar = 1/scalar; + for (unsigned int i = 0; i < dim; ++i) + array[i] = point[i] * one_over_scalar; + return Point(array,coordinate_system); + } + + /** + * add two points + */ + inline + Point operator+(const Point &point_right) const + { + WBAssert(coordinate_system == point_right.get_coordinate_system(), + "Cannot add two points which represent different coordinate systems."); + Point point_tmp(point,coordinate_system); + for (unsigned int i = 0; i < dim; ++i) + point_tmp[i] += point_right[i]; + + return point_tmp; + } + + + /** + * Subtract two points + */ + inline + Point operator-(const Point &point_right) const + { + WBAssert(coordinate_system == point_right.get_coordinate_system(), + "Cannot subtract two points which represent different coordinate systems. Internal has type " << static_cast(coordinate_system) + << ", other point has type " << static_cast(point_right.get_coordinate_system())); + Point point_tmp(point,coordinate_system); + for (unsigned int i = 0; i < dim; ++i) + point_tmp[i] -= point_right[i]; + + return point_tmp; + } + + + /** + * Multiply the vector with a scalar + */ + inline + Point &operator*=(const double scalar) + { + for (unsigned int i = 0; i < dim; ++i) + point[i] *= scalar; + return *this; + } + /** + * Divide the vector through a scalar + */ + inline + Point &operator/=(const double scalar) + { + for (unsigned int i = 0; i < dim; ++i) + point[i] /= scalar; + return *this; + } + + /** + * add two points + */ + inline + Point &operator+=(const Point &point_right) + { + WBAssert(coordinate_system == point_right.get_coordinate_system(), + "Cannot add two points which represent different coordinate systems."); + for (unsigned int i = 0; i < dim; ++i) + point[i] += point_right[i]; + return *this; + } + + /** + * Check if all values are the same. + * + * Note: compares floating points with an epsilon + */ + inline + bool operator==(const Point &point_) const + { + if (coordinate_system != point_.coordinate_system) + return false; + WorldBuilder::Point point_tmp(point,coordinate_system); + point_tmp -= point_; + if (std::fabs(point_tmp[0]) > std::numeric_limits::epsilon()) + return false; + if (std::fabs(point_tmp[1]) > std::numeric_limits::epsilon()) + return false; + if (dim == 3 && std::fabs(point_tmp[2]) > std::numeric_limits::epsilon()) + return false; + + return true; + } + + /** + * subtract two points + */ + inline + Point &operator-=(const Point &point_right) + { + WBAssert(coordinate_system == point_right.get_coordinate_system(), + "Cannot subtract two points which represent different coordinate systems."); + for (unsigned int i = 0; i < dim; ++i) + point[i] -= point_right[i]; + return *this; + } + + /** + * access index (const) + */ + inline + const double &operator[](const size_t index) const + { + WBAssert(index <= dim, "Can't ask for element " << index << " in an point with dimension " << dim << '.'); + return point[index]; + } + + + /** + * access index + */ + inline double &operator[](const size_t index) + { + WBAssert(index <= dim, "Can't ask for element " << index << " in an point with dimension " << dim << '.'); + return point[index]; + } + + /** + * Computes the distance between this and a given point. + * In spherical coordinates it returns the central angle in radians. + */ + double + distance(const Point<2> &two) const; + + /** + * Computes the cheapest relative distance between this and a given point in spherical coordinates. + * The return value itself is only guartenteed to have the property that a + * larger value is further away. + * In the current implementation that means for the cartasian case the squared + * value is returned and for the spherical value the result of the havearsine + * function without asin and sqrt is returned. + */ + double + cheap_relative_distance_spherical(const Point<2> &two) const + { + const double d_longitude = two[0] - this->point[0]; + const double d_latitude = two[1] - this->point[1]; + const double sin_d_lat = FT::sin(d_latitude * 0.5); + const double sin_d_long = FT::sin(d_longitude * 0.5); + return (sin_d_lat * sin_d_lat) + (sin_d_long*sin_d_long) * FT::cos(this->point[1]) * FT::cos(two[1]); + } + + /** + * Computes the cheapest relative distance between this and a given point in cartesian coordinates. + * The return value itself is only guartenteed to have the property that a + * larger value is further away. + * In the current implementation that means for the cartasian case the squared + * value is returned and for the spherical value the result of the havearsine + * function without asin and sqrt is returned. + */ + double + cheap_relative_distance_cartesian(const Point<2> &two) const + { + const double x_distance_to_reference_point = point[0]-two[0]; + const double y_distance_to_reference_point = point[1]-two[1]; + return (x_distance_to_reference_point*x_distance_to_reference_point) + (y_distance_to_reference_point*y_distance_to_reference_point); + } + + /** + * return the internal array which stores the point data. + */ + inline + const std::array &get_array() const + { + return point; + } + + + /** + * returns the coordinate system associated with the data. + */ + inline + CoordinateSystem get_coordinate_system() const + { + return coordinate_system; + } + + + /** + * Computes the L2 norm: sqrt(x_i * x_i + y_i * y_i + z_i * z_i) in 3d. + */ + inline + double norm() const + { + return std::sqrt(this->norm_square()); + } + + + /** + * Computes the square of the norm, which is the sum of the absolute squares + * x_i * x_i + y_i * y_i + z_i * z_i in 3d. + */ + inline + double norm_square() const + { + WBAssertThrow(false,"This function is only available in 2d or 3d."); + return 0; + } + + /** + * Outputs the values of the point to std cout separated by spaces. This does not + * output the coordinate system. + */ + friend std::ostream &operator<<( std::ostream &output, const Point &stream_point ) + { + for (size_t i = 0; i < dim-1; i++) + { + output << stream_point[i] << ' '; + } + output << stream_point[dim-1]; + + return output; + } + + + private: + std::array point; + CoordinateSystem coordinate_system; + + }; + + template <> + inline + double Point<2>::norm_square() const + { + return (point[0] * point[0]) + (point[1] * point[1]); + } + + template <> + inline + double Point<3>::norm_square() const + { + return (point[0] * point[0]) + (point[1] * point[1]) + (point[2] * point[2]); + } + + template + inline + Point operator*(const double scalar, const Point &point) + { + return point*scalar; + } +} // namespace WorldBuilder +#endif diff --git a/contrib/world_builder/include/world_builder/types/array.h.bak b/contrib/world_builder/include/world_builder/types/array.h.bak new file mode 100644 index 00000000000..f2dba5dc7ca --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/array.h.bak @@ -0,0 +1,119 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_ARRAY_H +#define WORLD_BUILDER_TYPES_ARRAY_H + + +#include "world_builder/types/interface.h" + + +namespace WorldBuilder +{ + class Parameters; + + namespace Types + { + /** + * This class represents an array of values which can be of any Types. It + * stores the type of values it is holding and an vector of indices where + * the values are actually stored in the parameters vector which hold all + * the values of that type. This type can also hold a unique pointer to + * the type is should hold. This is used for declaring types.The difference + * between an array and a list is that the array holds the values retrievable + * by index, and a list holds the values strictly ordered, only accessible + * an iterator. An other difference it that lists have a name. + */ + class Array final: public Interface + { + public: + /** + * Constructor for the declaration + */ + Array(const Interface &type, + const unsigned int min_items = 0, + const unsigned int max_items = std::numeric_limits::max(), + const bool unique_items = false); + + /** + * Constructor for cloning an array. + */ + Array(Array const &other); + + + /** + * Destructor + */ + ~Array() override final; + + /** + * Todo + */ + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const override final; + + /** + * An enum of the type which this class points to + * @see Types::type + */ + Types::type inner_type; + + /** + * This class is sometimes responsible for the object it points to, but + * sometimes it is not responsible for the object is points to. + * When it is responsible the unique_inner_type points to it and the + * inner_type should have size zero. When it is not responsible, + * unique_inner_type should point to the nullptr and inner_type should + * have a size larger then zero. + * @see inner_type_index + */ + std::unique_ptr inner_type_ptr; + + + /** + * Todo + */ + bool required; + + /** + * Todo + */ + unsigned int min_items; + + /** + * Todo + */ + unsigned int max_items; + + /** + * Todo + */ + bool unique_items; + + protected: + Array *clone_impl() const override final + { + return new Array(*this); + }; + }; + } // namespace Types +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/types/bool.h.bak b/contrib/world_builder/include/world_builder/types/bool.h.bak new file mode 100644 index 00000000000..77bafbb7c60 --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/bool.h.bak @@ -0,0 +1,77 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_BOOL_H +#define WORLD_BUILDER_TYPES_BOOL_H + + +#include "world_builder/types/interface.h" + + +namespace WorldBuilder +{ + class Parameters; + + namespace Types + { + + /** + * This class represents a bool value with documentation + */ + class Bool final: public Interface + { + public: + /** + * A constructor for the load_entry function + */ + Bool(const bool default_value); + + /** + * Copy constructor + */ + Bool(Bool const &other); + + /** + * Destructor + */ + ~Bool() override final; + + + /** + * Todo + */ + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const override final; + + bool default_value; + + protected: + Bool *clone_impl() const override final + { + return new Bool(*this); + }; + + private: + + }; + } // namespace Types +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/types/double.h.bak b/contrib/world_builder/include/world_builder/types/double.h.bak new file mode 100644 index 00000000000..05bd3b74de3 --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/double.h.bak @@ -0,0 +1,76 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_DOUBLE_H +#define WORLD_BUILDER_TYPES_DOUBLE_H + + +#include "world_builder/types/interface.h" + + +namespace WorldBuilder +{ + class Parameters; + + namespace Types + { + + /** + * This class represents a double value with documentation + */ + class Double final: public Interface + { + public: + /** + * A constructor for the load_entry function + */ + Double(const double default_value); + + /** + * Copy constructor + */ + Double(Double const &other); + + /** + * Destructor + */ + ~Double() override final; + + /** + * Todo + */ + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const override final; + + double default_value; + + protected: + Double *clone_impl() const override final + { + return new Double(*this); + }; + + private: + + }; + } // namespace Types +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/types/int.h.bak b/contrib/world_builder/include/world_builder/types/int.h.bak new file mode 100644 index 00000000000..44cd4f13c65 --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/int.h.bak @@ -0,0 +1,80 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_INT_H +#define WORLD_BUILDER_TYPES_INT_H + + +#include "world_builder/types/interface.h" + + +namespace WorldBuilder +{ + class Parameters; + + namespace Types + { + + /** + * This class represents a bool value with documentation + */ + class Int final: public Interface + { + public: + /** + * A constructor for the load_entry function + */ + Int(int default_value = 0); + + /** + * Copy constructor + */ + Int(Int const &other); + + /** + * Destructor + */ + ~Int() override final; + + + /** + * Todo + */ + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const override final; + + int value {0}; + int default_value; + + protected: + /** + * This implements the actual cloneing for the clone function in the base class. + */ + Int *clone_impl() const override final + { + return new Int(*this); + }; + private: + + }; + } // namespace Types +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/types/interface.h.bak b/contrib/world_builder/include/world_builder/types/interface.h.bak new file mode 100644 index 00000000000..40cd8b58616 --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/interface.h.bak @@ -0,0 +1,93 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_INTERFACE_H +#define WORLD_BUILDER_TYPES_INTERFACE_H + +#include "rapidjson/pointer.h" +#include "assert.h" + +#include +#include + +namespace WorldBuilder +{ + class Parameters; + + /** + * This class is an interface for the specific plate tectonic feature classes, + * such as continental plate, oceanic plate and subduction zone. + */ + namespace Types + { + + enum class type + { + None,Bool,String,Double,Int,UnsignedInt,Array,Object,List,Point2D,Point3D,CoordinateSystem,PluginSystem,Segment,ConstantLayer,ValueAtPoints,OneOf + }; + + class Interface + { + public: + /** + * Constructor + */ + Interface(); + + /** + * Destructor + */ + virtual + ~Interface(); + + /** + * Todo + */ + virtual + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const = 0; + + /** + * clone + */ + virtual + std::unique_ptr clone() const + { + return std::unique_ptr(clone_impl()); + } + + /** + * read in the world builder file + */ + + type get_type() const; + + + protected: + type type_name {type::None}; + + + virtual + Interface *clone_impl() const = 0; + }; + } // namespace Types +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/types/object.h.bak b/contrib/world_builder/include/world_builder/types/object.h.bak new file mode 100644 index 00000000000..a188450ff13 --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/object.h.bak @@ -0,0 +1,87 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_OBJECT_H +#define WORLD_BUILDER_TYPES_OBJECT_H + +#include + +#include "world_builder/types/interface.h" + + +namespace WorldBuilder +{ + class Parameters; + + namespace Types + { + /** + * This class represents an object of values which can be of any Types. It + * stores the type of values it is holding and an vector of indices where + * the values are actually stored in the parameters vector which hold all + * the values of that type. This type can also hold a unique pointer to + * the type is should hold. This is used for declaring types.The difference + * between an object and a list is that the object holds the values retrievable + * by index, and a list holds the values strictly ordered, only accessible + * an iterator. An other difference it that lists have a name. + */ + class Object final: public Interface + { + public: + /** + * Constructor for the declaration + */ + Object(std::vector required = std::vector(), + const bool additional_properties = false); + + /** + * Copy constructor + */ + Object(Object const &other); + + /** + * Destructor + */ + ~Object() final; + + /** + * Todo + */ + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const override final; + + + /** + * Todo + */ + std::vector required; + bool additional_properties; + + protected: + Object *clone_impl() const override final + { + return new Object(*this); + }; + + }; + } // namespace Types +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/types/one_of.h.bak b/contrib/world_builder/include/world_builder/types/one_of.h.bak new file mode 100644 index 00000000000..c4aedcaaa89 --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/one_of.h.bak @@ -0,0 +1,89 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_ONE_OF_H +#define WORLD_BUILDER_TYPES_ONE_OF_H + + +#include "world_builder/types/interface.h" +#include + + +namespace WorldBuilder +{ + class Parameters; + + namespace Types + { + /** + * This class represents an a single choice between options (one of). + */ + class OneOf final: public Interface + { + public: + /** + * Constructor for the declaration + */ + OneOf(const Interface &type_1, + const Interface &type_2); + + /** + * Constructor for cloning an array. + */ + OneOf(OneOf const &other); + + + /** + * Destructor + */ + ~OneOf() override final; + + /** + * Write schema + */ + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const override final; + /** + * An enum of the type which this class points to + * @see Types::type + */ + Types::type inner_type; + + /** + * This class is sometimes responsible for the object it points to, but + * sometimes it is not responsible for the object is points to. + * When it is responsible the unique_inner_type points to it and the + * inner_type should have size zero. When it is not responsible, + * unique_inner_type should point to the nullptr and inner_type should + * have a size larger then zero. + * @see inner_type_index + */ + std::vector> inner_types_ptr; + + protected: + OneOf *clone_impl() const override final + { + return new OneOf(*this); + }; + }; + } // namespace Types +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/types/plugin_system.h.bak b/contrib/world_builder/include/world_builder/types/plugin_system.h.bak new file mode 100644 index 00000000000..a3ac0827929 --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/plugin_system.h.bak @@ -0,0 +1,85 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_PLUGIN_SYSTEM_H +#define WORLD_BUILDER_TYPES_PLUGIN_SYSTEM_H + + +#include "world_builder/features/interface.h" + + +namespace WorldBuilder +{ + class Parameters; + + namespace Types + { + + /** + * This class represents a plate tectonic feature class, such as the + * continental plate class, oceanic plate class and subduction zone class. + */ + class PluginSystem final: public Interface + { + public: + /** + * constructor + */ + PluginSystem(std::string default_value_, + void ( *declare_entries)(Parameters &, const std::string &, const std::vector &), + std::vector required_entries, + const bool allow_multiple = true); + + + /** + * Copy constructor + */ + PluginSystem(PluginSystem const &plugin_system); + + /** + * Destructor + */ + ~PluginSystem() override final; + + /** + * Todo + */ + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const override final; + + + std::string default_value; + void( *declare_entries)(Parameters &, const std::string &, const std::vector &); + std::vector required_entries; + bool allow_multiple; + + protected: + PluginSystem *clone_impl() const override final + { + return new PluginSystem(*this); + }; + + private: + + }; + } // namespace Types +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/types/point.h.bak b/contrib/world_builder/include/world_builder/types/point.h.bak new file mode 100644 index 00000000000..d73ce91c3e4 --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/point.h.bak @@ -0,0 +1,132 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_POINT_H +#define WORLD_BUILDER_TYPES_POINT_H + + +#include "world_builder/point.h" +#include "world_builder/types/interface.h" + + +namespace WorldBuilder +{ + class Parameters; + + namespace Types + { + + /** + * This class represents a continental plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + template + class Point final: public Interface + { + public: + + /** + * A constructor used for the load_entry function + */ + Point(); + + /** + * A constructor used for the load_entry function + */ + Point(const WorldBuilder::Point &default_value, std::string description); + + /** + * A constructor used for cloning and the set_entry function + */ + Point(const WorldBuilder::Point &value, const WorldBuilder::Point &default_value, std::string description); + + /** + * Copy constructor + */ + Point(Point const &other); + + /** + * Destructor + */ + ~Point() override final; + + /** + * Todo + */ + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const override final; + + /** + * dot product + */ + double operator*(const Point &point) const; + + + /** + * Multiply the vector with a scalar + */ + WorldBuilder::Point operator*(const double scalar) const; + + /** + * add two points + */ + WorldBuilder::Point operator+(const Point &point) const; + + + /** + * Subtract two points + */ + WorldBuilder::Point operator-(const Point &point) const; + + /** + * access index (const) + */ + const double &operator[](const unsigned int index) const; + + + /** + * access index + */ + double &operator[](const unsigned int index); + + + + WorldBuilder::Point value; + WorldBuilder::Point default_value; + std::string description; + + protected: + Point *clone_impl() const override final + { + return new Point(*this); + }; + + private: + + }; + + template + WorldBuilder::Point operator*(const double scalar, const Point &point); + } // namespace Types +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/types/segment.h.bak b/contrib/world_builder/include/world_builder/types/segment.h.bak new file mode 100644 index 00000000000..6ab28793047 --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/segment.h.bak @@ -0,0 +1,100 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_SEGMENT_H +#define WORLD_BUILDER_TYPES_SEGMENT_H + + +#include "world_builder/types/plugin_system.h" + + +namespace WorldBuilder +{ + class Parameters; + + namespace Types + { + + /** + * This class represents a segment value with documentation + */ + class Segment : public Interface + { + public: + /** + * A constructor + */ + Segment(const double default_length, + const WorldBuilder::Point<2> &default_thickness, + const WorldBuilder::Point<2> &default_top_truncation, + const WorldBuilder::Point<2> &default_angle, + const Types::Interface &temperature_plugin_system, + const Types::Interface &composition_plugin_system, + const Types::Interface &grains_plugin_system_); + + /** + * A constructor for the load_entry function + */ + Segment(double default_length, + WorldBuilder::Point<2> default_thickness, + WorldBuilder::Point<2> default_angle, + std::string description); + + /** + * Copy constructor + */ + Segment(Segment const &other); + + + /** + * Destructor + */ + ~Segment() override; + + /** + * Todo + */ + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const override final; + + + double value_length; + double default_length; + WorldBuilder::Point<2> value_thickness; + WorldBuilder::Point<2> default_thickness; + WorldBuilder::Point<2> default_top_truncation; + WorldBuilder::Point<2> value_angle; + WorldBuilder::Point<2> default_angle; + std::unique_ptr temperature_plugin_system; + std::unique_ptr composition_plugin_system; + std::unique_ptr grains_plugin_system; + + protected: + Segment *clone_impl() const override final + { + return new Segment(*this); + }; + private: + + }; + } // namespace Types +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/types/string.h.bak b/contrib/world_builder/include/world_builder/types/string.h.bak new file mode 100644 index 00000000000..6a83b654c52 --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/string.h.bak @@ -0,0 +1,103 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_STRING_H +#define WORLD_BUILDER_TYPES_STRING_H + +#include + +#include "world_builder/types/interface.h" + + +namespace WorldBuilder +{ + class Parameters; + + namespace Types + { + + /** + * This class represents a continental plate and can implement submodules + * for temperature and composition. These submodules determine what + * the returned temperature or composition of the temperature and composition + * functions of this class will be. + */ + class String final: public Interface + { + public: + /** + * constructor + */ + String(std::string default_value); + + /** + * constructor + */ + String(std::string default_value, const std::string &restricted_value); + + /** + * constructor + */ + String(std::string default_value, std::vector restricted_values); + + /** + * constructor + */ + //String(std::string default_value, std::string description); + + + /** + * A constructor for the clone and set_entry function + */ + String(std::string value, std::string default_value, std::string description); + + /** + * Copy constructor + */ + String(String const &other); + + /** + * Destructor + */ + ~String() final; + + /** + * Todo + */ + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const override final; + + + std::string value; + std::string default_value; + std::string description; + std::vector restricted_values; + + + protected: + String *clone_impl() const override final + { + return new String(*this); + }; + }; + } // namespace Types +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/types/unsigned_int.h.bak b/contrib/world_builder/include/world_builder/types/unsigned_int.h.bak new file mode 100644 index 00000000000..1afd9a62f9b --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/unsigned_int.h.bak @@ -0,0 +1,80 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_UNSIGNED_INT_H +#define WORLD_BUILDER_TYPES_UNSIGNED_INT_H + + +#include "world_builder/types/interface.h" + + +namespace WorldBuilder +{ + class Parameters; + + namespace Types + { + + /** + * This class represents a bool value with documentation + */ + class UnsignedInt final: public Interface + { + public: + /** + * A constructor for the load_entry function + */ + UnsignedInt(unsigned int default_value = 0); + + /** + * Copy constructor + */ + UnsignedInt(UnsignedInt const &other); + + /** + * Destructor + */ + ~UnsignedInt() override final; + + + /** + * Todo + */ + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const override final; + + unsigned int value {0}; + unsigned int default_value; + + protected: + /** + * This implements the actual cloneing for the clone function in the base class. + */ + UnsignedInt *clone_impl() const override final + { + return new UnsignedInt(*this); + }; + private: + + }; + } // namespace Types +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/types/value_at_points.h.bak b/contrib/world_builder/include/world_builder/types/value_at_points.h.bak new file mode 100644 index 00000000000..a3878b616cd --- /dev/null +++ b/contrib/world_builder/include/world_builder/types/value_at_points.h.bak @@ -0,0 +1,80 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_TYPES_VALUE_AT_POINTS_H +#define WORLD_BUILDER_TYPES_VALUE_AT_POINTS_H + +#include "world_builder/types/point.h" +#include + + +namespace WorldBuilder +{ + class Parameters; + + namespace Types + { + /** + * This class represents a depth surface value with documentation + */ + class ValueAtPoints : public Interface + { + public: + /** + * A constructor + */ + ValueAtPoints(const double default_value, + uint64_t max_values_in_array, + std::vector> default_points_ = std::vector>()); + + /** + * Copy constructor + */ + ValueAtPoints(ValueAtPoints const &other); + + + /** + * Destructor + */ + ~ValueAtPoints() override; + + /** + * Write schema + */ + void write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const override final; + + double default_value; + uint64_t max_values_in_array; + std::vector > default_points; + + protected: + ValueAtPoints *clone_impl() const override final + { + return new ValueAtPoints(*this); + }; + private: + + }; + } // namespace Types + +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/utilities.h.bak b/contrib/world_builder/include/world_builder/utilities.h.bak new file mode 100644 index 00000000000..9b5d2687a2d --- /dev/null +++ b/contrib/world_builder/include/world_builder/utilities.h.bak @@ -0,0 +1,494 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_UTILITIES_H +#define WORLD_BUILDER_UTILITIES_H + + +#include "world_builder/nan.h" +#include "world_builder/coordinate_systems/interface.h" +#include "world_builder/objects/natural_coordinate.h" +#include "world_builder/objects/bezier_curve.h" +#include + + +namespace WorldBuilder +{ + + namespace CoordinateSystems + { + class Interface; + } // namespace CoordinateSystems + namespace Utilities + { + + /** + * provide a short way to test if two doubles are equal. + * Based on https://stackoverflow.com/a/4010279. + * Removed a==b test since it triggers warnings. If used in + * performance critical parts where this could matter, a fast + * version could be added. + */ + inline bool approx(double a, double b, double error_factor=1e4) + { + return std::abs(a-b)::epsilon()* + error_factor; + } + + /** + * Given a 2d point and a list of points which form a polygon, computes if + * the point falls within the polygon. For spherical coordinates it will + * return true if the point or the point where the longitude is shifted + * by 2 * PI is inside on of the polygons. It calls + * polygon_contains_point_implementation to do the real work. + */ + bool + polygon_contains_point(const std::vector > &point_list, + const Point<2> &point); + + /** + * Given a 2d point and a list of points which form a polygon, computes if the point + * falls within the polygon. + */ + bool + polygon_contains_point_implementation(const std::vector > &point_list, + const Point<2> &point); + + + /** + * Given a 2d point, a semi-major axis, and an eccentricity, computes where + * the point falls within the ellipse. If the fraction is larger than 1, the + * point is outside the ellipse. + */ + double + fraction_from_ellipse_center (const Point<2> &ellipse_center, + const double semi_major_axis, + const double eccentricity, + const double rotation_angle, + const Point<2> &point); + + + /** + * Given a 2d point and a list of points which form a polygon, compute the smallest + * distance of the point to the polygon. The sign is negative for points outside of + * the polygon and positive for points inside the polygon. + */ + double + signed_distance_to_polygon(const std::vector > &point_list_, + const Point<2> &point_); + + + /** + * Returns spherical coordinates of a Cartesian point. The returned array + * is filled with radius, phi and theta (polar angle). If the dimension is + * set to 2 theta is omitted. Phi is always normalized to [0,2*pi]. + * + */ + std::array + cartesian_to_spherical_coordinates(const Point<3> &position); + + /** + * Return the Cartesian point of a spherical position defined by radius, + * phi and theta (polar angle). If the dimension is set to 2 theta is + * omitted. + */ + Point<3> + spherical_to_cartesian_coordinates(const std::array &scoord); + + /** + * Returns ellipsoidal coordinates of a Cartesian point. The returned array + * is filled with phi, theta and radius. + * + */ + std::array + cartesian_to_ellipsoidal_coordinates(const Point<3> &position, + const double semi_major_axis_a, + const double eccentricity); + + /** + * Return the Cartesian point of a ellipsoidal position defined by phi, + * phi and radius. + */ + Point<3> + ellipsoidal_to_cartesian_coordinates(const std::array &phi_theta_d, + const double semi_major_axis_a, + const double eccentricity); + + /** + * A function that takes a string representation of the name of a + * coordinate system (as represented by the CoordinateSystem enum) + * and returns the corresponding value. + */ + CoordinateSystem + string_to_coordinate_system (const std::string & /*coordinate_system*/); + + + /** + * Convert point to array + */ + template + std::array convert_point_to_array(const Point &point); + + /** + * Converts a string to a double + */ + double + string_to_double(const std::string &string); + + /** + * Converts a string to a int + */ + int + string_to_int(const std::string &string); + + + /** + * Converts a string to a unsigned int + */ + unsigned int + string_to_unsigned_int(const std::string &string); + + + /** + * Cross product between two 3d points. + */ + Point<3> cross_product(const Point<3> &a, const Point<3> &b); + + /** + * Enum class for interolation type + */ + enum class InterpolationType + { + None, + Linear, + MonotoneSpline, + ContinuousMonotoneSpline, + Invalid, + }; + + /** + * Class for linear and monotone spline interpolation + */ + class interpolation + { + public: + /** + * Initialize the spline. This function assumes that all y points are spaced 1 in the x direction. + * + * @param y Values in the interpolation points. + */ + void set_points(const std::vector &y); + + + /** + * Evaluate at point @p x. + */ + inline + double operator() (const double x) const + { + if (x >= 0. && x <= static_cast(mx_size_min)) + { + const size_t idx = static_cast(x); + const double h = x-static_cast(idx); + return ((m[idx][0]*h + m[idx][1])*h + m[idx][2])*h + m[idx][3]; + } + const size_t idx = std::min(static_cast(std::max( static_cast(x), static_cast(0))),mx_size_min); + const double h = x-static_cast(idx); + return (m[idx][1]*h + m[idx][2])*h + m[idx][3]; + } + + + inline + double operator() (const double x, const size_t idx, const double h) const + { + return (x >= 0. && x <= static_cast(mx_size_min)) + ? + ((m[idx][0]*h + m[idx][1])*h + m[idx][2])*h + m[idx][3] + : + (m[idx][1]*h + m[idx][2])*h + m[idx][3]; + } + + + /** + * Evaluate at point @p x. assumes x is between 0 and mx_size_min. + * assume size_t idx = (size_t)x and h = x-idx. + */ + inline + double value_inside (const size_t idx, const double h) const + { + WBAssert(idx <= mx_size_min, "Internal error: using value_inside outside the range of 0 to " << mx_size_min << ", but value was outside of this range: " << idx << "."); + WBAssert(h >= 0 && h <= 1., "Internal error: using value_inside outside the range of 0 to " << mx_size_min << ", but value was outside of this range: " << h << "."); + return ((m[idx][0]*h + m[idx][1])*h + m[idx][2])*h + m[idx][3]; + } + + + /** + * Evaluate at point @p x. assumes x is between 0 and mx_size_min. + * assume size_t idx = (size_t)x and h = x-idx. + */ + inline + double value_outside (const size_t idx, const double h) const + { + WBAssert(idx <= mx_size_min, "Internal error: using value_inside outside the range of 0 to " << mx_size_min << ", but value was outside of this range: " << idx << "."); + WBAssert(!(static_cast(idx) + h >= 0 && static_cast(idx) + h <= 1.), "Internal error: using value_inside outside the range of 0 to " << mx_size_min << ", but value was outside of this range: " << static_cast(idx) + h << " (h=" << h << ", idx = " << idx << ")."); + return (m[idx][1]*h + m[idx][2])*h + m[idx][3]; + } + + + /** + * number of x coordinates of points + */ + size_t mx_size_min; + + /** + * interpolation parameters + * \[ + * f(x) = a*(x-x_i)^3 + b*(x-x_i)^2 + c*(x-x_i) + y_i + * \] + */ + std::vector> m; //m_a, m_b, m_c, m_y; + + private: + }; + + /** + * A struct that is used to hold the return values of the function + * distance_point_from_curved_planes(). See there for a documentation + * of the meaning of the member variables. The variables are describing + * a where a point is with respect to a plane/surface. The surface is + * meshed by a grid. The axis parallel to the surface are formed by + * sections, and the axis perpendicuar to the surface are formed segments. + * Both sections and elements represent a whole cell in the grid, which is + * an integer. This structure also provides the fraction in each direction + * the closest point on the plane is along these two axes (sections and + * segments). These variables are called fractions. + * + * This structure furthermore provides the distance the provided point is + * from the closest point on the surface and the average angle. The variable + * local_thickness will not be automatically filled by the distance_point_from_curved_planes + * function. + */ + struct PointDistanceFromCurvedPlanes + { + /** + * Constructor + */ + PointDistanceFromCurvedPlanes(CoordinateSystem coordinate_system) + : + distance_from_plane(NaN::DSNAN), + distance_along_plane(NaN::DSNAN), + fraction_of_section(NaN::DSNAN), + fraction_of_segment(NaN::DSNAN), + section(NaN::ISNAN), + segment(NaN::ISNAN), + average_angle(NaN::DSNAN), + depth_reference_surface(NaN::DSNAN), + closest_trench_point(Point<3>(coordinate_system)) + {} + + /** + * The shortest distance between point and plane. + */ + double distance_from_plane; + + /** + * The distance between the start of the first segment (usually at + * the surface) to the provided point following the (curved) plane. + */ + double distance_along_plane; + + /** + * The fraction of the section that lies before the projected point + * on the plane (when looking from the start point of the section). + */ + double fraction_of_section; + + /** + * The fraction of the segment that lies before the projected point + * on the plane (when looking from the start point of the segment). + */ + double fraction_of_segment; + + /** + * The number of the section that is closest to the point + */ + size_t section; + + /** + * The number of the segment that is closest to the point. + */ + size_t segment; + + /** + * The average dip angle of the plane at the location where the + * point is projected onto the plane. + */ + double average_angle; + + /** + * The depth of the closest point on reference surface. + */ + double depth_reference_surface; + + /** + * The closest point on the trench line in cartesian coordinates. + */ + Point<3> closest_trench_point; + }; + + /** + * Computes the distance of a point to a curved plane. + * TODO: add more info on how this works/is implemented. + * \param check_point This is the cartesian point of which we want to know the + * distance to the curved planes + * \param check_point_natural the check_point in the natural coordinates of the + * current coordinate system. + * \param reference_point This is a 2d point in natural coordinates at the + * surface which the curved planes dip towards. Natural coordinates are in + * cartesian (x,y,z) in meters and in spherical radius in meters and longitude + * and latitude in radians. + * \param point_list This is a vector of 2d Points in natural coordinates at the + * surface which define the line along the surface at which the curved planes + * start. Natural coordinates are in cartesian (x,y,z) in meters and in spherical + * radius in meters and longitude and latitude in radians. + * \param plane_segment_lengths This is a vector of vectors of doubles. It contains + * the length of every segment at point in the point_list (in the same order as + * the point_list. + * \param plane_segment_angles This is a vector of vectors of 2d points. It contains + * the begin and end angle of every segment at point in the point_list (in the same + * order as the point_list. + * \param start_radius This value contains the radius or height from bottom of the box + * at which the plane starts. This means that the start_radius effectively becomes the + * surface for this slab. + * \param coordinate_system This is a reference to the coordinate system of the + * World Builder. This is used to convert cartesian to natural coordinates and back. + * \param only_positive This value determines whether only the part below the + * plane should count as distance or both sides of the plane. It is called only_positive + * because the area below the plane, the distance is positive, and above the plane the + * distance is negative. + * \param interpolation_type This value determines what interpolation type should be used + * when determining the location with respect to the curved plane. + * \param spline_x the spline representing the x coordinate. + * \param spline_y the spline representing the y coordinate. + * \param global_x_list This is a list of one dimensional coorindates, with zero or the + * amount of coordinates entries, used for interpolation. An empty list is interpreted + * as a list filled with {0,1,2,...,number of coordinates}. Filling this list with other + * values changes the returned section fraction. It allows for, for example, adding + * extra coordinates automatically, and still reference the user provided coordinates by + * the original number. Note that no whole numbers may be skipped. So for a list of 4 points, + * {0,0.5,1,2} is allowed, but {0,2,3,4} is not. + * + * The function returns a struct that contains which segment and section of the curved + * planes the point is closest to, what fraction of those segment and section lies before + * the point (looking from the start of segment/section), the distance + * of the point from the plane and the distance of the point along the plane, + * and the average angle of the closest segment/section. + */ + PointDistanceFromCurvedPlanes distance_point_from_curved_planes(const Point<3> &check_point, + const Objects::NaturalCoordinate &check_point_natural, + const Point<2> &reference_point, + const std::vector > &point_list, + const std::vector > &plane_segment_lengths, + const std::vector > > &plane_segment_angles, + const double start_radius, + const std::unique_ptr &coordinate_system, + const bool only_positive, + const Objects::BezierCurve &bezier_curve); + + + + /** + * Ensure angle is between 0 and 360 degrees + */ + double wrap_angle(const double angle); + + /** + * Interpolate between two angles (angle1 and angle2), + * with fraction defining the weighting between the two, + * taking into account we might cross over from 360 to 0 degrees. + */ + double interpolate_angle_across_zero(const double angle_1, + const double angle_2, + const double fraction); + + /** + * Transform a rotation matrix into euler angles + */ + std::array + euler_angles_from_rotation_matrix(const std::array,3> &rotation_matrix); + + /** + * Transform euler angles into a rotation matrix + */ + std::array,3> + euler_angles_to_rotation_matrix(double phi1, double theta, double phi2); + + /** + * Read a file and distribute the content over all MPI processes. + * If WB_WITH_MPI is not defined, this function will just read the file. + * + * @param filename The name of the file to read. + * @return The content of the file. + */ + std::string + read_and_distribute_file_content(const std::string &filename); + + /** + * Calculate the distance of a point from a mid oceanic ridge, and also calculate + * the spreading velocity of the ridge at this point. + * TODO: make the spreading velocity spatially/temporally variable + * + * @param mid_oceanic_ridges The coordinates of the mid oceanic ridges + * @param mid_oceanic_spreading_velocities The spreading rate of the mid oceanic ridges at each ridge coordinate + * @param coordinate_system The coordinate system + * @param position_in_natural_coordinates_at_min_depth the current position in natural_coordinates + * @param subducting_plate_velocities the subducting plate velocities, currently this is only an optional parameter + * that can be used in the mass conserving subducting plate temperature model. This parameter allows the user to + * track the effect of ridge migration on the slab thermal structure + * @param ridge_migration_times the times that the corresponding section of the ridge has been moving, in years. This + * is used in combination with subducting_plate_velocities, and mid_oceanic_spreading_velocities to compute the distance + * that the spreading center has migrated. This vector is obtained from the input parameter "spreading velocity" in the + * mass conserving model when "spreading velocity" has the form: [ [t1,[[v11, v12, ...]], [t2,[[v21, v22, ...]], ... ]. + * where tn is the time that ridge section n has been moving. + * @return The content of the file. + */ + std::vector + calculate_ridge_distance_and_spreading(std::vector>> mid_oceanic_ridges, + std::vector> mid_oceanic_spreading_velocities, + const std::unique_ptr &coordinate_system, + const Objects::NaturalCoordinate &position_in_natural_coordinates_at_min_depth, + const std::vector> &subducting_plate_velocities, + const std::vector &ridge_migration_times); + + // todo_effective + /** + * Calculate the effective plate ages of a point on the slab surface, and also calculates + * the effective trench ages at the start of subduction. + * @param ridge_parameters The distance and spreading velocity relative to a mid ocean ridge + * @param distance_along_plane The distance along the slab surface plane + * @return The effective plate age and the trench age + */ + std::vector + calculate_effective_trench_and_plate_ages(std::vector ridge_parameters, double distance_along_plane); + + } // namespace Utilities +} // namespace WorldBuilder + + +#endif diff --git a/contrib/world_builder/include/world_builder/world.h.bak b/contrib/world_builder/include/world_builder/world.h.bak new file mode 100644 index 00000000000..0627eb60d84 --- /dev/null +++ b/contrib/world_builder/include/world_builder/world.h.bak @@ -0,0 +1,316 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_WORLD_H +#define WORLD_BUILDER_WORLD_H + +#include "world_builder/grains.h" +#include "world_builder/parameters.h" +#include "world_builder/utilities.h" +#include "world_builder/objects/distance_from_surface.h" + +#include + +/** +* The global namespace for the Geodynamic World Builder +*/ +namespace WorldBuilder +{ + + namespace Features + { + class Interface; + } // namespace Features + + class World + { + public: + /** + * Constructor. This constructor requires the parameter filename. Other parameters + * are optional. + * \param filename a string with the location of + * the world builder file to initialize the world. + * \param has_output_dir a bool indicating whether the world builder is allowed to + * write out information to a directly. + * \param output_dir a string with the location of the directory where the world builder + * is allowed to write information to if it is allowed by the bool has_output_dir. + * \param random_number_seed a double containing a seed for the random number generator. + * The world builder uses a deterministic random number generator for some plugins. This + * is a deterministic random number generator on prorpose because even though you might + * want to use random numbers to initialize some fields, the result should be reproducible. + * Note that when the world builder is used in for example MPI programs you should supply + * the world builder created each MPI process a different seed. You can use the MPI RANK + * for this (seed is seed + MPI_RANK). Because the generator is deterministic (known and + * documented algorithm), we can test the results and they should be the same even for different + * compilers and machines. + */ + World(std::string filename, bool has_output_dir = false, const std::string &output_dir = "", unsigned long random_number_seed = 1, const bool limit_debug_consistency_checks = true); + + /** + * Destructor + */ + ~World(); + + + /** + * Describe what the world builder file should look like + */ + static void declare_entries(Parameters &prm); + + /** + * read in the world builder file + */ + void parse_entries(Parameters &prm); + + /** + * Returns different values at a single point in one go stored in a vector of doubles. + * + * The properties input decides what each entry means, and the output is generated in the + * same order as the properties input. The properties input consists of + * a 3D array, where the first entry identifies the property and the last two entries + * provide extra information about that property. + * + * Temperature is identified by 1 and no extra information is needed. So temperature + * input usually looks like {1,0,0}. A temperature query prodoces one entry in the output + * vector. + * + * Composition is identified by 2. This produces one + * value in the output. The second entry identifies the composition number and the third + * number is not used. So a commposition query asking about composition 1 looks like this: + * {2,1,0}. A composition query prodoces one entry in the output vector. + * + * Grains are identified by 2. The second entry is the grain composition number and the third + * entry is the number of grains. A query about the grains, where it asks about composition 1 + * (for example enstatite) and 500 grains, looks like this: {2,1,500}. + * A composition query prodoces n_grains*10 entries in the output vector. The first n_grains + * entries are the sizes of all the grains, and the other 9 entries are sets of rotation + * matrices. The rotation matrix entries are ordered [0][0],[0][1],[0][2],[1][0],[1][1],etc. + */ + std::vector properties(const std::array &point, + const double depth, + const std::vector> &properties) const; + + /** + * Returns different values at a single point in one go stored in a vector of doubles. + * + * The properties input decides what each entry means, and the output is generated in the + * same order as the properties input. The properties input consists of + * a 3D array, where the first entry identifies the property and the last two entries + * provide extra information about that property. + * + * Temperature is identified by 1 and no extra information is needed. So temperature + * input usually looks like {1,0,0}. A temperature query prodoces one entry in the output + * vector. + * + * Composition is identified by 2. This produces one + * value in the output. The second entry identifies the composition number and the third + * number is not used. So a composition query asking about composition 1 looks like this: + * {2,1,0}. A composition query prodoces one entry in the output vector. + * + * Grains are identified by 3. The second entry is the grain composition number and the third + * entry is the number of grains. A query about the grains, where it asks about composition 1 + * (for example enstatite) and 500 grains, looks like this: {3,1,500}. + * A composition query prodoces n_grains*10 entries in the output vector. The first n_grains + * entries are the sizes of all the grains, and the other 9 entries are sets of rotation + * matrices. The rotation matrix entries are ordered [0][0],[0][1],[0][2],[1][0],[1][1],etc. + * + * The tag is identified by 4 and no extra information is needed. So the tag + * input usually looks like {4,0,0}. A tag query prodoces one entry in the output + * vector, representing the index of the tag of the last/dominant feature. + */ + std::vector properties(const std::array &point, + const double depth, + const std::vector> &properties) const; + + /** + * Returns the temperature based on a 2d Cartesian point, the depth in the + * model at that point and the gravity norm at that point. + */ + double temperature(const std::array &point, const double depth) const; + + /** + * Returns the temperature based on a 3d Cartesian point, the depth in the + * model at that point and the gravity norm at that point. + */ + double temperature(const std::array &point, const double depth) const; + + /** + * Returns the temperature based on a 2d Cartesian point, the depth in the + * model at that point and the gravity norm at that point. + * Note: gravity norm is no longer used, instead use the gravity model from the input file. + */ + [[deprecated("Replaced by a temperature function without the gravity. This function will be removed in future versions.")]] + double temperature(const std::array &point, const double depth, const double gravity_norm) const; + + /** + * Returns the temperature based on a 3d Cartesian point, the depth in the + * model at that point and the gravity norm at that point. + * Note: gravity norm is no longer used, instead use the gravity model from the input file. + */ + [[deprecated("Replaced by a temperature function without the gravity. This function will be removed in future versions.")]] + double temperature(const std::array &point, const double depth, const double gravity_norm) const; + + /** + * Returns the composition value based on a 2d Cartesian point, the depth in + * the model at that point and the gravity norm at that point. + */ + double composition(const std::array &point, const double depth, const unsigned int composition_number) const; + + /** + * Returns the composition value based on a 3d Cartesian point, the depth in + * the model at that point and the gravity norm at that point. + */ + double composition(const std::array &point, const double depth, const unsigned int composition_number) const; + + /** + * Returns the grain orientations and sizes based on a 2d Cartesian point, the depth in + * the model at that point and the gravity norm at that point. + */ + WorldBuilder::grains grains(const std::array &point, + const double depth, + const unsigned int composition_number, + size_t number_of_grains) const; + + /** + * Returns the grain orientations and sizes based on a 3d Cartesian point, the depth in + * the model at that point and the gravity norm at that point. + */ + WorldBuilder::grains grains(const std::array &point, + 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, + * calculated 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. + */ + int MPI_RANK; + + /** + * The MPI size. Set to one if MPI is not available. + */ + int MPI_SIZE; + + /** + * Return a reference to the mt19937 random number. + * The seed is provided to the world builder at construction. + */ + std::mt19937 &get_random_number_engine(); + + /** + * This is the parameter class, which stores all the values loaded in + * from the parameter file or which are set directly. + */ + Parameters parameters; + + /** + * Todo + */ + std::vector > cross_section; + + /** + * Todo + */ + Point<2> surface_coord_conversions; + + /** + * Todo + */ + double potential_mantle_temperature; + + /** + * Todo + */ + double surface_temperature; + + /** + * Todo + */ + bool force_surface_temperature; + + /** + * Todo + */ + double thermal_expansion_coefficient; + + /** + * Todo + */ + double specific_heat; + + /** + * Todo + */ + double thermal_diffusivity; + + /** + * Todo + */ + double maximum_distance_between_coordinates; + + /** + * Todo + */ + std::string interpolation; + + /** + * A list of all the feature tags. + */ + std::vector feature_tags; + + private: + /** + * The minimum dimension. If cross section data is provided, it is set + * to 2, which means the 2d function of temperature and composition can + * be used. Otherwise it is set to 3, which means that they can't be + * used. + */ + unsigned int dim; + + + /** + * random number generator engine + */ + std::mt19937 random_number_engine; + + /** + * limits some of the consistency checks in debug mode. + * Current only prevents a check whether depth in spherical + * coordinates is consistent with the computed depth from + * x,y,z and provided radius. + * Note: Recommended to keep it at false, unless you know what you are doing. + */ + bool limit_debug_consistency_checks; + + + + }; +} // namespace WorldBuilder + +#endif diff --git a/contrib/world_builder/include/world_builder/wrapper_c.h.bak b/contrib/world_builder/include/world_builder/wrapper_c.h.bak new file mode 100644 index 00000000000..e1598ab666b --- /dev/null +++ b/contrib/world_builder/include/world_builder/wrapper_c.h.bak @@ -0,0 +1,71 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_WRAPPER_C_H +#define WORLD_BUILDER_WRAPPER_C_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This function creates an object of the world builder and returns a pointer + * to it. This pointer can then be used to call the temperature and composition + * functions. When done call the release world function to destroy the object. + */ +void create_world(void **ptr_ptr_world, const char *world_builder_file, const bool *has_output_dir, const char *output_dir, const unsigned long random_number_seed); + +/** + * This function return the temperature at a specific location given x, z, depth and + * gravity. + * Note: gravity value is no longer used, instead use the gravity model from the input file. + */ +void temperature_2d(void *ptr_ptr_world, double x, double z, double depth, double *temperature); + +/** + * This function return the temperature at a specific location given x, y, z, depth and + * gravity. + */ +void temperature_3d(void *ptr_ptr_world, double x, double y, double z, double depth, double *temperature); + +/** + * This function return the composition at a specific location given x, z, depth and + * composition number. + */ +void composition_2d(void *ptr_ptr_world, double x, double z, double depth, unsigned int composition_number, double *composition); + +/** + * This function return the composition at a specific location given x, y, z, depth and + * composition number. + */ +void composition_3d(void *ptr_ptr_world, double x, double y, double z, double depth, unsigned int composition_number, double *composition); + +/** + * The destructor for the world builder class. Call this function when done with the + * world builder. + */ +void release_world(void *ptr_ptr_world); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/world_builder/include/world_builder/wrapper_cpp.h.bak b/contrib/world_builder/include/world_builder/wrapper_cpp.h.bak new file mode 100644 index 00000000000..610ff1bbc58 --- /dev/null +++ b/contrib/world_builder/include/world_builder/wrapper_cpp.h.bak @@ -0,0 +1,94 @@ +/* + 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 . +*/ + +#ifndef WORLD_BUILDER_WRAPPER_CPP_H +#define WORLD_BUILDER_WRAPPER_CPP_H + +#include +#include "world_builder/deprecate.h" + +namespace wrapper_cpp +{ + /** + * This class is to be used by SWIG. To make it easy for SWIG we do not use any + * other world builder header file in this header file. This means that the class + * stores a void pointer internally. The cpp implementation can use the world builder + * header files. + */ + class WorldBuilderWrapper + { + public: + /** + * constructor + */ + WorldBuilderWrapper(std::string filename, bool has_output_dir = false, const std::string &output_dir = "", const unsigned long random_number_seed = 1.0); + + /** + * destructor + */ + ~WorldBuilderWrapper(); + + /** + * This function return the temperature at a specific location given x, z, depth and + * gravity. + */ + double temperature_2d(double x, double z, double depth); + + /** + * This function return the temperature at a specific location given x, y, z, depth and + * gravity. + */ + double temperature_3d(double x, double y, double z, double depth); + + /** + * DEPRECATED: Replaced by a temperature function without the gravity. This function will be removed in future versions. + * This function return the temperature at a specific location given x, z, depth and + * gravity. + * Note: gravity value is no longer used, instead use the gravity model from the input file. + */ + double temperature_2d(double x, double z, double depth, double gravity); + + /** + * DEPRECATED: Replaced by a temperature function without the gravity. This function will be removed in future versions. + * This function return the temperature at a specific location given x, y, z, depth and + * gravity. + * Note: gravity value is no longer used, instead use the gravity model from the input file. + */ + double temperature_3d(double x, double y, double z, double depth, double gravity); + + /** + * This function return the composition at a specific location given x, z, depth and + * composition number. + */ + double composition_2d(double x, double z, double depth, unsigned int composition_number); + + /** + * This function return the composition at a specific location given x, y, z, depth and + * composition number. + */ + double composition_3d(double x, double y, double z, double depth, unsigned int composition_number); + + + private: + void *ptr_ptr_world; + + + }; +} // namespace wrapper_cpp +#endif diff --git a/contrib/world_builder/source/gwb-dat/main.cc.bak b/contrib/world_builder/source/gwb-dat/main.cc.bak new file mode 100644 index 00000000000..0ef4ca636a2 --- /dev/null +++ b/contrib/world_builder/source/gwb-dat/main.cc.bak @@ -0,0 +1,343 @@ +/* + Copyright (C) 2018 - 2021 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 "app/main.h" + +#include "world_builder/assert.h" +#include "world_builder/consts.h" +#include "world_builder/point.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" + +#ifdef WB_WITH_MPI +// we don't need the c++ MPI wrappers +#define OMPI_SKIP_MPICXX 1 +#define MPICH_SKIP_MPICXX +#include +#endif + +#include +#include +#include +#include + +#ifndef NDEBUG +#ifdef WB_USE_FP_EXCEPTIONS +#include +#endif +#endif + +using namespace WorldBuilder::Utilities; + +bool find_command_line_option(char **begin, char **end, const std::string &option) +{ + return std::find(begin, end, option) != end; +} + +int main(int argc, char **argv) +{ + +#ifndef NDEBUG +#ifdef WB_USE_FP_EXCEPTIONS + // Some implementations seem to not initialize the floating point exception + // bits to zero. Make sure we start from a clean state. + feclearexcept(FE_DIVBYZERO|FE_INVALID); + + // enable floating point exceptions + feenableexcept(FE_DIVBYZERO|FE_INVALID); +#endif +#endif + + /** + * First parse the command line options + */ + std::string wb_file; + std::string data_file; + + unsigned int dim = 3; + unsigned int compositions = 0; + unsigned int grain_compositions = 0; + size_t n_grains = 0; + bool convert_spherical = false; + bool limit_debug_consistency_checks = false; + bool output_json_files = false; + + if (find_command_line_option(argv, argv+argc, "-h") || find_command_line_option(argv, argv+argc, "--help")) + { + std::cout << "This program allows to use the world builder library directly with a world builder file and a data file. " + "The data file will be filled with initial conditions from the world as set by the world builder file." << std::endl + << "Besides providing two files, where the first is the world builder file and the second is the data file, the available options are: " << std::endl + << "-h or --help to get this help screen." << std::endl; + return 0; + } + + if (find_command_line_option(argv, argv+argc, "-ldcc") || find_command_line_option(argv, argv+argc, "--limit-debug-consistency-checks")) + limit_debug_consistency_checks = true; + + if (find_command_line_option(argv, argv+argc, "--output-json-files")) + output_json_files = true; + + if (argc == 1) + { + std::cout << "Error: There where no files passed to the World Builder, use --help for more " << std::endl + << "information on how to use the World Builder app." << std::endl; + return 0; + } + + + if (argc == 2) + { + std::cout << "Error: The World Builder app requires at least two files, a World Builder file " << std::endl + << "and a data file to convert." << std::endl; + return 0; + } + + if ((argc == 3 && limit_debug_consistency_checks && output_json_files) || (argc == 4 && !(!limit_debug_consistency_checks != !output_json_files)) || (argc == 5 && (!limit_debug_consistency_checks && !output_json_files)) || argc > 5) + { + std::cout << "Only exactly two command line arguments may be given, which should be the world builder file location and the data file location (in that order) " + << "or exactly three command line arguments, which should be the world builder file location, the data file location and --limit-debug-consistency-checks or --output-json-files (in that order)," + "or exactly four command line arguments, which should be the world builder file location, the data file location and --limit-debug-consistency-checks and --output-json-files (in that order)," + << ", argc = " << argc << ", limit_debug_consistency_checks = " << (limit_debug_consistency_checks ? "true" : "false") << ", output_json_files = " << (output_json_files ? "true" : "false") << std::endl; + return 0; + } + + int MPI_RANK = 0; +#ifdef WB_WITH_MPI + int MPI_SIZE = 1; + MPI_Init(&argc,&argv); + MPI_Comm_rank(MPI_COMM_WORLD, &MPI_RANK); + MPI_Comm_size(MPI_COMM_WORLD, &MPI_SIZE); +#endif + + if (MPI_RANK == 0) + { + wb_file = argv[1]; + data_file = argv[2]; + + /** + * Try to start the world builder + */ + std::unique_ptr world; + //try + { + const std::string output_dir = wb_file.substr(0,wb_file.find_last_of("/\\") + 1); + world = std::make_unique(wb_file, output_json_files, output_dir,1,limit_debug_consistency_checks); + } + /*catch (std::exception &e) + { + std::cerr << "Could not start the World builder, error: " << e.what() << "\n"; + return 1; + } + catch (...) + { + std::cerr << "Exception of unknown type!\n"; + return 1; + }*/ + + + /** + * Read the data from the data files + */ + std::ifstream data_stream(data_file); + + // move the data into a vector of strings + std::vector > data; + std::string temp; + + while (std::getline(data_stream, temp)) + { + std::istringstream buffer(temp); + std::vector line((std::istream_iterator(buffer)), + std::istream_iterator()); + + // remove the comma's in case it is a comma separated file. + // TODO: make it split for comma's and/or spaces + for (auto &line_i : line) + line_i.erase(std::remove(line_i.begin(), line_i.end(), ','), line_i.end()); + + data.push_back(line); + } + + // Read config from data if present + for (auto &line_i : data) + { + if (!line_i.empty() && line_i[0] == "#" && line_i[1] == "dim" && line_i[2] == "=") + { + dim = string_to_unsigned_int(line_i[3]); + } + + if (!line_i.empty() && line_i[0] == "#" && line_i[1] == "compositions" && line_i[2] == "=") + compositions = string_to_unsigned_int(line_i[3]); + + if (!line_i.empty() && line_i[0] == "#" && line_i[1] == "grain" && line_i[2] == "compositions" && line_i[3] == "=") + grain_compositions = string_to_unsigned_int(line_i[4]); + + if (!line_i.empty() && line_i[0] == "#" && line_i[1] == "number" && line_i[2] == "of" && line_i[3] == "grains" && line_i[4] == "=") + n_grains = string_to_unsigned_int(line_i[5]); + + if (!line_i.empty() && line_i[0] == "#" && line_i[1] == "convert" && line_i[2] == "spherical" && line_i[3] == "=" && line_i[4] == "true") + convert_spherical = true; + } + + // set properties + std::vector> properties; + properties.push_back({{1,0,0}}); // temperature + + for (size_t c = 0; c < compositions; ++c) + properties.push_back({{2,static_cast(c),0}}); // composition c + + for (size_t gc = 0; gc < grain_compositions; ++gc) + properties.push_back({{3,static_cast(gc),static_cast(n_grains)}}); // grains gc + + properties.push_back({{4,0,0}}); // tag + + + switch (dim) + { + case 2: + WBAssertThrow(!convert_spherical, "Converting to spherical values is only available in 3D."); + // set the header + std::cout << "# x z d T "; + + for (unsigned int c = 0; c < compositions; ++c) + std::cout << 'c' << c << ' '; + + for (unsigned int gc = 0; gc < grain_compositions; ++gc) + for (size_t g = 0; g < n_grains; g++) + std::cout << "gs" << gc << '-' << g << ' ' // gs = grain size, gm = grain rotation matrix + << "gm" << gc << '-' << g << "[0:0] " << "gm" << gc << '-' << g << "[0:1] " << "gm" << gc << '-' << g << "[0:2] " + << "gm" << gc << '-' << g << "[1:0] " << "gm" << gc << '-' << g << "[1:1] " << "gm" << gc << '-' << g << "[1:2] " + << "gm" << gc << '-' << g << "[2:0] " << "gm" << gc << '-' << g << "[2:1] " << "gm" << gc << '-' << g << "[2:2] "; + + std::cout << "tag "; + std::cout < 0 && data[i][0] != "#") + { + + WBAssertThrow(data[i].size() == dim + 1, "The file needs to contain dim + 1 entries, but contains " << data[i].size() << " entries " + " on line " << i+1 << " of the data file (" << data_file << "). Dim is " << dim << '.'); + const std::array coords = {{ + string_to_double(data[i][0]), + string_to_double(data[i][1]) + } + }; + std::cout << data[i][0] << ' ' << data[i][1] << ' ' << data[i][2] << ' '; + std::vector output = world->properties(coords, string_to_double(data[i][2]),properties); + std::cout << output[0] << ' '; + + for (unsigned int c = 0; c < compositions; ++c) + { + std::cout << output[1+c] << ' '; + } + + for (unsigned int gc = 0; gc < grain_compositions; ++gc) + { + const size_t start = 1+compositions+gc*n_grains*10; + for (unsigned int g = 0; g < n_grains; ++g) + { + std::cout << output[start+g] << ' ' + << output[start+n_grains+g*9] << ' ' << output[start+n_grains+g*9+1] << ' ' << output[start+n_grains+g*9+2] << ' ' + << output[start+n_grains+g*9+3] << ' ' << output[start+n_grains+g*9+4] << ' ' << output[start+n_grains+g*9+5] << ' ' + << output[start+n_grains+g*9+6] << ' ' << output[start+n_grains+g*9+7] << ' ' << output[start+n_grains+g*9+8] << ' '; + + } + } + std::cout << " " << output[output.size()-1] << std::endl; + + } + break; + case 3: + // set the header + std::cout << "# x y z d g T "; + + for (unsigned int c = 0; c < compositions; ++c) + std::cout << 'c' << c << ' '; + + for (unsigned int gc = 0; gc < grain_compositions; ++gc) + for (size_t g = 0; g < n_grains; g++) + std::cout << "gs" << gc << '-' << g << ' ' // gs = grain size, gm = grain rotation matrix + << "gm" << gc << '-' << g << "[0:0] " << "gm" << gc << '-' << g << "[0:1] " << "gm" << gc << '-' << g << "[0:2] " + << "gm" << gc << '-' << g << "[1:0] " << "gm" << gc << '-' << g << "[1:1] " << "gm" << gc << '-' << g << "[1:2] " + << "gm" << gc << '-' << g << "[2:0] " << "gm" << gc << '-' << g << "[2:1] " << "gm" << gc << '-' << g << "[2:2] "; + + std::cout << "tag "; + std::cout < 0 && data[i][0] != "#") + { + WBAssertThrow(data[i].size() == dim + 1, "The file needs to contain dim + 1 entries, but contains " << data[i].size() << " entries " + " on line " << i+1 << " of the data file (" << data_file << "). Dim is " << dim << '.'); + std::array coords = {{ + string_to_double(data[i][0]), // x or R + string_to_double(data[i][1]) *(convert_spherical ? (WorldBuilder::Consts::PI/180.): 1.), // y or long + string_to_double(data[i][2]) *(convert_spherical ? (WorldBuilder::Consts::PI/180.): 1.) // z or lat + } + }; + + if (convert_spherical) + { + coords = spherical_to_cartesian_coordinates(coords).get_array(); + } + + std::cout << data[i][0] << ' ' << data[i][1] << ' ' << data[i][2] << ' ' << data[i][3] << ' '; + std::vector output = world->properties(coords, string_to_double(data[i][3]),properties); + std::cout << output[0] << ' '; + + for (unsigned int c = 0; c < compositions; ++c) + { + std::cout << output[1+c] << ' '; + } + + for (unsigned int gc = 0; gc < grain_compositions; ++gc) + { + const size_t start = 1+compositions+gc*n_grains*10; + for (unsigned int g = 0; g < n_grains; ++g) + { + std::cout << output[start+g] << ' ' + << output[start+n_grains+g*9] << ' ' << output[start+n_grains+g*9+1] << ' ' << output[start+n_grains+g*9+2] << ' ' + << output[start+n_grains+g*9+3] << ' ' << output[start+n_grains+g*9+4] << ' ' << output[start+n_grains+g*9+5] << ' ' + << output[start+n_grains+g*9+6] << ' ' << output[start+n_grains+g*9+7] << ' ' << output[start+n_grains+g*9+8] << ' '; + + } + } + std::cout << " " << output[output.size()-1] << std::endl; + + } + break; + default: + std::cout << "The World Builder can only be run in 2d and 3d but a different space dimension " << std::endl + << "is given: dim = " << dim << '.'; + +#ifdef WB_WITH_MPI + MPI_Finalize(); +#endif + return 0; + } + } +#ifdef WB_WITH_MPI + MPI_Finalize(); +#endif + return 0; +} diff --git a/contrib/world_builder/source/gwb-grid/main.cc.bak b/contrib/world_builder/source/gwb-grid/main.cc.bak new file mode 100644 index 00000000000..a8b931b31a0 --- /dev/null +++ b/contrib/world_builder/source/gwb-grid/main.cc.bak @@ -0,0 +1,1672 @@ +/* + Copyright (C) 2018 - 2021 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 . +*/ + +/** + * Much of this code was based on GHOST (https://github.com/cedrict/GHOST), + * and was contribute to the World Builder with the permission and help of + * the author of GHOST. + */ + +#include "visualization/main.h" + +#include "world_builder/assert.h" +#include "world_builder/coordinate_system.h" +#include "world_builder/nan.h" +#include "world_builder/point.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" +#include "world_builder/config.h" + +#include +#include + + +#include "vtu11/vtu11.hpp" +#undef max +#undef min + +#ifdef WB_WITH_MPI +// we don't need the c++ MPI wrappers +#define OMPI_SKIP_MPICXX 1 +#define MPICH_SKIP_MPICXX +#include +#endif + +#ifndef NDEBUG +#ifdef WB_USE_FP_EXCEPTIONS +#include +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace WorldBuilder; +using namespace WorldBuilder::Utilities; + + + +/** + * Filter the cells of a VTU mesh based on a given tag. All tags with smaller value than @p first_tag will be removed + */ +void filter_vtu_mesh(int dim, + const std::vector &include_tag, + vtu11::Vtu11UnstructuredMesh &input_mesh, + const std::vector &input_data, + vtu11::Vtu11UnstructuredMesh &output_mesh, + std::vector &output_data); + +void filter_vtu_mesh(int dim, + const std::vector &include_tag, + vtu11::Vtu11UnstructuredMesh &input_mesh, + const std::vector &input_data, + vtu11::Vtu11UnstructuredMesh &output_mesh, + std::vector &output_data) +{ + output_data.resize(input_data.size()); + const std::int64_t invalid = -1; + std::vector vertex_index_map(input_mesh.points().size(), invalid); + + const unsigned int n_vert_per_cell = (dim==3)?8:4; + + const std::size_t n_cells = input_mesh.types().size(); + std::uint64_t dst_cellid = 0; + for (std::size_t cellidx = 0; cellidx (input_mesh.connectivity()[idx]); + highest_tag = std::max(highest_tag,static_cast(input_data[2][src_vid])); + } + if (highest_tag < 0 || include_tag[static_cast(highest_tag)]==false) + continue; + + ++dst_cellid; + + for (size_t idx=cellidx*n_vert_per_cell; idx<(cellidx+1)*n_vert_per_cell; ++idx) + { + const size_t src_vid = static_cast(input_mesh.connectivity()[idx]); + + std::int64_t dst_vid = vertex_index_map[src_vid]; + if (dst_vid == invalid) + { + dst_vid = static_cast(output_mesh.points().size()/3); + vertex_index_map[src_vid] = dst_vid; + + for (unsigned int i=0; i<3; ++i) + output_mesh.points().push_back(input_mesh.points()[src_vid*3+i]); + + for (unsigned int d=0; d(dst_cellid*n_vert_per_cell)); + + output_mesh.types().push_back(input_mesh.types()[cellidx]); + } +} + +/** + * A very simple threadpool class. The threadpool currently only supports a + * parallel for function, to easily parallelize the for function. + * + * Todo: might need something more advanced and safe in the future. + */ +class ThreadPool +{ + public: + + /** + * Constructor + */ + explicit ThreadPool(size_t number_of_threads) + { + pool.resize(number_of_threads); + } + + /** + * A function which allows to parallelize for loops. + */ + template + void parallel_for(size_t start, size_t end, Callable func) + { + // Determine the size of the slice for the loop + const size_t n = end - start + 1; + size_t slice = static_cast(std::round(n / static_cast((pool.size())))); + slice = std::max(slice, static_cast(1)); + + // Function which loops the passed function func + auto loop_function = [&func] (size_t k1, size_t k2) + { + for (size_t k = k1; k < k2; k++) + { + func(k); + } + }; + + // Launch jobs + size_t i1 = start; + size_t i2 = std::min(start + slice, end); + for (size_t i = 0; i + 1 < pool.size() && i1 < end; ++i) + { + pool[i] = std::thread(loop_function, i1, i2); + i1 = i2; + i2 = std::min(i2 + slice, end); + } + if (i1 < end) + { + pool[pool.size()-1] = std::thread(loop_function, i1, end); + } + + // Wait for jobs to finish + for (std::thread &t : pool) + { + if (t.joinable()) + { + t.join(); + } + } + } + + private: + std::vector pool; + +}; + + +void project_on_sphere(double radius, double &x_, double &y_, double &z_) +{ + double x = x_; + double y = y_; + double z = z_; + const WorldBuilder::Point<3> in_point(std::array {{x,y,z}}, WorldBuilder::CoordinateSystem::cartesian); + const WorldBuilder::Point<3> output_point(std::array {{0,0,0}}, WorldBuilder::CoordinateSystem::cartesian); + const double r = in_point.norm(); + const double theta = std::atan2(in_point[1],in_point[0]); + const double phi = std::acos(in_point[2]/r); + + x_ = radius * std::cos(theta) * std::sin(phi); + y_ = radius * std::sin(theta) * std::sin(phi); + z_ = radius * std::cos(phi); + +} + +void lay_points(double x1, double y1, double z1, + double x2, double y2, double z2, + double x3, double y3, double z3, + double x4, double y4, double z4, + std::vector &x, std::vector &y, std::vector &z, + std::vector &hull, size_t level) +{ + // TODO: Assert that the vectors have the correct size; + size_t counter = 0; + for (size_t j = 0; j < level+1; ++j) + { + for (size_t i = 0; i < level+1; ++i) + { + // equidistant (is this irrelevant?) + // double r = -1.0 + (2.0 / level) * i; + // double s = -1.0 + (2.0 / level) * j; + + // equiangular + const double pi4 = Consts::PI*0.25; + const double x0 = -pi4 + static_cast(i) * 2.0 * static_cast(pi4)/static_cast(level); + const double y0 = -pi4 + static_cast(j) * 2.0 * static_cast(pi4)/static_cast(level); + const double r = std::tan(x0); + const double s = std::tan(y0); + + + const double N1 = 0.25 * (1.0 - r) * (1.0 - s); + const double N2 = 0.25 * (1.0 + r) * (1.0 - s); + const double N3 = 0.25 * (1.0 + r) * (1.0 + s); + const double N4 = 0.25 * (1.0 - r) * (1.0 + s); + + x[counter] = x1 * N1 + x2 * N2 + x3 * N3 + x4 * N4; + y[counter] = y1 * N1 + y2 * N2 + y3 * N3 + y4 * N4; + z[counter] = z1 * N1 + z2 * N2 + z3 * N3 + z4 * N4; + + if (i == 0) hull[counter] = true; + if (j == 0) hull[counter] = true; + if (i == level) hull[counter] = true; + if (j == level) hull[counter] = true; + counter++; + } + } +} + + +std::vector get_command_line_options_vector(int argc, char **argv) +{ + std::vector vector; + for (int i=1; i < argc; ++i) + vector.emplace_back(argv[i]); + + return vector; +} + +bool find_command_line_option(char **begin, char **end, const std::string &option) +{ + return std::find(begin, end, option) != end; +} + +int main(int argc, char **argv) +{ + +#ifndef NDEBUG +#ifdef WB_USE_FP_EXCEPTIONS + // Some implementations seem to not initialize the floating point exception + // bits to zero. Make sure we start from a clean state. + feclearexcept(FE_DIVBYZERO|FE_INVALID); + + // enable floating point exceptions + feenableexcept(FE_DIVBYZERO|FE_INVALID); +#endif +#endif + + /** + * First parse the command line options + */ + std::string wb_file; + std::string data_file; + + // If set to true, we will output one visualization file per "tag" + // with only the cells corresponding to that tag included. + bool output_by_tag = false; + // If set to true, we output a .filtered.vtu file without the background/mantle + bool output_filtered = false; + + size_t dim = 3; + size_t compositions = 0; + + // common + std::string grid_type = "chunk"; + + size_t n_cell_x = NaN::ISNAN; // x or long + size_t n_cell_y = NaN::ISNAN; // y or lat + size_t n_cell_z = NaN::ISNAN; // z or depth + + + // spherical + double x_min = NaN::DSNAN; // x or long + double x_max = NaN::DSNAN; // x or long + double y_min = NaN::DSNAN; // y or lat + double y_max = NaN::DSNAN; // y or lat + double z_min = NaN::DSNAN; // z or inner_radius + double z_max = NaN::DSNAN; // z or outer_radius + + // Conservative choice for the number of threads to use: + size_t number_of_threads = std::min(20u,1+std::thread::hardware_concurrency()/2); + unsigned int max_resolution = std::numeric_limits::max(); + + try + { + if (find_command_line_option(argv, argv+argc, "-v") || find_command_line_option(argv, argv+argc, "--version")) + { + std::cout << "World Builder Grid Visualization tool.\n" + << "GWB Version: " << WorldBuilder::Version::MAJOR << "." + << WorldBuilder::Version::MINOR << "." + << WorldBuilder::Version::PATCH << "." + << WorldBuilder::Version::LABEL << "\n" + << "git hash: " << WorldBuilder::Version::GIT_SHA1 << " branch: " << WorldBuilder::Version::GIT_BRANCH + << std::endl; + return 0; + } + + if (find_command_line_option(argv, argv+argc, "-h") || find_command_line_option(argv, argv+argc, "--help")) + { + std::cout << "World Builder Grid Visualization tool.\n" + << "This program loads a world builder file and generates a visualization on a structured grid " + << "based on information specified in a separate .grid configuration file.\n\n" + << "Usage:\n" + << argv[0] << " [-j N] [--filtered] [--by-tag] example.wb example.grid\n\n" + << "Available options:\n" + << " -j N Specify the number of threads the visualizer is allowed to use. Default: " << number_of_threads << ".\n" + << " --filtered Also produce a .filtered.vtu that removes cells only containing mantle or background.\n" + << " --by-tag Also produce a sequence of .N.vtu files that only contain cells of a specific tag.\n" + << " --resolution-limit X Specify a maximum resolution." + << " -h or --help To get this help screen.\n" + << " -v or --version To see version information.\n"; + return 0; + } + + std::vector options_vector = get_command_line_options_vector(argc, argv); + + for (size_t i = 0; i < options_vector.size(); ++i) + { + if (options_vector[i] == "-j") + { + number_of_threads = Utilities::string_to_unsigned_int(options_vector[i+1]); + options_vector.erase(options_vector.begin()+static_cast::difference_type>(i)); + options_vector.erase(options_vector.begin()+static_cast::difference_type>(i)); + --i; + continue; + } + if (options_vector[i] == "--filtered") + { + output_filtered = true; + options_vector.erase(options_vector.begin()+static_cast::difference_type>(i)); + --i; + continue; + } + if (options_vector[i] == "--by-tag") + { + output_by_tag = true; + options_vector.erase(options_vector.begin()+static_cast::difference_type>(i)); + --i; + continue; + } + if (options_vector[i] == "--resolution-limit") + { + max_resolution = Utilities::string_to_unsigned_int(options_vector[i+1]); + options_vector.erase(options_vector.begin()+static_cast::difference_type>(i)); + options_vector.erase(options_vector.begin()+static_cast::difference_type>(i)); + --i; + continue; + } + } + + if (options_vector.size() != 2) + { + std::cout << "World Builder Grid Visualization tool.\n" + << "Usage: " << argv[0] << " example.wb example.grid\n" + << "Try '" << argv[0] << " --help' for more information." << std::endl; + return 0; + } + + + wb_file = options_vector[0]; + data_file = options_vector[1]; + + } + catch (std::exception &e) + { + std::cerr << "error: " << e.what() << "\n"; + return 1; + } + catch (...) + { + std::cerr << "Exception of unknown type!\n"; + return 1; + } + + + int MPI_RANK = 0; +#ifdef WB_WITH_MPI + MPI_Init(&argc,&argv); + MPI_Comm_rank(MPI_COMM_WORLD, &MPI_RANK); +#endif + + std::cout << "[1/6] Parsing file... \r"; + + if (MPI_RANK == 0) + { + /** + * Try to start the world builder + */ + std::cout << "[2/6] Starting the world builder with " << number_of_threads << " threads... \r"; + std::cout.flush(); + + std::unique_ptr world; + try + { + world = std::make_unique(wb_file); + } + catch (std::exception &e) + { + std::cerr << "Could not start the World builder from file '" << wb_file << "', error: " << e.what() << "\n"; + +#ifdef WB_WITH_MPI + MPI_Finalize(); +#endif + return 1; + } + catch (...) + { + std::cerr << "Exception of unknown type!\n"; + +#ifdef WB_WITH_MPI + MPI_Finalize(); +#endif + return 1; + } + + /** + * start the thread pool + */ + ThreadPool pool(number_of_threads); + + /** + * Read the data from the data files + */ + std::cout << "[3/6] Reading grid file... \r"; + std::cout.flush(); + + + std::ifstream data_stream(data_file); + + // if config file is available, parse it + WBAssertThrow(data_stream.good(), + "Could not find the provided config file at the specified location: " + data_file); + + + // move the data into a vector of strings + std::vector > data; + std::string temp; + + while (std::getline(data_stream, temp)) + { + std::istringstream buffer(temp); + std::vector line((std::istream_iterator(buffer)), + std::istream_iterator()); + + // remove the comma's in case it is a comma separated file. + // TODO: make it split for comma's and/or spaces + for (auto &line_i : line) + line_i.erase(std::remove(line_i.begin(), line_i.end(), ','), line_i.end()); + + data.push_back(line); + } + + std::string vtu_output_format = "RawBinaryCompressed"; + // Read config from data if present + for (auto &line_i : data) + { + if (line_i.empty()) + continue; + + if (line_i[0] == "#") + continue; + + if (line_i[0] == "grid_type" && line_i[1] == "=") + { + grid_type = line_i[2]; + } + + if (line_i[0] == "dim" && line_i[1] == "=") + { + dim = string_to_unsigned_int(line_i[2]); + } + + if (line_i[0] == "vtu_output_format" && line_i[1] == "=") + { + vtu_output_format = line_i[2]; + } + + if (line_i[0] == "compositions" && line_i[1] == "=") + compositions = string_to_unsigned_int(line_i[2]); + + if (line_i[0] == "x_min" && line_i[1] == "=") + x_min = string_to_double(line_i[2]); + if (line_i[0] == "x_max" && line_i[1] == "=") + x_max = string_to_double(line_i[2]); + if (line_i[0] == "y_min" && line_i[1] == "=") + y_min = string_to_double(line_i[2]); + if (line_i[0] == "y_max" && line_i[1] == "=") + y_max = string_to_double(line_i[2]); + if (line_i[0] == "z_min" && line_i[1] == "=") + z_min = string_to_double(line_i[2]); + if (line_i[0] == "z_max" && line_i[1] == "=") + z_max = string_to_double(line_i[2]); + + if (line_i[0] == "n_cell_x" && line_i[1] == "=") + n_cell_x = std::min(string_to_unsigned_int(line_i[2]),max_resolution); + if (line_i[0] == "n_cell_y" && line_i[1] == "=") + n_cell_y = std::min(string_to_unsigned_int(line_i[2]),max_resolution); + if (line_i[0] == "n_cell_z" && line_i[1] == "=") + n_cell_z = std::min(string_to_unsigned_int(line_i[2]),max_resolution); + + } + + WBAssertThrow(dim == 2 || dim == 3, "dim should be set in the grid file and can only be 2 or 3."); + + WBAssertThrow(!std::isnan(x_min), "x_min is not a number:" << x_min << ". This value has probably not been provided in the grid file."); + WBAssertThrow(!std::isnan(x_max), "x_max is not a number:" << x_max << ". This value has probably not been provided in the grid file."); + WBAssertThrow(dim == 2 || !std::isnan(y_min), "y_min is not a number:" << y_min << ". This value has probably not been provided in the grid file."); + WBAssertThrow(dim == 2 || !std::isnan(y_max), "y_max is not a number:" << y_max << ". This value has probably not been provided in the grid file."); + WBAssertThrow(!std::isnan(z_min), "z_min is not a number:" << z_min << ". This value has probably not been provided in the grid file."); + WBAssertThrow(!std::isnan(z_max), "z_max is not a number:" << z_max << ". This value has probably not been provided in the grid file."); + + + WBAssertThrow(n_cell_x != 0, "n_cell_z may not be equal to zero: " << n_cell_x << '.'); + // int's cannot generally be nan's (see https://stackoverflow.com/questions/3949457/can-an-integer-be-nan-in-c), + // but visual studio is giving problems over this, so it is taken out for now. + //WBAssertThrow(!std::isnan(n_cell_x), "n_cell_z is not a number:" << n_cell_x << '.'); + + WBAssertThrow(dim == 3 || n_cell_z != 0, "In 3d n_cell_z may not be equal to zero: " << n_cell_y << '.'); + // int's cannot generally be nan's (see https://stackoverflow.com/questions/3949457/can-an-integer-be-nan-in-c), + // but visual studio is giving problems over this, so it is taken out for now. + //WBAssertThrow(!std::isnan(n_cell_z), "n_cell_z is not a number:" << n_cell_y << '.'); + + WBAssertThrow(n_cell_z != 0, "n_cell_z may not be equal to zero: " << n_cell_z << '.'); + // int's cannot generally be nan's (see https://stackoverflow.com/questions/3949457/can-an-integer-be-nan-in-c), + // but visual studio is giving problems over this, so it is taken out for now. + //WBAssertThrow(!std::isnan(n_cell_z), "n_cell_z is not a number:" << n_cell_z << '.'); + + + + + + /** + * All variables set by the user + */ + + if (grid_type == "sphere") + WBAssert(n_cell_x == n_cell_y, "For the sphere grid the amount of cells in the x (long) and y (lat) direction have to be the same."); + + if (grid_type == "spherical" || + grid_type == "chunk" || + grid_type == "annulus") + { + x_min *= (Consts::PI/180); + x_max *= (Consts::PI/180); + y_min *= (Consts::PI/180); + y_max *= (Consts::PI/180); + } + + + + /** + * All variables needed for the visualization + */ + size_t n_cell = NaN::ISNAN; + size_t n_p = NaN::ISNAN; + + std::vector grid_x(0); + std::vector grid_y(0); + std::vector grid_z(0); + std::vector grid_depth(0); + + std::vector > grid_connectivity(0); + + + const bool compress_size = true; + + + + + /** + * Begin making the grid + */ + std::cout << "[4/6] Building the grid... \r"; + std::cout.flush(); + WBAssertThrow(dim == 2 || dim == 3, "Dimension should be 2d or 3d."); + if (grid_type == "cartesian") + { + n_cell = n_cell_x * n_cell_z * (dim == 3 ? n_cell_y : 1); + if (!compress_size && dim == 3) + n_p = n_cell * 8 ; // it shouldn't matter for 2d in the output, so just do 3d. + else + n_p = (n_cell_x + 1) * (n_cell_z + 1) * (dim == 3 ? (n_cell_y + 1) : 1); + + + const double dx = (x_max - x_min) / static_cast(n_cell_x); + const double dy = dim == 2 ? 0 : (y_max - y_min) / static_cast(n_cell_y); + const double dz = (z_max - z_min) / static_cast(n_cell_z); + + + WBAssertThrow(!std::isnan(dx), "dz is not a number:" << dz << '.'); + WBAssertThrow(dim == 2 || !std::isnan(dy), "dz is not a number:" << dz << '.'); + WBAssertThrow(!std::isnan(dz), "dz is not a number:" << dz << '.'); + + // todo: determine whether a input variable is desirable for this. + const double surface = z_max; + + grid_x.resize(n_p); + grid_z.resize(n_p); + + if (dim == 3) + grid_y.resize(n_p); + + grid_depth.resize(n_p); + + // compute positions + size_t counter = 0; + if (dim == 2) + { + for (size_t j = 0; j <= n_cell_z; ++j) + { + for (size_t i = 0; i <= n_cell_x; ++i) + { + grid_x[counter] = x_min + static_cast(i) * dx; + grid_z[counter] = z_min + static_cast(j) * dz; + grid_depth[counter] = (surface - z_min) - static_cast(j) * dz; + counter++; + } + } + } + else + { + if (compress_size) + { + for (size_t i = 0; i <= n_cell_x; ++i) + { + for (size_t j = 0; j <= n_cell_y; ++j) + { + for (size_t k = 0; k <= n_cell_z; ++k) + { + grid_x[counter] = x_min + static_cast(i) * dx; + grid_y[counter] = y_min + static_cast(j) * dy; + grid_z[counter] = z_min + static_cast(k) * dz; + grid_depth[counter] = (surface - z_min) - static_cast(k) * dz; + counter++; + } + } + } + } + else + { + for (size_t i = 0; i < n_cell_x; ++i) + { + for (size_t j = 0; j < n_cell_y; ++j) + { + for (size_t k = 0; k < n_cell_z; ++k) + { + // position is defined by the vtk file format + // position 0 of this cell + grid_x[counter] = x_min + static_cast(i) * dx; + grid_y[counter] = y_min + static_cast(j) * dy; + grid_z[counter] = z_min + static_cast(k) * dz; + grid_depth[counter] = (surface - z_min) - static_cast(k) * dz; + counter++; + // position 1 of this cell + grid_x[counter] = x_min + (static_cast(i) + 1.0) * dx; + grid_y[counter] = y_min + static_cast(j) * dy; + grid_z[counter] = z_min + static_cast(k) * dz; + grid_depth[counter] = (surface - z_min) - static_cast(k) * dz; + counter++; + // position 2 of this cell + grid_x[counter] = x_min + (static_cast(i) + 1.0) * dx; + grid_y[counter] = y_min + (static_cast(j) + 1.0) * dy; + grid_z[counter] = z_min + static_cast(k) * dz; + grid_depth[counter] = (surface - z_min) - static_cast(k) * dz; + counter++; + // position 3 of this cell + grid_x[counter] = x_min + static_cast(i) * dx; + grid_y[counter] = y_min + (static_cast(j) + 1.0) * dy; + grid_z[counter] = z_min + static_cast(k) * dz; + grid_depth[counter] = (surface - z_min) - static_cast(k) * dz; + counter++; + // position 0 of this cell + grid_x[counter] = x_min + static_cast(i) * dx; + grid_y[counter] = y_min + static_cast(j) * dy; + grid_z[counter] = z_min + (static_cast(k) + 1.0) * dz; + grid_depth[counter] = (surface - z_min) - (static_cast(k) + 1.0) * dz; + counter++; + // position 1 of this cell + grid_x[counter] = x_min + (static_cast(i) + 1.0) * dx; + grid_y[counter] = y_min + static_cast(j) * dy; + grid_z[counter] = z_min + (static_cast(k) + 1.0) * dz; + grid_depth[counter] = (surface - z_min) - (static_cast(k) + 1.0) * dz; + counter++; + // position 2 of this cell + grid_x[counter] = x_min + (static_cast(i) + 1.0) * dx; + grid_y[counter] = y_min + (static_cast(j) + 1.0) * dy; + grid_z[counter] = z_min + (static_cast(k) + 1.0) * dz; + grid_depth[counter] = (surface - z_min) - (static_cast(k) + 1.0) * dz; + counter++; + // position 3 of this cell + grid_x[counter] = x_min + static_cast(i) * dx; + grid_y[counter] = y_min + (static_cast(j) + 1.0) * dy; + grid_z[counter] = z_min + (static_cast(k) + 1.0) * dz; + grid_depth[counter] = (surface - z_min) - (static_cast(k) + 1.0) * dz; + WBAssert(counter < n_p, "Assert counter smaller then n_P: counter = " << counter << ", n_p = " << n_p); + counter++; + } + } + } + } + } + + // compute connectivity. Local to global mapping. + grid_connectivity.resize(n_cell,std::vector((dim-1)*4)); + + counter = 0; + if (dim == 2) + { + for (size_t j = 1; j <= n_cell_z; ++j) + { + for (size_t i = 1; i <= n_cell_x; ++i) + { + grid_connectivity[counter][0] = i + (j - 1) * (n_cell_x + 1) - 1; + grid_connectivity[counter][1] = i + 1 + (j - 1) * (n_cell_x + 1) - 1; + grid_connectivity[counter][2] = i + 1 + j * (n_cell_x + 1) - 1; + grid_connectivity[counter][3] = i + j * (n_cell_x + 1) - 1; + counter++; + } + } + } + else + { + if (compress_size) + { + for (size_t i = 1; i <= n_cell_x; ++i) + { + for (size_t j = 1; j <= n_cell_y; ++j) + { + for (size_t k = 1; k <= n_cell_z; ++k) + { + grid_connectivity[counter][0] = (n_cell_y + 1) * (n_cell_z + 1) * (i - 1) + (n_cell_z + 1) * (j - 1) + k - 1; + grid_connectivity[counter][1] = (n_cell_y + 1) * (n_cell_z + 1) * (i ) + (n_cell_z + 1) * (j - 1) + k - 1; + grid_connectivity[counter][2] = (n_cell_y + 1) * (n_cell_z + 1) * (i ) + (n_cell_z + 1) * (j ) + k - 1; + grid_connectivity[counter][3] = (n_cell_y + 1) * (n_cell_z + 1) * (i - 1) + (n_cell_z + 1) * (j ) + k - 1; + grid_connectivity[counter][4] = (n_cell_y + 1) * (n_cell_z + 1) * (i - 1) + (n_cell_z + 1) * (j - 1) + k; + grid_connectivity[counter][5] = (n_cell_y + 1) * (n_cell_z + 1) * (i ) + (n_cell_z + 1) * (j - 1) + k; + grid_connectivity[counter][6] = (n_cell_y + 1) * (n_cell_z + 1) * (i ) + (n_cell_z + 1) * (j ) + k; + grid_connectivity[counter][7] = (n_cell_y + 1) * (n_cell_z + 1) * (i - 1) + (n_cell_z + 1) * (j ) + k; + counter++; + } + } + } + } + else + { + for (size_t i = 0; i < n_cell; ++i) + { + grid_connectivity[i][0] = counter; + grid_connectivity[i][1] = counter + 1; + grid_connectivity[i][2] = counter + 2; + grid_connectivity[i][3] = counter + 3; + grid_connectivity[i][4] = counter + 4; + grid_connectivity[i][5] = counter + 5; + grid_connectivity[i][6] = counter + 6; + grid_connectivity[i][7] = counter + 7; + counter = counter + 8; + } + } + } + } + else if (grid_type == "annulus") + { + /** + * An annulus which is a 2d hollow sphere. + * TODO: make it so you can determine your own cross section. + */ + WBAssertThrow(dim == 2, "The annulus only works in 2d."); + + + const double inner_radius = z_min; + const double outer_radius = z_max; + + const double l_outer = 2.0 * Consts::PI * outer_radius; + + const double lr = outer_radius - inner_radius; + const double dr = lr / static_cast(n_cell_z); + + const size_t n_cell_t = static_cast((2.0 * Consts::PI * outer_radius)/dr); + + // compute the amount of cells + n_cell = n_cell_t *n_cell_z; + n_p = n_cell_t *(n_cell_z + 1); // one less then cartesian because two cells overlap. + + const double sx = l_outer / static_cast(n_cell_t); + const double sz = dr; + + grid_x.resize(n_p); + grid_z.resize(n_p); + grid_depth.resize(n_p); + + size_t counter = 0; + for (size_t j = 0; j <= n_cell_z; ++j) + { + for (size_t i = 1; i <= n_cell_t; ++i) + { + grid_x[counter] = (static_cast(i) - 1.0) * sx; + grid_z[counter] = static_cast(j) * sz; + counter++; + } + } + + counter = 0; + for (size_t j = 1; j <= n_cell_z+1; ++j) + { + for (size_t i = 1; i <= n_cell_t; ++i) + { + const double xi = grid_x[counter]; + const double zi = grid_z[counter]; + const double theta = xi / l_outer * 2.0 * Consts::PI; + grid_x[counter] = std::cos(theta) * (inner_radius + zi); + grid_z[counter] = std::sin(theta) * (inner_radius + zi); + grid_depth[counter] = outer_radius - std::sqrt(grid_x[counter] * grid_x[counter] + grid_z[counter] * grid_z [counter]); + grid_depth[counter] = (std::fabs(grid_depth[counter]) < 1e-8 ? 0 : grid_depth[counter]); + counter++; + } + } + + grid_connectivity.resize(n_cell,std::vector(4)); + counter = 0; + for (size_t j = 1; j <= n_cell_z; ++j) + { + for (size_t i = 1; i <= n_cell_t; ++i) + { + std::vector cell_connectivity(4); + cell_connectivity[0] = counter + 1; + cell_connectivity[1] = counter + 1 + 1; + cell_connectivity[2] = i + j * n_cell_t + 1; + cell_connectivity[3] = i + j * n_cell_t; + if (i == n_cell_t) + { + cell_connectivity[1] = cell_connectivity[1] - n_cell_t; + cell_connectivity[2] = cell_connectivity[2] - n_cell_t; + } + grid_connectivity[counter][0] = cell_connectivity[1] - 1; + grid_connectivity[counter][1] = cell_connectivity[0] - 1; + grid_connectivity[counter][2] = cell_connectivity[3] - 1; + grid_connectivity[counter][3] = cell_connectivity[2] - 1; + counter++; + } + } + } + else if (grid_type == "chunk") + { + const double inner_radius = z_min; + const double outer_radius = z_max; + + WBAssertThrow(x_min <= x_max, "The minimum longitude must be less than the maximum longitude."); + WBAssertThrow(y_min <= y_max, "The minimum latitude must be less than the maximum latitude."); + WBAssertThrow(inner_radius < outer_radius, "The inner radius must be less than the outer radius."); + + WBAssertThrow(x_min - x_max <= 2.0 * Consts::PI, "The difference between the minimum and maximum longitude " + " must be less than or equal to 360 degree."); + + WBAssertThrow(y_min >= - 0.5 * Consts::PI, "The minimum latitude must be larger then or equal to -90 degree."); + WBAssertThrow(y_min <= 0.5 * Consts::PI, "The maximum latitude must be smaller then or equal to 90 degree."); + + const double opening_angle_long_rad = (x_max - x_min); + const double opening_angle_lat_rad = (y_max - y_min); + + n_cell = n_cell_x * n_cell_z * (dim == 3 ? n_cell_y : 1); + if (!compress_size && dim == 3) + n_p = n_cell * 8 ; // it shouldn't matter for 2d in the output, so just do 3d. + else + n_p = (n_cell_x + 1) * (n_cell_z + 1) * (dim == 3 ? (n_cell_y + 1) : 1); + + const double dlong = opening_angle_long_rad / static_cast(n_cell_x); + const double dlat = dim == 3 ? opening_angle_lat_rad / static_cast(n_cell_y) : 0.; + const double lr = outer_radius - inner_radius; + const double dr = lr / static_cast(n_cell_z); + + grid_x.resize(n_p); + grid_y.resize(dim == 3 ? n_p : 0); + grid_z.resize(n_p); + grid_depth.resize(n_p); + + std::cout << "[4/6] Building the grid: stage 1 of 3 \r"; + std::cout.flush(); + size_t counter = 0; + if (dim == 2) + { + for (size_t i = 1; i <= n_cell_x + 1; ++i) + for (size_t j = 1; j <= n_cell_z + 1; ++j) + { + grid_x[counter] = x_min + (static_cast(i) - 1.0) * dlong; + grid_z[counter] = inner_radius + (static_cast(j) - 1.0) * dr; + grid_depth[counter] = lr - (static_cast(j) - 1.0) * dr; + counter++; + } + } + else + { + if (compress_size) + { + for (size_t i = 1; i <= n_cell_x + 1; ++i) + for (size_t j = 1; j <= n_cell_y + 1; ++j) + for (size_t k = 1; k <= n_cell_z + 1; ++k) + { + grid_x[counter] = x_min + (static_cast(i) - 1.0) * dlong; + grid_y[counter] = y_min + (static_cast(j) - 1.0) * dlat; + grid_z[counter] = inner_radius + (static_cast(k) - 1.0) * dr; + grid_depth[counter] = lr - (static_cast(k) - 1.0) * dr; + counter++; + } + } + else + { + for (size_t i = 0; i < n_cell_x; ++i) + { + for (size_t j = 0; j < n_cell_y; ++j) + { + for (size_t k = 0; k < n_cell_z; ++k) + { + // position is defined by the vtk file format + // position 0 of this cell + grid_x[counter] = x_min + static_cast(i) * dlong; + grid_y[counter] = y_min + static_cast(j) * dlat; + grid_z[counter] = inner_radius + static_cast(k) * dr; + grid_depth[counter] = lr - static_cast(k) * dr; + counter++; + // position 1 of this cell + grid_x[counter] = x_min + (static_cast(i) + 1.0) * dlong; + grid_y[counter] = y_min + static_cast(j) * dlat; + grid_z[counter] = inner_radius + static_cast(k) * dr; + grid_depth[counter] = lr - static_cast(k) * dr; + counter++; + // position 2 of this cell + grid_x[counter] = x_min + (static_cast(i) + 1.0) * dlong; + grid_y[counter] = y_min + (static_cast(j) + 1.0) * dlat; + grid_z[counter] = inner_radius + static_cast(k) * dr; + grid_depth[counter] = lr - static_cast(k) * dr; + counter++; + // position 3 of this cell + grid_x[counter] = x_min + static_cast(i) * dlong; + grid_y[counter] = y_min + (static_cast(j) + 1.0) * dlat; + grid_z[counter] = inner_radius + static_cast(k) * dr; + grid_depth[counter] = lr - static_cast(k) * dr; + counter++; + // position 0 of this cell + grid_x[counter] = x_min + static_cast(i) * dlong; + grid_y[counter] = y_min + static_cast(j) * dlat; + grid_z[counter] = inner_radius + (static_cast(k) + 1.0) * dr; + grid_depth[counter] = lr - (static_cast(k) + 1.0) * dr; + counter++; + // position 1 of this cell + grid_x[counter] = x_min + (static_cast(i) + 1.0) * dlong; + grid_y[counter] = y_min + static_cast(j) * dlat; + grid_z[counter] = inner_radius + (static_cast(k) + 1.0) * dr; + grid_depth[counter] = lr - (static_cast(k) + 1.0) * dr; + counter++; + // position 2 of this cell + grid_x[counter] = x_min + (static_cast(i) + 1.0) * dlong; + grid_y[counter] = y_min + (static_cast(j) + 1.0) * dlat; + grid_z[counter] = inner_radius + (static_cast(k) + 1.0) * dr; + grid_depth[counter] = lr - (static_cast(k) + 1.0) * dr; + counter++; + // position 3 of this cell + grid_x[counter] = x_min + static_cast(i) * dlong; + grid_y[counter] = y_min + (static_cast(j) + 1.0) * dlat; + grid_z[counter] = inner_radius + (static_cast(k) + 1.0) * dr; + grid_depth[counter] = lr - (static_cast(k) + 1.0) * dr; + WBAssert(counter < n_p, "Assert counter smaller then n_P: counter = " << counter << ", n_p = " << n_p); + counter++; + } + } + } + } + } + + std::cout << "[4/6] Building the grid: stage 2 of 3 \r"; + std::cout.flush(); + if (dim == 2) + { + for (size_t i = 0; i < n_p; ++i) + { + + const double longitude = grid_x[i]; + const double radius = grid_z[i]; + + grid_x[i] = radius * std::cos(longitude); + grid_z[i] = radius * std::sin(longitude); + } + } + else + { + for (size_t i = 0; i < n_p; ++i) + { + + const double longitude = grid_x[i]; + const double latitutde = grid_y[i]; + const double radius = grid_z[i]; + + grid_x[i] = radius * std::cos(latitutde) * std::cos(longitude); + grid_y[i] = radius * std::cos(latitutde) * std::sin(longitude); + grid_z[i] = radius * std::sin(latitutde); + } + } + std::cout << "[4/6] Building the grid: stage 3 of 3 \r"; + std::cout.flush(); + // compute connectivity. Local to global mapping. + grid_connectivity.resize(n_cell,std::vector((dim-1)*4)); + + counter = 0; + if (dim == 2) + { + for (size_t i = 1; i <= n_cell_x; ++i) + { + for (size_t j = 1; j <= n_cell_z; ++j) + { + grid_connectivity[counter][0] = (n_cell_z + 1) * (i - 1) + j - 1; + grid_connectivity[counter][1] = (n_cell_z + 1) * (i - 1) + j; + grid_connectivity[counter][2] = (n_cell_z + 1) * (i ) + j; + grid_connectivity[counter][3] = (n_cell_z + 1) * (i ) + j - 1; + + counter = counter+1; + std::cout << "[4/6] Building the grid: stage 3 of 3 [" << (static_cast(i)/static_cast(n_cell))*100.0 << "%] \r"; + std::cout.flush(); + } + } + } + else + { + if (compress_size) + { + for (size_t i = 1; i <= n_cell_x; ++i) + { + for (size_t j = 1; j <= n_cell_y; ++j) + { + for (size_t k = 1; k <= n_cell_z; ++k) + { + grid_connectivity[counter][0] = (n_cell_y + 1) * (n_cell_z + 1) * (i - 1) + (n_cell_z + 1) * (j - 1) + k - 1; + grid_connectivity[counter][1] = (n_cell_y + 1) * (n_cell_z + 1) * (i ) + (n_cell_z + 1) * (j - 1) + k - 1; + grid_connectivity[counter][2] = (n_cell_y + 1) * (n_cell_z + 1) * (i ) + (n_cell_z + 1) * (j ) + k - 1; + grid_connectivity[counter][3] = (n_cell_y + 1) * (n_cell_z + 1) * (i - 1) + (n_cell_z + 1) * (j ) + k - 1; + grid_connectivity[counter][4] = (n_cell_y + 1) * (n_cell_z + 1) * (i - 1) + (n_cell_z + 1) * (j - 1) + k; + grid_connectivity[counter][5] = (n_cell_y + 1) * (n_cell_z + 1) * (i ) + (n_cell_z + 1) * (j - 1) + k; + grid_connectivity[counter][6] = (n_cell_y + 1) * (n_cell_z + 1) * (i ) + (n_cell_z + 1) * (j ) + k; + grid_connectivity[counter][7] = (n_cell_y + 1) * (n_cell_z + 1) * (i - 1) + (n_cell_z + 1) * (j ) + k; + counter++; + } + } + } + } + else + { + for (size_t i = 0; i < n_cell; ++i) + { + grid_connectivity[i][0] = counter; + grid_connectivity[i][1] = counter + 1; + grid_connectivity[i][2] = counter + 2; + grid_connectivity[i][3] = counter + 3; + grid_connectivity[i][4] = counter + 4; + grid_connectivity[i][5] = counter + 5; + grid_connectivity[i][6] = counter + 6; + grid_connectivity[i][7] = counter + 7; + counter = counter + 8; + std::cout << "[4/6] Building the grid: stage 3 of 3 [" << (static_cast(i)/static_cast(n_cell))*100.0 << "%] \r"; + std::cout.flush(); + } + } + } + } + else if (grid_type == "sphere") + { + + WBAssertThrow(dim == 3, "The sphere only works in 3d."); + + + const double inner_radius = z_min; + const double outer_radius = z_max; + + const size_t n_block = 12; + + const size_t block_n_cell = n_cell_x*n_cell_x; + const size_t block_n_p = (n_cell_x + 1) * (n_cell_x + 1); + const size_t block_n_v = 4; + + + std::vector > block_grid_x(n_block,std::vector(block_n_p)); + std::vector > block_grid_y(n_block,std::vector(block_n_p)); + std::vector > block_grid_z(n_block,std::vector(block_n_p)); + std::vector > > block_grid_connectivity(n_block,std::vector >(block_n_cell,std::vector(block_n_v))); + std::vector > block_grid_hull(n_block,std::vector(block_n_p)); + + /** + * block node layout + */ + for (size_t i_block = 0; i_block < n_block; ++i_block) + { + const size_t block_n_cell_x = n_cell_x; + const size_t block_n_cell_y = n_cell_x; + const double Lx = 1.0; + const double Ly = 1.0; + + size_t counter = 0; + for (size_t j = 0; j <= block_n_cell_y; ++j) + { + for (size_t i = 0; i <= block_n_cell_y; ++i) + { + block_grid_x[i_block][counter] = static_cast(i) * Lx / static_cast(block_n_cell_x); + block_grid_y[i_block][counter] = static_cast(j) * Ly / static_cast(block_n_cell_y); + block_grid_z[i_block][counter] = 0.0; + counter++; + } + } + + counter = 0; + // using i=1 and j=1 here because i an j are not used in lookup and storage + // so the code can remain very similar to ghost and the cartesian code. + for (size_t j = 1; j <= block_n_cell_y; ++j) + { + for (size_t i = 1; i <= block_n_cell_x; ++i) + { + block_grid_connectivity[i_block][counter][0] = i + (j - 1) * (block_n_cell_x + 1) - 1; + block_grid_connectivity[i_block][counter][1] = i + 1 + (j - 1) * (block_n_cell_x + 1) - 1; + block_grid_connectivity[i_block][counter][2] = i + 1 + j * (block_n_cell_x + 1) - 1; + block_grid_connectivity[i_block][counter][3] = i + j * (block_n_cell_x + 1) - 1; + counter++; + } + } + } + + /** + * map blocks + */ + double radius = 1; + + // four corners + double xA = -1.0; + double yA = 0.0; + double zA = -1.0 / std::sqrt(2.0); + + double xB = 1.0; + double yB = 0.0; + double zB = -1.0 / std::sqrt(2.0); + + double xC = 0.0; + double yC = -1.0; + double zC = 1.0 / std::sqrt(2.0); + + double xD = 0.0; + double yD = 1.0; + double zD = 1.0 / std::sqrt(2.0); + + // middles of faces + double xM = (xA+xB+xC)/3.0; + double yM = (yA+yB+yC)/3.0; + double zM = (zA+zB+zC)/3.0; + + double xN = (xA+xD+xC)/3.0; + double yN = (yA+yD+yC)/3.0; + double zN = (zA+zD+zC)/3.0; + + double xP = (xA+xD+xB)/3.0; + double yP = (yA+yD+yB)/3.0; + double zP = (zA+zD+zB)/3.0; + + double xQ = (xC+xD+xB)/3.0; + double yQ = (yC+yD+yB)/3.0; + double zQ = (zC+zD+zB)/3.0; + + // middle of edges + double xF = (xB+xC)/2.0; + double yF = (yB+yC)/2.0; + double zF = (zB+zC)/2.0; + + double xG = (xA+xC)/2.0; + double yG = (yA+yC)/2.0; + double zG = (zA+zC)/2.0; + + double xE = (xB+xA)/2.0; + double yE = (yB+yA)/2.0; + double zE = (zB+zA)/2.0; + + double xH = (xD+xC)/2.0; + double yH = (yD+yC)/2.0; + double zH = (zD+zC)/2.0; + + double xJ = (xD+xA)/2.0; + double yJ = (yD+yA)/2.0; + double zJ = (zD+zA)/2.0; + + double xK = (xD+xB)/2.0; + double yK = (yD+yB)/2.0; + double zK = (zD+zB)/2.0; + + // Making sure points A..Q are on a sphere + project_on_sphere(radius,xA,yA,zA); + project_on_sphere(radius,xB,yB,zB); + project_on_sphere(radius,xC,yC,zC); + project_on_sphere(radius,xD,yD,zD); + project_on_sphere(radius,xE,yE,zE); + project_on_sphere(radius,xF,yF,zF); + project_on_sphere(radius,xG,yG,zG); + project_on_sphere(radius,xH,yH,zH); + project_on_sphere(radius,xJ,yJ,zJ); + project_on_sphere(radius,xK,yK,zK); + project_on_sphere(radius,xM,yM,zM); + project_on_sphere(radius,xN,yN,zN); + project_on_sphere(radius,xP,yP,zP); + project_on_sphere(radius,xQ,yQ,zQ); + + lay_points(xM,yM,zM,xG,yG,zG,xA,yA,zA,xE,yE,zE,block_grid_x[0], block_grid_y[0], block_grid_z[0],block_grid_hull[0], n_cell_x); + lay_points(xF,yF,zF,xM,yM,zM,xE,yE,zE,xB,yB,zB,block_grid_x[1], block_grid_y[1], block_grid_z[1],block_grid_hull[1], n_cell_x); + lay_points(xC,yC,zC,xG,yG,zG,xM,yM,zM,xF,yF,zF,block_grid_x[2], block_grid_y[2], block_grid_z[2],block_grid_hull[2], n_cell_x); + lay_points(xG,yG,zG,xN,yN,zN,xJ,yJ,zJ,xA,yA,zA,block_grid_x[3], block_grid_y[3], block_grid_z[3],block_grid_hull[3], n_cell_x); + lay_points(xC,yC,zC,xH,yH,zH,xN,yN,zN,xG,yG,zG,block_grid_x[4], block_grid_y[4], block_grid_z[4],block_grid_hull[4], n_cell_x); + lay_points(xH,yH,zH,xD,yD,zD,xJ,yJ,zJ,xN,yN,zN,block_grid_x[5], block_grid_y[5], block_grid_z[5],block_grid_hull[5], n_cell_x); + lay_points(xA,yA,zA,xJ,yJ,zJ,xP,yP,zP,xE,yE,zE,block_grid_x[6], block_grid_y[6], block_grid_z[6],block_grid_hull[6], n_cell_x); + lay_points(xJ,yJ,zJ,xD,yD,zD,xK,yK,zK,xP,yP,zP,block_grid_x[7], block_grid_y[7], block_grid_z[7],block_grid_hull[7], n_cell_x); + lay_points(xP,yP,zP,xK,yK,zK,xB,yB,zB,xE,yE,zE,block_grid_x[8], block_grid_y[8], block_grid_z[8],block_grid_hull[8], n_cell_x); + lay_points(xQ,yQ,zQ,xK,yK,zK,xD,yD,zD,xH,yH,zH,block_grid_x[9], block_grid_y[9], block_grid_z[9],block_grid_hull[9], n_cell_x); + lay_points(xQ,yQ,zQ,xH,yH,zH,xC,yC,zC,xF,yF,zF,block_grid_x[10], block_grid_y[10], block_grid_z[10],block_grid_hull[10], n_cell_x); + lay_points(xQ,yQ,zQ,xF,yF,zF,xB,yB,zB,xK,yK,zK,block_grid_x[11], block_grid_y[11], block_grid_z[11],block_grid_hull[11], n_cell_x); + + // make sure all points end up on a sphere + for (size_t i_block = 0; i_block < n_block; ++i_block) + { + for (size_t i_point = 0; i_point < block_n_p; ++i_point) + { + project_on_sphere(radius,block_grid_x[i_block][i_point],block_grid_y[i_block][i_point],block_grid_z[i_block][i_point]); + } + } + + /** + * merge blocks + */ + std::vector temp_x(n_block * block_n_p); + std::vector temp_y(n_block * block_n_p); + std::vector temp_z(n_block * block_n_p); + std::vector sides(n_block * block_n_p); + + for (size_t i = 0; i < n_block; ++i) + { + size_t counter = 0; + for (size_t j = i * block_n_p; j < i * block_n_p + block_n_p; ++j) + { + WBAssert(j < temp_x.size(), "j should be smaller then the size of the array temp_x."); + WBAssert(j < temp_y.size(), "j should be smaller then the size of the array temp_y."); + WBAssert(j < temp_z.size(), "j should be smaller then the size of the array temp_z."); + temp_x[j] = block_grid_x[i][counter]; + temp_y[j] = block_grid_y[i][counter]; + temp_z[j] = block_grid_z[i][counter]; + sides[j] = block_grid_hull[i][counter]; + counter++; + } + } + + + std::vector double_points(n_block * block_n_p,false); + std::vector point_to(n_block * block_n_p); + + for (size_t i = 0; i < n_block * block_n_p; ++i) + point_to[i] = i; + + // TODO: This becomes problematic with too large values of outer radius. Find a better way, maybe through an epsilon. + const double distance = 1e-12*outer_radius; + + size_t counter = 0; + size_t amount_of_double_points = 0; + for (size_t i = 1; i < n_block * block_n_p; ++i) + { + if (sides[i]) + { + const double gxip = temp_x[i]; + const double gyip = temp_y[i]; + const double gzip = temp_z[i]; + for (size_t j = 0; j < i-1; ++j) + { + if (sides[j]) + { + if (std::fabs(gxip-temp_x[j]) < distance && + std::fabs(gyip-temp_y[j]) < distance && + std::fabs(gzip-temp_z[j]) < distance) + { + double_points[i] = true; + point_to[i] = j; + amount_of_double_points++; + break; + } + } + } + } + } + + + const size_t shell_n_p = n_block * block_n_p - amount_of_double_points; + const size_t shell_n_cell = n_block * block_n_cell; + const size_t shell_n_v = block_n_v; + + std::vector shell_grid_x(shell_n_p); + std::vector shell_grid_y(shell_n_p); + std::vector shell_grid_z(shell_n_p); + std::vector > shell_grid_connectivity(shell_n_cell,std::vector(shell_n_v)); + + counter = 0; + for (size_t i = 0; i < n_block * block_n_p; ++i) + { + if (!double_points[i]) + { + shell_grid_x[counter] = fabs(temp_x[i]) < 1e-8 ? 0. : temp_x[i]; + shell_grid_y[counter] = fabs(temp_y[i]) < 1e-8 ? 0. : temp_y[i]; + shell_grid_z[counter] = fabs(temp_z[i]) < 1e-8 ? 0. : temp_z[i]; + + counter++; + } + } + + for (size_t i = 0; i < n_block; ++i) + { + counter = 0; + for (size_t j = i * block_n_cell; j < i * block_n_cell + block_n_cell; ++j) + { + for (size_t k = 0; k < shell_n_v; ++k) + { + shell_grid_connectivity[j][k] = block_grid_connectivity[i][counter][k] + i * block_n_p; + } + counter++; + } + } + + for (size_t i = 0; i < shell_n_cell; ++i) + { + for (size_t j = 0; j < shell_n_v; ++j) + { + shell_grid_connectivity[i][j] = point_to[shell_grid_connectivity[i][j]]; + } + } + + std::vector compact(n_block * block_n_p); + + counter = 0; + for (size_t i = 0; i < n_block * block_n_p; ++i) + { + if (!double_points[i]) + { + compact[i] = counter; + counter++; + } + } + + + for (size_t i = 0; i < shell_n_cell; ++i) + { + for (size_t j = 0; j < shell_n_v; ++j) + { + shell_grid_connectivity[i][j] = compact[shell_grid_connectivity[i][j]]; + } + } + + + /** + * build hollow sphere + */ + + std::vector temp_shell_grid_x(shell_n_p); + std::vector temp_shell_grid_y(shell_n_p); + std::vector temp_shell_grid_z(shell_n_p); + + const size_t n_v = shell_n_v * 2; + n_p = (n_cell_z + 1) * shell_n_p; + n_cell = (n_cell_z) * shell_n_cell; + + grid_x.resize(n_p); + grid_y.resize(n_p); + grid_z.resize(n_p); + grid_depth.resize(n_p); + grid_connectivity.resize(n_cell,std::vector(n_v)); + + + for (size_t i = 0; i < n_cell_z + 1; ++i) + { + temp_shell_grid_x = shell_grid_x; + temp_shell_grid_y = shell_grid_y; + temp_shell_grid_z = shell_grid_z; + + // We do not need to copy the shell_grid_connectivity into a + // temperorary variable, because we do not change it. We can + // directly use it. + + radius = inner_radius + ((outer_radius - inner_radius) / static_cast(n_cell_z)) * static_cast(i); + for (size_t j = 0; j < shell_n_p; ++j) + { + WBAssert(j < temp_shell_grid_x.size(), "ERROR: j = " << j << ", temp_shell_grid_x.size() = " << temp_shell_grid_x.size()); + WBAssert(j < temp_shell_grid_y.size(), "ERROR: j = " << j << ", temp_shell_grid_y.size() = " << temp_shell_grid_y.size()); + WBAssert(j < temp_shell_grid_z.size(), "ERROR: j = " << j << ", temp_shell_grid_z.size() = " << temp_shell_grid_z.size()); + project_on_sphere(radius, temp_shell_grid_x[j], temp_shell_grid_y[j], temp_shell_grid_z[j]); + } + + const size_t i_beg = i * shell_n_p; + const size_t i_end = (i+1) * shell_n_p; + counter = 0; + for (size_t j = i_beg; j < i_end; ++j) + { + WBAssert(j < grid_x.size(), "ERROR: j = " << j << ", grid_x.size() = " << grid_x.size()); + WBAssert(j < grid_y.size(), "ERROR: j = " << j << ", grid_y.size() = " << grid_y.size()); + WBAssert(j < grid_z.size(), "ERROR: j = " << j << ", grid_z.size() = " << grid_z.size()); + grid_x[j] = temp_shell_grid_x[counter]; + grid_y[j] = temp_shell_grid_y[counter]; + grid_z[j] = temp_shell_grid_z[counter]; + grid_depth[j] = outer_radius - std::sqrt(grid_x[j] * grid_x[j] + grid_y[j] * grid_y[j] + grid_z[j] * grid_z[j]); + grid_depth[j] = (std::fabs(grid_depth[j]) < 1e-8 ? 0 : grid_depth[j]); + + counter++; + } + } + + for (size_t i = 0; i < n_cell_z; ++i) + { + const size_t i_beg = i * shell_n_cell; + const size_t i_end = (i+1) * shell_n_cell; + counter = 0; + for (size_t j = i_beg; j < i_end; ++j) + { + for (size_t k = 0; k < shell_n_v; ++k) + { + grid_connectivity[j][k] = shell_grid_connectivity[counter][k] + i * shell_n_p; + } + counter++; + } + + + counter = 0; + for (size_t j = i_beg; j < i_end; ++j) + { + for (size_t k = shell_n_v ; k < 2 * shell_n_v; ++k) + { + WBAssert(k-shell_n_v < shell_grid_connectivity[counter].size(), "k - shell_n_v is larger then shell_grid_connectivity[counter]: k= " << k << ", shell_grid_connectivity[counter].size() = " << shell_grid_connectivity[counter].size()); + grid_connectivity[j][k] = shell_grid_connectivity[counter][k-shell_n_v] + (i+1) * shell_n_p; + } + counter++; + } + } + } + else + { + WBAssertThrow(false, "Geometry type '" << grid_type << "' is not a valid geometry type. Valid geometry types are: " + << "'cartesian', 'annulus', 'chunk' and 'sphere'. " + << "Please note that the annulus can only be used in 2d and the sphere can only be used in 3d."); + } + + // create paraview file. + std::cout << "[5/6] Preparing to write the paraview file... \r"; + std::cout.flush(); + + const std::string base_filename = wb_file.substr(wb_file.find_last_of("/\\") + 1); + std::string::size_type const p(base_filename.find_last_of('.')); + const std::string file_without_extension = base_filename.substr(0, p); + + const std::stringstream buffer; + const std::ofstream myfile; + + std::cout << "[5/6] Preparing to write the paraview file: stage 1 of 6, converting the points \r"; + std::cout.flush(); + std::vector points(grid_x.size()*3, 0.0); + if (dim == 2) + for (size_t i = 0; i < n_p; ++i) + { + points[i*3] = grid_x[i]; + points[i*3+1] = grid_z[i]; + // third one is zero + } + else + { + for (size_t i = 0; i < n_p; ++i) + { + points[i*3] = grid_x[i]; + points[i*3+1] = grid_y[i]; + points[i*3+2] = grid_z[i]; + } + } + std::cout << "[5/6] Preparing to write the paraview file: stage 2 of 6, converting the connectivity \r"; + std::cout.flush(); + const size_t pow_2_dim = dim == 2 ? 4 : 8; + std::vector connectivity(n_cell*pow_2_dim); + if (dim == 2) + for (size_t i = 0; i < n_cell; ++i) + { + connectivity[i*pow_2_dim] = static_cast(grid_connectivity[i][0]); + connectivity[i*pow_2_dim+1] = static_cast(grid_connectivity[i][1]); + connectivity[i*pow_2_dim+2] = static_cast(grid_connectivity[i][2]); + connectivity[i*pow_2_dim+3] = static_cast(grid_connectivity[i][3]); + } + else + for (size_t i = 0; i < n_cell; ++i) + { + + connectivity[i*pow_2_dim] = static_cast(grid_connectivity[i][0]); + connectivity[i*pow_2_dim+1] = static_cast(grid_connectivity[i][1]); + connectivity[i*pow_2_dim+2] = static_cast(grid_connectivity[i][2]); + connectivity[i*pow_2_dim+3] = static_cast(grid_connectivity[i][3]); + connectivity[i*pow_2_dim+4] = static_cast(grid_connectivity[i][4]); + connectivity[i*pow_2_dim+5] = static_cast(grid_connectivity[i][5]); + connectivity[i*pow_2_dim+6] = static_cast(grid_connectivity[i][6]); + connectivity[i*pow_2_dim+7] = static_cast(grid_connectivity[i][7]); + } + std::cout << "[5/6] Preparing to write the paraview file: stage 3 of 6, creating the offsets \r"; + std::cout.flush(); + std::vector offsets(n_cell); + if (dim == 2) + for (size_t i = 0; i < n_cell; ++i) + offsets[i] = static_cast((i+1) * 4); + else + for (size_t i = 0; i < n_cell; ++i) + offsets[i] = static_cast((i+1) * 8); + + std::cout << "[5/6] Preparing to write the paraview file: stage 4 of 6, creating the Data set info \r"; + std::cout.flush(); + std::vector types(n_cell, dim == 2 ? 9 : 12); + + // Create tuples with (name, association, number of components) for each data set + std::vector dataSetInfo + { + { "Depth", vtu11::DataSetType::PointData, 1 }, + { "Temperature", vtu11::DataSetType::PointData, 1 }, + { "Tag", vtu11::DataSetType::PointData, 1 }, + }; + for (size_t c = 0; c < compositions; ++c) + { + dataSetInfo.emplace_back( "Composition "+std::to_string(c), vtu11::DataSetType::PointData, 1 ); + } + + std::cout << "[5/6] Preparing to write the paraview file: stage 5 of 5, computing the properties \r"; + std::cout.flush(); + + std::vector> properties; + properties.push_back({{1,0,0}}); // temperature + + properties.push_back({{4,0,0}}); // tag + + for (unsigned int c = 0; c < compositions; ++c) + properties.push_back({{2,c,0}}); // composition c + + + // compute temperature + std::vector data_set(3+compositions); + data_set[0] = grid_depth; + data_set[1].resize(n_p); + data_set[2].resize(n_p); + for (size_t c = 0; c < compositions; ++c) + data_set[3+c].resize(n_p); + + if (dim == 2) + { + pool.parallel_for(0, n_p, [&] (size_t i) + { + const std::array coords = {{grid_x[i], grid_z[i]}}; + std::vector output = world->properties(coords, grid_depth[i],properties); + data_set[1][i] = output[0]; + data_set[2][i] = output[1]; + for (size_t c = 0; c < compositions; ++c) + { + data_set[3+c][i] = output[2+c]; + } + }); + } + else + { + pool.parallel_for(0, n_p, [&] (size_t i) + { + const std::array coords = {{grid_x[i], grid_y[i], grid_z[i]}}; + std::vector output = world->properties(coords, grid_depth[i],properties); + data_set[1][i] = output[0]; + data_set[2][i] = output[1]; + for (size_t c = 0; c < compositions; ++c) + { + data_set[3+c][i] = output[2+c]; + } + }); + } + std::cout << "[6/6] Writing the paraview file \r"; + std::cout.flush(); + + { + vtu11::Vtu11UnstructuredMesh mesh { points, connectivity, offsets, types }; + vtu11::writeVtu( file_without_extension + ".vtu", mesh, dataSetInfo, data_set, vtu_output_format ); + + if (output_filtered) + { + std::vector include_tag(world->feature_tags.size(), true); + for (unsigned int idx = 0; idxfeature_tags[idx]=="mantle layer") + include_tag[idx] = false; + } + std::vector filtered_points; + std::vector filtered_connectivity; + std::vector filtered_offsets; + std::vector filtered_types; + + vtu11::Vtu11UnstructuredMesh filtered_mesh {filtered_points, filtered_connectivity, filtered_offsets, filtered_types}; + std::vector filtered_data_set; + + filter_vtu_mesh(static_cast(dim), include_tag, mesh, data_set, filtered_mesh, filtered_data_set); + vtu11::writeVtu( file_without_extension + ".filtered.vtu", filtered_mesh, dataSetInfo, filtered_data_set, vtu_output_format ); + } + + if (output_by_tag) + { + for (unsigned int idx = 0; idxfeature_tags.size(); ++idx) + { + if (world->feature_tags[idx]=="mantle layer") + continue; + + std::vector filtered_points; + std::vector filtered_connectivity; + std::vector filtered_offsets; + std::vector filtered_types; + + vtu11::Vtu11UnstructuredMesh filtered_mesh {filtered_points, filtered_connectivity, filtered_offsets, filtered_types}; + std::vector filtered_data_set; + + std::vector include_tag(world->feature_tags.size(), false); + include_tag[idx]=true; + filter_vtu_mesh(static_cast(dim), include_tag, mesh, data_set, filtered_mesh, filtered_data_set); + const std::string filename = file_without_extension + "."+ std::to_string(idx)+".vtu"; + vtu11::writeVtu( filename, filtered_mesh, dataSetInfo, filtered_data_set, vtu_output_format ); + } + } + } + std::cout << " \r"; + std::cout.flush(); + } + +#ifdef WB_WITH_MPI + MPI_Finalize(); +#endif + return 0; +} diff --git a/contrib/world_builder/source/world_builder/coordinate_systems/cartesian.cc.bak b/contrib/world_builder/source/world_builder/coordinate_systems/cartesian.cc.bak new file mode 100644 index 00000000000..a6222ae9161 --- /dev/null +++ b/contrib/world_builder/source/world_builder/coordinate_systems/cartesian.cc.bak @@ -0,0 +1,103 @@ +/* + 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/coordinate_systems/cartesian.h" +#include "world_builder/types/object.h" + + +namespace WorldBuilder +{ + namespace CoordinateSystems + { + Cartesian::Cartesian(WorldBuilder::World *world_) + { + this->world = world_; + } + + Cartesian::~Cartesian() + = default; + + void + Cartesian::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + prm.declare_entry("", Types::Object(), + "A Cartesian coordinate system. Coordinates are (x,y,z) and extend infinitely in all directions."); + } + + void + Cartesian::parse_entries(Parameters & /*prm*/) + {} + + + CoordinateSystem + Cartesian::natural_coordinate_system() const + { + return CoordinateSystem::cartesian; + } + + + DepthMethod + Cartesian::depth_method() const + { + return DepthMethod::none; + } + + + std::array + Cartesian::cartesian_to_natural_coordinates(const std::array &position) const + { + return position; + } + + + std::array + Cartesian::natural_to_cartesian_coordinates(const std::array &position) const + { + return position; + } + + + double + Cartesian::distance_between_points_at_same_depth(const Point<3> &point_1, const Point<3> &point_2) const + { + WBAssert(point_1.get_coordinate_system() == cartesian, + "Can not convert non-Cartesian points through the Cartesian coordinate system."); + WBAssert(point_2.get_coordinate_system() == cartesian, + "Can not convert non-Cartesian points through the Cartesian coordinate system."); + // Todo: check that points are at the same depth. + const Point<3> difference = point_1-point_2; + const Point<2> point_at_depth(difference[0],difference[1], cartesian); + + return point_at_depth.norm(); + } + + + double + Cartesian::max_model_depth() const + { + return std::numeric_limits::infinity(); + } + + /** + * Register plugin + */ + WB_REGISTER_COORDINATE_SYSTEM(Cartesian, cartesian) + } // namespace CoordinateSystems +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/coordinate_systems/interface.cc.bak b/contrib/world_builder/source/world_builder/coordinate_systems/interface.cc.bak new file mode 100644 index 00000000000..6332ef2b2ce --- /dev/null +++ b/contrib/world_builder/source/world_builder/coordinate_systems/interface.cc.bak @@ -0,0 +1,100 @@ +/* + 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/coordinate_systems/interface.h" + +#include + +#include "world_builder/types/object.h" + + +namespace WorldBuilder +{ + namespace CoordinateSystems + { + + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, const std::string &parent_name, const std::vector &required_entries) + { + + unsigned int counter = 0; + for (auto &iter : 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), "Coordinate system object"); + + prm.declare_entry("model",Types::String("",iter.first), + "The name of the coordinate system to use."); + + iter.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 CoordinateSystems +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/coordinate_systems/invalid.cc.bak b/contrib/world_builder/source/world_builder/coordinate_systems/invalid.cc.bak new file mode 100644 index 00000000000..72ca62e9034 --- /dev/null +++ b/contrib/world_builder/source/world_builder/coordinate_systems/invalid.cc.bak @@ -0,0 +1,88 @@ +/* + 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/coordinate_systems/invalid.h" +#include "world_builder/types/object.h" + + +namespace WorldBuilder +{ + namespace CoordinateSystems + { + Invalid::Invalid(WorldBuilder::World *world_) + { + this->world = world_; + } + + Invalid::~Invalid() + = default; + + void + Invalid::parse_entries(Parameters & /*prm*/) + {} + + + CoordinateSystem + Invalid::natural_coordinate_system() const + { + return CoordinateSystem::invalid; + } + + + DepthMethod + Invalid::depth_method() const + { + return DepthMethod::none; + } + + + std::array + Invalid::cartesian_to_natural_coordinates(const std::array & /*position*/) const + { + return {{NaN::DQNAN,NaN::DQNAN,NaN::DQNAN}}; + } + + + std::array + Invalid::natural_to_cartesian_coordinates(const std::array & /*position*/) const + { + return {{NaN::DQNAN,NaN::DQNAN,NaN::DQNAN}}; + } + + + double + Invalid::distance_between_points_at_same_depth(const Point<3> & /*point_1*/, const Point<3> & /*point_2*/) const + { + return NaN::DQNAN; + } + + + double + Invalid::max_model_depth() const + { + return NaN::DQNAN; + } + + /** + * Not registering plugin because this is only used for testing. + */ + //WB_REGISTER_COORDINATE_SYSTEM(Invalid, invalid) + } // namespace CoordinateSystems +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/coordinate_systems/spherical.cc.bak b/contrib/world_builder/source/world_builder/coordinate_systems/spherical.cc.bak new file mode 100644 index 00000000000..0ed922b9b9b --- /dev/null +++ b/contrib/world_builder/source/world_builder/coordinate_systems/spherical.cc.bak @@ -0,0 +1,146 @@ +/* + 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/coordinate_systems/spherical.h" + + +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/utilities.h" + +namespace WorldBuilder +{ + namespace CoordinateSystems + { + Spherical::Spherical(WorldBuilder::World *world_) + { + this->world = world_; + } + + Spherical::~Spherical() + = default; + + void + Spherical::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + + // Add depth method to the required parameters. + prm.declare_entry("", Types::Object({"depth method"}), + "A spherical coordinate system. The coordinates are (radius, longitude, latitude). " + "The radius is set in this plugin, the longitude extends at least from -360 to 360 degrees, " + "and the latitude extends from -90 to 90. It is required to choose a depth method. Please " + "see the manual for more information."); + + + prm.declare_entry("depth method", + Types::String("",std::vector({"starting point", "begin segment","begin at end segment", "continuous"})), + R"(Which depth method to use in the spherical case. The available options are 'starting point', )" + R"('begin segment' and 'begin at end segment'. See the manual section on coordinate systems for )" + R"(more info.)"); + + prm.declare_entry("radius", + Types::Double(6371000.), + R"(The radius of the sphere.)"); + + + } + + void + Spherical::parse_entries(Parameters &prm) + { + prm.enter_subsection("coordinate system"); + { + const std::string string_depth_method = prm.get("depth method"); + if (string_depth_method == "starting point") + used_depth_method = DepthMethod::angle_at_starting_point_with_surface; + else if (string_depth_method == "begin segment") + used_depth_method = DepthMethod::angle_at_begin_segment_with_surface; + else if (string_depth_method == "begin at end segment") + used_depth_method = DepthMethod::angle_at_begin_segment_applied_to_end_segment_with_surface; + //else if (string_depth_method == "continuous") + //used_depth_method = DepthMethod::continuous_angle_with_surface; + else + WBAssertThrow(true,"Option " << string_depth_method << " is not a valid depth method for spherical " + "coordinates. The available options are 'starting point', 'begin segment' and 'begin at end segment'. " + "The option 'continuous' is not yet available."); + + radius_sphere = prm.get("radius"); + } + prm.leave_subsection(); + } + + + CoordinateSystem + Spherical::natural_coordinate_system() const + { + return CoordinateSystem::spherical; + } + + + DepthMethod + Spherical::depth_method() const + { + return used_depth_method; + } + + + std::array + Spherical::cartesian_to_natural_coordinates(const std::array &position) const + { + return Utilities::cartesian_to_spherical_coordinates(Point<3>(position,cartesian)); + } + + + std::array + Spherical::natural_to_cartesian_coordinates(const std::array &position) const + { + return Utilities::spherical_to_cartesian_coordinates(position).get_array(); + } + + double + Spherical::distance_between_points_at_same_depth(const Point<3> &point_1, const Point<3> &point_2) const + { + WBAssert(point_1.get_coordinate_system() == spherical, + "Can not convert non spherical points through the spherical coordinate system."); + WBAssert(point_2.get_coordinate_system() == spherical, + "Can not convert non spherical points through the spherical coordinate system."); + const double radius = point_1[0]; + WBAssert((radius - point_2[0]) < std::numeric_limits::epsilon() * std::max(1.0,radius), "The radius of point 1 is not the same as the radius of point 2."); + + // based on https://math.stackexchange.com/questions/1304169/distance-between-two-points-on-a-sphere + const Point<3> point_1_cart = Utilities::spherical_to_cartesian_coordinates(point_1.get_array()); + const Point<3> point_2_cart = Utilities::spherical_to_cartesian_coordinates(point_2.get_array()); + + return radius * std::acos(std::min(1.,std::max(0.,point_1_cart*point_2_cart/(radius*radius)))); + } + + + double + Spherical::max_model_depth() const + { + return radius_sphere; + } + + /** + * Register plugin + */ + WB_REGISTER_COORDINATE_SYSTEM(Spherical, spherical) + } // namespace CoordinateSystems +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/continental_plate.cc.bak b/contrib/world_builder/source/world_builder/features/continental_plate.cc.bak new file mode 100644 index 00000000000..31ca36646b9 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/continental_plate.cc.bak @@ -0,0 +1,270 @@ +/* + 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/features/continental_plate.h" + + +#include "world_builder/features/continental_plate_models/composition/interface.h" +#include "world_builder/features/continental_plate_models/grains/interface.h" +#include "world_builder/features/continental_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/plugin_system.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + +#include + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + ContinentalPlate::ContinentalPlate(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + { + this->world = world_; + this->name = "continental plate"; + } + + ContinentalPlate::~ContinentalPlate() + = default; + + void ContinentalPlate::make_snippet(Parameters &prm) + { + using namespace rapidjson; + Document &declarations = prm.declarations; + + const std::string path = prm.get_full_json_path(); + + Pointer((path + "/body").c_str()).Set(declarations,"object"); + Pointer((path + "/body/model").c_str()).Set(declarations,"continental plate"); + Pointer((path + "/body/name").c_str()).Set(declarations,"${1:My Plate}"); + Pointer((path + "/body/coordinates").c_str()).Create(declarations).SetArray(); + } + + + + void + ContinentalPlate::declare_entries(Parameters &prm, + const std::string & /*unused*/, + const std::vector &required_entries) + { + + + + prm.declare_entry("", Types::Object(required_entries), "Continental plate object. Requires properties `model` and `coordinates`."); + + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth from which this feature is present"); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth to which this feature is present"); + prm.declare_entry("temperature models", + Types::PluginSystem("", Features::ContinentalPlateModels::Temperature::Interface::declare_entries, {"model"}), + "A list of temperature models."); + prm.declare_entry("composition models", + Types::PluginSystem("", Features::ContinentalPlateModels::Composition::Interface::declare_entries, {"model"}), + "A list of composition models."); + prm.declare_entry("grains models", + Types::PluginSystem("", Features::ContinentalPlateModels::Grains::Interface::declare_entries, {"model"}), + "A list of grains models."); + } + + void + ContinentalPlate::parse_entries(Parameters &prm) + { + const CoordinateSystem coordinate_system = prm.coordinate_system->natural_coordinate_system(); + + this->name = prm.get("name"); + + std::string tag = prm.get("tag"); + if (tag == "") + { + tag = "continental plate"; + } + this->tag_index = FeatureUtilities::add_vector_unique(this->world->feature_tags,tag); + + this->get_coordinates("coordinates", prm, coordinate_system); + + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + + + prm.get_unique_pointers("temperature models", temperature_models); + + prm.enter_subsection("temperature models"); + { + for (unsigned int i = 0; i < temperature_models.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + temperature_models[i]->parse_entries(prm,coordinates); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.get_unique_pointers("composition models", composition_models); + + prm.enter_subsection("composition models"); + { + for (unsigned int i = 0; i < composition_models.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + composition_models[i]->parse_entries(prm, coordinates); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.get_unique_pointers("grains models", grains_models); + + prm.enter_subsection("grains models"); + { + for (unsigned int i = 0; i < grains_models.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + grains_models[i]->parse_entries(prm,coordinates); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + } + + + + void + ContinentalPlate::properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity_norm, + const std::vector &entry_in_output, + std::vector &output) const + { + if (depth <= max_depth && depth >= min_depth && + WorldBuilder::Utilities::polygon_contains_point(coordinates, Point<2>(position_in_natural_coordinates.get_surface_coordinates(), + world->parameters.coordinate_system->natural_coordinate_system()))) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i_property = 0; i_property < properties.size(); ++i_property) + { + switch (properties[i_property][0]) + { + case 1: // temperature + { + for (const auto &temperature_model: temperature_models) + { + output[entry_in_output[i_property]] = temperature_model->get_temperature(position_in_cartesian_coordinates, + position_in_natural_coordinates, + depth, + gravity_norm, + output[entry_in_output[i_property]], + min_depth_local, + max_depth_local); + + WBAssert(!std::isnan(output[entry_in_output[i_property]]), "Temperature is not a number: " << output[entry_in_output[i_property]] + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(output[entry_in_output[i_property]]), "Temperature is not a finite: " << output[entry_in_output[i_property]] + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + + } + break; + case 2: // composition + + for (const auto &composition_model: composition_models) + { + output[entry_in_output[i_property]] = composition_model->get_composition(position_in_cartesian_coordinates, + position_in_natural_coordinates, + depth, + properties[i_property][1], + output[entry_in_output[i_property]], + min_depth_local, + max_depth_local); + + WBAssert(!std::isnan(output[entry_in_output[i_property]]), "Composition is not a number: " << output[entry_in_output[i_property]] + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(output[entry_in_output[i_property]]), "Composition is not a finite: " << output[entry_in_output[i_property]] + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + + } + + break; + } + case 3: // grains + { + WorldBuilder::grains grains(output,properties[i_property][2],entry_in_output[i_property]); + for (const auto &grains_model: grains_models) + { + grains = grains_model->get_grains(position_in_cartesian_coordinates, + position_in_natural_coordinates, + depth, + properties[i_property][1], + grains, + min_depth_local, + max_depth_local); + + } + grains.unroll_into(output,entry_in_output[i_property]); + break; + } + case 4: + { + output[entry_in_output[i_property]] = static_cast(tag_index); + break; + } + default: + { + WBAssertThrow(false, + "Internal error: Unimplemented property provided. " << + "Only temperature (1), composition (2), grains (3) or tag (4) are allowed. " + "Provided property number was: " << properties[i_property][0]); + } + } + } + } + } + } + + WB_REGISTER_FEATURE(ContinentalPlate, continental plate) + + } // namespace Features +} // namespace WorldBuilder diff --git a/contrib/world_builder/source/world_builder/features/continental_plate_models/composition/interface.cc.bak b/contrib/world_builder/source/world_builder/features/continental_plate_models/composition/interface.cc.bak new file mode 100644 index 00000000000..6f48a19c616 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/continental_plate_models/composition/interface.cc.bak @@ -0,0 +1,80 @@ +/* + 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/features/continental_plate_models/composition/interface.h" + +#include + +namespace WorldBuilder +{ + namespace Features + { + namespace ContinentalPlateModels + { + namespace Composition + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + prm.declare_model_entries("composition",parent_name, get_declare_map(),required_entries); + } + + + 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 Composition + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/continental_plate_models/composition/random.cc.bak b/contrib/world_builder/source/world_builder/features/continental_plate_models/composition/random.cc.bak new file mode 100644 index 00000000000..cfb0d2086b5 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/continental_plate_models/composition/random.cc.bak @@ -0,0 +1,144 @@ +/* + 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/features/continental_plate_models/composition/random.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" +#include + + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + using namespace FeatureUtilities; + namespace ContinentalPlateModels + { + namespace Composition + { + Random::Random(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + { + this->world = world_; + this->name = "random"; + } + + Random::~Random() + = default; + + void + Random::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform compositional model. Sets constant compositional field."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the labels of the composition which are present there."); + + prm.declare_entry("min value", Types::Array(Types::Double(0.0),1), + "Minimum value of the range within which we want to generate a random compositional value " + "corresponding to the compositional field."); + + prm.declare_entry("max value", Types::Array(Types::Double(1.0),1), + "Maximum value of the range within which we want to generate a random compositional value " + "corresponding to the compositional field."); + + prm.declare_entry("operation", Types::String("replace", std::vector {"replace", "replace defined only", "add", "subtract"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value. Replacing implies that all compositions not " + "explicitly defined are set to zero. To only replace the defined compositions use the replace only defined option."); + + } + + void + Random::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + + compositions = prm.get_vector("compositions"); + min_value = prm.get_vector("min value"); + max_value = prm.get_vector("max value"); + operation = string_operations_to_enum(prm.get("operation")); + } + + + double + Random::get_composition(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i : compositions) + { + if (i == composition_number) + { + std::uniform_real_distribution<> dist(min_value[0], max_value[0]); + const double composition_ = dist(world->get_random_number_engine()); + return apply_operation(operation,composition,composition_); + } + } + + if (operation == Operations::REPLACE) + return 0.0; + } + } + return composition; + } + WB_REGISTER_FEATURE_CONTINENTAL_PLATE_COMPOSITION_MODEL(Random, random) + } // namespace Composition + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/continental_plate_models/composition/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/continental_plate_models/composition/uniform.cc.bak new file mode 100644 index 00000000000..51130ef82c3 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/continental_plate_models/composition/uniform.cc.bak @@ -0,0 +1,136 @@ +/* + 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/features/continental_plate_models/composition/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + using namespace FeatureUtilities; + namespace ContinentalPlateModels + { + namespace Composition + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform compositional model. Sets constant compositional field."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the labels of the composition which are present there."); + + prm.declare_entry("fractions", Types::Array(Types::Double(1.0),1), + "TA list of compositional fractions corresponding to the compositions list."); + + prm.declare_entry("operation", Types::String("replace", std::vector {"replace", "replace defined only", "add", "subtract"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value. Replacing implies that all compositions not " + "explicitly defined are set to zero. To only replace the defined compositions use the replace only defined option."); + + } + + void + Uniform::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + + compositions = prm.get_vector("compositions"); + fractions = prm.get_vector("fractions"); + operation = string_operations_to_enum(prm.get("operation")); + + WBAssertThrow(compositions.size() == fractions.size(), + "There are not the same amount of compositions and fractions."); + } + + + double + Uniform::get_composition(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + return apply_operation(operation,composition,fractions[i]); + } + } + + if (operation == Operations::REPLACE) + return 0.0; + } + } + return composition; + } + WB_REGISTER_FEATURE_CONTINENTAL_PLATE_COMPOSITION_MODEL(Uniform, uniform) + } // namespace Composition + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/continental_plate_models/grains/interface.cc.bak b/contrib/world_builder/source/world_builder/features/continental_plate_models/grains/interface.cc.bak new file mode 100644 index 00000000000..c10e151f158 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/continental_plate_models/grains/interface.cc.bak @@ -0,0 +1,81 @@ +/* + 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/features/continental_plate_models/grains/interface.h" + +#include + + +namespace WorldBuilder +{ + namespace Features + { + namespace ContinentalPlateModels + { + namespace Grains + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + prm.declare_model_entries("grains",parent_name, get_declare_map(),required_entries); + } + + + 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 Grains + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/continental_plate_models/grains/random_uniform_distribution.cc.bak b/contrib/world_builder/source/world_builder/features/continental_plate_models/grains/random_uniform_distribution.cc.bak new file mode 100644 index 00000000000..516b9413ad6 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/continental_plate_models/grains/random_uniform_distribution.cc.bak @@ -0,0 +1,225 @@ +/* + 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/features/continental_plate_models/grains/random_uniform_distribution.h" + +#include + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace ContinentalPlateModels + { + namespace Grains + { + RandomUniformDistribution::RandomUniformDistribution(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "random uniform distribution"; + } + + RandomUniformDistribution::~RandomUniformDistribution() + = default; + + void + RandomUniformDistribution::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Random uniform distribution grains model. The size of the grains can be independently set " + "to a single value or to a random distribution."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be randomized between 0 and 1."); + + prm.declare_entry("normalize grain sizes", + Types::Array(Types::Bool(true),0), + "A list of whether the sizes of the grains should be normalized or not. If normalized, the total of the grains of a composition will be equal to 1."); + + + + } + + void + RandomUniformDistribution::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + compositions = prm.get_vector("compositions"); + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + normalize_grain_sizes = prm.get_vector("normalize grain sizes"); + + + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == normalize_grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and normalize_grain_sizes (" << normalize_grain_sizes.size() << ")."); + } + + + WorldBuilder::grains + RandomUniformDistribution::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + WorldBuilder::grains grains_local = grains_; + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::uniform_real_distribution<> dist(0.0,1.0); + for (auto &&it_rotation_matrices : grains_local.rotation_matrices) + { + // set a uniform random a_cosine_matrix per grain + // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120). + // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c + // and is licenend accourding to this website with the following licence: + // + // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and + // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit + // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems + // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, + // don't be a jerk, and remember that anything free comes with no guarantee."" + // + // The book saids in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in + // the public domain, and is yours to study, modify, and use." + + // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2. + const double one = dist(world->get_random_number_engine()); + const double two = dist(world->get_random_number_engine()); + const double three = dist(world->get_random_number_engine()); + + const double theta = 2.0 * Consts::PI * one; // Rotation about the pole (Z) + const double phi = 2.0 * Consts::PI * two; // For direction of pole deflection. + const double z = 2.0* three; //For magnitude of pole deflection. + + // Compute a vector V used for distributing points over the sphere + // via the reflection I - V Transpose(V). This formulation of V + // will guarantee that if x[1] and x[2] are uniformly distributed, + // the reflected points will be uniform on the sphere. Note that V + // has length sqrt(2) to eliminate the 2 in the Householder matrix. + + const double r = std::sqrt( z ); + const double Vx = std::sin( phi ) * r; + const double Vy = std::cos( phi ) * r; + const double Vz = std::sqrt( 2.F - z ); + + // Compute the row vector S = Transpose(V) * R, where R is a simple + // rotation by theta about the z-axis. No need to compute Sz since + // it's just Vz. + + const double st = std::sin( theta ); + const double ct = std::cos( theta ); + const double Sx = Vx * ct - Vy * st; + const double Sy = Vx * st + Vy * ct; + + // Construct the rotation matrix ( V Transpose(V) - I ) R, which + // is equivalent to V S - R. + + it_rotation_matrices[0][0] = Vx * Sx - ct; + it_rotation_matrices[0][1] = Vx * Sy - st; + it_rotation_matrices[0][2] = Vx * Vz; + + it_rotation_matrices[1][0] = Vy * Sx + st; + it_rotation_matrices[1][1] = Vy * Sy - ct; + it_rotation_matrices[1][2] = Vy * Vz; + + it_rotation_matrices[2][0] = Vz * Sx; + it_rotation_matrices[2][1] = Vz * Sy; + it_rotation_matrices[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0 + } + + double total_size = 0; + for (auto &&it_sizes : grains_local.sizes) + { + it_sizes = grain_sizes[i] < 0 ? dist(world->get_random_number_engine()) : grain_sizes[i]; + total_size += it_sizes; + } + + if (normalize_grain_sizes[i]) + { + const double one_over_total_size = 1/total_size; + std::transform(grains_local.sizes.begin(), grains_local.sizes.end(), grains_local.sizes.begin(), + [one_over_total_size](double sizes) -> double { return sizes *one_over_total_size; }); + } + + + return grains_local; + } + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_CONTINENTAL_PLATE_GRAINS_MODEL(RandomUniformDistribution, random uniform distribution) + } // namespace Grains + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/continental_plate_models/grains/random_uniform_distribution_deflected.cc.bak b/contrib/world_builder/source/world_builder/features/continental_plate_models/grains/random_uniform_distribution_deflected.cc.bak new file mode 100644 index 00000000000..02150f29edc --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/continental_plate_models/grains/random_uniform_distribution_deflected.cc.bak @@ -0,0 +1,231 @@ +/* + 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/features/continental_plate_models/grains/random_uniform_distribution_deflected.h" + +#include + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace ContinentalPlateModels + { + namespace Grains + { + RandomUniformDistributionDeflected::RandomUniformDistributionDeflected(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "random uniform distribution deflected"; + } + + RandomUniformDistributionDeflected::~RandomUniformDistributionDeflected() + = default; + + void + RandomUniformDistributionDeflected::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Random uniform distribution grains model. The size of the grains can be independently set " + "to a single value or to a random distribution."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be randomized between 0 and 1."); + + prm.declare_entry("normalize grain sizes", + Types::Array(Types::Bool(true),0), + "A list of whether the sizes of the grains should be normalized or not. If normalized, the total of the grains of a composition will be equal to 1."); + + prm.declare_entry("deflections", + Types::Array(Types::Double(1),0), + "A list of the deflections of all of the grains in each composition between 0 and 1."); + + + + } + + void + RandomUniformDistributionDeflected::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + compositions = prm.get_vector("compositions"); + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + normalize_grain_sizes = prm.get_vector("normalize grain sizes"); + deflections = prm.get_vector("deflections"); + + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == normalize_grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and normalize_grain_sizes (" << normalize_grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == deflections.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and deflections (" << deflections.size() << ")."); + } + + + WorldBuilder::grains + RandomUniformDistributionDeflected::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + WorldBuilder::grains grains_local = grains_; + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::uniform_real_distribution<> dist(0.0,1.0); + for (auto &&it_rotation_matrices : grains_local.rotation_matrices) + { + // set a uniform random a_cosine_matrix per grain + // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120). + // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c + // and is licenend accourding to this website with the following licence: + // + // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and + // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit + // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems + // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, + // don't be a jerk, and remember that anything free comes with no guarantee."" + // + // The book saids in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in + // the public domain, and is yours to study, modify, and use." + + // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2. + const double one = dist(world->get_random_number_engine()); + const double two = dist(world->get_random_number_engine()); + const double three = dist(world->get_random_number_engine()); + + const double theta = 2.0 * Consts::PI * one * deflections[i]; // Rotation about the pole (Z) + const double phi = 2.0 * Consts::PI * two; // For direction of pole deflection. + const double z = 2.0* three * deflections[i]; //For magnitude of pole deflection. + + // Compute a vector V used for distributing points over the sphere + // via the reflection I - V Transpose(V). This formulation of V + // will guarantee that if x[1] and x[2] are uniformly distributed, + // the reflected points will be uniform on the sphere. Note that V + // has length sqrt(2) to eliminate the 2 in the Householder matrix. + + const double r = std::sqrt( z ); + const double Vx = std::sin( phi ) * r; + const double Vy = std::cos( phi ) * r; + const double Vz = std::sqrt( 2.F - z ); + + // Compute the row vector S = Transpose(V) * R, where R is a simple + // rotation by theta about the z-axis. No need to compute Sz since + // it's just Vz. + + const double st = std::sin( theta ); + const double ct = std::cos( theta ); + const double Sx = Vx * ct - Vy * st; + const double Sy = Vx * st + Vy * ct; + + // Construct the rotation matrix ( V Transpose(V) - I ) R, which + // is equivalent to V S - R. + + it_rotation_matrices[0][0] = Vx * Sx - ct; + it_rotation_matrices[0][1] = Vx * Sy - st; + it_rotation_matrices[0][2] = Vx * Vz; + + it_rotation_matrices[1][0] = Vy * Sx + st; + it_rotation_matrices[1][1] = Vy * Sy - ct; + it_rotation_matrices[1][2] = Vy * Vz; + + it_rotation_matrices[2][0] = Vz * Sx; + it_rotation_matrices[2][1] = Vz * Sy; + it_rotation_matrices[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0 + } + + double total_size = 0; + for (auto &&it_sizes : grains_local.sizes) + { + it_sizes = grain_sizes[i] < 0 ? dist(world->get_random_number_engine()) : grain_sizes[i]; + total_size += it_sizes; + } + + if (normalize_grain_sizes[i]) + { + const double one_over_total_size = 1/total_size; + std::transform(grains_local.sizes.begin(), grains_local.sizes.end(), grains_local.sizes.begin(), + [one_over_total_size](double sizes) -> double { return sizes *one_over_total_size; }); + } + + + return grains_local; + } + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_CONTINENTAL_PLATE_GRAINS_MODEL(RandomUniformDistributionDeflected, random uniform distribution deflected) + } // namespace Grains + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/continental_plate_models/grains/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/continental_plate_models/grains/uniform.cc.bak new file mode 100644 index 00000000000..110bd919078 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/continental_plate_models/grains/uniform.cc.bak @@ -0,0 +1,177 @@ +/* + 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/features/continental_plate_models/grains/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/utilities.h" + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace ContinentalPlateModels + { + namespace Grains + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform grains model. All grains start exactly the same."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("rotation matrices", Types::Array(Types::Array(Types::Array(Types::Double(0),3,3),3,3),0), + "A list with the rotation matrices of the grains which are present there for each compositions."); + + prm.declare_entry("Euler angles z-x-z", Types::Array(Types::Array(Types::Double(0),3,3),0), + "A list with the z-x-z Euler angles of the grains which are present there for each compositions."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace", "multiply"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(-1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be set so that the total is equal to 1."); + + + } + + void + Uniform::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + compositions = prm.get_vector("compositions"); + + const bool set_euler_angles = prm.check_entry("Euler angles z-x-z"); + const bool set_rotation_matrices = prm.check_entry("rotation matrices"); + + WBAssertThrow(!(set_euler_angles == true && set_rotation_matrices == true), + "Only Euler angles or Rotation matrices may be set, but both are set for " << prm.get_full_json_path()); + + + WBAssertThrow(!(set_euler_angles == false && set_rotation_matrices == false), + "Euler angles or Rotation matrices have to be set, but neither are set for " << prm.get_full_json_path()); + + if (set_euler_angles) + { + std::vector > euler_angles_vector = prm.get_vector >("Euler angles z-x-z"); + rotation_matrices.resize(euler_angles_vector.size()); + for (size_t i = 0; i,3> >("rotation matrices"); + } + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + + + WBAssertThrow(compositions.size() == rotation_matrices.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and rotation_matrices (" << rotation_matrices.size() << ")."); + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + } + + + WorldBuilder::grains + Uniform::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + WorldBuilder::grains grains_local = grains_; + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::fill(grains_local.rotation_matrices.begin(),grains_local.rotation_matrices.end(),rotation_matrices[i]); + + const double size = grain_sizes[i] < 0 ? 1.0/static_cast(grains_local.sizes.size()) : grain_sizes[i]; + std::fill(grains_local.sizes.begin(),grains_local.sizes.end(),size); + + return grains_local; + } + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_CONTINENTAL_PLATE_GRAINS_MODEL(Uniform, uniform) + } // namespace Grains + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/adiabatic.cc.bak b/contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/adiabatic.cc.bak new file mode 100644 index 00000000000..88d83639032 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/adiabatic.cc.bak @@ -0,0 +1,171 @@ +/* + 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/features/continental_plate_models/temperature/adiabatic.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + using namespace FeatureUtilities; + namespace ContinentalPlateModels + { + namespace Temperature + { + Adiabatic::Adiabatic(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + potential_mantle_temperature(NaN::DSNAN), + thermal_expansion_coefficient(NaN::DSNAN), + specific_heat(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "adiabatic"; + } + + Adiabatic::~Adiabatic() + = default; + + void + Adiabatic::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + prm.declare_entry("", Types::Object(), + "Adiabatic temperature model. Uses global values by default."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("potential mantle temperature", Types::Double(-1), + "The potential temperature of the mantle at the surface in Kelvin. " + "If the value is lower then zero, the global value is used."); + + prm.declare_entry("thermal expansion coefficient", Types::Double(-1), + "The thermal expansion coefficient in $K^{-1}$. " + "If the value is lower then zero, the global value is used."); + + prm.declare_entry("specific heat", Types::Double(-1), + "The specific heat in $J kg^{-1} K^{-1}$. " + "If the value is lower then zero, the global value is used."); + + } + + void + Adiabatic::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + operation = string_operations_to_enum(prm.get("operation")); + + potential_mantle_temperature = prm.get("potential mantle temperature"); + if (potential_mantle_temperature < 0) + potential_mantle_temperature = this->world->potential_mantle_temperature; + + + thermal_expansion_coefficient = prm.get("thermal expansion coefficient"); + if (thermal_expansion_coefficient < 0) + thermal_expansion_coefficient = this->world->thermal_expansion_coefficient; + + specific_heat = prm.get("specific heat"); + if (specific_heat < 0) + specific_heat = this->world->specific_heat; + + // Some assertions in debug mode can't hurt and have helped before. + WBAssert(!std::isnan(potential_mantle_temperature), + "potential_mantle_temperature is not a number: " << potential_mantle_temperature << '.'); + WBAssert(std::isfinite(potential_mantle_temperature), + "potential_mantle_temperature is not a finite: " << potential_mantle_temperature << '.'); + + WBAssert(!std::isnan(thermal_expansion_coefficient), + "thermal_expansion_coefficient is not a number: " << thermal_expansion_coefficient << '.'); + WBAssert(std::isfinite(thermal_expansion_coefficient), + "thermal_expansion_coefficient is not a finite: " << thermal_expansion_coefficient << '.'); + + WBAssert(!std::isnan(specific_heat), + "specific_heat is not a number: " << specific_heat << '.'); + WBAssert(std::isfinite(thermal_expansion_coefficient), + "specific_heat is not a finite: " << specific_heat << '.'); + + } + + + double + Adiabatic::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity_norm, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + const double adabatic_temperature = potential_mantle_temperature * + std::exp(((thermal_expansion_coefficient * gravity_norm) / + specific_heat) * depth); + + + WBAssert(!std::isnan(adabatic_temperature), + "adabatic_temperature is not a number: " << adabatic_temperature << ". " + <<"Parameters: potential_mantle_temperature = " << potential_mantle_temperature + <<", thermal_expansion_coefficient = " << thermal_expansion_coefficient + << ", gravity_norm = " << gravity_norm + << ", specific_heat = " << specific_heat + << ", depth = " << depth); + + WBAssert(std::isfinite(adabatic_temperature), + "adabatic_temperature is not a finite: " << adabatic_temperature << '.'); + + return apply_operation(operation,temperature_,adabatic_temperature); + } + } + return temperature_; + } + + WB_REGISTER_FEATURE_CONTINENTAL_PLATE_TEMPERATURE_MODEL(Adiabatic, adiabatic) + } // namespace Temperature + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/interface.cc.bak b/contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/interface.cc.bak new file mode 100644 index 00000000000..1e582d955ce --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/interface.cc.bak @@ -0,0 +1,94 @@ +/* + 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/features/continental_plate_models/temperature/interface.h" + +#include + +#include "world_builder/types/string.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace ContinentalPlateModels + { + namespace Temperature + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + // The type needs to be stored in a separate value, otherwise there are memory issues + const Types::String type = Types::String("replace", std::vector {"replace", "add", "subtract"}); + + prm.declare_model_entries("temperature",parent_name, get_declare_map(),required_entries, + { + std::tuple + { + "operation", type, + "Whether the value should replace any value previously defined at this location (replace), " + "add the value to the previously define value (add) or subtract the value to the previously " + "define value (subtract)." + } + }); + } + + + 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 Temperature + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/linear.cc.bak b/contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/linear.cc.bak new file mode 100644 index 00000000000..2c92fae4f7d --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/linear.cc.bak @@ -0,0 +1,157 @@ +/* + 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/features/continental_plate_models/temperature/linear.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + using namespace FeatureUtilities; + namespace ContinentalPlateModels + { + namespace Temperature + { + Linear::Linear(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + top_temperature(NaN::DSNAN), + bottom_temperature(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "linear"; + } + + Linear::~Linear() + = default; + + void + Linear::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `max depth` to the required parameters. + prm.declare_entry("", Types::Object({"max depth"}), + "Linear temperature model. Can be set to use an adiabatic temperature at the boundaries."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("top temperature", Types::Double(293.15), + "The temperature at the top in degree Kelvin of this feature." + "If the value is below zero, the an adiabatic temperature is used."); + + prm.declare_entry("bottom temperature", Types::Double(-1), + "The temperature at the top in degree Kelvin of this feature. " + "If the value is below zero, an adiabatic temperature is used."); + + } + + void + Linear::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + WBAssert(max_depth >= min_depth, "max depth needs to be larger or equal to min depth."); + operation = string_operations_to_enum(prm.get("operation")); + top_temperature = prm.get("top temperature"); + bottom_temperature = prm.get("bottom temperature"); + } + + + double + Linear::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity_norm, + double temperature_, + const double feature_min_depth, + const double feature_max_depth) const + { + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + const double min_depth_local_local = std::max(feature_min_depth, min_depth_local); + const double max_depth_local_local = std::min(feature_max_depth, max_depth_local); + + double top_temperature_local = top_temperature; + if (top_temperature_local < 0) + { + top_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient * gravity_norm) / + this->world->specific_heat) * min_depth_local_local); + } + + double bottom_temperature_local = bottom_temperature; + if (bottom_temperature_local < 0) + { + bottom_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient * gravity_norm) / + this->world->specific_heat) * max_depth_local_local); + } + + const double new_temperature = top_temperature_local + (max_depth_local_local - min_depth_local_local < 10.0*std::numeric_limits::epsilon() ? 0.0 : + (depth - min_depth_local) * + ((bottom_temperature_local - top_temperature_local) / (max_depth_local_local - min_depth_local_local))); + + WBAssert(!std::isnan(new_temperature), "Temperature is not a number: " << new_temperature + << ", based on a temperature model with the name " << this->name); + WBAssert(std::isfinite(new_temperature), "Temperature is not a finite: " << new_temperature + << ", based on a temperature model with the name " << this->name + << ", top_temperature_local = " << top_temperature_local << ", depth = " << depth << ", min_depth_local = " << min_depth_local + << ", bottom_temperature_local= " << bottom_temperature_local << ", top_temperature_local=" << top_temperature_local + << ",max_depth_local_local=" << max_depth_local_local << ", min_depth_local_local =" << min_depth_local_local + << ", feature_max_depth = " << feature_max_depth << ", feature_max_depth = " << feature_max_depth); + + return apply_operation(operation,temperature_,new_temperature); + } + } + + + return temperature_; + } + + WB_REGISTER_FEATURE_CONTINENTAL_PLATE_TEMPERATURE_MODEL(Linear, linear) + } // namespace Temperature + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/uniform.cc.bak new file mode 100644 index 00000000000..ff4b8d695b3 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/continental_plate_models/temperature/uniform.cc.bak @@ -0,0 +1,114 @@ +/* + 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/features/continental_plate_models/temperature/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/value_at_points.h" + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace ContinentalPlateModels + { + namespace Temperature + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + temperature(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `temperature` to the required parameters. + prm.declare_entry("", Types::Object({"temperature"}), + "Uniform temperature model. Set the temperature to a constant value."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("temperature", Types::Double(293.15), + "The temperature in degree Kelvin which this feature should have"); + + } + + void + Uniform::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + operation = string_operations_to_enum(prm.get("operation")); + temperature = prm.get("temperature"); + } + + + double + Uniform::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double /*gravity*/, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + if (depth <= max_depth && depth >= min_depth) + { + return apply_operation(operation,temperature_,temperature); + } + } + return temperature_; + } + + WB_REGISTER_FEATURE_CONTINENTAL_PLATE_TEMPERATURE_MODEL(Uniform, uniform) + } // namespace Temperature + } // namespace ContinentalPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/fault.cc.bak b/contrib/world_builder/source/world_builder/features/fault.cc.bak new file mode 100644 index 00000000000..7f0c43fd5bf --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/fault.cc.bak @@ -0,0 +1,730 @@ +/* + 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/features/fault.h" + + +#include "glm/glm.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/point.h" +#include "world_builder/types/segment.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/world.h" +#include + +using namespace std; + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + Fault::Fault(WorldBuilder::World *world_) + : + reference_point(0,0,cartesian) + { + this->world = world_; + this->name = "fault"; + } + + Fault::~Fault() + = default; + + + + void Fault::make_snippet(Parameters &prm) + { + using namespace rapidjson; + Document &declarations = prm.declarations; + + const std::string path = prm.get_full_json_path(); + + Pointer((path + "/body").c_str()).Set(declarations,"object"); + Pointer((path + "/body/model").c_str()).Set(declarations,"fault"); + Pointer((path + "/body/name").c_str()).Set(declarations,"${1:My Fault}"); + Pointer((path + "/body/coordinates").c_str()).Create(declarations).SetArray(); + Pointer((path + "/body/segments").c_str()).Create(declarations).SetArray(); + Pointer((path + "/body/sections").c_str()).Create(declarations).SetArray(); + } + + + + void + Fault::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + + // This statement is needed because of the recursion associated with + // the sections entry. + if (parent_name == "items") + { + prm.enter_subsection("properties"); + } + else + { + prm.declare_entry("", Types::Object(required_entries), "Fault object. Requires properties `model` and `coordinates`."); + } + prm.declare_entry("min depth", Types::Double(0), + "The depth to which this feature is present"); + prm.declare_entry("max depth", Types::Double(std::numeric_limits::max()), + "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("segments", Types::Array(Types::Segment(0,Point<2>(0,0,invalid),Point<2>(0,0,invalid),Point<2>(0,0,invalid), + Types::PluginSystem("", Features::FaultModels::Temperature::Interface::declare_entries, {"model"}), + Types::PluginSystem("", Features::FaultModels::Composition::Interface::declare_entries, {"model"}), + Types::PluginSystem("", Features::FaultModels::Grains::Interface::declare_entries, {"model"}))), + "The depth to which this feature is present"); + + prm.declare_entry("temperature models", + Types::PluginSystem("", Features::FaultModels::Temperature::Interface::declare_entries, {"model"}), + "A list of temperature models."); + prm.declare_entry("composition models", + Types::PluginSystem("", Features::FaultModels::Composition::Interface::declare_entries, {"model"}), + "A list of composition models."); + prm.declare_entry("grains models", + Types::PluginSystem("", Features::FaultModels::Grains::Interface::declare_entries, {"model"}), + "A list of grains models."); + + if (parent_name != "items") + { + // This only happens if we are not in sections + prm.declare_entry("sections", Types::Array(Types::PluginSystem("",Features::Fault::declare_entries, {"coordinate"}, false)),"A list of feature properties for a coordinate."); + } + else + { + + // this only happens in sections + prm.declare_entry("coordinate", Types::UnsignedInt(0), + "The coordinate which should be overwritten"); + + prm.leave_subsection(); + } + } + + void + Fault::parse_entries(Parameters &prm) + { + const CoordinateSystem coordinate_system = prm.coordinate_system->natural_coordinate_system(); + + this->name = prm.get("name"); + + std::string tag = prm.get("tag"); + if (tag == "") + { + tag = "fault"; + } + this->tag_index = FeatureUtilities::add_vector_unique(this->world->feature_tags,tag); + + this->get_coordinates("coordinates", prm, coordinate_system); + + + starting_depth = prm.get("min depth"); + maximum_depth = prm.get("max depth"); + + const size_t n_sections = this->original_number_of_coordinates; + + reference_point = prm.get >("dip point"); + + if (coordinate_system == spherical) + { + // When spherical, input is in degrees, so change to radians for internal use. + reference_point *= (Consts::PI/180); + } + + default_temperature_models.resize(0); + default_composition_models.resize(0); + default_grains_models.resize(0); + prm.get_shared_pointers("temperature models", default_temperature_models); + prm.get_shared_pointers("composition models", default_composition_models); + prm.get_shared_pointers("grains models", default_grains_models); + + // get the default segments. + default_segment_vector = prm.get_vector >("segments", default_temperature_models, default_composition_models,default_grains_models); + + + // This vector stores segments to this coordinate/section. + // First used (raw) pointers to the segment relevant to this coordinate/section, + // but I do not trust it won't fail when memory is moved. So storing the all the data now. + segment_vector.resize(0); + segment_vector.resize(n_sections, default_segment_vector); + + + // now search whether a section is present, if so, replace the default segments. + std::vector > sections_vector; + prm.get_unique_pointers("sections", sections_vector); + + prm.enter_subsection("sections"); + for (unsigned int i_section = 0; i_section < n_sections; ++i_section) + { + // first check whether this section/coordinate has a a special overwrite + for (unsigned int i_sector = 0; i_sector < sections_vector.size(); ++i_sector) + { + prm.enter_subsection(std::to_string(i_sector)); + { + const unsigned int change_coord_number = prm.get("coordinate"); + + WBAssertThrow(segment_vector.size() > change_coord_number, "Error: for subducting plate with name: '" << this->name + << "', trying to change the section of coordinate " << change_coord_number + << " while only " << segment_vector.size() << " coordinates are defined."); + + std::vector > local_default_temperature_models; + std::vector > local_default_composition_models; + std::vector > local_default_grains_models; + + if (!prm.get_shared_pointers("temperature models", local_default_temperature_models)) + { + // no local temperature model, use global default + local_default_temperature_models = default_temperature_models; + } + + if (!prm.get_shared_pointers("composition models", local_default_composition_models)) + { + // no local composition model, use global default + local_default_composition_models = default_composition_models; + } + + if (!prm.get_shared_pointers("grains models", local_default_grains_models)) + { + // no local grains model, use global default + local_default_grains_models = default_grains_models; + } + + segment_vector[change_coord_number] = prm.get_vector >("segments", local_default_temperature_models, local_default_composition_models, local_default_grains_models); + + WBAssertThrow(segment_vector[change_coord_number].size() == default_segment_vector.size(), + "Error: There are not the same amount of segments in section with coordinate " << change_coord_number + << " (" << segment_vector[change_coord_number].size() << " segments) as in the default segment (" + << default_segment_vector.size() << " segments). This is not allowed."); + + prm.enter_subsection("segments"); + { + for (unsigned int i = 0; i < segment_vector[change_coord_number].size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + prm.enter_subsection("temperature models"); + { + for (unsigned int j = 0; j < segment_vector[change_coord_number][i].temperature_systems.size(); ++j) + { + prm.enter_subsection(std::to_string(j)); + { + segment_vector[change_coord_number][i].temperature_systems[j]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.enter_subsection("composition models"); + { + for (unsigned int j = 0; j < segment_vector[change_coord_number][i].composition_systems.size(); ++j) + { + prm.enter_subsection(std::to_string(j)); + { + segment_vector[change_coord_number][i].composition_systems[j]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.enter_subsection("grains models"); + { + for (unsigned int j = 0; j < segment_vector[change_coord_number][i].grains_systems.size(); ++j) + { + prm.enter_subsection(std::to_string(j)); + { + segment_vector[change_coord_number][i].grains_systems[j]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + } + prm.leave_subsection(); + } + + } + prm.leave_subsection(); + + + prm.enter_subsection("segments"); + { + for (unsigned int i = 0; i < default_segment_vector.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + prm.enter_subsection("temperature models"); + { + for (unsigned int j = 0; j < default_segment_vector[i].temperature_systems.size(); ++j) + { + prm.enter_subsection(std::to_string(j)); + { + default_segment_vector[i].temperature_systems[j]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.enter_subsection("composition models"); + { + for (unsigned int j = 0; j < default_segment_vector[i].composition_systems.size(); ++j) + { + prm.enter_subsection(std::to_string(j)); + { + default_segment_vector[i].composition_systems[j]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.enter_subsection("grains models"); + { + for (unsigned int j = 0; j < default_segment_vector[i].grains_systems.size(); ++j) + { + prm.enter_subsection(std::to_string(j)); + { + default_segment_vector[i].grains_systems[j]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + maximum_fault_thickness = 0; + maximum_total_fault_length = 0; + total_fault_length.resize(original_number_of_coordinates); + fault_segment_lengths.resize(original_number_of_coordinates); + fault_segment_thickness.resize(original_number_of_coordinates); + fault_segment_top_truncation.resize(original_number_of_coordinates); + fault_segment_angles.resize(original_number_of_coordinates); + + for (unsigned int i = 0; i < segment_vector.size(); ++i) + { + double local_total_fault_length = 0; + fault_segment_lengths[i].resize(segment_vector[i].size()); + fault_segment_thickness[i].resize(segment_vector[i].size(), Point<2>(invalid)); + fault_segment_top_truncation[i].resize(segment_vector[i].size(), Point<2>(invalid)); + fault_segment_angles[i].resize(segment_vector[i].size(), Point<2>(invalid)); + + for (unsigned int j = 0; j < segment_vector[i].size(); ++j) + { + fault_segment_lengths[i][j] = segment_vector[i][j].value_length; + local_total_fault_length += segment_vector[i][j].value_length; + + fault_segment_thickness[i][j] = segment_vector[i][j].value_thickness; + maximum_fault_thickness = std::max(maximum_fault_thickness, fault_segment_thickness[i][j][0]); + maximum_fault_thickness = std::max(maximum_fault_thickness, fault_segment_thickness[i][j][1]); + fault_segment_top_truncation[i][j] = segment_vector[i][j].value_top_truncation; + + fault_segment_angles[i][j] = segment_vector[i][j].value_angle * (Consts::PI/180); + } + total_fault_length[i] = local_total_fault_length; + maximum_total_fault_length = std::max(maximum_total_fault_length, local_total_fault_length); + } + + + // Find minimal and maximal coordinates. Do this by finding the + // leftmost/rightmost point with regard to either the [0] or [1] + // coordinate, and then takes its [0] or [1] element. + auto compare_x_coordinate = [](auto p1, auto p2) + { + return p1[0]parameters.coordinate_system->natural_coordinate_system() == CoordinateSystem::spherical) + { + const double starting_radius_inv = 1 / (world->parameters.coordinate_system->max_model_depth()); + std::pair, Point<2> > &spherical_bounding_box = surface_bounding_box.get_boundary_points(); + + const double buffer_around_fault_spherical = 2 * Consts::PI * buffer_around_fault_cartesian * starting_radius_inv; + + spherical_bounding_box.first = {(min_along_x - buffer_around_fault_spherical * min_lat_cos_inv) , + (min_along_y - buffer_around_fault_spherical), spherical + } ; + + spherical_bounding_box.second = {(max_along_x + buffer_around_fault_spherical * max_lat_cos_inv) , + (max_along_y + buffer_around_fault_spherical), spherical + }; + } + else if (world->parameters.coordinate_system->natural_coordinate_system() == CoordinateSystem::cartesian) + { + std::pair, Point<2> > &bounding_box = surface_bounding_box.get_boundary_points(); + bounding_box.first = {min_along_x, min_along_y, cartesian}; + bounding_box.second = {max_along_x, max_along_y, cartesian}; + surface_bounding_box.extend(buffer_around_fault_cartesian); + } + } + + + const BoundingBox<2> & + Fault::get_surface_bounding_box () const + { + return surface_bounding_box; + } + + + void + Fault::properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity_norm, + const std::vector &entry_in_output, + std::vector &output) const + { + // The 'depth coordinate' is the z-coordinate in Cartesian coordinates, and radius in spherical coordinates. + // The depth input parameter is the distance from the surface to the position, + // 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] + << ", position_in_natural_coordinates.get_depth_coordinate() = " << position_in_natural_coordinates.get_depth_coordinate() + << ", depth = " << depth + << ", starting_depth " << starting_depth + ); + + // todo: explain and check -starting_depth + if (depth <= maximum_depth && depth >= starting_depth && depth <= maximum_total_fault_length + maximum_fault_thickness && + get_surface_bounding_box().point_inside(Point<2>(position_in_natural_coordinates.get_surface_coordinates(), + world->parameters.coordinate_system->natural_coordinate_system()))) + { + // todo: explain + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes distance_from_planes = + WorldBuilder::Utilities::distance_point_from_curved_planes(position_in_cartesian_coordinates, + position_in_natural_coordinates, + reference_point, + coordinates, + fault_segment_lengths, + fault_segment_angles, + starting_radius, + this->world->parameters.coordinate_system, + true, + this->bezier_curve); + + const double distance_from_plane = distance_from_planes.distance_from_plane; + const double distance_along_plane = distance_from_planes.distance_along_plane; + const double section_fraction = distance_from_planes.fraction_of_section; + const size_t current_section = distance_from_planes.section; + const size_t next_section = current_section + 1; + const size_t current_segment = distance_from_planes.segment; + const double segment_fraction = distance_from_planes.fraction_of_segment; + + if (abs(distance_from_plane) < std::numeric_limits::infinity() || (distance_along_plane) < std::numeric_limits::infinity()) + { + // We want to do both section (horizontal) and segment (vertical) interpolation. + // first for thickness + const double thickness_up = fault_segment_thickness[current_section][current_segment][0] + + section_fraction + * (fault_segment_thickness[next_section][current_segment][0] + - fault_segment_thickness[current_section][current_segment][0]); + const double thickness_down = fault_segment_thickness[current_section][current_segment][1] + + section_fraction + * (fault_segment_thickness[next_section][current_segment][1] + - fault_segment_thickness[current_section][current_segment][1]); + const double thickness_local = thickness_up + segment_fraction * (thickness_down - thickness_up); + + + // if the thickness is zero, we don't need to compute anything, so return. + if (std::fabs(thickness_local) < 2.0 * std::numeric_limits::epsilon()) + return; + + // secondly for top truncation + const double top_truncation_up = fault_segment_top_truncation[current_section][current_segment][0] + + section_fraction + * (fault_segment_top_truncation[next_section][current_segment][0] + - fault_segment_top_truncation[current_section][current_segment][0]); + const double top_truncation_down = fault_segment_top_truncation[current_section][current_segment][1] + + section_fraction + * (fault_segment_top_truncation[next_section][current_segment][1] + - fault_segment_top_truncation[current_section][current_segment][1]); + const double top_truncation_local = top_truncation_up + segment_fraction * (top_truncation_down - top_truncation_up); + + // if the thickness is smaller than what is truncated off at the top, we don't need to compute anything, so return. + if (thickness_local < top_truncation_local) + return; + + + + const double max_fault_length = total_fault_length[current_section] + + section_fraction * + (total_fault_length[next_section] - total_fault_length[current_section]); + const AdditionalParameters additional_parameters = {max_fault_length,thickness_local}; + + // Check if we are inside the fault. + // Every distance from -thickness/2 to +thickness/2 is inside the fault. + if (std::fabs(distance_from_plane) <= thickness_local * 0.5 && + distance_along_plane > 0 && + distance_along_plane <= max_fault_length) + { + for (unsigned int i_property = 0; i_property < properties.size(); ++i_property) + { + switch (properties[i_property][0]) + { + case 1: // temperature + { + double temperature_current_section = output[entry_in_output[i_property]]; + double temperature_next_section = output[entry_in_output[i_property]]; + + for (const auto &temperature_model: segment_vector[current_section][current_segment].temperature_systems) + { + temperature_current_section = temperature_model->get_temperature(position_in_cartesian_coordinates, + depth, + gravity_norm, + temperature_current_section, + starting_depth, + maximum_depth, + distance_from_planes, + additional_parameters); + + WBAssert(!std::isnan(temperature_current_section), "Temperature is not a number: " << temperature_current_section + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(temperature_current_section), "Temperature is not finite: " << temperature_current_section + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + + } + + for (const auto &temperature_model: segment_vector[next_section][current_segment].temperature_systems) + { + temperature_next_section = temperature_model->get_temperature(position_in_cartesian_coordinates, + depth, + gravity_norm, + temperature_next_section, + starting_depth, + maximum_depth, + distance_from_planes, + additional_parameters); + + WBAssert(!std::isnan(temperature_next_section), "Temperature is not a number: " << temperature_next_section + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(temperature_next_section), "Temperature is not a finite: " << temperature_next_section + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + + } + + // linear interpolation between current and next section temperatures + output[entry_in_output[i_property]] = temperature_current_section + section_fraction * (temperature_next_section - temperature_current_section); + break; + } + case 2: // composition + { + double composition_current_section = output[entry_in_output[i_property]]; + double composition_next_section = output[entry_in_output[i_property]]; + + for (const auto &composition_model: segment_vector[current_section][current_segment].composition_systems) + { + composition_current_section = composition_model->get_composition(position_in_cartesian_coordinates, + depth, + properties[i_property][1], + composition_current_section, + starting_depth, + maximum_depth, + distance_from_planes, + additional_parameters); + + WBAssert(!std::isnan(composition_current_section), "Composition_current_section is not a number: " << composition_current_section + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(composition_current_section), "Composition_current_section is not finite: " << composition_current_section + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + + } + + for (const auto &composition_model: segment_vector[next_section][current_segment].composition_systems) + { + composition_next_section = composition_model->get_composition(position_in_cartesian_coordinates, + depth, + properties[i_property][1], + composition_next_section, + starting_depth, + maximum_depth, + distance_from_planes, + additional_parameters); + + WBAssert(!std::isnan(composition_next_section), "Composition_next_section is not a number: " << composition_next_section + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(composition_next_section), "Composition_next_section is not finite: " << composition_next_section + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + + } + + // linear interpolation between current and next section temperatures + output[entry_in_output[i_property]] = composition_current_section + section_fraction * (composition_next_section - composition_current_section); + break; + } + case 3: // grains + { + WorldBuilder::grains grains(output,properties[i_property][2],entry_in_output[i_property]); + WorldBuilder::grains grains_current_section = grains; + WorldBuilder::grains grains_next_section = grains; + + for (const auto &grains_model: segment_vector[current_section][current_segment].grains_systems) + { + grains_current_section = grains_model->get_grains(position_in_cartesian_coordinates, + depth, + properties[i_property][1], + grains_current_section, + starting_depth, + maximum_depth, + distance_from_planes, + additional_parameters); + + } + + for (const auto &grains_model: segment_vector[next_section][current_segment].grains_systems) + { + grains_next_section = grains_model->get_grains(position_in_cartesian_coordinates, + depth, + properties[i_property][1], + grains_next_section, + starting_depth, + maximum_depth, + distance_from_planes, + additional_parameters); + + } + + // linear interpolation between current and next section temperatures + for (size_t i = 0; i < grains.sizes.size(); i++) + { + grains.sizes[i] = grains_current_section.sizes[i] + section_fraction * (grains_next_section.sizes[i] - grains_current_section.sizes[i]); + } + + // average two rotations matrices through quaternions. + for (size_t i = 0; i < grains_current_section.rotation_matrices.size(); i++) + { + const glm::quaternion::quat quat_current = glm::quaternion::quat_cast(grains_current_section.rotation_matrices[i]); + const glm::quaternion::quat quat_next = glm::quaternion::quat_cast(grains_next_section.rotation_matrices[i]); + + const glm::quaternion::quat quat_average = glm::quaternion::slerp(quat_current,quat_next,section_fraction); + + grains.rotation_matrices[i] = glm::quaternion::mat3_cast(quat_average); + } + + grains.unroll_into(output,entry_in_output[i_property]); + break; + } + case 4: + { + output[entry_in_output[i_property]] = static_cast(tag_index); + break; + } + default: + { + WBAssertThrow(false, + "Internal error: Unimplemented property provided. " << + "Only temperature (1), composition (2), grains (3) or tag (4) are allowed. " + "Provided property number was: " << properties[i_property][0]); + } + } + } + + } + } + } + + } + + Objects::PlaneDistances + Fault::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 + ); + + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes distance_from_planes = + WorldBuilder::Utilities::distance_point_from_curved_planes(position_in_cartesian_coordinates, + position_in_natural_coordinates, + reference_point, + coordinates, + fault_segment_lengths, + fault_segment_angles, + starting_radius, + this->world->parameters.coordinate_system, + false, + this->bezier_curve); + + Objects::PlaneDistances plane_distances(distance_from_planes.distance_from_plane, distance_from_planes.distance_along_plane); + return plane_distances; + } + + /** + * Register plugin + */ + WB_REGISTER_FEATURE(Fault, fault) + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/fault_models/composition/interface.cc.bak b/contrib/world_builder/source/world_builder/features/fault_models/composition/interface.cc.bak new file mode 100644 index 00000000000..ed645a38e29 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/fault_models/composition/interface.cc.bak @@ -0,0 +1,81 @@ +/* + 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/features/fault_models/composition/interface.h" + +#include + + +namespace WorldBuilder +{ + namespace Features + { + namespace FaultModels + { + namespace Composition + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + prm.declare_model_entries("composition",parent_name, get_declare_map(),required_entries); + } + + + 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 Composition + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/fault_models/composition/smooth.cc.bak b/contrib/world_builder/source/world_builder/features/fault_models/composition/smooth.cc.bak new file mode 100644 index 00000000000..e9e31c1bdf7 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/fault_models/composition/smooth.cc.bak @@ -0,0 +1,129 @@ +/* + 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/features/fault_models/composition/smooth.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace FaultModels + { + namespace Composition + { + Smooth::Smooth(WorldBuilder::World *world_) + : + min_distance(NaN::DSNAN), + side_distance(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "smooth"; + } + + Smooth::~Smooth() + = default; + + void + Smooth::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), "Compositional model object"); + + prm.declare_entry("min distance fault center", Types::Double(0), + "The distance in meters from which the composition of this feature is present."); + prm.declare_entry("side distance fault center", Types::Double(std::numeric_limits::max()), + "The distance over which the composition is reduced from 1 to 0."); + prm.declare_entry("center fractions", Types::Array(Types::Double(1.0),1), + "The composition fraction at the center of the fault."); + prm.declare_entry("side fractions", Types::Array(Types::Double(0.0),1), + "The composition fraction at the sides of this feature."); + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the labels of the composition which are present there."); + prm.declare_entry("operation", Types::String("replace", std::vector {"replace", "replace defined only", "add", "subtract"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value. Replacing implies that all compositions not " + "explicitly defined are set to zero. To only replace the defined compositions use the replace only defined option."); + } + + void + Smooth::parse_entries(Parameters &prm) + { + min_distance = prm.get("min distance fault center"); + side_distance = prm.get("side distance fault center"); + WBAssert(side_distance >= min_distance, "distance at the side needs to be larger or equal than the min distance."); + operation = string_operations_to_enum(prm.get("operation")); + center_fraction = prm.get_vector("center fractions"); + side_fraction = prm.get_vector("side fractions"); + compositions = prm.get_vector("compositions"); + } + + + double + Smooth::get_composition( const Point<3> & /*position*/, + const double /*depth*/, + const unsigned int composition_number, + double composition_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters & /*additional_parameters*/) const + { + double composition = composition_; + + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + + // Hyperbolic tangent goes from 0 to 1 over approximately x=(0, 2) without any arguments. The function is written + // so that the composition returned 1 to 0 over the side_distance on either sides. + composition = (center_fraction[i] - side_fraction[i]) * ( 1 - std::tanh(10 * (distance_from_planes.distance_from_plane + - side_distance/2)/side_distance ) )/2 ; + + return apply_operation(operation,composition_,composition); + } + } + + if (operation == Operations::REPLACE) + return 0.0; + + return composition; + } + + WB_REGISTER_FEATURE_FAULT_COMPOSITION_MODEL (Smooth, smooth) + } // namespace Composition + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/fault_models/composition/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/fault_models/composition/uniform.cc.bak new file mode 100644 index 00000000000..c125eb39440 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/fault_models/composition/uniform.cc.bak @@ -0,0 +1,124 @@ +/* + 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/features/fault_models/composition/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/utilities.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + using namespace FeatureUtilities; + namespace FaultModels + { + namespace Composition + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform compositional model. Sets constant compositional field."); + + // Declare entries of this plugin + prm.declare_entry("min distance fault center", Types::Double(0), + "The distance in meters from which the composition of this feature is present."); + prm.declare_entry("max distance fault center", Types::Double(std::numeric_limits::max()), + "The distance in meters to which the composition of this feature is present."); + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the labels of the composition which are present there."); + prm.declare_entry("fractions", Types::Array(Types::Double(1.0),1), + "TA list of compositional fractions corresponding to the compositions list."); + prm.declare_entry("operation", Types::String("replace", std::vector {"replace", "replace defined only", "add", "subtract"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value. Replacing implies that all compositions not " + "explicitly defined are set to zero. To only replace the defined compositions use the replace only defined option."); + + } + + void + Uniform::parse_entries(Parameters &prm) + { + min_depth = prm.get("min distance fault center"); + max_depth = prm.get("max distance fault center"); + compositions = prm.get_vector("compositions"); + fractions = prm.get_vector("fractions"); + operation = string_operations_to_enum(prm.get("operation")); + + WBAssertThrow(compositions.size() == fractions.size(), + "There are not the same amount of compositions and fractions."); + } + + + double + Uniform::get_composition(const Point<3> & /*position_in_cartesian_coordinates*/, + const double /*depth*/, + const unsigned int composition_number, + double composition, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_plane, + const AdditionalParameters & /*additional_parameters*/) const + { + if (std::fabs(distance_from_plane.distance_from_plane) <= max_depth && std::fabs(distance_from_plane.distance_from_plane) >= min_depth) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + return apply_operation(operation,composition,fractions[i]); + } + } + + if (operation == Operations::REPLACE) + return 0.0; + } + return composition; + } + WB_REGISTER_FEATURE_FAULT_COMPOSITION_MODEL(Uniform, uniform) + } // namespace Composition + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/fault_models/grains/interface.cc.bak b/contrib/world_builder/source/world_builder/features/fault_models/grains/interface.cc.bak new file mode 100644 index 00000000000..12de398c263 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/fault_models/grains/interface.cc.bak @@ -0,0 +1,111 @@ +/* + 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/features/fault_models/grains/interface.h" + +#include + +#include "world_builder/types/object.h" +#include "world_builder/types/string.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace FaultModels + { + namespace Grains + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + 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()) + { + // prevent infinite recursion + if (it.first != parent_name) + { + prm.enter_subsection("oneOf"); + { + prm.enter_subsection(std::to_string(counter)); + { + prm.enter_subsection("properties"); + { + prm.declare_entry("", Types::Object(required_entries), "grains object"); + + prm.declare_entry("model", Types::String("",it.first), + "The name of the grains model."); + + 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 Grains + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/fault_models/grains/random_uniform_distribution.cc.bak b/contrib/world_builder/source/world_builder/features/fault_models/grains/random_uniform_distribution.cc.bak new file mode 100644 index 00000000000..06ccaebcad0 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/fault_models/grains/random_uniform_distribution.cc.bak @@ -0,0 +1,217 @@ +/* + 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/features/fault_models/grains/random_uniform_distribution.h" + +#include + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace FaultModels + { + namespace Grains + { + RandomUniformDistribution::RandomUniformDistribution(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "random uniform distribution"; + } + + RandomUniformDistribution::~RandomUniformDistribution() + = default; + + void + RandomUniformDistribution::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Random uniform distribution grains model. The size of the grains can be independently set " + "to a single value or to a random distribution."); + + // Declare entries of this plugin + prm.declare_entry("min distance fault center", Types::Double(0), + "The distance from the fault center in meters from which the composition of this feature is present."); + prm.declare_entry("max distance fault center", Types::Double(std::numeric_limits::max()), + "The distance from the fault in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be randomized between 0 and 1."); + + prm.declare_entry("normalize grain sizes", + Types::Array(Types::Bool(true),0), + "A list of whether the sizes of the grains should be normalized or not. If normalized, the total of the grains of a composition will be equal to 1."); + + + + } + + void + RandomUniformDistribution::parse_entries(Parameters &prm) + { + min_depth = prm.get("min distance fault center"); + max_depth = prm.get("max distance fault center"); + compositions = prm.get_vector("compositions"); + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + normalize_grain_sizes = prm.get_vector("normalize grain sizes"); + + + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == normalize_grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and normalize_grain_sizes (" << normalize_grain_sizes.size() << ")."); + } + + + WorldBuilder::grains + RandomUniformDistribution::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const double /*depth*/, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters & /*additional_parameters*/) const + { + WorldBuilder::grains grains_local = grains_; + if (std::fabs(distance_from_planes.distance_from_plane) <= max_depth && std::fabs(distance_from_planes.distance_from_plane) >= min_depth) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::uniform_real_distribution<> dist(0.0,1.0); + for (auto &&it_rotation_matrices : grains_local.rotation_matrices) + { + // set a uniform random a_cosine_matrix per grain + // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120). + // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c + // and is licenend accourding to this website with the following licence: + // + // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and + // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit + // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems + // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, + // don't be a jerk, and remember that anything free comes with no guarantee."" + // + // The book saids in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in + // the public domain, and is yours to study, modify, and use." + + // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2. + const double one = dist(world->get_random_number_engine()); + const double two = dist(world->get_random_number_engine()); + const double three = dist(world->get_random_number_engine()); + + const double theta = 2.0 * Consts::PI * one; // Rotation about the pole (Z) + const double phi = 2.0 * Consts::PI * two; // For direction of pole deflection. + const double z = 2.0* three; //For magnitude of pole deflection. + + // Compute a vector V used for distributing points over the sphere + // via the reflection I - V Transpose(V). This formulation of V + // will guarantee that if x[1] and x[2] are uniformly distributed, + // the reflected points will be uniform on the sphere. Note that V + // has length sqrt(2) to eliminate the 2 in the Householder matrix. + + const double r = std::sqrt( z ); + const double Vx = std::sin( phi ) * r; + const double Vy = std::cos( phi ) * r; + const double Vz = std::sqrt( 2.F - z ); + + // Compute the row vector S = Transpose(V) * R, where R is a simple + // rotation by theta about the z-axis. No need to compute Sz since + // it's just Vz. + + const double st = std::sin( theta ); + const double ct = std::cos( theta ); + const double Sx = Vx * ct - Vy * st; + const double Sy = Vx * st + Vy * ct; + + // Construct the rotation matrix ( V Transpose(V) - I ) R, which + // is equivalent to V S - R. + + it_rotation_matrices[0][0] = Vx * Sx - ct; + it_rotation_matrices[0][1] = Vx * Sy - st; + it_rotation_matrices[0][2] = Vx * Vz; + + it_rotation_matrices[1][0] = Vy * Sx + st; + it_rotation_matrices[1][1] = Vy * Sy - ct; + it_rotation_matrices[1][2] = Vy * Vz; + + it_rotation_matrices[2][0] = Vz * Sx; + it_rotation_matrices[2][1] = Vz * Sy; + it_rotation_matrices[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0 + } + + double total_size = 0; + for (auto &&it_sizes : grains_local.sizes) + { + it_sizes = grain_sizes[i] < 0 ? dist(world->get_random_number_engine()) : grain_sizes[i]; + total_size += it_sizes; + } + + if (normalize_grain_sizes[i]) + { + const double one_over_total_size = 1/total_size; + std::transform(grains_local.sizes.begin(), grains_local.sizes.end(), grains_local.sizes.begin(), + [one_over_total_size](double sizes) -> double { return sizes *one_over_total_size; }); + } + + return grains_local; + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_FAULT_GRAINS_MODEL(RandomUniformDistribution, random uniform distribution) + } // namespace Grains + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/fault_models/grains/random_uniform_distribution_deflected.cc.bak b/contrib/world_builder/source/world_builder/features/fault_models/grains/random_uniform_distribution_deflected.cc.bak new file mode 100644 index 00000000000..1f970ee202e --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/fault_models/grains/random_uniform_distribution_deflected.cc.bak @@ -0,0 +1,223 @@ +/* + 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/features/fault_models/grains/random_uniform_distribution_deflected.h" + +#include + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace FaultModels + { + namespace Grains + { + RandomUniformDistributionDeflected::RandomUniformDistributionDeflected(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "random uniform distribution deflected"; + } + + RandomUniformDistributionDeflected::~RandomUniformDistributionDeflected() + = default; + + void + RandomUniformDistributionDeflected::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Random uniform distribution grains model. The size of the grains can be independently set " + "to a single value or to a random distribution."); + + // Declare entries of this plugin + prm.declare_entry("min distance fault center", Types::Double(0), + "The distance from the fault center in meters from which the composition of this feature is present."); + prm.declare_entry("max distance fault center", Types::Double(std::numeric_limits::max()), + "The distance from the fault in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be randomized between 0 and 1."); + + prm.declare_entry("normalize grain sizes", + Types::Array(Types::Bool(true),0), + "A list of whether the sizes of the grains should be normalized or not. If normalized, the total of the grains of a composition will be equal to 1."); + + prm.declare_entry("deflections", + Types::Array(Types::Double(1),0), + "A list of the deflections of all of the grains in each composition between 0 and 1."); + + + + } + + void + RandomUniformDistributionDeflected::parse_entries(Parameters &prm) + { + min_depth = prm.get("min distance fault center"); + max_depth = prm.get("max distance fault center"); + compositions = prm.get_vector("compositions"); + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + normalize_grain_sizes = prm.get_vector("normalize grain sizes"); + deflections = prm.get_vector("deflections"); + + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == normalize_grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and normalize_grain_sizes (" << normalize_grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == deflections.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and deflections (" << deflections.size() << ")."); + } + + + WorldBuilder::grains + RandomUniformDistributionDeflected::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const double /*depth*/, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters & /*additional_parameters*/) const + { + WorldBuilder::grains grains_local = grains_; + if (std::fabs(distance_from_planes.distance_from_plane) <= max_depth && std::fabs(distance_from_planes.distance_from_plane) >= min_depth) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::uniform_real_distribution<> dist(0.0,1.0); + for (auto &&it_rotation_matrices : grains_local.rotation_matrices) + { + // set a uniform random a_cosine_matrix per grain + // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120). + // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c + // and is licenend accourding to this website with the following licence: + // + // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and + // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit + // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems + // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, + // don't be a jerk, and remember that anything free comes with no guarantee."" + // + // The book saids in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in + // the public domain, and is yours to study, modify, and use." + + // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2. + const double one = dist(world->get_random_number_engine()); + const double two = dist(world->get_random_number_engine()); + const double three = dist(world->get_random_number_engine()); + + const double theta = 2.0 * Consts::PI * one * deflections[i]; // Rotation about the pole (Z). + const double phi = 2.0 * Consts::PI * two; // For direction of pole deflection. + const double z = 2.0* three * deflections[i]; //For magnitude of pole deflection. + + // Compute a vector V used for distributing points over the sphere + // via the reflection I - V Transpose(V). This formulation of V + // will guarantee that if x[1] and x[2] are uniformly distributed, + // the reflected points will be uniform on the sphere. Note that V + // has length sqrt(2) to eliminate the 2 in the Householder matrix. + + const double r = std::sqrt( z ); + const double Vx = std::sin( phi ) * r; + const double Vy = std::cos( phi ) * r; + const double Vz = std::sqrt( 2.F - z ); + + // Compute the row vector S = Transpose(V) * R, where R is a simple + // rotation by theta about the z-axis. No need to compute Sz since + // it's just Vz. + + const double st = std::sin( theta ); + const double ct = std::cos( theta ); + const double Sx = Vx * ct - Vy * st; + const double Sy = Vx * st + Vy * ct; + + // Construct the rotation matrix ( V Transpose(V) - I ) R, which + // is equivalent to V S - R. + + it_rotation_matrices[0][0] = Vx * Sx - ct; + it_rotation_matrices[0][1] = Vx * Sy - st; + it_rotation_matrices[0][2] = Vx * Vz; + + it_rotation_matrices[1][0] = Vy * Sx + st; + it_rotation_matrices[1][1] = Vy * Sy - ct; + it_rotation_matrices[1][2] = Vy * Vz; + + it_rotation_matrices[2][0] = Vz * Sx; + it_rotation_matrices[2][1] = Vz * Sy; + it_rotation_matrices[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0 + } + + double total_size = 0; + for (auto &&it_sizes : grains_local.sizes) + { + it_sizes = grain_sizes[i] < 0 ? dist(world->get_random_number_engine()) : grain_sizes[i]; + total_size += it_sizes; + } + + if (normalize_grain_sizes[i]) + { + const double one_over_total_size = 1/total_size; + std::transform(grains_local.sizes.begin(), grains_local.sizes.end(), grains_local.sizes.begin(), + [one_over_total_size](double sizes) -> double { return sizes *one_over_total_size; }); + } + + return grains_local; + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_FAULT_GRAINS_MODEL(RandomUniformDistributionDeflected, random uniform distribution deflected) + } // namespace Grains + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/fault_models/grains/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/fault_models/grains/uniform.cc.bak new file mode 100644 index 00000000000..d1449f81bb9 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/fault_models/grains/uniform.cc.bak @@ -0,0 +1,169 @@ +/* + 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/features/fault_models/grains/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/utilities.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace FaultModels + { + namespace Grains + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform grains model. All grains start exactly the same."); + + // Declare entries of this plugin + prm.declare_entry("min distance fault center", Types::Double(0), + "The distance from the fault center in meters from which the composition of this feature is present."); + prm.declare_entry("max distance fault center", Types::Double(std::numeric_limits::max()), + "The distance from the fault in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("rotation matrices", Types::Array(Types::Array(Types::Array(Types::Double(0),3,3),3,3),0), + "A list with the labels of the grains which are present there for each compositions."); + + prm.declare_entry("Euler angles z-x-z", Types::Array(Types::Array(Types::Double(0),3,3),0), + "A list with the z-x-z Euler angles of the grains which are present there for each compositions."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(-1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be set so that the total is equal to 1."); + + + } + + void + Uniform::parse_entries(Parameters &prm) + { + min_depth = prm.get("min distance fault center"); + max_depth = prm.get("max distance fault center"); + compositions = prm.get_vector("compositions"); + + const bool set_euler_angles = prm.check_entry("Euler angles z-x-z"); + const bool set_rotation_matrices = prm.check_entry("rotation matrices"); + + WBAssertThrow(!(set_euler_angles == true && set_rotation_matrices == true), + "Only Euler angles or Rotation matrices may be set, but both are set for " << prm.get_full_json_path()); + + + WBAssertThrow(!(set_euler_angles == false && set_rotation_matrices == false), + "Euler angles or Rotation matrices have to be set, but neither are set for " << prm.get_full_json_path()); + + if (set_euler_angles) + { + std::vector > euler_angles_vector = prm.get_vector >("Euler angles z-x-z"); + rotation_matrices.resize(euler_angles_vector.size()); + for (size_t i = 0; i,3> >("rotation matrices"); + } + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + + + WBAssertThrow(compositions.size() == rotation_matrices.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and rotation_matrices (" << rotation_matrices.size() << ")."); + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + } + + + WorldBuilder::grains + Uniform::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const double /*depth*/, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters & /*additional_parameters*/) const + { + WorldBuilder::grains grains_local = grains_; + if (std::fabs(distance_from_planes.distance_from_plane) <= max_depth && std::fabs(distance_from_planes.distance_from_plane) >= min_depth) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::fill(grains_local.rotation_matrices.begin(),grains_local.rotation_matrices.end(),rotation_matrices[i]); + + const double size = grain_sizes[i] < 0 ? 1.0/static_cast(grains_local.sizes.size()) : grain_sizes[i]; + std::fill(grains_local.sizes.begin(),grains_local.sizes.end(),size); + + return grains_local; + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_FAULT_GRAINS_MODEL(Uniform, uniform) + } // namespace Grains + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/fault_models/temperature/adiabatic.cc.bak b/contrib/world_builder/source/world_builder/features/fault_models/temperature/adiabatic.cc.bak new file mode 100644 index 00000000000..64b98312018 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/fault_models/temperature/adiabatic.cc.bak @@ -0,0 +1,164 @@ +/* + 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/features/fault_models/temperature/adiabatic.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace FaultModels + { + namespace Temperature + { + Adiabatic::Adiabatic(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + potential_mantle_temperature(NaN::DSNAN), + thermal_expansion_coefficient(NaN::DSNAN), + specific_heat(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "adiabatic"; + } + + Adiabatic::~Adiabatic() + = default; + + void + Adiabatic::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + prm.declare_entry("", Types::Object(), + "Adiabatic temperature model. Uses global values by default."); + + // Declare entries of this plugin + prm.declare_entry("min distance fault center", Types::Double(0), + "todo The depth in meters from which the composition of this feature is present."); + + prm.declare_entry("max distance fault center", Types::Double(std::numeric_limits::max()), + "todo The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("potential mantle temperature", Types::Double(-1), + "The potential temperature of the mantle at the surface in Kelvin. " + "If the value is lower then zero, the global value is used."); + + prm.declare_entry("thermal expansion coefficient", Types::Double(-1), + "The thermal expansion coefficient in $K^{-1}$. " + "If the value is lower then zero, the global value is used."); + + prm.declare_entry("specific heat", Types::Double(-1), + "The specific heat in $J kg^{-1} K^{-1}$. " + "If the value is lower then zero, the global value is used."); + + } + + void + Adiabatic::parse_entries(Parameters &prm) + { + + min_depth = prm.get("min distance fault center"); + max_depth = prm.get("max distance fault center"); + operation = string_operations_to_enum(prm.get("operation")); + + potential_mantle_temperature = prm.get("potential mantle temperature"); + if (potential_mantle_temperature < 0) + potential_mantle_temperature = this->world->potential_mantle_temperature; + + + thermal_expansion_coefficient = prm.get("thermal expansion coefficient"); + if (thermal_expansion_coefficient < 0) + thermal_expansion_coefficient = this->world->thermal_expansion_coefficient; + + specific_heat = prm.get("specific heat"); + if (specific_heat < 0) + specific_heat = this->world->specific_heat; + + // Some assertions in debug mode can't hurt and have helped before. + WBAssert(!std::isnan(potential_mantle_temperature), + "potential_mantle_temperature is not a number: " << potential_mantle_temperature << '.'); + WBAssert(std::isfinite(potential_mantle_temperature), + "potential_mantle_temperature is not a finite: " << potential_mantle_temperature << '.'); + + WBAssert(!std::isnan(thermal_expansion_coefficient), + "thermal_expansion_coefficient is not a number: " << thermal_expansion_coefficient << '.'); + WBAssert(std::isfinite(thermal_expansion_coefficient), + "thermal_expansion_coefficient is not a finite: " << thermal_expansion_coefficient << '.'); + + WBAssert(!std::isnan(specific_heat), + "specific_heat is not a number: " << specific_heat << '.'); + WBAssert(std::isfinite(thermal_expansion_coefficient), + "specific_heat is not a finite: " << specific_heat << '.'); + + } + + + double + Adiabatic::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const double depth, + const double gravity_norm, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes & /*distance_from_planes*/, + const AdditionalParameters & /*additional_parameters*/) const + { + + if (depth <= max_depth && depth >= min_depth) + { + const double adabatic_temperature = potential_mantle_temperature * + std::exp(((thermal_expansion_coefficient * gravity_norm) / + specific_heat) * depth); + + + WBAssert(!std::isnan(adabatic_temperature), + "adabatic_temperature is not a number: " << adabatic_temperature << ". " + <<"Parameters: potential_mantle_temperature = " << potential_mantle_temperature + <<", thermal_expansion_coefficient = " << thermal_expansion_coefficient + << ", gravity_norm = " << gravity_norm + << ", specific_heat = " << specific_heat + << ", depth = " << depth); + + WBAssert(std::isfinite(adabatic_temperature), + "adabatic_temperature is not a finite: " << adabatic_temperature << '.'); + + return apply_operation(operation,temperature_,adabatic_temperature); + } + + return temperature_; + } + + WB_REGISTER_FEATURE_FAULT_TEMPERATURE_MODEL(Adiabatic, adiabatic) + } // namespace Temperature + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/fault_models/temperature/interface.cc.bak b/contrib/world_builder/source/world_builder/features/fault_models/temperature/interface.cc.bak new file mode 100644 index 00000000000..fe7d7b00284 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/fault_models/temperature/interface.cc.bak @@ -0,0 +1,95 @@ +/* + 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/features/fault_models/temperature/interface.h" + +#include + +#include "world_builder/types/string.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace FaultModels + { + namespace Temperature + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + // The type needs to be stored in a separate value, otherwise there are memory issues + const Types::String type = Types::String("replace", std::vector {"replace", "add", "subtract"}); + + prm.declare_model_entries("temperature",parent_name, get_declare_map(),required_entries, + { + std::tuple + { + "operation", type, + "Whether the value should replace any value previously defined at this location (replace), " + "add the value to the previously define value (add) or subtract the value to the previously " + "define value (subtract)." + } + }); + } + + + 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 Temperature + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/fault_models/temperature/linear.cc.bak b/contrib/world_builder/source/world_builder/features/fault_models/temperature/linear.cc.bak new file mode 100644 index 00000000000..16a1f2b03d7 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/fault_models/temperature/linear.cc.bak @@ -0,0 +1,140 @@ +/* + 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/features/fault_models/temperature/linear.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace FaultModels + { + namespace Temperature + { + Linear::Linear(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + center_temperature(NaN::DSNAN), + side_temperature(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "linear"; + } + + Linear::~Linear() + = default; + + void + Linear::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `max distance fault` center to the required parameters. + prm.declare_entry("", Types::Object({"max distance fault center"}), + "Linear temperature model. Can be set to use an adiabatic temperature at the boundaries."); + + // Declare entries of this plugin + prm.declare_entry("min distance fault center", Types::Double(0), + "The minimum distance to the center of the fault. This determines where the linear temperature starts."); + + prm.declare_entry("max distance fault center", Types::Double(std::numeric_limits::max()), + "The minimum distance to the center of the fault. This determines where the linear temperature end."); + + prm.declare_entry("center temperature", Types::Double(293.15), + "The temperature at the center of this feature in degree Kelvin." + "If the value is below zero, the an adiabatic temperature is used."); + + prm.declare_entry("side temperature", Types::Double(-1), + "The temperature at the sides of this feature in degree Kelvin. " + "If the value is below zero, an adiabatic temperature is used."); + + } + + void + Linear::parse_entries(Parameters &prm) + { + min_depth = prm.get("min distance fault center"); + max_depth = prm.get("max distance fault center"); + WBAssert(max_depth >= min_depth, "max depth needs to be larger or equal to min depth."); + operation = string_operations_to_enum(prm.get("operation")); + center_temperature = prm.get("center temperature"); + side_temperature = prm.get("side temperature"); + } + + + double + Linear::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const double /*depth*/, + const double gravity_norm, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters & /*additional_parameters*/) const + { + + if (std::fabs(distance_from_planes.distance_from_plane) <= max_depth && std::fabs(distance_from_planes.distance_from_plane) >= min_depth) + { + const double min_depth_local = min_depth; + const double max_depth_local = max_depth; + + double center_temperature_local = center_temperature; + if (center_temperature_local < 0) + { + center_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient * gravity_norm) / + this->world->specific_heat) * min_depth_local); + } + + double side_temperature_local = side_temperature; + if (side_temperature_local < 0) + { + side_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient * gravity_norm) / + this->world->specific_heat) * max_depth_local); + } + + const double new_temperature = center_temperature_local + + (std::fabs(distance_from_planes.distance_from_plane) - min_depth_local) * + ((side_temperature_local - center_temperature_local) / (max_depth_local - min_depth_local)); + + return apply_operation(operation,temperature_,new_temperature); + + } + + return temperature_; + } + + WB_REGISTER_FEATURE_FAULT_TEMPERATURE_MODEL(Linear, linear) + } // namespace Temperature + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/fault_models/temperature/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/fault_models/temperature/uniform.cc.bak new file mode 100644 index 00000000000..fdddb360d1a --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/fault_models/temperature/uniform.cc.bak @@ -0,0 +1,107 @@ +/* + 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/features/fault_models/temperature/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/utilities.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace FaultModels + { + namespace Temperature + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + temperature(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `temperature` and to the required parameters. + prm.declare_entry("", Types::Object({"temperature"}), + "Uniform temperature model. Set the temperature to a constant value."); + + // Declare entries of this plugin + prm.declare_entry("min distance fault center", Types::Double(0), + "The distance in meters from which the composition of this feature is present."); + + prm.declare_entry("max distance fault center", Types::Double(std::numeric_limits::max()), + "The distance in meters to which the composition of this feature is present."); + + prm.declare_entry("temperature", Types::Double(293.15), + "The temperature in degree Kelvin which this feature should have"); + + } + + void + Uniform::parse_entries(Parameters &prm) + { + min_depth = prm.get("min distance fault center"); + max_depth = prm.get("max distance fault center"); + operation = string_operations_to_enum(prm.get("operation")); + temperature = prm.get("temperature"); + } + + + double + Uniform::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const double /*depth*/, + const double /*gravity*/, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_plane, + const AdditionalParameters & /*additional_parameters*/) const + { + + if (std::fabs(distance_from_plane.distance_from_plane) <= max_depth && std::fabs(distance_from_plane.distance_from_plane) >= min_depth) + { + return apply_operation(operation,temperature_,temperature); + } + return temperature_; + } + + WB_REGISTER_FEATURE_FAULT_TEMPERATURE_MODEL(Uniform, uniform) + } // namespace Temperature + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/feature_utilities.cc.bak b/contrib/world_builder/source/world_builder/features/feature_utilities.cc.bak new file mode 100644 index 00000000000..4bbd05f3fa8 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/feature_utilities.cc.bak @@ -0,0 +1,56 @@ +/* + 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/features/feature_utilities.h" + + +namespace WorldBuilder +{ + namespace Features + { + namespace FeatureUtilities + { + Operations + string_operations_to_enum(const std::string &operation) + { + if (operation == "add") return Operations::ADD; + if (operation == "subtract") return Operations::SUBTRACT; + if (operation == "replace defined only") return Operations::REPLACE_DEFINED_ONLY; + + WBAssert(operation == "replace", "Could not find operation: " << operation << '.'); + return Operations::REPLACE; + } + + size_t + add_vector_unique(std::vector &vector,const std::string &add_string) + { + for (size_t i = 0; i < vector.size(); ++i) + { + if (vector[i] == add_string) + { + return i; + } + } + + vector.push_back(add_string); + return vector.size()-1; + } + } // namespace FeatureUtilities + } // namespace Features +} // namespace WorldBuilder diff --git a/contrib/world_builder/source/world_builder/features/interface.cc.bak b/contrib/world_builder/source/world_builder/features/interface.cc.bak new file mode 100644 index 00000000000..0678ad0635e --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/interface.cc.bak @@ -0,0 +1,209 @@ +/* + 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/features/interface.h" + +#include + +#include "world_builder/types/array.h" +#include "world_builder/types/object.h" +#include "world_builder/types/point.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace Internal + { + + + + /** + * A function to turn strings into interpolation type enums. + */ + static InterpolationType string_to_interpolation_type (const std::string &string) + { + if (string == "continuous monotone spline") + { + return InterpolationType::ContinuousMonotoneSpline; + } + + WBAssertThrow(false, + "You provided an interpolation type which is not supported: " << string + << "This may be due to all options besides continuous monotone spline have been " + << "removed since version 0.5. It is best to remove the interpolation variable " + << "from you input file as it may be removed in future versions."); + + return InterpolationType::Invalid; + } + } // namespace Internal + + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, const std::string &parent_name, const std::vector &required_entries) + { + + { + using namespace rapidjson; + Document &declarations = prm.declarations; + + prm.enter_subsection("defaultSnippets"); + const std::string path = prm.get_full_json_path(); + + unsigned int idx = 0; + for (auto &it : get_snippet_map()) + { + std::string item = path + "/"+std::to_string(idx); + + Pointer((item).c_str()).Set(declarations, "object"); + Pointer((item+"/label").c_str()).Set(declarations,("add a '" + it.first + "'").c_str()); + prm.enter_subsection(std::to_string(idx).c_str()); + it.second(prm); + prm.leave_subsection(); + + ++idx; + } + + prm.leave_subsection(); + } + + 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), "feature object"); + + prm.declare_entry("model", Types::String("",it.first), + "The model name of the feature determining its type."); + prm.declare_entry("name", Types::String(""), + "The name which the user has given to the feature. " + "This is mostly used for documentation purposes, and should in most cases be unique, " + "although this is not enforced."); + prm.declare_entry("tag", Types::String(""), + "A tag which can be given to a feature. This is meant to categorize different features. " + "If the tag is not provided or empty, it is set to the model name."); + prm.declare_entry("coordinates", Types::Array(Types::Point<2>(), 1), + "An array of 2d Points representing an array of coordinates where the feature is located."); + + prm.declare_entry("interpolation",Types::String("global"), + "What type of interpolation should be used to enforce the minimum points per " + "distance parameter. Options are 'global' and " + "'continuous monotone spline' interpolation. If this " + "value is set to global, the global value for interpolation is used. " + "This option is deprecated and will be removed in a future release."); + WBAssert(it.second != NULL, "No declare entries given."); + it.second(prm, parent_name, {}); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + counter++; + + } + } + + + void + Interface::get_coordinates(const std::string & /*unused*/, + Parameters &prm, + const CoordinateSystem coordinate_system) + { + coordinates = prm.get_vector >("coordinates"); + if (coordinate_system == CoordinateSystem::spherical) + std::transform(coordinates.begin(),coordinates.end(), coordinates.begin(), + [](const WorldBuilder::Point<2> &p) -> WorldBuilder::Point<2> { return p *Consts::PI / 180.0;}); + + + // If global is given, we use the global interpolation setting, otherwise use the provided value. + const std::string interpolation_type_string = prm.get("interpolation") == "global" ? this->world->interpolation : prm.get("interpolation"); + interpolation_type = WorldBuilder::Features::Internal::string_to_interpolation_type(interpolation_type_string); + + original_number_of_coordinates = coordinates.size(); + + WBAssert(interpolation_type == WorldBuilder::Utilities::InterpolationType::Linear || + interpolation_type == WorldBuilder::Utilities::InterpolationType::MonotoneSpline || + interpolation_type == WorldBuilder::Utilities::InterpolationType::ContinuousMonotoneSpline, + "For interpolation, linear and monotone spline are the only allowed values. " + << "You provided " << interpolation_type_string << '.'); + + bezier_curve = Objects::BezierCurve(coordinates); + + } + + + void + Interface::registerType(const std::string &name, + void ( *declare_entries)(Parameters &, const std::string &,const std::vector &), + void ( *make_snippet)(Parameters &), + ObjectFactory *factory) + { + get_factory_map()[name] = factory; + get_declare_map()[name] = declare_entries; + get_snippet_map()[name] = make_snippet; + } + + 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); + } + + Objects::PlaneDistances + Interface::distance_to_feature_plane(const Point<3> & /*unused*/, + const Objects::NaturalCoordinate & /*unused*/, + const double /*unused*/) const + { + WBAssertThrow(false, "The distance_to_feature_plane is not yet implemented for the desinated object"); + } + + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/mantle_layer.cc.bak b/contrib/world_builder/source/world_builder/features/mantle_layer.cc.bak new file mode 100644 index 00000000000..7e66108db0d --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/mantle_layer.cc.bak @@ -0,0 +1,264 @@ +/* + 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/features/mantle_layer.h" + + +#include "world_builder/features/mantle_layer_models/composition/interface.h" +#include "world_builder/features/mantle_layer_models/grains/interface.h" +#include "world_builder/features/mantle_layer_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/plugin_system.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + MantleLayer::MantleLayer(WorldBuilder::World *world_) + { + this->world = world_; + this->name = "mantle layer"; + } + + MantleLayer::~MantleLayer() + = default; + + + + void MantleLayer::make_snippet(Parameters &prm) + { + using namespace rapidjson; + Document &declarations = prm.declarations; + + const std::string path = prm.get_full_json_path(); + + Pointer((path + "/body").c_str()).Set(declarations,"object"); + Pointer((path + "/body/model").c_str()).Set(declarations,"mantle layer"); + Pointer((path + "/body/name").c_str()).Set(declarations,"${1:My Mantle Layer}"); + Pointer((path + "/body/coordinates").c_str()).Create(declarations).SetArray(); + Pointer((path + "/body/temperature models").c_str()).Create(declarations).SetArray(); + Pointer((path + "/body/composition models").c_str()).Create(declarations).SetArray(); + } + + + + void + MantleLayer::declare_entries(Parameters &prm, + const std::string &/*parent_name*/, + const std::vector &required_entries) + { + prm.declare_entry("", Types::Object(required_entries), "Mantle layer object. Requires properties `model` and `coordinates`."); + + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth from which this feature is present"); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth to which this feature is present"); + prm.declare_entry("temperature models", + Types::PluginSystem("", Features::MantleLayerModels::Temperature::Interface::declare_entries, {"model"}), + "A list of temperature models."); + prm.declare_entry("composition models", + Types::PluginSystem("", Features::MantleLayerModels::Composition::Interface::declare_entries, {"model"}), + "A list of composition models."); + prm.declare_entry("grains models", + Types::PluginSystem("", Features::MantleLayerModels::Grains::Interface::declare_entries, {"model"}), + "A list of grains models."); + } + + void + MantleLayer::parse_entries(Parameters &prm) + { + const CoordinateSystem coordinate_system = prm.coordinate_system->natural_coordinate_system(); + + this->name = prm.get("name"); + + std::string tag = prm.get("tag"); + if (tag == "") + { + tag = "mantle layer"; + } + this->tag_index = FeatureUtilities::add_vector_unique(this->world->feature_tags,tag); + + this->get_coordinates("coordinates", prm, coordinate_system); + + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + + + prm.get_unique_pointers("temperature models", temperature_models); + + prm.enter_subsection("temperature models"); + { + for (unsigned int i = 0; i < temperature_models.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + temperature_models[i]->parse_entries(prm,coordinates); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.get_unique_pointers("composition models", composition_models); + + prm.enter_subsection("composition models"); + { + for (unsigned int i = 0; i < composition_models.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + composition_models[i]->parse_entries(prm,coordinates); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.get_unique_pointers("grains models", grains_models); + + prm.enter_subsection("grains models"); + { + for (unsigned int i = 0; i < grains_models.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + grains_models[i]->parse_entries(prm,coordinates); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + } + + + void + MantleLayer::properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity_norm, + const std::vector &entry_in_output, + std::vector &output) const + { + if (depth <= max_depth && depth >= min_depth && + WorldBuilder::Utilities::polygon_contains_point(coordinates, Point<2>(position_in_natural_coordinates.get_surface_coordinates(), + world->parameters.coordinate_system->natural_coordinate_system()))) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i_property = 0; i_property < properties.size(); ++i_property) + { + switch (properties[i_property][0]) + { + case 1: // temperature + { + for (const auto &temperature_model: temperature_models) + { + output[entry_in_output[i_property]] = temperature_model->get_temperature(position_in_cartesian_coordinates, + position_in_natural_coordinates, + depth, + gravity_norm, + output[entry_in_output[i_property]], + min_depth_local, + max_depth_local); + + WBAssert(!std::isnan(output[entry_in_output[i_property]]), "Temperature is not a number: " << output[entry_in_output[i_property]] + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(output[entry_in_output[i_property]]), "Temperature is not a finite: " << output[entry_in_output[i_property]] + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + + } + break; + case 2: // composition + + for (const auto &composition_model: composition_models) + { + output[entry_in_output[i_property]] = composition_model->get_composition(position_in_cartesian_coordinates, + position_in_natural_coordinates, + depth, + properties[i_property][1], + output[entry_in_output[i_property]], + min_depth_local, + max_depth_local); + + WBAssert(!std::isnan(output[entry_in_output[i_property]]), "Composition is not a number: " << output[entry_in_output[i_property]] + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(output[entry_in_output[i_property]]), "Composition is not a finite: " << output[entry_in_output[i_property]] + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + + } + + break; + } + case 3: // grains + { + WorldBuilder::grains grains(output,properties[i_property][2],entry_in_output[i_property]); + for (const auto &grains_model: grains_models) + { + grains = grains_model->get_grains(position_in_cartesian_coordinates, + position_in_natural_coordinates, + depth, + properties[i_property][1], + grains, + min_depth_local, + max_depth_local); + + } + grains.unroll_into(output,entry_in_output[i_property]); + break; + } + case 4: + { + output[entry_in_output[i_property]] = static_cast(tag_index); + break; + } + break; + default: + { + WBAssertThrow(false, + "Internal error: Unimplemented property provided. " << + "Only temperature (1), composition (2), grains (3) or tag (4) are allowed. " + "Provided property number was: " << properties[i_property][0]); + } + } + } + } + } + } + + WB_REGISTER_FEATURE(MantleLayer, mantle layer) + + } // namespace Features +} // namespace WorldBuilder diff --git a/contrib/world_builder/source/world_builder/features/mantle_layer_models/composition/interface.cc.bak b/contrib/world_builder/source/world_builder/features/mantle_layer_models/composition/interface.cc.bak new file mode 100644 index 00000000000..0f626ab049e --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/mantle_layer_models/composition/interface.cc.bak @@ -0,0 +1,81 @@ +/* + 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/features/mantle_layer_models/composition/interface.h" + +#include + + +namespace WorldBuilder +{ + namespace Features + { + namespace MantleLayerModels + { + namespace Composition + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + prm.declare_model_entries("composition",parent_name, get_declare_map(),required_entries); + } + + + 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 Composition + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/mantle_layer_models/composition/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/mantle_layer_models/composition/uniform.cc.bak new file mode 100644 index 00000000000..a61230f5e12 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/mantle_layer_models/composition/uniform.cc.bak @@ -0,0 +1,131 @@ +/* + 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/features/mantle_layer_models/composition/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/utilities.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace MantleLayerModels + { + namespace Composition + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform compositional model. Sets constant compositional field."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the labels of the composition which are present there."); + prm.declare_entry("fractions", Types::Array(Types::Double(1.0),1), + "TA list of compositional fractions corresponding to the compositions list."); + prm.declare_entry("operation", Types::String("replace", std::vector {"replace", "replace defined only", "add", "subtract"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value. Replacing implies that all compositions not " + "explicitly defined are set to zero. To only replace the defined compositions use the replace only defined option."); + + } + + void + Uniform::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + compositions = prm.get_vector("compositions"); + fractions = prm.get_vector("fractions"); + operation = string_operations_to_enum(prm.get("operation")); + + WBAssertThrow(compositions.size() == fractions.size(), + "There are not the same amount of compositions and fractions."); + } + + + double + Uniform::get_composition(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + return apply_operation(operation,composition,fractions[i]); + } + } + + if (operation == Operations::REPLACE) + return 0.0; + } + } + return composition; + } + WB_REGISTER_FEATURE_MANTLE_LAYER_COMPOSITION_MODEL(Uniform, uniform) + } // namespace Composition + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/interface.cc.bak b/contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/interface.cc.bak new file mode 100644 index 00000000000..259b393aa45 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/interface.cc.bak @@ -0,0 +1,111 @@ +/* + 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/features/mantle_layer_models/grains/interface.h" + +#include + +#include "world_builder/types/object.h" +#include "world_builder/types/string.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace MantleLayerModels + { + namespace Grains + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + 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()) + { + // prevent infinite recursion + if (it.first != parent_name) + { + prm.enter_subsection("oneOf"); + { + prm.enter_subsection(std::to_string(counter)); + { + prm.enter_subsection("properties"); + { + prm.declare_entry("", Types::Object(required_entries), "grains object"); + + prm.declare_entry("model", Types::String("",it.first), + "The name of the grains model."); + + 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 Grains + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/random_uniform_distribution.cc.bak b/contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/random_uniform_distribution.cc.bak new file mode 100644 index 00000000000..9d75e3de185 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/random_uniform_distribution.cc.bak @@ -0,0 +1,224 @@ +/* + 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/features/mantle_layer_models/grains/random_uniform_distribution.h" + +#include + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace MantleLayerModels + { + namespace Grains + { + RandomUniformDistribution::RandomUniformDistribution(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "random uniform distribution"; + } + + RandomUniformDistribution::~RandomUniformDistribution() + = default; + + void + RandomUniformDistribution::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Random uniform distribution grains model. The size of the grains can be independently set " + "to a single value or to a random distribution."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be randomized between 0 and 1."); + + prm.declare_entry("normalize grain sizes", + Types::Array(Types::Bool(true),0), + "A list of whether the sizes of the grains should be normalized or not. If normalized, the total of the grains of a composition will be equal to 1."); + + + + } + + void + RandomUniformDistribution::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + compositions = prm.get_vector("compositions"); + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + normalize_grain_sizes = prm.get_vector("normalize grain sizes"); + + + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == normalize_grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and normalize_grain_sizes (" << normalize_grain_sizes.size() << ")."); + } + + + WorldBuilder::grains + RandomUniformDistribution::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + WorldBuilder::grains grains_local = grains_; + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::uniform_real_distribution<> dist(0.0,1.0); + for (auto &&it_rotation_matrices : grains_local.rotation_matrices) + { + // set a uniform random a_cosine_matrix per grain + // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120). + // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c + // and is licenend accourding to this website with the following licence: + // + // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and + // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit + // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems + // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, + // don't be a jerk, and remember that anything free comes with no guarantee."" + // + // The book saids in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in + // the public domain, and is yours to study, modify, and use." + + // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2. + const double one = dist(world->get_random_number_engine()); + const double two = dist(world->get_random_number_engine()); + const double three = dist(world->get_random_number_engine()); + + const double theta = 2.0 * Consts::PI * one; // Rotation about the pole (Z) + const double phi = 2.0 * Consts::PI * two; // For direction of pole deflection. + const double z = 2.0* three; //For magnitude of pole deflection. + + // Compute a vector V used for distributing points over the sphere + // via the reflection I - V Transpose(V). This formulation of V + // will guarantee that if x[1] and x[2] are uniformly distributed, + // the reflected points will be uniform on the sphere. Note that V + // has length sqrt(2) to eliminate the 2 in the Householder matrix. + + const double r = std::sqrt( z ); + const double Vx = std::sin( phi ) * r; + const double Vy = std::cos( phi ) * r; + const double Vz = std::sqrt( 2.F - z ); + + // Compute the row vector S = Transpose(V) * R, where R is a simple + // rotation by theta about the z-axis. No need to compute Sz since + // it's just Vz. + + const double st = std::sin( theta ); + const double ct = std::cos( theta ); + const double Sx = Vx * ct - Vy * st; + const double Sy = Vx * st + Vy * ct; + + // Construct the rotation matrix ( V Transpose(V) - I ) R, which + // is equivalent to V S - R. + + it_rotation_matrices[0][0] = Vx * Sx - ct; + it_rotation_matrices[0][1] = Vx * Sy - st; + it_rotation_matrices[0][2] = Vx * Vz; + + it_rotation_matrices[1][0] = Vy * Sx + st; + it_rotation_matrices[1][1] = Vy * Sy - ct; + it_rotation_matrices[1][2] = Vy * Vz; + + it_rotation_matrices[2][0] = Vz * Sx; + it_rotation_matrices[2][1] = Vz * Sy; + it_rotation_matrices[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0 + } + + double total_size = 0; + for (auto &&it_sizes : grains_local.sizes) + { + it_sizes = grain_sizes[i] < 0 ? dist(world->get_random_number_engine()) : grain_sizes[i]; + total_size += it_sizes; + } + + if (normalize_grain_sizes[i]) + { + const double one_over_total_size = 1/total_size; + std::transform(grains_local.sizes.begin(), grains_local.sizes.end(), grains_local.sizes.begin(), + [one_over_total_size](double sizes) -> double { return sizes *one_over_total_size; }); + } + + return grains_local; + } + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_MANTLE_LAYER_GRAINS_MODEL(RandomUniformDistribution, random uniform distribution) + } // namespace Grains + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/random_uniform_distribution_deflected.cc.bak b/contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/random_uniform_distribution_deflected.cc.bak new file mode 100644 index 00000000000..d3cf85005b2 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/random_uniform_distribution_deflected.cc.bak @@ -0,0 +1,231 @@ +/* + 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/features/mantle_layer_models/grains/random_uniform_distribution_deflected.h" + +#include + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace MantleLayerModels + { + namespace Grains + { + RandomUniformDistributionDeflected::RandomUniformDistributionDeflected(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "random uniform distribution deflected"; + } + + RandomUniformDistributionDeflected::~RandomUniformDistributionDeflected() + = default; + + void + RandomUniformDistributionDeflected::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Random uniform distribution grains model. The size of the grains can be independently set " + "to a single value or to a random distribution."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be randomized between 0 and 1."); + + prm.declare_entry("normalize grain sizes", + Types::Array(Types::Bool(true),0), + "A list of whether the sizes of the grains should be normalized or not. If normalized, the total of the grains of a composition will be equal to 1."); + + prm.declare_entry("deflections", + Types::Array(Types::Double(1),0), + "A list of the deflections of all of the grains in each composition between 0 and 1."); + + + + } + + void + RandomUniformDistributionDeflected::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + compositions = prm.get_vector("compositions"); + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + normalize_grain_sizes = prm.get_vector("normalize grain sizes"); + deflections = prm.get_vector("deflections"); + + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == normalize_grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and normalize_grain_sizes (" << normalize_grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == deflections.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and deflections (" << deflections.size() << ")."); + } + + + WorldBuilder::grains + RandomUniformDistributionDeflected::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + WorldBuilder::grains grains_local = grains_; + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::uniform_real_distribution<> dist(0.0,1.0); + for (auto &&it_rotation_matrices : grains_local.rotation_matrices) + { + // set a uniform random a_cosine_matrix per grain + // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120). + // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c + // and is licenend accourding to this website with the following licence: + // + // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and + // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit + // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems + // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, + // don't be a jerk, and remember that anything free comes with no guarantee."" + // + // The book saids in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in + // the public domain, and is yours to study, modify, and use." + + // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2. + const double one = dist(world->get_random_number_engine()); + const double two = dist(world->get_random_number_engine()); + const double three = dist(world->get_random_number_engine()); + + // the distribution is restricted by the deflection (between 0 and 1) + const double theta = 2.0 * Consts::PI * one * deflections[i]; // Rotation about the pole (Z) + const double phi = 2.0 * Consts::PI * two; // For direction of pole deflection. + const double z = 2.0* three * deflections[i]; //For magnitude of pole deflection. + + // Compute a vector V used for distributing points over the sphere + // via the reflection I - V Transpose(V). This formulation of V + // will guarantee that if x[1] and x[2] are uniformly distributed, + // the reflected points will be uniform on the sphere. Note that V + // has length sqrt(2) to eliminate the 2 in the Householder matrix. + + const double r = std::sqrt( z ); + const double Vx = std::sin( phi ) * r; + const double Vy = std::cos( phi ) * r; + const double Vz = std::sqrt( 2.F - z ); + + // Compute the row vector S = Transpose(V) * R, where R is a simple + // rotation by theta about the z-axis. No need to compute Sz since + // it's just Vz. + + const double st = std::sin( theta ); + const double ct = std::cos( theta ); + const double Sx = Vx * ct - Vy * st; + const double Sy = Vx * st + Vy * ct; + + // Construct the rotation matrix ( V Transpose(V) - I ) R, which + // is equivalent to V S - R. + + it_rotation_matrices[0][0] = Vx * Sx - ct; + it_rotation_matrices[0][1] = Vx * Sy - st; + it_rotation_matrices[0][2] = Vx * Vz; + + it_rotation_matrices[1][0] = Vy * Sx + st; + it_rotation_matrices[1][1] = Vy * Sy - ct; + it_rotation_matrices[1][2] = Vy * Vz; + + it_rotation_matrices[2][0] = Vz * Sx; + it_rotation_matrices[2][1] = Vz * Sy; + it_rotation_matrices[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0 + } + + double total_size = 0; + for (auto &&it_sizes : grains_local.sizes) + { + it_sizes = grain_sizes[i] < 0 ? dist(world->get_random_number_engine()) : grain_sizes[i]; + total_size += it_sizes; + } + + if (normalize_grain_sizes[i]) + { + const double one_over_total_size = 1/total_size; + std::transform(grains_local.sizes.begin(), grains_local.sizes.end(), grains_local.sizes.begin(), + [one_over_total_size](double sizes) -> double { return sizes *one_over_total_size; }); + } + + return grains_local; + } + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_MANTLE_LAYER_GRAINS_MODEL(RandomUniformDistributionDeflected, random uniform distribution deflected) + } // namespace Grains + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/uniform.cc.bak new file mode 100644 index 00000000000..dea13791d9e --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/mantle_layer_models/grains/uniform.cc.bak @@ -0,0 +1,176 @@ +/* + 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/features/mantle_layer_models/grains/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/utilities.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace MantleLayerModels + { + namespace Grains + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform grains model. All grains start exactly the same."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("rotation matrices", Types::Array(Types::Array(Types::Array(Types::Double(0),3,3),3,3),0), + "A list with the labels of the grains which are present there for each compositions."); + + prm.declare_entry("Euler angles z-x-z", Types::Array(Types::Array(Types::Double(0),3,3),0), + "A list with the z-x-z Euler angles of the grains which are present there for each compositions."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(-1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be set so that the total is equal to 1."); + + + } + + void + Uniform::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + compositions = prm.get_vector("compositions"); + + const bool set_euler_angles = prm.check_entry("Euler angles z-x-z"); + const bool set_rotation_matrices = prm.check_entry("rotation matrices"); + + WBAssertThrow(!(set_euler_angles == true && set_rotation_matrices == true), + "Only Euler angles or Rotation matrices may be set, but both are set for " << prm.get_full_json_path()); + + + WBAssertThrow(!(set_euler_angles == false && set_rotation_matrices == false), + "Euler angles or Rotation matrices have to be set, but neither are set for " << prm.get_full_json_path()); + + if (set_euler_angles) + { + std::vector > euler_angles_vector = prm.get_vector >("Euler angles z-x-z"); + rotation_matrices.resize(euler_angles_vector.size()); + for (size_t i = 0; i,3> >("rotation matrices"); + } + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + + + WBAssertThrow(compositions.size() == rotation_matrices.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and rotation_matrices (" << rotation_matrices.size() << ")."); + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + } + + + WorldBuilder::grains + Uniform::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + WorldBuilder::grains grains_local = grains_; + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::fill(grains_local.rotation_matrices.begin(),grains_local.rotation_matrices.end(),rotation_matrices[i]); + + const double size = grain_sizes[i] < 0 ? 1.0/static_cast(grains_local.sizes.size()) : grain_sizes[i]; + std::fill(grains_local.sizes.begin(),grains_local.sizes.end(),size); + + return grains_local; + } + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_MANTLE_LAYER_GRAINS_MODEL(Uniform, uniform) + } // namespace Grains + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/adiabatic.cc.bak b/contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/adiabatic.cc.bak new file mode 100644 index 00000000000..28c172b2e6c --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/adiabatic.cc.bak @@ -0,0 +1,172 @@ +/* + 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/features/mantle_layer_models/temperature/adiabatic.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + using namespace FeatureUtilities; + namespace MantleLayerModels + { + namespace Temperature + { + Adiabatic::Adiabatic(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + potential_mantle_temperature(NaN::DSNAN), + thermal_expansion_coefficient(NaN::DSNAN), + specific_heat(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "adiabatic"; + } + + Adiabatic::~Adiabatic() + = default; + + void + Adiabatic::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + prm.declare_entry("", Types::Object(), + "Adiabatic temperature model. Uses global values by default."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the temperature of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the temperature of this feature is present."); + + prm.declare_entry("potential mantle temperature", Types::Double(-1), + "The potential temperature of the mantle at the surface in Kelvin. " + "If the value is lower then zero, the global value is used."); + + prm.declare_entry("thermal expansion coefficient", Types::Double(-1), + "The thermal expansion coefficient in $K^{-1}$. " + "If the value is lower then zero, the global value is used."); + + prm.declare_entry("specific heat", Types::Double(-1), + "The specific heat in $J kg^{-1} K^{-1}$. " + "If the value is lower then zero, the global value is used."); + + } + + void + Adiabatic::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + operation = string_operations_to_enum(prm.get("operation")); + + potential_mantle_temperature = prm.get("potential mantle temperature"); + if (potential_mantle_temperature < 0) + potential_mantle_temperature = this->world->potential_mantle_temperature; + + + thermal_expansion_coefficient = prm.get("thermal expansion coefficient"); + if (thermal_expansion_coefficient < 0) + thermal_expansion_coefficient = this->world->thermal_expansion_coefficient; + + specific_heat = prm.get("specific heat"); + if (specific_heat < 0) + specific_heat = this->world->specific_heat; + + // Some assertions in debug mode can't hurt and have helped before. + WBAssert(!std::isnan(potential_mantle_temperature), + "potential_mantle_temperature is not a number: " << potential_mantle_temperature << '.'); + WBAssert(std::isfinite(potential_mantle_temperature), + "potential_mantle_temperature is not a finite: " << potential_mantle_temperature << '.'); + + WBAssert(!std::isnan(thermal_expansion_coefficient), + "thermal_expansion_coefficient is not a number: " << thermal_expansion_coefficient << '.'); + WBAssert(std::isfinite(thermal_expansion_coefficient), + "thermal_expansion_coefficient is not a finite: " << thermal_expansion_coefficient << '.'); + + WBAssert(!std::isnan(specific_heat), + "specific_heat is not a number: " << specific_heat << '.'); + WBAssert(std::isfinite(thermal_expansion_coefficient), + "specific_heat is not a finite: " << specific_heat << '.'); + + } + + + double + Adiabatic::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity_norm, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + const double adabatic_temperature = potential_mantle_temperature * + std::exp(((thermal_expansion_coefficient * gravity_norm) / + specific_heat) * depth); + + + WBAssert(!std::isnan(adabatic_temperature), + "adabatic_temperature is not a number: " << adabatic_temperature << ". " + <<"Parameters: potential_mantle_temperature = " << potential_mantle_temperature + <<", thermal_expansion_coefficient = " << thermal_expansion_coefficient + << ", gravity_norm = " << gravity_norm + << ", specific_heat = " << specific_heat + << ", depth = " << depth); + + WBAssert(std::isfinite(adabatic_temperature), + "adabatic_temperature is not a finite: " << adabatic_temperature << '.'); + + return apply_operation(operation,temperature_,adabatic_temperature); + } + } + + return temperature_; + } + + WB_REGISTER_FEATURE_MANTLE_LAYER_TEMPERATURE_MODEL(Adiabatic, adiabatic) + } // namespace Temperature + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/interface.cc.bak b/contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/interface.cc.bak new file mode 100644 index 00000000000..bfcd5474434 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/interface.cc.bak @@ -0,0 +1,94 @@ +/* + 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/features/mantle_layer_models/temperature/interface.h" + +#include + +#include "world_builder/types/string.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace MantleLayerModels + { + namespace Temperature + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + // The type needs to be stored in a separate value, otherwise there are memory issues + const Types::String type = Types::String("replace", std::vector {"replace", "add", "subtract"}); + + prm.declare_model_entries("temperature",parent_name, get_declare_map(),required_entries, + { + std::tuple + { + "operation", type, + "Whether the value should replace any value previously defined at this location (replace), " + "add the value to the previously define value (add) or subtract the value to the previously " + "define value (subtract)." + } + }); + } + + + 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 Temperature + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/linear.cc.bak b/contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/linear.cc.bak new file mode 100644 index 00000000000..b8e64d70ec7 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/linear.cc.bak @@ -0,0 +1,147 @@ +/* + 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/features/mantle_layer_models/temperature/linear.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace MantleLayerModels + { + namespace Temperature + { + Linear::Linear(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + top_temperature(NaN::DSNAN), + bottom_temperature(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "linear"; + } + + Linear::~Linear() + = default; + + void + Linear::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add max depth to the required parameters. + prm.declare_entry("", Types::Object({"max depth"}), + "Linear temperature model. Can be set to use an adiabatic temperature at the boundaries."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the temperature of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the temperature of this feature is present."); + + prm.declare_entry("top temperature", Types::Double(293.15), + "The temperature at the top in degree Kelvin of this feature." + "If the value is below zero, the an adiabatic temperature is used."); + + prm.declare_entry("bottom temperature", Types::Double(-1), + "The temperature at the top in degree Kelvin of this feature. " + "If the value is below zero, an adiabatic temperature is used."); + } + + void + Linear::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + WBAssert(max_depth >= min_depth, "max depth needs to be larger or equal to min depth."); + operation = string_operations_to_enum(prm.get("operation")); + top_temperature = prm.get("top temperature"); + bottom_temperature = prm.get("bottom temperature"); + } + + + double + Linear::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity_norm, + double temperature_, + const double feature_min_depth, + const double feature_max_depth) const + { + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + const double min_depth_local_local = std::max(feature_min_depth, min_depth_local); + const double max_depth_local_local = std::min(feature_max_depth, max_depth_local); + + double top_temperature_local = top_temperature; + if (top_temperature_local < 0) + { + top_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient * gravity_norm) / + this->world->specific_heat) * min_depth_local_local); + } + + double bottom_temperature_local = bottom_temperature; + if (bottom_temperature_local < 0) + { + bottom_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient * gravity_norm) / + this->world->specific_heat) * max_depth_local_local); + + } + + const double new_temperature = top_temperature_local + (max_depth_local_local - min_depth_local_local < 10.0*std::numeric_limits::epsilon() ? 0.0 : + (depth - min_depth_local_local) * + ((bottom_temperature_local - top_temperature_local) / (max_depth_local_local - min_depth_local_local))); + + return apply_operation(operation,temperature_,new_temperature); + } + } + + + return temperature_; + } + + WB_REGISTER_FEATURE_MANTLE_LAYER_TEMPERATURE_MODEL(Linear, linear) + } // namespace Temperature + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/uniform.cc.bak new file mode 100644 index 00000000000..742a922cb99 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/mantle_layer_models/temperature/uniform.cc.bak @@ -0,0 +1,117 @@ +/* + 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/features/mantle_layer_models/temperature/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/value_at_points.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace MantleLayerModels + { + namespace Temperature + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + temperature(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `temperature` and to the required parameters. + prm.declare_entry("", Types::Object({"temperature"}), + "Uniform temperature model. Set the temperature to a constant value."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the temperature of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the temperature of this feature is present."); + + prm.declare_entry("temperature", Types::Double(293.15), + "The temperature in degree Kelvin which this feature should have"); + + + } + + void + Uniform::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + operation = string_operations_to_enum(prm.get("operation")); + temperature = prm.get("temperature"); + } + + + double + Uniform::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double /*gravity*/, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + return apply_operation(operation,temperature_,temperature); + } + } + + return temperature_; + } + + WB_REGISTER_FEATURE_MANTLE_LAYER_TEMPERATURE_MODEL(Uniform, uniform) + } // namespace Temperature + } // namespace MantleLayerModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/oceanic_plate.cc.bak b/contrib/world_builder/source/world_builder/features/oceanic_plate.cc.bak new file mode 100644 index 00000000000..d7beaaf3b50 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/oceanic_plate.cc.bak @@ -0,0 +1,285 @@ +/* + 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/features/oceanic_plate.h" + +#include "world_builder/features/oceanic_plate_models/composition/interface.h" +#include "world_builder/features/oceanic_plate_models/grains/interface.h" +#include "world_builder/features/oceanic_plate_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/plugin_system.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + OceanicPlate::OceanicPlate(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + { + this->world = world_; + this->name = "oceanic plate"; + } + + OceanicPlate::~OceanicPlate() + = default; + + + + void OceanicPlate::make_snippet(Parameters &prm) + { + using namespace rapidjson; + Document &declarations = prm.declarations; + + const std::string path = prm.get_full_json_path(); + + /* + ideally: + { + "model": "fault", + "name": "${1:default name}", + "dip point":[0.0,0.0], + "coordinates": [[0.0,0.0]], + "segments": [], + "sections": [], + "temperature models":[{"model":"uniform", "temperature":600.0}], + "composition models":[{"model":"uniform", "compositions": [0], "fractions":[1.0]}] + } + */ + + Pointer((path + "/body").c_str()).Set(declarations,"object"); + Pointer((path + "/body/model").c_str()).Set(declarations,"oceanic plate"); + Pointer((path + "/body/name").c_str()).Set(declarations,"${1:My Oceanic Plate}"); + Pointer((path + "/body/coordinates").c_str()).Create(declarations).SetArray(); + Pointer((path + "/body/temperature models").c_str()).Create(declarations).SetArray(); + Pointer((path + "/body/composition models").c_str()).Create(declarations).SetArray(); + } + + + + void + OceanicPlate::declare_entries(Parameters &prm, + const std::string & /*unused*/, + const std::vector &required_entries) + { + prm.declare_entry("", Types::Object(required_entries), "Oceanic plate object. Requires properties `model` and `coordinates`."); + + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth from which this feature is present"); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth to which this feature is present"); + prm.declare_entry("temperature models", + Types::PluginSystem("", Features::OceanicPlateModels::Temperature::Interface::declare_entries, {"model"}), + "A list of temperature models."); + prm.declare_entry("composition models", + Types::PluginSystem("", Features::OceanicPlateModels::Composition::Interface::declare_entries, {"model"}), + "A list of composition models."); + prm.declare_entry("grains models", + Types::PluginSystem("", Features::OceanicPlateModels::Grains::Interface::declare_entries, {"model"}), + "A list of grains models."); + } + + void + OceanicPlate::parse_entries(Parameters &prm) + { + + const CoordinateSystem coordinate_system = prm.coordinate_system->natural_coordinate_system(); + + this->name = prm.get("name"); + + std::string tag = prm.get("tag"); + if (tag == "") + { + tag = "oceanic plate"; + } + this->tag_index = FeatureUtilities::add_vector_unique(this->world->feature_tags,tag); + + this->get_coordinates("coordinates", prm, coordinate_system); + + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + + + prm.get_unique_pointers("temperature models", temperature_models); + + prm.enter_subsection("temperature models"); + { + for (unsigned int i = 0; i < temperature_models.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + temperature_models[i]->parse_entries(prm,coordinates); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.get_unique_pointers("composition models", composition_models); + + prm.enter_subsection("composition models"); + { + for (unsigned int i = 0; i < composition_models.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + composition_models[i]->parse_entries(prm,coordinates); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.get_unique_pointers("grains models", grains_models); + + prm.enter_subsection("grains models"); + { + for (unsigned int i = 0; i < grains_models.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + grains_models[i]->parse_entries(prm,coordinates); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + } + + + void + OceanicPlate::properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity_norm, + const std::vector &entry_in_output, + std::vector &output) const + { + if (depth <= max_depth && depth >= min_depth && + WorldBuilder::Utilities::polygon_contains_point(coordinates, Point<2>(position_in_natural_coordinates.get_surface_coordinates(), + world->parameters.coordinate_system->natural_coordinate_system()))) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i_property = 0; i_property < properties.size(); ++i_property) + { + switch (properties[i_property][0]) + { + case 1: // temperature + { + for (const auto &temperature_model: temperature_models) + { + output[entry_in_output[i_property]] = temperature_model->get_temperature(position_in_cartesian_coordinates, + position_in_natural_coordinates, + depth, + gravity_norm, + output[entry_in_output[i_property]], + min_depth_local, + max_depth_local); + + WBAssert(!std::isnan(output[entry_in_output[i_property]]), "Temperature is not a number: " << output[entry_in_output[i_property]] + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(output[entry_in_output[i_property]]), "Temperature is not a finite: " << output[entry_in_output[i_property]] + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + + } + break; + case 2: // composition + + for (const auto &composition_model: composition_models) + { + output[entry_in_output[i_property]] = composition_model->get_composition(position_in_cartesian_coordinates, + position_in_natural_coordinates, + depth, + properties[i_property][1], + output[entry_in_output[i_property]], + min_depth_local, + max_depth_local); + + WBAssert(!std::isnan(output[entry_in_output[i_property]]), "Composition is not a number: " << output[entry_in_output[i_property]] + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(output[entry_in_output[i_property]]), "Composition is not a finite: " << output[entry_in_output[i_property]] + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + + } + + break; + } + case 3: // grains + { + WorldBuilder::grains grains(output,properties[i_property][2],entry_in_output[i_property]); + for (const auto &grains_model: grains_models) + { + grains = grains_model->get_grains(position_in_cartesian_coordinates, + position_in_natural_coordinates, + depth, + properties[i_property][1], + grains, + min_depth_local, + max_depth_local); + + } + grains.unroll_into(output,entry_in_output[i_property]); + break; + } + case 4: + { + output[entry_in_output[i_property]] = static_cast(tag_index); + break; + } + break; + default: + { + WBAssertThrow(false, + "Internal error: Unimplemented property provided. " << + "Only temperature (1), composition (2), grains (3) or tag (4) are allowed. " + "Provided property number was: " << properties[i_property][0]); + } + } + } + } + } + } + + /** + * Register plugin + */ + WB_REGISTER_FEATURE(OceanicPlate, oceanic plate) + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/oceanic_plate_models/composition/interface.cc.bak b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/composition/interface.cc.bak new file mode 100644 index 00000000000..543e29701ce --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/composition/interface.cc.bak @@ -0,0 +1,81 @@ +/* + 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/features/oceanic_plate_models/composition/interface.h" + +#include + + +namespace WorldBuilder +{ + namespace Features + { + namespace OceanicPlateModels + { + namespace Composition + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + prm.declare_model_entries("composition",parent_name, get_declare_map(),required_entries); + } + + + 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 Composition + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/oceanic_plate_models/composition/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/composition/uniform.cc.bak new file mode 100644 index 00000000000..ea2c7f7c0dc --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/composition/uniform.cc.bak @@ -0,0 +1,129 @@ +/* + 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/features/oceanic_plate_models/composition/uniform.h" + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace OceanicPlateModels + { + namespace Composition + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform compositional model. Sets constant compositional field."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the labels of the composition which are present there."); + prm.declare_entry("fractions", Types::Array(Types::Double(1.0),1), + "TA list of compositional fractions corresponding to the compositions list."); + prm.declare_entry("operation", Types::String("replace", std::vector {"replace", "replace defined only", "add", "subtract"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value. Replacing implies that all compositions not " + "explicitly defined are set to zero. To only replace the defined compositions use the replace only defined option."); + + } + + void + Uniform::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + compositions = prm.get_vector("compositions"); + fractions = prm.get_vector("fractions"); + operation = string_operations_to_enum(prm.get("operation")); + + WBAssertThrow(compositions.size() == fractions.size(), + "There are not the same amount of compositions and fractions."); + } + + + double + Uniform::get_composition(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + double composition, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + return apply_operation(operation,composition,fractions[i]); + } + } + + if (operation == Operations::REPLACE) + return 0.0; + } + } + return composition; + } + WB_REGISTER_FEATURE_OCEANIC_PLATE_COMPOSITION_MODEL(Uniform, uniform) + } // namespace Composition + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/interface.cc.bak b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/interface.cc.bak new file mode 100644 index 00000000000..f7e1b13aa56 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/interface.cc.bak @@ -0,0 +1,111 @@ +/* + 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/features/oceanic_plate_models/grains/interface.h" + +#include + +#include "world_builder/types/object.h" +#include "world_builder/types/string.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace OceanicPlateModels + { + namespace Grains + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + 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()) + { + // prevent infinite recursion + if (it.first != parent_name) + { + prm.enter_subsection("oneOf"); + { + prm.enter_subsection(std::to_string(counter)); + { + prm.enter_subsection("properties"); + { + prm.declare_entry("", Types::Object(required_entries), "grains object"); + + prm.declare_entry("model", Types::String("",it.first), + "The name of the grains model."); + + 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 Grains + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution.cc.bak b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution.cc.bak new file mode 100644 index 00000000000..95f95476802 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution.cc.bak @@ -0,0 +1,224 @@ +/* + 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/features/oceanic_plate_models/grains/random_uniform_distribution.h" + +#include + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace OceanicPlateModels + { + namespace Grains + { + RandomUniformDistribution::RandomUniformDistribution(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "random uniform distribution"; + } + + RandomUniformDistribution::~RandomUniformDistribution() + = default; + + void + RandomUniformDistribution::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Random uniform distribution grains model. The size of the grains can be independently set " + "to a single value or to a random distribution."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be randomized between 0 and 1."); + + prm.declare_entry("normalize grain sizes", + Types::Array(Types::Bool(true),0), + "A list of whether the sizes of the grains should be normalized or not. If normalized, the total of the grains of a composition will be equal to 1."); + + + + } + + void + RandomUniformDistribution::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + compositions = prm.get_vector("compositions"); + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + normalize_grain_sizes = prm.get_vector("normalize grain sizes"); + + + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == normalize_grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and normalize_grain_sizes (" << normalize_grain_sizes.size() << ")."); + } + + + WorldBuilder::grains + RandomUniformDistribution::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + WorldBuilder::grains grains_local = grains_; + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::uniform_real_distribution<> dist(0.0,1.0); + for (auto &&it_rotation_matrices : grains_local.rotation_matrices) + { + // set a uniform random a_cosine_matrix per grain + // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120). + // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c + // and is licenend accourding to this website with the following licence: + // + // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and + // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit + // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems + // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, + // don't be a jerk, and remember that anything free comes with no guarantee."" + // + // The book saids in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in + // the public domain, and is yours to study, modify, and use." + + // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2. + const double one = dist(world->get_random_number_engine()); + const double two = dist(world->get_random_number_engine()); + const double three = dist(world->get_random_number_engine()); + + const double theta = 2.0 * Consts::PI * one; // Rotation about the pole (Z) + const double phi = 2.0 * Consts::PI * two; // For direction of pole deflection. + const double z = 2.0* three; //For magnitude of pole deflection. + + // Compute a vector V used for distributing points over the sphere + // via the reflection I - V Transpose(V). This formulation of V + // will guarantee that if x[1] and x[2] are uniformly distributed, + // the reflected points will be uniform on the sphere. Note that V + // has length sqrt(2) to eliminate the 2 in the Householder matrix. + + const double r = std::sqrt( z ); + const double Vx = std::sin( phi ) * r; + const double Vy = std::cos( phi ) * r; + const double Vz = std::sqrt( 2.F - z ); + + // Compute the row vector S = Transpose(V) * R, where R is a simple + // rotation by theta about the z-axis. No need to compute Sz since + // it's just Vz. + + const double st = std::sin( theta ); + const double ct = std::cos( theta ); + const double Sx = Vx * ct - Vy * st; + const double Sy = Vx * st + Vy * ct; + + // Construct the rotation matrix ( V Transpose(V) - I ) R, which + // is equivalent to V S - R. + + it_rotation_matrices[0][0] = Vx * Sx - ct; + it_rotation_matrices[0][1] = Vx * Sy - st; + it_rotation_matrices[0][2] = Vx * Vz; + + it_rotation_matrices[1][0] = Vy * Sx + st; + it_rotation_matrices[1][1] = Vy * Sy - ct; + it_rotation_matrices[1][2] = Vy * Vz; + + it_rotation_matrices[2][0] = Vz * Sx; + it_rotation_matrices[2][1] = Vz * Sy; + it_rotation_matrices[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0 + } + + double total_size = 0; + for (auto &&it_sizes : grains_local.sizes) + { + it_sizes = grain_sizes[i] < 0 ? dist(world->get_random_number_engine()) : grain_sizes[i]; + total_size += it_sizes; + } + + if (normalize_grain_sizes[i]) + { + const double one_over_total_size = 1/total_size; + std::transform(grains_local.sizes.begin(), grains_local.sizes.end(), grains_local.sizes.begin(), + [one_over_total_size](double sizes) -> double { return sizes *one_over_total_size; }); + } + + return grains_local; + } + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_OCEANIC_PLATE_GRAINS_MODEL(RandomUniformDistribution, random uniform distribution) + } // namespace Grains + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution_deflected.cc.bak b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution_deflected.cc.bak new file mode 100644 index 00000000000..ffac673631f --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/random_uniform_distribution_deflected.cc.bak @@ -0,0 +1,230 @@ +/* + 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/features/oceanic_plate_models/grains/random_uniform_distribution_deflected.h" + +#include + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace OceanicPlateModels + { + namespace Grains + { + RandomUniformDistributionDeflected::RandomUniformDistributionDeflected(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "random uniform distribution deflected"; + } + + RandomUniformDistributionDeflected::~RandomUniformDistributionDeflected() + = default; + + void + RandomUniformDistributionDeflected::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Random uniform distribution grains model. The size of the grains can be independently set " + "to a single value or to a random distribution."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be randomized between 0 and 1."); + + prm.declare_entry("normalize grain sizes", + Types::Array(Types::Bool(true),0), + "A list of whether the sizes of the grains should be normalized or not. If normalized, the total of the grains of a composition will be equal to 1."); + + prm.declare_entry("deflections", + Types::Array(Types::Double(1),0), + "A list of the deflections of all of the grains in each composition between 0 and 1."); + + + + } + + void + RandomUniformDistributionDeflected::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + compositions = prm.get_vector("compositions"); + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + normalize_grain_sizes = prm.get_vector("normalize grain sizes"); + deflections = prm.get_vector("deflections"); + + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == normalize_grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and normalize_grain_sizes (" << normalize_grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == deflections.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and deflections (" << deflections.size() << ")."); + } + + + WorldBuilder::grains + RandomUniformDistributionDeflected::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + WorldBuilder::grains grains_local = grains_; + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::uniform_real_distribution<> dist(0.0,1.0); + for (auto &&it_rotation_matrices : grains_local.rotation_matrices) + { + // set a uniform random a_cosine_matrix per grain + // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120). + // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c + // and is licenend accourding to this website with the following licence: + // + // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and + // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit + // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems + // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, + // don't be a jerk, and remember that anything free comes with no guarantee."" + // + // The book saids in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in + // the public domain, and is yours to study, modify, and use." + + // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2. + const double one = dist(world->get_random_number_engine()); + const double two = dist(world->get_random_number_engine()); + const double three = dist(world->get_random_number_engine()); + + const double theta = 2.0 * Consts::PI * one * deflections[i]; // Rotation about the pole (Z) + const double phi = 2.0 * Consts::PI * two; // For direction of pole deflection. + const double z = 2.0* three * deflections[i]; //For magnitude of pole deflection. + + // Compute a vector V used for distributing points over the sphere + // via the reflection I - V Transpose(V). This formulation of V + // will guarantee that if x[1] and x[2] are uniformly distributed, + // the reflected points will be uniform on the sphere. Note that V + // has length sqrt(2) to eliminate the 2 in the Householder matrix. + + const double r = std::sqrt( z ); + const double Vx = std::sin( phi ) * r; + const double Vy = std::cos( phi ) * r; + const double Vz = std::sqrt( 2.F - z ); + + // Compute the row vector S = Transpose(V) * R, where R is a simple + // rotation by theta about the z-axis. No need to compute Sz since + // it's just Vz. + + const double st = std::sin( theta ); + const double ct = std::cos( theta ); + const double Sx = Vx * ct - Vy * st; + const double Sy = Vx * st + Vy * ct; + + // Construct the rotation matrix ( V Transpose(V) - I ) R, which + // is equivalent to V S - R. + + it_rotation_matrices[0][0] = Vx * Sx - ct; + it_rotation_matrices[0][1] = Vx * Sy - st; + it_rotation_matrices[0][2] = Vx * Vz; + + it_rotation_matrices[1][0] = Vy * Sx + st; + it_rotation_matrices[1][1] = Vy * Sy - ct; + it_rotation_matrices[1][2] = Vy * Vz; + + it_rotation_matrices[2][0] = Vz * Sx; + it_rotation_matrices[2][1] = Vz * Sy; + it_rotation_matrices[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0 + } + + double total_size = 0; + for (auto &&it_sizes : grains_local.sizes) + { + it_sizes = grain_sizes[i] < 0 ? dist(world->get_random_number_engine()) : grain_sizes[i]; + total_size += it_sizes; + } + + if (normalize_grain_sizes[i]) + { + const double one_over_total_size = 1/total_size; + std::transform(grains_local.sizes.begin(), grains_local.sizes.end(), grains_local.sizes.begin(), + [one_over_total_size](double sizes) -> double { return sizes *one_over_total_size; }); + } + + return grains_local; + } + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_OCEANIC_PLATE_GRAINS_MODEL(RandomUniformDistributionDeflected, random uniform distribution deflected) + } // namespace Grains + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/uniform.cc.bak new file mode 100644 index 00000000000..ddb408107a9 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/grains/uniform.cc.bak @@ -0,0 +1,177 @@ +/* + 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/features/oceanic_plate_models/grains/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/utilities.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace OceanicPlateModels + { + namespace Grains + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform grains model. All grains start exactly the same."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the composition of this feature is present."); + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("rotation matrices", Types::Array(Types::Array(Types::Array(Types::Double(0),3,3),3,3),0), + "A list with the labels of the grains which are present there for each compositions."); + + prm.declare_entry("Euler angles z-x-z", Types::Array(Types::Array(Types::Double(0),3,3),0), + "A list with the z-x-z Euler angles of the grains which are present there for each compositions."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(-1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be set so that the total is equal to 1."); + + + } + + void + Uniform::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + compositions = prm.get_vector("compositions"); + + const bool set_euler_angles = prm.check_entry("Euler angles z-x-z"); + const bool set_rotation_matrices = prm.check_entry("rotation matrices"); + + WBAssertThrow(!(set_euler_angles == true && set_rotation_matrices == true), + "Only Euler angles or Rotation matrices may be set, but both are set for " << prm.get_full_json_path()); + + + WBAssertThrow(!(set_euler_angles == false && set_rotation_matrices == false), + "Euler angles or Rotation matrices have to be set, but neither are set for " << prm.get_full_json_path()); + + if (set_euler_angles) + { + std::vector > euler_angles_vector = prm.get_vector >("Euler angles z-x-z"); + rotation_matrices.resize(euler_angles_vector.size()); + for (size_t i = 0; i,3> >("rotation matrices"); + } + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + + + WBAssertThrow(compositions.size() == rotation_matrices.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and rotation_matrices (" << rotation_matrices.size() << ")."); + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + } + + + WorldBuilder::grains + Uniform::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + WorldBuilder::grains grains_local = grains_; + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::fill(grains_local.rotation_matrices.begin(),grains_local.rotation_matrices.end(),rotation_matrices[i]); + + const double size = grain_sizes[i] < 0 ? 1.0/static_cast(grains_local.sizes.size()) : grain_sizes[i]; + std::fill(grains_local.sizes.begin(),grains_local.sizes.end(),size); + + + return grains_local; + } + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_OCEANIC_PLATE_GRAINS_MODEL(Uniform, uniform) + } // namespace Grains + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/adiabatic.cc.bak b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/adiabatic.cc.bak new file mode 100644 index 00000000000..d41973ad571 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/adiabatic.cc.bak @@ -0,0 +1,173 @@ +/* + 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/features/oceanic_plate_models/temperature/adiabatic.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace OceanicPlateModels + { + namespace Temperature + { + Adiabatic::Adiabatic(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + potential_mantle_temperature(NaN::DSNAN), + thermal_expansion_coefficient(NaN::DSNAN), + specific_heat(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "adiabatic"; + } + + Adiabatic::~Adiabatic() + = default; + + void + Adiabatic::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + prm.declare_entry("", Types::Object(), + "Adiabatic temperature model. Uses global values by default."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the temperature of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the temperature of this feature is present."); + + prm.declare_entry("potential mantle temperature", Types::Double(-1), + "The potential temperature of the mantle at the surface in Kelvin. " + "If the value is lower then zero, the global value is used."); + + prm.declare_entry("thermal expansion coefficient", Types::Double(-1), + "The thermal expansion coefficient in $K^{-1}$. " + "If the value is lower then zero, the global value is used."); + + prm.declare_entry("specific heat", Types::Double(-1), + "The specific heat in $J kg^{-1} K^{-1}$. " + "If the value is lower then zero, the global value is used."); + + } + + void + Adiabatic::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + operation = string_operations_to_enum(prm.get("operation")); + + potential_mantle_temperature = prm.get("potential mantle temperature"); + if (potential_mantle_temperature < 0) + potential_mantle_temperature = this->world->potential_mantle_temperature; + + + thermal_expansion_coefficient = prm.get("thermal expansion coefficient"); + if (thermal_expansion_coefficient < 0) + thermal_expansion_coefficient = this->world->thermal_expansion_coefficient; + + specific_heat = prm.get("specific heat"); + if (specific_heat < 0) + specific_heat = this->world->specific_heat; + + // Some assertions in debug mode can't hurt and have helped before. + WBAssert(!std::isnan(potential_mantle_temperature), + "potential_mantle_temperature is not a number: " << potential_mantle_temperature << '.'); + WBAssert(std::isfinite(potential_mantle_temperature), + "potential_mantle_temperature is not a finite: " << potential_mantle_temperature << '.'); + + WBAssert(!std::isnan(thermal_expansion_coefficient), + "thermal_expansion_coefficient is not a number: " << thermal_expansion_coefficient << '.'); + WBAssert(std::isfinite(thermal_expansion_coefficient), + "thermal_expansion_coefficient is not a finite: " << thermal_expansion_coefficient << '.'); + + WBAssert(!std::isnan(specific_heat), + "specific_heat is not a number: " << specific_heat << '.'); + WBAssert(std::isfinite(thermal_expansion_coefficient), + "specific_heat is not a finite: " << specific_heat << '.'); + + } + + + double + Adiabatic::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity_norm, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + const double adabatic_temperature = potential_mantle_temperature * + std::exp(((thermal_expansion_coefficient * gravity_norm) / + specific_heat) * depth); + + + WBAssert(!std::isnan(adabatic_temperature), + "adabatic_temperature is not a number: " << adabatic_temperature << ". " + <<"Parameters: potential_mantle_temperature = " << potential_mantle_temperature + <<", thermal_expansion_coefficient = " << thermal_expansion_coefficient + << ", gravity_norm = " << gravity_norm + << ", specific_heat = " << specific_heat + << ", depth = " << depth); + + WBAssert(std::isfinite(adabatic_temperature), + "adabatic_temperature is not a finite: " << adabatic_temperature << '.'); + + return apply_operation(operation,temperature_,adabatic_temperature); + } + } + + + return temperature_; + } + + WB_REGISTER_FEATURE_OCEANIC_PLATE_TEMPERATURE_MODEL(Adiabatic, adiabatic) + } // namespace Temperature + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/half_space_model.cc.bak b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/half_space_model.cc.bak new file mode 100644 index 00000000000..e6d80f203dc --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/half_space_model.cc.bak @@ -0,0 +1,210 @@ +/* + 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/features/oceanic_plate_models/temperature/half_space_model.h" + + +#include "world_builder/consts.h" +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/point.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" +#include + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace OceanicPlateModels + { + namespace Temperature + { + HalfSpaceModel::HalfSpaceModel(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + top_temperature(NaN::DSNAN), + bottom_temperature(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "half space model"; + } + + HalfSpaceModel::~HalfSpaceModel() + = default; + + void + HalfSpaceModel::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `ridge coordinates`, `spreading velocity`, `max depth` to the required parameters. + prm.declare_entry("", Types::Object({"ridge coordinates", "spreading velocity", "max depth"}), + "Half space cooling mode"); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the temperature of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the temperature of this feature is present." + "Because half-space reaches background temperature asymptotically, " + "this value should be ~2 times the nominal plate thickness of 100 km" ); + + prm.declare_entry("top temperature", Types::Double(293.15), + "The actual surface temperature in degree Kelvin for this feature."); + + prm.declare_entry("bottom temperature", Types::Double(-1), + "The mantle temperature for the half-space cooling model" + "in degree Kelvin for this feature. If the model has an adiabatic gradient" + "this should be the mantle potential temperature, and T = Tad + Thalf. "); + + prm.declare_entry("spreading velocity", Types::OneOf(Types::Double(0.05),Types::Array(Types::ValueAtPoints(0.05, std::numeric_limits::max()))), + "The spreading velocity of the plate in meter per year. " + "This is the velocity with which one side moves away from the ridge."); + + prm.declare_entry("ridge coordinates", Types::Array(Types::Array(Types::Point<2>(), 2),1), + "An list of ridges. Each ridge is a lists of at least 2 2d points which " + "define the location of the ridge. You need to define at least one ridge." + "So the an example with two ridges is " + "[[[10,20],[20,30],[10,40]],[[50,10],[60,10]]]."); + } + + void + HalfSpaceModel::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + operation = string_operations_to_enum(prm.get("operation")); + top_temperature = prm.get("top temperature"); + bottom_temperature = prm.get("bottom temperature"); + spreading_velocities = prm.get_value_at_array("spreading velocity"); + + mid_oceanic_ridges = prm.get_vector>>("ridge coordinates"); + const double dtr = prm.coordinate_system->natural_coordinate_system() == spherical ? Consts::PI / 180.0 : 1.0; + for (auto &ridge_coordinates : mid_oceanic_ridges) + for (auto &ridge_coordinate : ridge_coordinates) + { + ridge_coordinate *= dtr; + } + + unsigned int ridge_point_index = 0; + for (const auto &mid_oceanic_ridge : mid_oceanic_ridges) + { + std::vector spreading_rates_for_ridge; + for (unsigned int index_y = 0; index_y < mid_oceanic_ridge.size(); index_y++) + { + if (spreading_velocities.second.size() <= 1) + { + spreading_rates_for_ridge.push_back(spreading_velocities.second[0]); + } + else + { + spreading_rates_for_ridge.push_back(spreading_velocities.second[ridge_point_index]); + } + ridge_point_index += 1; + } + spreading_velocities_at_each_ridge_point.push_back(spreading_rates_for_ridge); + } + } + + double + HalfSpaceModel::get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity_norm, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + Objects::NaturalCoordinate position_in_natural_coordinates_at_min_depth = Objects::NaturalCoordinate(position, + *(world->parameters.coordinate_system)); + position_in_natural_coordinates_at_min_depth.get_ref_depth_coordinate() += depth-min_depth; + std::vector> subducting_plate_velocities = {{0}}; + std::vector ridge_migration_times = {0.0}; + + double bottom_temperature_local = bottom_temperature; + + if (bottom_temperature_local < 0) + { + bottom_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient* gravity_norm) / + this->world->specific_heat) * depth); + } + + std::vector ridge_parameters = Utilities::calculate_ridge_distance_and_spreading(mid_oceanic_ridges, + spreading_velocities_at_each_ridge_point, + world->parameters.coordinate_system, + position_in_natural_coordinates_at_min_depth, + subducting_plate_velocities, + ridge_migration_times); + + + + const double thermal_diffusivity = this->world->thermal_diffusivity; + const double age = ridge_parameters[1] / ridge_parameters[0]; + + double temperature = bottom_temperature_local; + + temperature = temperature + (age > 0 ? (top_temperature - bottom_temperature_local)*std::erfc(depth/(2*std::sqrt(thermal_diffusivity*age))) : 0.); + + WBAssert(!std::isnan(temperature), "Temperature inside half-space cooling model is not a number: " << temperature + << ". Relevant variables: bottom_temperature_local = " << bottom_temperature_local + << ", top_temperature = " << top_temperature + << ", max_depth = " << max_depth + << ", spreading_velocity = " << ridge_parameters[0] + << ", thermal_diffusivity = " << thermal_diffusivity + << ", age = " << age << '.'); + WBAssert(std::isfinite(temperature), "Temperature inside half-space cooling model is not a finite: " << temperature << ". Relevant variables: bottom_temperature_local = " << bottom_temperature_local + << ", top_temperature = " << top_temperature + << ", spreading_velocity = " << ridge_parameters[0] + << ", thermal_diffusivity = " << thermal_diffusivity + << ", age = " << age << '.'); + + + return apply_operation(operation,temperature_,temperature); + + } + } + return temperature_; + } + + WB_REGISTER_FEATURE_OCEANIC_PLATE_TEMPERATURE_MODEL(HalfSpaceModel, half space model) + } // namespace Temperature + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/interface.cc.bak b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/interface.cc.bak new file mode 100644 index 00000000000..ddebc6632c8 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/interface.cc.bak @@ -0,0 +1,94 @@ +/* + 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/features/oceanic_plate_models/temperature/interface.h" + +#include + +#include "world_builder/types/string.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace OceanicPlateModels + { + namespace Temperature + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + // The type needs to be stored in a separate value, otherwise there are memory issues + const Types::String type = Types::String("replace", std::vector {"replace", "add", "subtract"}); + + prm.declare_model_entries("temperature",parent_name, get_declare_map(),required_entries, + { + std::tuple + { + "operation", type, + "Whether the value should replace any value previously defined at this location (replace), " + "add the value to the previously define value (add) or subtract the value to the previously " + "define value (subtract)." + } + }); + } + + + 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 Temperature + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/linear.cc.bak b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/linear.cc.bak new file mode 100644 index 00000000000..3dad3b341bb --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/linear.cc.bak @@ -0,0 +1,145 @@ +/* + 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/features/oceanic_plate_models/temperature/linear.h" + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace OceanicPlateModels + { + namespace Temperature + { + Linear::Linear(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + top_temperature(NaN::DSNAN), + bottom_temperature(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "linear"; + } + + Linear::~Linear() + = default; + + void + Linear::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add max depth to the required parameters. + prm.declare_entry("", Types::Object({"max depth"}), + "Linear temperature model. Can be set to use an adiabatic temperature at the boundaries."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the temperature of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the temperature of this feature is present."); + + prm.declare_entry("top temperature", Types::Double(293.15), + "The temperature at the top in degree Kelvin of this feature." + "If the value is below zero, the an adiabatic temperature is used."); + + prm.declare_entry("bottom temperature", Types::Double(-1), + "The temperature at the top in degree Kelvin of this feature. " + "If the value is below zero, an adiabatic temperature is used."); + } + + void + Linear::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + WBAssert(max_depth >= min_depth, "max depth needs to be larger or equal to min depth."); + operation = string_operations_to_enum(prm.get("operation")); + top_temperature = prm.get("top temperature"); + bottom_temperature = prm.get("bottom temperature"); + } + + + double + Linear::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity_norm, + double temperature_, + const double feature_min_depth, + const double feature_max_depth) const + { + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + const double min_depth_local_local = std::max(feature_min_depth, min_depth_local); + const double max_depth_local_local = std::min(feature_max_depth, max_depth_local); + + double top_temperature_local = top_temperature; + if (top_temperature_local < 0) + { + top_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient * gravity_norm) / + this->world->specific_heat) * min_depth_local_local); + } + + double bottom_temperature_local = bottom_temperature; + if (bottom_temperature_local < 0) + { + bottom_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient * gravity_norm) / + this->world->specific_heat) * max_depth_local_local); + } + + const double new_temperature = top_temperature_local + (max_depth_local_local - min_depth_local_local < 10.0*std::numeric_limits::epsilon() ? 0.0 : + (depth - min_depth_local_local) * + ((bottom_temperature_local - top_temperature_local) / (max_depth_local_local - min_depth_local_local))); + + return apply_operation(operation,temperature_,new_temperature); + } + } + + + return temperature_; + } + + WB_REGISTER_FEATURE_OCEANIC_PLATE_TEMPERATURE_MODEL(Linear, linear) + } // namespace Temperature + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/plate_model.cc.bak b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/plate_model.cc.bak new file mode 100644 index 00000000000..9184711f9a1 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/oceanic_plate_models/temperature/plate_model.cc.bak @@ -0,0 +1,214 @@ +/* + 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/features/oceanic_plate_models/temperature/plate_model.h" + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/point.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace OceanicPlateModels + { + namespace Temperature + { + PlateModel::PlateModel(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + top_temperature(NaN::DSNAN), + bottom_temperature(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "plate model"; + } + + PlateModel::~PlateModel() + = default; + + void + PlateModel::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add temperature to the required parameters. + prm.declare_entry("", Types::Object({"max depth"}), + "Plate model."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the temperature of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the temperature of this feature is present."); + + prm.declare_entry("top temperature", Types::Double(293.15), + "The temperature in degree Kelvin which this feature should have"); + + prm.declare_entry("bottom temperature", Types::Double(-1), + "The temperature in degree Kelvin which this feature should have"); + + prm.declare_entry("spreading velocity", Types::OneOf(Types::Double(0.05),Types::Array(Types::ValueAtPoints(0.05, std::numeric_limits::max()))), + "The spreading velocity of the plate in meter per year. " + "This is the velocity with which one side moves away from the ridge."); + + prm.declare_entry("ridge coordinates", Types::Array(Types::Array(Types::Point<2>(), 2),1), + "An list of ridges. Each ridge is a lists of at least 2 2d points which " + "define the location of the ridge. You need to define at least one ridge." + "So the an example with two ridges is " + "[[[10,20],[20,30],[10,40]],[[50,10],[60,10]]]."); + + } + + void + PlateModel::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + operation = string_operations_to_enum(prm.get("operation")); + top_temperature = prm.get("top temperature"); + bottom_temperature = prm.get("bottom temperature"); + spreading_velocities = prm.get_value_at_array("spreading velocity"); + + mid_oceanic_ridges = prm.get_vector>>("ridge coordinates"); + const double dtr = prm.coordinate_system->natural_coordinate_system() == spherical ? Consts::PI / 180.0 : 1.0; + for (auto &ridge_coordinates : mid_oceanic_ridges) + for (auto &ridge_coordinate : ridge_coordinates) + { + ridge_coordinate *= dtr; + } + + unsigned int ridge_point_index = 0; + for (const auto &mid_oceanic_ridge : mid_oceanic_ridges) + { + std::vector spreading_rates_for_ridge; + for (unsigned int index_y = 0; index_y < mid_oceanic_ridge.size(); index_y++) + { + if (spreading_velocities.second.size() <= 1) + { + spreading_rates_for_ridge.push_back(spreading_velocities.second[0]); + } + else + { + spreading_rates_for_ridge.push_back(spreading_velocities.second[ridge_point_index]); + } + ridge_point_index += 1; + } + spreading_velocities_at_each_ridge_point.push_back(spreading_rates_for_ridge); + } + } + + + double + PlateModel::get_temperature(const Point<3> &position, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity_norm, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + Objects::NaturalCoordinate position_in_natural_coordinates_at_min_depth = Objects::NaturalCoordinate(position, + *(world->parameters.coordinate_system)); + position_in_natural_coordinates_at_min_depth.get_ref_depth_coordinate() += depth-min_depth; + std::vector> subducting_plate_velocities = {{0}}; + std::vector ridge_migration_times = {0.0}; + double bottom_temperature_local = bottom_temperature; + + if (bottom_temperature_local < 0) + { + bottom_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient* gravity_norm) / + this->world->specific_heat) * depth); + } + + const int summation_number = 100; + + std::vector ridge_parameters = Utilities::calculate_ridge_distance_and_spreading(mid_oceanic_ridges, + spreading_velocities_at_each_ridge_point, + world->parameters.coordinate_system, + position_in_natural_coordinates_at_min_depth, + subducting_plate_velocities, + ridge_migration_times); + + const double thermal_diffusivity = this->world->thermal_diffusivity; + const double age = ridge_parameters[1] / ridge_parameters[0]; + double temperature = top_temperature + (bottom_temperature_local - top_temperature) * (depth / max_depth); + + // This formula addresses the horizontal heat transfer by having the spreading velocity and distance to the ridge in it. + // (Chapter 7 Heat, Fowler M. The solid earth: an introduction to global geophysics[M]. Cambridge University Press, 1990) + for (int i = 1; iworld = world_; + this->name = "plate model constant age"; + } + + PlateModelConstantAge::~PlateModelConstantAge() + = default; + + void + PlateModelConstantAge::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add temperature to the required parameters. + prm.declare_entry("", Types::Object({"max depth"}), + "Plate model, but with a fixed age."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the temperature of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the temperature of this feature is present."); + + prm.declare_entry("top temperature", Types::Double(293.15), + "The temperature in degree Kelvin which this feature should have"); + + prm.declare_entry("bottom temperature", Types::Double(-1), + "The temperature in degree Kelvin which this feature should have"); + + prm.declare_entry("plate age", Types::Double(80e3), + "The age of the plate in year. " + "This age is assigned to the whole plate. "); + } + + void + PlateModelConstantAge::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + operation = string_operations_to_enum(prm.get("operation")); + top_temperature = prm.get("top temperature"); + bottom_temperature = prm.get("bottom temperature"); + plate_age = prm.get("plate age")*31557600; + } + + + double + PlateModelConstantAge::get_temperature(const Point<3> & /*position*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double gravity_norm, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + double bottom_temperature_local = bottom_temperature; + + if (bottom_temperature_local < 0) + { + bottom_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient* gravity_norm) / + this->world->specific_heat) * depth); + } + const int sommation_number = 100; + + // some aliases + //const double top_temperature = top_temperature; + const double thermal_diffusivity = this->world->thermal_diffusivity; + double temperature = top_temperature + (bottom_temperature_local - top_temperature) * (depth / max_depth); + + // This formula ignores the horizontal heat transfer by just having the age of the plate in it. + // (Chapter 7 Heat, Fowler M. The solid earth: an introduction to global geophysics[M]. Cambridge University Press, 1990) + for (int i = 1; iworld = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `temperature` and to the required parameters. + prm.declare_entry("", Types::Object({"temperature"}), + "Uniform temperature model. Set the temperature to a constant value."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::OneOf(Types::Double(0),Types::Array(Types::ValueAtPoints(0., 2.))), + "The depth in meters from which the temperature of this feature is present."); + + prm.declare_entry("max depth", Types::OneOf(Types::Double(std::numeric_limits::max()),Types::Array(Types::ValueAtPoints(std::numeric_limits::max(), 2.))), + "The depth in meters to which the temperature of this feature is present."); + + prm.declare_entry("temperature", Types::Double(293.15), + "The temperature in degree Kelvin which this feature should have"); + + } + + void + Uniform::parse_entries(Parameters &prm, const std::vector> &coordinates) + { + + min_depth_surface = Objects::Surface(prm.get("min depth",coordinates)); + min_depth = min_depth_surface.minimum; + max_depth_surface = Objects::Surface(prm.get("max depth",coordinates)); + max_depth = max_depth_surface.maximum; + operation = string_operations_to_enum(prm.get("operation")); + temperature = prm.get("temperature"); + } + + + double + Uniform::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const double /*gravity*/, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + + if (depth <= max_depth && depth >= min_depth) + { + const double min_depth_local = min_depth_surface.constant_value ? min_depth : min_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + const double max_depth_local = max_depth_surface.constant_value ? max_depth : max_depth_surface.local_value(position_in_natural_coordinates.get_surface_point()).interpolated_value; + if (depth <= max_depth_local && depth >= min_depth_local) + { + return apply_operation(operation,temperature_,temperature); + } + } + + return temperature_; + } + + WB_REGISTER_FEATURE_OCEANIC_PLATE_TEMPERATURE_MODEL(Uniform, uniform) + } // namespace Temperature + } // namespace OceanicPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/plume.cc.bak b/contrib/world_builder/source/world_builder/features/plume.cc.bak new file mode 100644 index 00000000000..3e3ca597318 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/plume.cc.bak @@ -0,0 +1,403 @@ +/* + 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/features/plume.h" + + +#include "world_builder/features/plume_models/composition/interface.h" +#include "world_builder/features/plume_models/grains/interface.h" +#include "world_builder/features/plume_models/temperature/interface.h" +#include "world_builder/features/feature_utilities.h" +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/plugin_system.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/world.h" + +#include +#include + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + Plume::Plume(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + { + this->world = world_; + this->name = "plume"; + } + + Plume::~Plume() + = default; + + + + void Plume::make_snippet(Parameters &prm) + { + using namespace rapidjson; + Document &declarations = prm.declarations; + + const std::string path = prm.get_full_json_path(); + + Pointer((path + "/body").c_str()).Set(declarations,"object"); + Pointer((path + "/body/model").c_str()).Set(declarations,"plume"); + Pointer((path + "/body/name").c_str()).Set(declarations,"${1:My Plume}"); + Pointer((path + "/body/coordinates").c_str()).Create(declarations).SetArray(); + Pointer((path + "/body/temperature models").c_str()).Create(declarations).SetArray(); + Pointer((path + "/body/composition models").c_str()).Create(declarations).SetArray(); + } + + + + void + Plume::declare_entries(Parameters &prm, + const std::string & /*unused*/, + const std::vector &required_entries) + { + prm.declare_entry("", Types::Object(required_entries), "Plume object. Requires properties `model` and `coordinates`."); + + prm.declare_entry("min depth", Types::Double(0), + "The depth from which this feature is present, in other words, the " + "depth of the tip of the plume. If the first entry in the cross " + "section depths has a greater depth, an ellipsoidal plume head will " + "be added in between. Units: m."); + prm.declare_entry("max depth", Types::Double(std::numeric_limits::max()), + "The depth to which this feature is present. Units: m."); + prm.declare_entry("cross section depths", Types::Array(Types::Double(0)), + "The depths of the elliptic cross section of the plume. Units: m."); + prm.declare_entry("semi-major axis", Types::Array(Types::Double(100.e3)), + "The lengths of the semi-major axes of the elliptic cross sections of the plume. " + "In spherical coordinates, this is in degrees, otherwise in meters."); + prm.declare_entry("eccentricity", Types::Array(Types::Double(0)), + "The eccentricities of the cross sections."); + prm.declare_entry("rotation angles", Types::Array(Types::Double(0)), + "The directions that the semi-major axis of the elliptic cross-sections " + "are pointing to, in degrees. This direction is expressed as the angle from " + "geographic North in spherical coordinates, or as the angle from the Y axis " + "(clockwise) in Cartesian coordinates. " + "The angle should be between 0 and 360 degrees."); + + prm.declare_entry("temperature models", + Types::PluginSystem("", Features::PlumeModels::Temperature::Interface::declare_entries, {"model"}), + "A list of temperature models."); + prm.declare_entry("composition models", + Types::PluginSystem("", Features::PlumeModels::Composition::Interface::declare_entries, {"model"}), + "A list of composition models."); + prm.declare_entry("grains models", + Types::PluginSystem("", Features::PlumeModels::Grains::Interface::declare_entries, {"model"}), + "A list of grains models."); + } + + void + Plume::parse_entries(Parameters &prm) + { + const CoordinateSystem coordinate_system = prm.coordinate_system->natural_coordinate_system(); + + this->name = prm.get("name"); + + std::string tag = prm.get("tag"); + if (tag == "") + { + tag = "plume"; + } + this->tag_index = FeatureUtilities::add_vector_unique(this->world->feature_tags,tag); + + this->get_coordinates("coordinates", prm, coordinate_system); + + min_depth = prm.get("min depth"); + max_depth = prm.get("max depth"); + + depths = prm.get_vector("cross section depths"); + semi_major_axis_lengths = prm.get_vector("semi-major axis"); + eccentricities = prm.get_vector("eccentricity"); + rotation_angles = prm.get_vector("rotation angles"); + + for (unsigned int i = 0; i < depths.size()-1; ++i) + WBAssert(depths[i] < depths[i+1], + "The depths of the elliptic cross sections of the plume need to be listed in ascending order."); + + WBAssert(depths.size() == coordinates.size(), + "The cross section depths array needs to have the same number of entries as there are coordinates. At the moment there are: " + << depths.size() + << " depth entries but " + << coordinates.size() + << " coordinates!"); + + WBAssert(semi_major_axis_lengths.size() == coordinates.size(), + "The semi-major axis array needs to have the same number of entries as there are coordinates. At the moment there are: " + << semi_major_axis_lengths.size() + << " semi-major axis entries but " + << coordinates.size() + << " coordinates!"); + + WBAssert(eccentricities.size() == coordinates.size(), + "The eccentricity array needs to have the same number of entries as there are coordinates. At the moment there are: " + << eccentricities.size() + << " eccentricity entries but " + << coordinates.size() + << " coordinates!"); + + WBAssert(rotation_angles.size() == coordinates.size(), + "The rotation angles array needs to have the same number of entries as there are coordinates. At the moment there are: " + << rotation_angles.size() + << " rotation angle entries but " + << coordinates.size() + << " coordinates!"); + + + // Convert degrees to radians, convert from geographical to mathematical + for (double &rotation_angle : rotation_angles) + rotation_angle = Consts::PI/2. - rotation_angle * Consts::PI/180.; + + // convert semi_major_axis_lengths to radians if we are in spherical coordinates + if (world->parameters.coordinate_system->natural_coordinate_system() == CoordinateSystem::spherical) + for (double &semi_major_axis_length : semi_major_axis_lengths) + { + semi_major_axis_length *= Consts::PI/180.; + } + + prm.get_unique_pointers("temperature models", temperature_models); + + prm.enter_subsection("temperature models"); + { + for (unsigned int i = 0; i < temperature_models.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + temperature_models[i]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.get_unique_pointers("composition models", composition_models); + + prm.enter_subsection("composition models"); + { + for (unsigned int i = 0; i < composition_models.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + composition_models[i]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.get_unique_pointers("grains models", grains_models); + + prm.enter_subsection("grains models"); + { + for (unsigned int i = 0; i < grains_models.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + grains_models[i]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + } + + + + void + Plume::properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity_norm, + const std::vector &entry_in_output, + std::vector &output) const + { + // Figure out if the point is within the plume + auto upper = std::upper_bound(depths.begin(), depths.end(), depth); + + Point<2> plume_center(coordinates[0]); + double semi_major_axis_length; + double eccentricity; + double rotation_angle; + + if (depth < min_depth) + return; + else if (upper - depths.begin() == 0) + { + // interpolate to make the top of the plume spherical + plume_center = coordinates.front(); + eccentricity = eccentricities.front(); + rotation_angle = rotation_angles.front(); + + const double fraction = (depth - min_depth) / (depths.front() - min_depth); + + const double a = depths.front() - min_depth; + const double b = semi_major_axis_lengths.front(); + const double y = (1. - fraction) * a; + + // use ellipse equation: + semi_major_axis_length = std::sqrt((1 - std::pow(y/a,2)) * b*b); + } + else if (upper - depths.end() == 0) + { + plume_center = coordinates.back(); + semi_major_axis_length = semi_major_axis_lengths.back(); + eccentricity = eccentricities.back(); + rotation_angle = rotation_angles.back(); + } + else + { + const unsigned int index = static_cast(std::distance(depths.begin(), upper)); + const double fraction = (depth - depths[index-1]) / (depths[index] - depths[index-1]); + + plume_center[0] = (1-fraction) * coordinates[index-1][0] + fraction * (coordinates[index][0]); + plume_center[1] = (1-fraction) * coordinates[index-1][1] + fraction * (coordinates[index][1]); + + semi_major_axis_length = (1-fraction) * semi_major_axis_lengths[index-1] + fraction * semi_major_axis_lengths[index]; + eccentricity = (1-fraction) * eccentricities[index-1] + fraction * eccentricities[index]; + + // For the angles, we only want to go between zero and pi, and we have to make sure we + // interpolate the values close to zero/pi correctly: + rotation_angle = interpolate_angle_across_zero(rotation_angles[index-1], rotation_angles[index], fraction); + } + + const Point<2> surface_point(position_in_natural_coordinates.get_surface_coordinates(), + world->parameters.coordinate_system->natural_coordinate_system()); + + double relative_distance_from_center = + WorldBuilder::Utilities::fraction_from_ellipse_center(plume_center, + semi_major_axis_length, + eccentricity, + rotation_angle, + surface_point); + + // If we are in the tip, we have to compute the difference diffently: + if (depth >= min_depth && depth < depths.front()) + { + const double a = semi_major_axis_lengths.front(); + const double b = a * std::sqrt(1 - std::pow(eccentricity, 2)); + const double c = depths.front() - min_depth; + + const double x = (surface_point[0] - plume_center[0]) * std::cos(rotation_angle) + (surface_point[1] - plume_center[1])* std::sin(rotation_angle); + const double y = -(surface_point[0] - plume_center[0]) * std::sin(rotation_angle) + (surface_point[1] - plume_center[1])* std::cos(rotation_angle); + const double z = depths.front() - depth; + + // use ellipsoid equation: + relative_distance_from_center = (x*x)/(a*a) + (y*y)/(b*b) + (z*z)/(c*c); + } + + if (depth <= max_depth && depth >= min_depth && relative_distance_from_center <= 1.) + { + + for (unsigned int i_property = 0; i_property < properties.size(); ++i_property) + { + switch (properties[i_property][0]) + { + case 1: // temperature + { + for (const auto &temperature_model: temperature_models) + { + output[entry_in_output[i_property]] = temperature_model->get_temperature(position_in_cartesian_coordinates, + position_in_natural_coordinates, + depth, + gravity_norm, + output[entry_in_output[i_property]], + min_depth, + max_depth, + relative_distance_from_center); + + WBAssert(!std::isnan(output[entry_in_output[i_property]]), "Temperature is not a number: " << output[entry_in_output[i_property]] + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(output[entry_in_output[i_property]]), "Temperature is not finite: " << output[entry_in_output[i_property]] + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + + } + break; + case 2: // composition + + for (const auto &composition_model: composition_models) + { + output[entry_in_output[i_property]] = composition_model->get_composition(position_in_cartesian_coordinates, + position_in_natural_coordinates, + depth, + properties[i_property][1], + output[entry_in_output[i_property]], + min_depth, + max_depth); + + WBAssert(!std::isnan(output[entry_in_output[i_property]]), "Composition is not a number: " << output[entry_in_output[i_property]] + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(output[entry_in_output[i_property]]), "Composition is not finite: " << output[entry_in_output[i_property]] + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + + } + + break; + } + case 3: // grains + { + WorldBuilder::grains grains(output,properties[i_property][2],entry_in_output[i_property]); + for (const auto &grains_model: grains_models) + { + grains = grains_model->get_grains(position_in_cartesian_coordinates, + position_in_natural_coordinates, + depth, + properties[i_property][1], + grains, + min_depth, + max_depth); + + } + grains.unroll_into(output,entry_in_output[i_property]); + break; + } + case 4: + { + output[entry_in_output[i_property]] = static_cast(tag_index); + break; + } + default: + { + WBAssertThrow(false, + "Internal error: Unimplemented property provided. " << + "Only temperature (1), composition (2), grains (3) or tag (4) are allowed. " + "Provided property number was: " << properties[i_property][0]); + } + } + } + } + } + + WB_REGISTER_FEATURE(Plume, plume) + + } // namespace Features +} // namespace WorldBuilder \ No newline at end of file diff --git a/contrib/world_builder/source/world_builder/features/plume_models/composition/interface.cc.bak b/contrib/world_builder/source/world_builder/features/plume_models/composition/interface.cc.bak new file mode 100644 index 00000000000..0921105f353 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/plume_models/composition/interface.cc.bak @@ -0,0 +1,80 @@ +/* + 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/features/plume_models/composition/interface.h" + +#include + +namespace WorldBuilder +{ + namespace Features + { + namespace PlumeModels + { + namespace Composition + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + prm.declare_model_entries("composition",parent_name, get_declare_map(),required_entries); + } + + + 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 Composition + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/plume_models/composition/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/plume_models/composition/uniform.cc.bak new file mode 100644 index 00000000000..66065e75d46 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/plume_models/composition/uniform.cc.bak @@ -0,0 +1,129 @@ +/* + 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/features/plume_models/composition/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + using namespace FeatureUtilities; + namespace PlumeModels + { + namespace Composition + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform compositional model. Sets constant compositional field."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::Double(0), + "The depth in meters from which the composition of this feature is present."); + prm.declare_entry("max depth", Types::Double(std::numeric_limits::max()), + "The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the labels of the composition which are present there."); + + prm.declare_entry("fractions", Types::Array(Types::Double(1.0),1), + "TA list of compositional fractions corresponding to the compositions list."); + + prm.declare_entry("operation", Types::String("replace", std::vector {"replace", "replace defined only", "add", "subtract"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value. Replacing implies that all compositions not " + "explicitly defined are set to zero. To only replace the defined compositions use the replace only defined option."); + + } + + void + Uniform::parse_entries(Parameters &prm) + { + min_depth = prm.get("min depth"); + max_depth = prm.get("max depth"); + + compositions = prm.get_vector("compositions"); + fractions = prm.get_vector("fractions"); + operation = string_operations_to_enum(prm.get("operation")); + + WBAssertThrow(compositions.size() == fractions.size(), + "There are not the same amount of compositions and fractions."); + } + + + double + Uniform::get_composition(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate & /*position_in_natural_coordinates*/, + const double depth, + const unsigned int composition_number, + double composition, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + if (depth <= max_depth && depth >= min_depth) + { + + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + return apply_operation(operation,composition,fractions[i]); + } + } + + if (operation == Operations::REPLACE) + return 0.0; + } + return composition; + } + WB_REGISTER_FEATURE_PLUME_COMPOSITION_MODEL(Uniform, uniform) + } // namespace Composition + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/plume_models/grains/interface.cc.bak b/contrib/world_builder/source/world_builder/features/plume_models/grains/interface.cc.bak new file mode 100644 index 00000000000..69abaa7394a --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/plume_models/grains/interface.cc.bak @@ -0,0 +1,81 @@ +/* + 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/features/plume_models/grains/interface.h" + +#include + + +namespace WorldBuilder +{ + namespace Features + { + namespace PlumeModels + { + namespace Grains + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + prm.declare_model_entries("grains",parent_name, get_declare_map(),required_entries); + } + + + 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 Grains + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/plume_models/grains/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/plume_models/grains/uniform.cc.bak new file mode 100644 index 00000000000..d6976a7ff4f --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/plume_models/grains/uniform.cc.bak @@ -0,0 +1,169 @@ +/* + 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/features/plume_models/grains/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/utilities.h" + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace PlumeModels + { + namespace Grains + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform grains model. All grains start exactly the same."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::Double(0), + "The depth in meters from which the grains of this feature are present."); + prm.declare_entry("max depth", Types::Double(std::numeric_limits::max()), + "The depth in meters to which the grains of this feature are present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("rotation matrices", Types::Array(Types::Array(Types::Array(Types::Double(0),3,3),3,3),0), + "A list with the rotation matrices of the grains which are present there for each compositions."); + + prm.declare_entry("Euler angles z-x-z", Types::Array(Types::Array(Types::Double(0),3,3),0), + "A list with the z-x-z Euler angles of the grains which are present there for each compositions."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace", "multiply"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(-1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be set so that the total is equal to 1."); + + + } + + void + Uniform::parse_entries(Parameters &prm) + { + min_depth = prm.get("min depth"); + max_depth = prm.get("max depth"); + compositions = prm.get_vector("compositions"); + + const bool set_euler_angles = prm.check_entry("Euler angles z-x-z"); + const bool set_rotation_matrices = prm.check_entry("rotation matrices"); + + WBAssertThrow(!(set_euler_angles == true && set_rotation_matrices == true), + "Only Euler angles or Rotation matrices may be set, but both are set for " << prm.get_full_json_path()); + + + WBAssertThrow(!(set_euler_angles == false && set_rotation_matrices == false), + "Euler angles or Rotation matrices have to be set, but neither are set for " << prm.get_full_json_path()); + + if (set_euler_angles) + { + std::vector > euler_angles_vector = prm.get_vector >("Euler angles z-x-z"); + rotation_matrices.resize(euler_angles_vector.size()); + for (size_t i = 0; i,3> >("rotation matrices"); + } + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + + + WBAssertThrow(compositions.size() == rotation_matrices.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and rotation_matrices (" << rotation_matrices.size() << ")."); + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + } + + + WorldBuilder::grains + Uniform::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate & /*position_in_natural_coordinates*/, + const double depth, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/) const + { + WorldBuilder::grains grains_local = grains_; + if (depth <= max_depth && depth >= min_depth) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::fill(grains_local.rotation_matrices.begin(),grains_local.rotation_matrices.end(),rotation_matrices[i]); + + const double size = grain_sizes[i] < 0 ? 1.0/static_cast(grains_local.sizes.size()) : grain_sizes[i]; + std::fill(grains_local.sizes.begin(),grains_local.sizes.end(),size); + + return grains_local; + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_PLUME_GRAINS_MODEL(Uniform, uniform) + } // namespace Grains + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/plume_models/temperature/gaussian.cc.bak b/contrib/world_builder/source/world_builder/features/plume_models/temperature/gaussian.cc.bak new file mode 100644 index 00000000000..e7fc12d4277 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/plume_models/temperature/gaussian.cc.bak @@ -0,0 +1,166 @@ +/* + 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/features/plume_models/temperature/gaussian.h" + + +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/array.h" +#include "world_builder/world.h" + +#include + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace PlumeModels + { + namespace Temperature + { + Gaussian::Gaussian(WorldBuilder::World *world_) + : + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "gaussian"; + } + + Gaussian::~Gaussian() + = default; + + void + Gaussian::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `max distance fault` center to the required parameters. + prm.declare_entry("", Types::Object({"centerline temperatures"}), + "Gaussian temperature model. The temperature is interpolated between the plume center " + "and margin (as defined by the plume feature) using a Gaussian function: " + "T(r) = T_center(z) exp(-r^2/(2 sigma^2). " + "The temperature at the plume centerline T_center can be changed with depth by defining " + "an array of depths and centerline temperatures, and temperature is interpolated linearly " + "with depth. Similarly, the sigma of the Gaussian function (relative to the width of " + "the plume as given by the plume feature) can be changed with depth. " + "Temperature is always interpolated in a horizonzal/radial plane, except for the plume " + "head: If the first depth of the plume centerline and the minimum depth of the plume " + "feature are different, an ellipsoidal plume head is created in this depth range. " + "Within this plume head, temperature is interpolated radially, i.e., depending on the " + "distance from the center of the ellipsoid."); + + prm.declare_entry("depths", Types::Array(Types::Double(0)), + "The list of depths where both the temperature in the center of the plume " + "and the width of the temperature anomaly in terms of the sigma of a Gaussian " + "function can be provided. Temperature is interpolated linearly in vertical " + "direction between these depths. Units: m."); + prm.declare_entry("centerline temperatures", Types::Array(Types::Double(0)), + "The temperature at the center of this feature in degree Kelvin." + "If the value is below zero, then an adiabatic temperature is used."); + prm.declare_entry("gaussian sigmas", Types::Array(Types::Double(0.3)), + "The sigma (standard deviation) of the Gaussian function used to compute the " + "temperature distribution within the plume. This sigma is non-dimensional, i.e. " + "it is defined relative to the distance between the plume center and margin as " + "defined by the plume feature. Choosing a sigma of 1 therefore means that the " + "temperature at the plume margin is set to a fraction of 1/sqrt(e) (approx. 0.61) " + "of the centerline temperature. To achieve a smoother transition between the " + "plume temperature and the outside temperature a smaller values has to be chosen " + "for the gaussian sigmas."); + } + + void + Gaussian::parse_entries(Parameters &prm) + { + operation = string_operations_to_enum(prm.get("operation")); + + depths = prm.get_vector("depths"); + center_temperatures = prm.get_vector("centerline temperatures"); + gaussian_sigmas = prm.get_vector("gaussian sigmas"); + + WBAssert(center_temperatures.size() == depths.size() && gaussian_sigmas.size() == depths.size(), + "The depths, center_temperatures and gaussian_sigmas arrays need to have the same number of entries. " + "At the moment there are: " + << depths.size() << " depth entries, " + << center_temperatures.size() << " centerline temperature entries, and " + << gaussian_sigmas.size() << " gaussian sigma entries!"); + } + + + double + Gaussian::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate & /*position_in_natural_coordinates*/, + const double depth, + const double gravity_norm, + double temperature_, + const double feature_min_depth, + const double feature_max_depth, + const double relative_distance_from_center) const + { + if (depth <= feature_max_depth && depth >= feature_min_depth && relative_distance_from_center <= 1.) + { + // Figure out if the point is within the plume + auto upper = std::upper_bound(depths.begin(), depths.end(), depth); + + double center_temperature_local; + double gaussian_sigma; + + if (upper - depths.begin() == 0) + { + center_temperature_local = center_temperatures.front(); + gaussian_sigma = gaussian_sigmas.front(); + } + else if (upper - depths.end() == 0) + { + center_temperature_local = center_temperatures.back(); + gaussian_sigma = gaussian_sigmas.back(); + } + else + { + const unsigned int index = static_cast(std::distance(depths.begin(), upper)); + const double fraction = (depth - depths[index-1]) / (depths[index] - depths[index-1]); + + center_temperature_local = (1-fraction) * center_temperatures[index-1] + fraction * center_temperatures[index]; + gaussian_sigma = (1-fraction) * gaussian_sigmas[index-1] + fraction * gaussian_sigmas[index]; + } + + if (center_temperature_local < 0) + { + center_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient * gravity_norm) / + this->world->specific_heat) * depth); + } + + const double new_temperature = center_temperature_local * std::exp(-relative_distance_from_center/(2.*std::pow(gaussian_sigma, 2))); + + return apply_operation(operation,temperature_,new_temperature); + + } + + return temperature_; + } + + WB_REGISTER_FEATURE_PLUME_TEMPERATURE_MODEL(Gaussian, gaussian) + } // namespace Temperature + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/plume_models/temperature/interface.cc.bak b/contrib/world_builder/source/world_builder/features/plume_models/temperature/interface.cc.bak new file mode 100644 index 00000000000..98c36d94b9a --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/plume_models/temperature/interface.cc.bak @@ -0,0 +1,94 @@ +/* + 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/features/plume_models/temperature/interface.h" + +#include + +#include "world_builder/types/string.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace PlumeModels + { + namespace Temperature + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + // The type needs to be stored in a separate value, otherwise there are memory issues + const Types::String type = Types::String("replace", std::vector {"replace", "add", "subtract"}); + + prm.declare_model_entries("temperature",parent_name, get_declare_map(),required_entries, + { + std::tuple + { + "operation", type, + "Whether the value should replace any value previously defined at this location (replace), " + "add the value to the previously define value (add) or subtract the value to the previously " + "define value (subtract)." + } + }); + } + + + 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 Temperature + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/plume_models/temperature/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/plume_models/temperature/uniform.cc.bak new file mode 100644 index 00000000000..99438d63b31 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/plume_models/temperature/uniform.cc.bak @@ -0,0 +1,106 @@ +/* + 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/features/plume_models/temperature/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/value_at_points.h" + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace PlumeModels + { + namespace Temperature + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + temperature(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `temperature` to the required parameters. + prm.declare_entry("", Types::Object({"temperature"}), + "Uniform temperature model. Set the temperature to a constant value."); + + // Declare entries of this plugin + prm.declare_entry("min depth", Types::Double(0), + "The depth in meters from which the temperature of this feature is present."); + prm.declare_entry("max depth", Types::Double(std::numeric_limits::max()), + "The depth in meters to which the temperature of this feature is present."); + + prm.declare_entry("temperature", Types::Double(293.15), + "The temperature in degree Kelvin which this feature should have"); + + } + + void + Uniform::parse_entries(Parameters &prm) + { + min_depth = prm.get("min depth"); + max_depth = prm.get("max depth"); + operation = string_operations_to_enum(prm.get("operation")); + temperature = prm.get("temperature"); + } + + + double + Uniform::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const Objects::NaturalCoordinate & /*position_in_natural_coordinates*/, + const double depth, + const double /*gravity*/, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const double /*relative_distance_from_center*/) const + { + if (depth <= max_depth && depth >= min_depth) + { + return apply_operation(operation,temperature_,temperature); + } + return temperature_; + } + + WB_REGISTER_FEATURE_PLUME_TEMPERATURE_MODEL(Uniform, uniform) + } // namespace Temperature + } // namespace PlumeModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate.cc.bak new file mode 100644 index 00000000000..8d5faa53360 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate.cc.bak @@ -0,0 +1,762 @@ +/* + 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/features/subducting_plate.h" + + +#include "glm/glm.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/point.h" +#include "world_builder/types/segment.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/world.h" +#include + +using namespace std; + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + SubductingPlate::SubductingPlate(WorldBuilder::World *world_) + : + reference_point(0,0,cartesian) + { + this->world = world_; + this->name = "subducting plate"; + } + + SubductingPlate::~SubductingPlate() + = default; + + + + void SubductingPlate::make_snippet(Parameters &prm) + { + using namespace rapidjson; + Document &declarations = prm.declarations; + + const std::string path = prm.get_full_json_path(); + + /* + ideally: + { + "model": "fault", + "name": "${1:default name}", + "dip point":[0.0,0.0], + "coordinates": [[0.0,0.0]], + "segments": [], + "sections": [], + "temperature models":[{"model":"uniform", "temperature":600.0}], + "composition models":[{"model":"uniform", "compositions": [0], "fractions":[1.0]}] + } + */ + + Pointer((path + "/body").c_str()).Set(declarations,"object"); + Pointer((path + "/body/model").c_str()).Set(declarations,"subducting plate"); + Pointer((path + "/body/name").c_str()).Set(declarations,"${1:My Subducting Plate}"); + Pointer((path + "/body/coordinates").c_str()).Create(declarations).SetArray(); + Pointer((path + "/body/temperature models").c_str()).Create(declarations).SetArray(); + Pointer((path + "/body/composition models").c_str()).Create(declarations).SetArray(); + } + + + + void + SubductingPlate::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + // This statement is needed because of the recursion associated with + // the sections entry. + if (parent_name == "items") + { + prm.enter_subsection("properties"); + } + else + { + prm.declare_entry("", Types::Object(required_entries), "Subducting slab object. Requires properties `model` and `coordinates`."); + } + + + prm.declare_entry("min depth", Types::Double(0), + "The depth to which this feature is present"); + prm.declare_entry("max depth", Types::Double(std::numeric_limits::max()), + "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("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"}), + Types::PluginSystem("", Features::SubductingPlateModels::Grains::Interface::declare_entries, {"model"}))), + "The depth to which this feature is present");*/ + 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"}), + Types::PluginSystem("", Features::SubductingPlateModels::Grains::Interface::declare_entries, {"model"}))), + "The depth to which this feature is present"); + + prm.declare_entry("temperature models", + Types::PluginSystem("", Features::SubductingPlateModels::Temperature::Interface::declare_entries, {"model"}), + "A list of temperature models."); + prm.declare_entry("composition models", + Types::PluginSystem("", Features::SubductingPlateModels::Composition::Interface::declare_entries, {"model"}), + "A list of composition models."); + prm.declare_entry("grains models", + Types::PluginSystem("", Features::SubductingPlateModels::Grains::Interface::declare_entries, {"model"}), + "A list of grains models."); + + if (parent_name != "items") + { + // This only happens if we are not in sections + prm.declare_entry("sections", Types::Array(Types::PluginSystem("",Features::SubductingPlate::declare_entries, {"coordinate"}, false)),"A list of feature properties for a coordinate."); + } + else + { + + // this only happens in sections + prm.declare_entry("coordinate", Types::UnsignedInt(0), + "The coordinate which should be overwritten"); + + prm.leave_subsection(); + } + } + + void + SubductingPlate::parse_entries(Parameters &prm) + { + const CoordinateSystem coordinate_system = prm.coordinate_system->natural_coordinate_system(); + + this->name = prm.get("name"); + + std::string tag = prm.get("tag"); + if (tag == "") + { + tag = "subducting plate"; + } + this->tag_index = FeatureUtilities::add_vector_unique(this->world->feature_tags,tag); + + this->get_coordinates("coordinates", prm, coordinate_system); + + + starting_depth = prm.get("min depth"); + maximum_depth = prm.get("max depth"); + + const size_t n_sections = this->original_number_of_coordinates; + + reference_point = prm.get >("dip point"); + + if (coordinate_system == spherical) + { + // When spherical, input is in degrees, so change to radians for internal use. + reference_point *= (Consts::PI/180.); + } + + default_temperature_models.resize(0); + default_composition_models.resize(0); + default_grains_models.resize(0); + prm.get_shared_pointers("temperature models", default_temperature_models); + prm.get_shared_pointers("composition models", default_composition_models); + prm.get_shared_pointers("grains models", default_grains_models); + + // get the default segments. + default_segment_vector = prm.get_vector >("segments", default_temperature_models, default_composition_models, default_grains_models); + + + // This vector stores segments to this coordinate/section. + //First used (raw) pointers to the segment relevant to this coordinate/section, + // but I do not trust it won't fail when memory is moved. So storing the all the data now. + segment_vector.resize(0); + segment_vector.resize(n_sections, default_segment_vector); + + + // now search whether a section is present, if so, replace the default segments. + std::vector > sections_vector; + prm.get_unique_pointers("sections", sections_vector); + + prm.enter_subsection("sections"); + for (unsigned int i_section = 0; i_section < n_sections; ++i_section) + { + // first check whether this section/coordinate has a a special overwrite + for (unsigned int i_sector = 0; i_sector < sections_vector.size(); ++i_sector) + { + prm.enter_subsection(std::to_string(i_sector)); + { + const unsigned int change_coord_number = prm.get("coordinate"); + + WBAssertThrow(segment_vector.size() > change_coord_number, "Error: for subducting plate with name: '" << this->name + << "', trying to change the section of coordinate " << change_coord_number + << " while only " << segment_vector.size() << " coordinates are defined."); + + std::vector > local_default_temperature_models; + std::vector > local_default_composition_models; + std::vector > local_default_grains_models; + + if (!prm.get_shared_pointers("temperature models", local_default_temperature_models)) + { + // no local temperature model, use global default + local_default_temperature_models = default_temperature_models; + } + + if (!prm.get_shared_pointers("composition models", local_default_composition_models)) + { + // no local composition model, use global default + local_default_composition_models = default_composition_models; + } + + if (!prm.get_shared_pointers("grains models", local_default_grains_models)) + { + // no local composition model, use global default + local_default_grains_models = default_grains_models; + } + + segment_vector[change_coord_number] = prm.get_vector >("segments", local_default_temperature_models, local_default_composition_models, local_default_grains_models); + + + WBAssertThrow(segment_vector[change_coord_number].size() == default_segment_vector.size(), + "Error: There are not the same amount of segments in section with coordinate " << change_coord_number + << " (" << segment_vector[change_coord_number].size() << " segments) as in the default segment (" + << default_segment_vector.size() << " segments). This is not allowed."); + + prm.enter_subsection("segments"); + { + for (unsigned int i = 0; i < segment_vector[change_coord_number].size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + prm.enter_subsection("temperature models"); + { + for (unsigned int j = 0; j < segment_vector[change_coord_number][i].temperature_systems.size(); ++j) + { + prm.enter_subsection(std::to_string(j)); + { + segment_vector[change_coord_number][i].temperature_systems[j]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.enter_subsection("composition models"); + { + for (unsigned int j = 0; j < segment_vector[change_coord_number][i].composition_systems.size(); ++j) + { + prm.enter_subsection(std::to_string(j)); + { + segment_vector[change_coord_number][i].composition_systems[j]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + prm.enter_subsection("grains models"); + { + for (unsigned int j = 0; j < segment_vector[change_coord_number][i].grains_systems.size(); ++j) + { + prm.enter_subsection(std::to_string(j)); + { + segment_vector[change_coord_number][i].grains_systems[j]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + } + prm.leave_subsection(); + } + + } + prm.leave_subsection(); + + + prm.enter_subsection("segments"); + { + for (unsigned int i = 0; i < default_segment_vector.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + prm.enter_subsection("temperature models"); + { + for (unsigned int j = 0; j < default_segment_vector[i].temperature_systems.size(); ++j) + { + prm.enter_subsection(std::to_string(j)); + { + default_segment_vector[i].temperature_systems[j]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.enter_subsection("composition models"); + { + for (unsigned int j = 0; j < default_segment_vector[i].composition_systems.size(); ++j) + { + prm.enter_subsection(std::to_string(j)); + { + default_segment_vector[i].composition_systems[j]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + + prm.enter_subsection("grains models"); + { + for (unsigned int j = 0; j < default_segment_vector[i].grains_systems.size(); ++j) + { + prm.enter_subsection(std::to_string(j)); + { + default_segment_vector[i].grains_systems[j]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + + maximum_slab_thickness = 0; + maximum_total_slab_length = 0; + total_slab_length.resize(original_number_of_coordinates); + slab_segment_lengths.resize(original_number_of_coordinates); + slab_segment_thickness.resize(original_number_of_coordinates); + slab_segment_top_truncation.resize(original_number_of_coordinates); + slab_segment_angles.resize(original_number_of_coordinates); + + for (unsigned int i = 0; i < segment_vector.size(); ++i) + { + double local_total_slab_length = 0; + slab_segment_lengths[i].resize(segment_vector[i].size()); + slab_segment_thickness[i].resize(segment_vector[i].size(), Point<2>(invalid)); + slab_segment_top_truncation[i].resize(segment_vector[i].size(), Point<2>(invalid)); + slab_segment_angles[i].resize(segment_vector[i].size(), Point<2>(invalid)); + for (unsigned int j = 0; j < segment_vector[i].size(); ++j) + { + slab_segment_lengths[i][j] = segment_vector[i][j].value_length; + local_total_slab_length += segment_vector[i][j].value_length; + + slab_segment_thickness[i][j] = segment_vector[i][j].value_thickness; + maximum_slab_thickness = std::max(maximum_slab_thickness, slab_segment_thickness[i][j][0]); + maximum_slab_thickness = std::max(maximum_slab_thickness, slab_segment_thickness[i][j][1]); + slab_segment_top_truncation[i][j] = segment_vector[i][j].value_top_truncation; + + slab_segment_angles[i][j] = segment_vector[i][j].value_angle * (Consts::PI/180); + } + total_slab_length[i] = local_total_slab_length; + maximum_total_slab_length = std::max(maximum_total_slab_length, local_total_slab_length); + } + + // Here, we compute the spherical bounding box using the two extreme points of the box containing all the surface + // coordinates and an additional buffer zone that accounts for the slab thickness and length. The first and second + // points correspond to the lower left and the upper right corners of the bounding box, respectively (see the + // documentation in include/bounding_box.h). + // For the spherical system, the buffer zone along the longitudal direction is calculated using the + // corresponding latitude points. + + // Find minimal and maximal coordinates. Do this by finding the + // leftmost/rightmost point with regard to either the [0] or [1] + // coordinate, and then takes its [0] or [1] element. + auto compare_x_coordinate = [](auto p1, auto p2) + { + return p1[0]parameters.coordinate_system->natural_coordinate_system() == CoordinateSystem::spherical) + { + const double starting_radius_inv = 1 / (world->parameters.coordinate_system->max_model_depth()); + std::pair, Point<2> > &spherical_bounding_box = surface_bounding_box.get_boundary_points(); + + const double buffer_around_slab_spherical = 2 * Consts::PI * buffer_around_slab_cartesian * starting_radius_inv; + + spherical_bounding_box.first = {(min_along_x - buffer_around_slab_spherical * min_lat_cos_inv) , + (min_along_y - buffer_around_slab_spherical), spherical + } ; + + spherical_bounding_box.second = {(max_along_x + buffer_around_slab_spherical * max_lat_cos_inv) , + (max_along_y + buffer_around_slab_spherical), spherical + }; + } + else if (world->parameters.coordinate_system->natural_coordinate_system() == CoordinateSystem::cartesian) + { + std::pair, Point<2> > &bounding_box = surface_bounding_box.get_boundary_points(); + bounding_box.first = {min_along_x, min_along_y, cartesian}; + bounding_box.second = {max_along_x, max_along_y, cartesian}; + surface_bounding_box.extend(buffer_around_slab_cartesian); + } + } + + + + const BoundingBox<2> & + SubductingPlate::get_surface_bounding_box () const + { + return surface_bounding_box; + } + + + void + SubductingPlate::properties(const Point<3> &position_in_cartesian_coordinates, + const Objects::NaturalCoordinate &position_in_natural_coordinates, + const double depth, + const std::vector> &properties, + const double gravity_norm, + const std::vector &entry_in_output, + std::vector &output) 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] + << ", position_in_natural_coordinates.get_depth_coordinate() = " << position_in_natural_coordinates.get_depth_coordinate() + << ", depth = " << depth + << ", starting_depth " << starting_depth + ); + + // todo: explain and check -starting_depth + if (depth <= maximum_depth && depth >= starting_depth && depth <= maximum_total_slab_length + maximum_slab_thickness && + get_surface_bounding_box().point_inside(Point<2>(position_in_natural_coordinates.get_surface_coordinates(), + world->parameters.coordinate_system->natural_coordinate_system()))) + { + /*WBAssert(coordinates.size() == slab_segment_lengths.size(), + "Internal error: The size of coordinates (" << coordinates.size() + << ") and slab_segment_lengths (" << slab_segment_lengths.size() << ") are different."); + WBAssert(coordinates.size() == slab_segment_angles.size(), + "Internal error: The size of coordinates (" << coordinates.size() + << ") and slab_segment_angles (" << slab_segment_angles.size() << ") are different."); + WBAssert(coordinates.size() == slab_segment_angles.size(), + "Internal error: The size of coordinates (" << coordinates.size() + << ") and one_dimensional_coordinates (" << one_dimensional_coordinates.size() << ") are different.");*/ + // todo: explain + const 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->bezier_curve); + + const double distance_from_plane = distance_from_planes.distance_from_plane; + const double distance_along_plane = distance_from_planes.distance_along_plane; + const double section_fraction = distance_from_planes.fraction_of_section; + const size_t current_section = distance_from_planes.section; + const size_t next_section = current_section + 1; + const size_t current_segment = distance_from_planes.segment; // the original value was a unsigned in, converting it back. + //const size_t next_segment = current_segment + 1; + const double segment_fraction = distance_from_planes.fraction_of_segment; + + if (abs(distance_from_plane) < std::numeric_limits::infinity() || (distance_along_plane) < std::numeric_limits::infinity()) + { + // We want to do both section (horizontal) and segment (vertical) interpolation. + // first for thickness + const double thickness_up = slab_segment_thickness[current_section][current_segment][0] + + section_fraction + * (slab_segment_thickness[next_section][current_segment][0] + - slab_segment_thickness[current_section][current_segment][0]); + const double thickness_down = slab_segment_thickness[current_section][current_segment][1] + + section_fraction + * (slab_segment_thickness[next_section][current_segment][1] + - slab_segment_thickness[current_section][current_segment][1]); + const double thickness_local = thickness_up + segment_fraction * (thickness_down - thickness_up); + + // if the thickness is zero, we don't need to compute anything, so return. + if (std::fabs(thickness_local) < 2.0 * std::numeric_limits::epsilon()) + return; + + // secondly for top truncation + const double top_truncation_up = slab_segment_top_truncation[current_section][current_segment][0] + + section_fraction + * (slab_segment_top_truncation[next_section][current_segment][0] + - slab_segment_top_truncation[current_section][current_segment][0]); + const double top_truncation_down = slab_segment_top_truncation[current_section][current_segment][1] + + section_fraction + * (slab_segment_top_truncation[next_section][current_segment][1] + - slab_segment_top_truncation[current_section][current_segment][1]); + const double top_truncation_local = top_truncation_up + segment_fraction * (top_truncation_down - top_truncation_up); + + // if the thickness is smaller than what is truncated off at the top, we don't need to compute anything, so return. + if (thickness_local < top_truncation_local) + return; + + const double max_slab_length = total_slab_length[current_section] + + section_fraction * + (total_slab_length[next_section] - total_slab_length[current_section]); + + if (distance_from_plane >= top_truncation_local && + distance_from_plane <= thickness_local && + distance_along_plane >= 0 && + distance_along_plane <= max_slab_length) + { + // Inside the slab! + const Features::AdditionalParameters additional_parameters = {max_slab_length,thickness_local}; + for (unsigned int i_property = 0; i_property < properties.size(); ++i_property) + { + switch (properties[i_property][0]) + { + case 1: // temperature + { + double temperature_current_section = output[entry_in_output[i_property]]; + double temperature_next_section = output[entry_in_output[i_property]]; + + for (const auto &temperature_model: segment_vector[current_section][current_segment].temperature_systems) + { + temperature_current_section = temperature_model->get_temperature(position_in_cartesian_coordinates, + depth, + gravity_norm, + temperature_current_section, + starting_depth, + maximum_depth, + distance_from_planes, + additional_parameters); + + WBAssert(!std::isnan(temperature_current_section), "Temperature is not a number: " << temperature_current_section + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(temperature_current_section), "Temperature is not a finite: " << temperature_current_section + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + + } + + for (const auto &temperature_model: segment_vector[next_section][current_segment].temperature_systems) + { + temperature_next_section = temperature_model->get_temperature(position_in_cartesian_coordinates, + depth, + gravity_norm, + temperature_next_section, + starting_depth, + maximum_depth, + distance_from_planes, + additional_parameters); + + WBAssert(!std::isnan(temperature_next_section), "Temperature is not a number: " << temperature_next_section + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(temperature_next_section), "Temperature is not a finite: " << temperature_next_section + << ", based on a temperature model with the name " << temperature_model->get_name() << ", in feature " << this->name); + + } + + // linear interpolation between current and next section temperatures + output[entry_in_output[i_property]] = temperature_current_section + section_fraction * (temperature_next_section - temperature_current_section); + break; + } + case 2: // composition + { + double composition_current_section = output[entry_in_output[i_property]]; + double composition_next_section = output[entry_in_output[i_property]]; + + for (const auto &composition_model: segment_vector[current_section][current_segment].composition_systems) + { + composition_current_section = composition_model->get_composition(position_in_cartesian_coordinates, + depth, + properties[i_property][1], + composition_current_section, + starting_depth, + maximum_depth, + distance_from_planes, + additional_parameters); + + WBAssert(!std::isnan(composition_current_section), "Composition_current_section is not a number: " << composition_current_section + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(composition_current_section), "Composition_current_section is not a finite: " << composition_current_section + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + + } + + for (const auto &composition_model: segment_vector[next_section][current_segment].composition_systems) + { + composition_next_section = composition_model->get_composition(position_in_cartesian_coordinates, + depth, + properties[i_property][1], + composition_next_section, + starting_depth, + maximum_depth, + distance_from_planes, + additional_parameters); + + WBAssert(!std::isnan(composition_next_section), "Composition_next_section is not a number: " << composition_next_section + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + WBAssert(std::isfinite(composition_next_section), "Composition_next_section is not a finite: " << composition_next_section + << ", based on a composition model with the name " << composition_model->get_name() << ", in feature " << this->name); + + } + + // linear interpolation between current and next section temperatures + output[entry_in_output[i_property]] = composition_current_section + section_fraction * (composition_next_section - composition_current_section); + break; + } + case 3: // grains + { + WorldBuilder::grains grains(output,properties[i_property][2],entry_in_output[i_property]); + WorldBuilder::grains grains_current_section = grains; + WorldBuilder::grains grains_next_section = grains; + + for (const auto &grains_model: segment_vector[current_section][current_segment].grains_systems) + { + grains_current_section = grains_model->get_grains(position_in_cartesian_coordinates, + depth, + properties[i_property][1], + grains_current_section, + starting_depth, + maximum_depth, + distance_from_planes, + additional_parameters); + + } + + for (const auto &grains_model: segment_vector[next_section][current_segment].grains_systems) + { + grains_next_section = grains_model->get_grains(position_in_cartesian_coordinates, + depth, + properties[i_property][1], + grains_next_section, + starting_depth, + maximum_depth, + distance_from_planes, + additional_parameters); + + } + + // linear interpolation between current and next section temperatures + for (size_t i = 0; i < grains.sizes.size(); i++) + { + grains.sizes[i] = grains_current_section.sizes[i] + section_fraction * (grains_next_section.sizes[i] - grains_current_section.sizes[i]); + } + + // average two rotations matrices throu quaternions. + for (size_t i = 0; i < grains_current_section.rotation_matrices.size(); i++) + { + const glm::quaternion::quat quat_current = glm::quaternion::quat_cast(grains_current_section.rotation_matrices[i]); + const glm::quaternion::quat quat_next = glm::quaternion::quat_cast(grains_next_section.rotation_matrices[i]); + + const glm::quaternion::quat quat_average = glm::quaternion::slerp(quat_current,quat_next,section_fraction); + + grains.rotation_matrices[i] = glm::quaternion::mat3_cast(quat_average); + } + + grains.unroll_into(output,entry_in_output[i_property]); + break; + } + case 4: + { + output[entry_in_output[i_property]] = static_cast(tag_index); + break; + } + default: + { + WBAssertThrow(false, + "Internal error: Unimplemented property provided. " << + "Only temperature (1), composition (2), grains (3) or tag (4) are allowed. " + "Provided property number was: " << properties[i_property][0]); + } + } + } + + } + } + } + + } + + 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 + ); + + const 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->bezier_curve); + + Objects::PlaneDistances plane_distances(distance_from_planes.distance_from_plane, distance_from_planes.distance_along_plane); + return plane_distances; + } + + /** + * Register plugin + */ + WB_REGISTER_FEATURE(SubductingPlate, subducting plate) + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/composition/interface.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/composition/interface.cc.bak new file mode 100644 index 00000000000..8690913524e --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/composition/interface.cc.bak @@ -0,0 +1,82 @@ +/* + 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/features/subducting_plate_models/composition/interface.h" + +#include + + + +namespace WorldBuilder +{ + namespace Features + { + namespace SubductingPlateModels + { + namespace Composition + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + prm.declare_model_entries("composition",parent_name, get_declare_map(),required_entries); + } + + + 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 Composition + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/composition/smooth.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/composition/smooth.cc.bak new file mode 100644 index 00000000000..6501fca135a --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/composition/smooth.cc.bak @@ -0,0 +1,131 @@ +/* + 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/features/subducting_plate_models/composition/smooth.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace SubductingPlateModels + { + namespace Composition + { + Smooth::Smooth(WorldBuilder::World *world_) + : + min_distance(NaN::DSNAN), + side_distance(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "smooth"; + } + + Smooth::~Smooth() + = default; + + void + Smooth::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), "Compositional model object"); + + prm.declare_entry("min distance slab top", Types::Double(0), + "The distance in meters from which the composition of this layer is present."); + prm.declare_entry("max distance slab top", Types::Double(0), + "The distance in meters from which the composition of this layer is present."); + prm.declare_entry("top fractions", Types::Array(Types::Double(1.0),1), + "The composition fraction at the top of the slab (layer)."); + prm.declare_entry("bottom fractions", Types::Array(Types::Double(0.0),1), + "The composition fraction at the bottom of the slab (layer)."); + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the labels of the composition which are present there."); + prm.declare_entry("operation", Types::String("replace", std::vector {"replace", "replace defined only", "add", "subtract"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value. Replacing implies that all compositions not " + "explicitly defined are set to zero. To only replace the defined compositions use the replace only defined option."); + } + + void + Smooth::parse_entries(Parameters &prm) + { + min_distance = prm.get("min distance slab top"); + max_distance = prm.get("max distance slab top"); + side_distance = std::abs(max_distance-min_distance); + //WBAssert(side_distance >= min_distance, "distance at the side needs to be larger or equal than the min distance."); + operation = string_operations_to_enum(prm.get("operation")); + top_fraction = prm.get_vector("top fractions"); + bottom_fraction = prm.get_vector("bottom fractions"); + compositions = prm.get_vector("compositions"); + } + + + double + Smooth::get_composition( const Point<3> & /*position*/, + const double /*depth*/, + const unsigned int composition_number, + double composition_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters & /*additional_parameters*/) const + { + double composition = composition_; + if (distance_from_planes.distance_from_plane <= max_distance && distance_from_planes.distance_from_plane >= min_distance) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + + // Hyperbolic tangent goes from 0 to 1 over approximately x=(0, 2) without any arguments. The function is written + // so that the composition returned 1 to 0 over the side_distance on either sides. + const double scaling = ( 1 - std::tanh(10 * (distance_from_planes.distance_from_plane-side_distance/2.0-min_distance)/side_distance ) )/2.0; + composition = top_fraction[i]*scaling + bottom_fraction[i] * (1-scaling); + + return apply_operation(operation,composition_,composition); + } + } + + if (operation == Operations::REPLACE) + return 0.0; + } + return composition; + } + + WB_REGISTER_FEATURE_SUBDUCTING_PLATE_COMPOSITION_MODEL (Smooth, smooth) + } // namespace Composition + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/composition/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/composition/uniform.cc.bak new file mode 100644 index 00000000000..9d7ae9627d1 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/composition/uniform.cc.bak @@ -0,0 +1,123 @@ +/* + 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/features/subducting_plate_models/composition/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/utilities.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace SubductingPlateModels + { + namespace Composition + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform compositional model. Sets constant compositional field."); + + // Declare entries of this plugin + prm.declare_entry("min distance slab top", Types::Double(0), + "todo The depth in meters from which the composition of this feature is present."); + prm.declare_entry("max distance slab top", Types::Double(std::numeric_limits::max()), + "todo The depth in meters to which the composition of this feature is present."); + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the labels of the composition which are present there."); + prm.declare_entry("fractions", Types::Array(Types::Double(1.0),1), + "TA list of compositional fractions corresponding to the compositions list."); + prm.declare_entry("operation", Types::String("replace", std::vector {"replace", "replace defined only", "add", "subtract"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value. Replacing implies that all compositions not " + "explicitly defined are set to zero. To only replace the defined compositions use the replace only defined option."); + + } + + void + Uniform::parse_entries(Parameters &prm) + { + min_depth = prm.get("min distance slab top"); + max_depth = prm.get("max distance slab top"); + compositions = prm.get_vector("compositions"); + fractions = prm.get_vector("fractions"); + operation = string_operations_to_enum(prm.get("operation")); + + WBAssertThrow(compositions.size() == fractions.size(), + "There are not the same amount of compositions and fractions."); + } + + + double + Uniform::get_composition(const Point<3> & /*position_in_cartesian_coordinates*/, + const double /*depth*/, + const unsigned int composition_number, + double composition, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_plane, + const AdditionalParameters & /*additional_parameters*/) const + { + if (distance_from_plane.distance_from_plane <= max_depth && distance_from_plane.distance_from_plane >= min_depth) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + return apply_operation(operation,composition,fractions[i]); + } + } + + if (operation == Operations::REPLACE) + return 0.0; + } + return composition; + } + WB_REGISTER_FEATURE_SUBDUCTING_PLATE_COMPOSITION_MODEL(Uniform, uniform) + } // namespace Composition + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/interface.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/interface.cc.bak new file mode 100644 index 00000000000..50faddd23af --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/interface.cc.bak @@ -0,0 +1,111 @@ +/* + 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/features/subducting_plate_models/grains/interface.h" + +#include + +#include "world_builder/types/object.h" +#include "world_builder/types/string.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace SubductingPlateModels + { + namespace Grains + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + 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()) + { + // prevent infinite recursion + if (it.first != parent_name) + { + prm.enter_subsection("oneOf"); + { + prm.enter_subsection(std::to_string(counter)); + { + prm.enter_subsection("properties"); + { + prm.declare_entry("", Types::Object(required_entries), "grains object"); + + prm.declare_entry("model", Types::String("",it.first), + "The name of the grains model."); + + 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 Grains + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/random_uniform_distribution.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/random_uniform_distribution.cc.bak new file mode 100644 index 00000000000..4317a90579d --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/random_uniform_distribution.cc.bak @@ -0,0 +1,217 @@ +/* + 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/features/subducting_plate_models/grains/random_uniform_distribution.h" + +#include + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace SubductingPlateModels + { + namespace Grains + { + RandomUniformDistribution::RandomUniformDistribution(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "random uniform distribution"; + } + + RandomUniformDistribution::~RandomUniformDistribution() + = default; + + void + RandomUniformDistribution::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Random uniform distribution grains model. The size of the grains can be independently set " + "to a single value or to a random distribution."); + + // Declare entries of this plugin + prm.declare_entry("min distance slab top", Types::Double(0), + "The distance from the slab top in meters from which the composition of this feature is present."); + prm.declare_entry("max distance slab top", Types::Double(std::numeric_limits::max()), + "The distance from the slab top in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be randomized between 0 and 1."); + + prm.declare_entry("normalize grain sizes", + Types::Array(Types::Bool(true),0), + "A list of whether the sizes of the grains should be normalized or not. If normalized, the total of the grains of a composition will be equal to 1."); + + + + } + + void + RandomUniformDistribution::parse_entries(Parameters &prm) + { + min_depth = prm.get("min distance slab top"); + max_depth = prm.get("max distance slab top"); + compositions = prm.get_vector("compositions"); + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + normalize_grain_sizes = prm.get_vector("normalize grain sizes"); + + + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == normalize_grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and normalize_grain_sizes (" << normalize_grain_sizes.size() << ")."); + } + + + WorldBuilder::grains + RandomUniformDistribution::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const double /*depth*/, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters & /*additional_parameters*/) const + { + WorldBuilder::grains grains_local = grains_; + if (distance_from_planes.distance_from_plane <= max_depth && distance_from_planes.distance_from_plane >= min_depth) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::uniform_real_distribution<> dist(0.0,1.0); + for (auto &&it_rotation_matrices : grains_local.rotation_matrices) + { + // set a uniform random a_cosine_matrix per grain + // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120). + // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c + // and is licenend accourding to this website with the following licence: + // + // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and + // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit + // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems + // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, + // don't be a jerk, and remember that anything free comes with no guarantee."" + // + // The book saids in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in + // the public domain, and is yours to study, modify, and use." + + // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2. + const double one = dist(world->get_random_number_engine()); + const double two = dist(world->get_random_number_engine()); + const double three = dist(world->get_random_number_engine()); + + const double theta = 2.0 * Consts::PI * one; // Rotation about the pole (Z) + const double phi = 2.0 * Consts::PI * two; // For direction of pole deflection. + const double z = 2.0* three; //For magnitude of pole deflection. + + // Compute a vector V used for distributing points over the sphere + // via the reflection I - V Transpose(V). This formulation of V + // will guarantee that if x[1] and x[2] are uniformly distributed, + // the reflected points will be uniform on the sphere. Note that V + // has length sqrt(2) to eliminate the 2 in the Householder matrix. + + const double r = std::sqrt( z ); + const double Vx = std::sin( phi ) * r; + const double Vy = std::cos( phi ) * r; + const double Vz = std::sqrt( 2.F - z ); + + // Compute the row vector S = Transpose(V) * R, where R is a simple + // rotation by theta about the z-axis. No need to compute Sz since + // it's just Vz. + + const double st = std::sin( theta ); + const double ct = std::cos( theta ); + const double Sx = Vx * ct - Vy * st; + const double Sy = Vx * st + Vy * ct; + + // Construct the rotation matrix ( V Transpose(V) - I ) R, which + // is equivalent to V S - R. + + it_rotation_matrices[0][0] = Vx * Sx - ct; + it_rotation_matrices[0][1] = Vx * Sy - st; + it_rotation_matrices[0][2] = Vx * Vz; + + it_rotation_matrices[1][0] = Vy * Sx + st; + it_rotation_matrices[1][1] = Vy * Sy - ct; + it_rotation_matrices[1][2] = Vy * Vz; + + it_rotation_matrices[2][0] = Vz * Sx; + it_rotation_matrices[2][1] = Vz * Sy; + it_rotation_matrices[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0 + } + + double total_size = 0; + for (auto &&it_sizes : grains_local.sizes) + { + it_sizes = grain_sizes[i] < 0 ? dist(world->get_random_number_engine()) : grain_sizes[i]; + total_size += it_sizes; + } + + if (normalize_grain_sizes[i]) + { + const double one_over_total_size = 1/total_size; + std::transform(grains_local.sizes.begin(), grains_local.sizes.end(), grains_local.sizes.begin(), + [one_over_total_size](double sizes) -> double { return sizes *one_over_total_size; }); + } + + return grains_local; + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_SUBDUCTING_PLATE_GRAINS_MODEL(RandomUniformDistribution, random uniform distribution) + } // namespace Grains + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/random_uniform_distribution_deflected.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/random_uniform_distribution_deflected.cc.bak new file mode 100644 index 00000000000..bf9ac3a3e05 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/random_uniform_distribution_deflected.cc.bak @@ -0,0 +1,223 @@ +/* + 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/features/subducting_plate_models/grains/random_uniform_distribution_deflected.h" + +#include + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace SubductingPlateModels + { + namespace Grains + { + RandomUniformDistributionDeflected::RandomUniformDistributionDeflected(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "random uniform distribution deflected"; + } + + RandomUniformDistributionDeflected::~RandomUniformDistributionDeflected() + = default; + + void + RandomUniformDistributionDeflected::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions to the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Random uniform distribution grains model. The size of the grains can be independently set " + "to a single value or to a random distribution."); + + // Declare entries of this plugin + prm.declare_entry("min distance slab top", Types::Double(0), + "The distance from the slab top in meters from which the composition of this feature is present."); + prm.declare_entry("max distance slab top", Types::Double(std::numeric_limits::max()), + "The distance from the slab top in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be randomized between 0 and 1."); + + prm.declare_entry("normalize grain sizes", + Types::Array(Types::Bool(true),0), + "A list of whether the sizes of the grains should be normalized or not. If normalized, the total of the grains of a composition will be equal to 1."); + + prm.declare_entry("deflections", + Types::Array(Types::Double(1),0), + "A list of the deflections of all of the grains in each composition between 0 and 1."); + + + + } + + void + RandomUniformDistributionDeflected::parse_entries(Parameters &prm) + { + min_depth = prm.get("min distance slab top"); + max_depth = prm.get("max distance slab top"); + compositions = prm.get_vector("compositions"); + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + normalize_grain_sizes = prm.get_vector("normalize grain sizes"); + deflections = prm.get_vector("deflections"); + + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == normalize_grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and normalize_grain_sizes (" << normalize_grain_sizes.size() << ")."); + WBAssertThrow(compositions.size() == deflections.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and deflections (" << deflections.size() << ")."); + } + + + WorldBuilder::grains + RandomUniformDistributionDeflected::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const double /*depth*/, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters & /*additional_parameters*/) const + { + WorldBuilder::grains grains_local = grains_; + if (distance_from_planes.distance_from_plane <= max_depth && distance_from_planes.distance_from_plane >= min_depth) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::uniform_real_distribution<> dist(0.0,1.0); + for (auto &&it_rotation_matrices : grains_local.rotation_matrices) + { + // set a uniform random a_cosine_matrix per grain + // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120). + // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c + // and is licenend accourding to this website with the following licence: + // + // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and + // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit + // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems + // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, + // don't be a jerk, and remember that anything free comes with no guarantee."" + // + // The book saids in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in + // the public domain, and is yours to study, modify, and use." + + // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2. + const double one = dist(world->get_random_number_engine()); + const double two = dist(world->get_random_number_engine()); + const double three = dist(world->get_random_number_engine()); + + const double theta = 2.0 * Consts::PI * one * deflections[i]; // Rotation about the pole (Z) + const double phi = 2.0 * Consts::PI * two; // For direction of pole deflection. + const double z = 2.0* three * deflections[i]; //For magnitude of pole deflection. + + // Compute a vector V used for distributing points over the sphere + // via the reflection I - V Transpose(V). This formulation of V + // will guarantee that if x[1] and x[2] are uniformly distributed, + // the reflected points will be uniform on the sphere. Note that V + // has length sqrt(2) to eliminate the 2 in the Householder matrix. + + const double r = std::sqrt( z ); + const double Vx = std::sin( phi ) * r; + const double Vy = std::cos( phi ) * r; + const double Vz = std::sqrt( 2.F - z ); + + // Compute the row vector S = Transpose(V) * R, where R is a simple + // rotation by theta about the z-axis. No need to compute Sz since + // it's just Vz. + + const double st = std::sin( theta ); + const double ct = std::cos( theta ); + const double Sx = Vx * ct - Vy * st; + const double Sy = Vx * st + Vy * ct; + + // Construct the rotation matrix ( V Transpose(V) - I ) R, which + // is equivalent to V S - R. + + it_rotation_matrices[0][0] = Vx * Sx - ct; + it_rotation_matrices[0][1] = Vx * Sy - st; + it_rotation_matrices[0][2] = Vx * Vz; + + it_rotation_matrices[1][0] = Vy * Sx + st; + it_rotation_matrices[1][1] = Vy * Sy - ct; + it_rotation_matrices[1][2] = Vy * Vz; + + it_rotation_matrices[2][0] = Vz * Sx; + it_rotation_matrices[2][1] = Vz * Sy; + it_rotation_matrices[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0 + } + + double total_size = 0; + for (auto &&it_sizes : grains_local.sizes) + { + it_sizes = grain_sizes[i] < 0 ? dist(world->get_random_number_engine()) : grain_sizes[i]; + total_size += it_sizes; + } + + if (normalize_grain_sizes[i]) + { + const double one_over_total_size = 1/total_size; + std::transform(grains_local.sizes.begin(), grains_local.sizes.end(), grains_local.sizes.begin(), + [one_over_total_size](double sizes) -> double { return sizes *one_over_total_size; }); + } + + return grains_local; + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_SUBDUCTING_PLATE_GRAINS_MODEL(RandomUniformDistributionDeflected, random uniform distribution deflected) + } // namespace Grains + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/uniform.cc.bak new file mode 100644 index 00000000000..672dac7948b --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/grains/uniform.cc.bak @@ -0,0 +1,169 @@ +/* + 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/features/subducting_plate_models/grains/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/utilities.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace SubductingPlateModels + { + namespace Grains + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN) + + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add compositions the required parameters. + prm.declare_entry("", Types::Object({"compositions"}), + "Uniform grains model. All grains start exactly the same."); + + // Declare entries of this plugin + prm.declare_entry("min distance slab top", Types::Double(0), + "The distance from the slab top in meters from which the composition of this feature is present."); + prm.declare_entry("max distance slab top", Types::Double(std::numeric_limits::max()), + "The distance from the slab top in meters to which the composition of this feature is present."); + + prm.declare_entry("compositions", Types::Array(Types::UnsignedInt(),0), + "A list with the integer labels of the composition which are present there."); + + prm.declare_entry("rotation matrices", Types::Array(Types::Array(Types::Array(Types::Double(0),3,3),3,3),0), + "A list with the labels of the grains which are present there for each compositions."); + + prm.declare_entry("Euler angles z-x-z", Types::Array(Types::Array(Types::Double(0),3,3),0), + "A list with the z-x-z Euler angles of the grains which are present there for each compositions."); + + prm.declare_entry("orientation operation", Types::String("replace", std::vector {"replace"}), + "Whether the value should replace any value previously defined at this location (replace) or " + "add the value to the previously define value (add, not implemented). Replacing implies that all values not " + "explicitly defined are set to zero."); + + prm.declare_entry("grain sizes", + Types::Array(Types::Double(-1),0), + "A list of the size of all of the grains in each composition. If set to <0, the size will be set so that the total is equal to 1."); + + + } + + void + Uniform::parse_entries(Parameters &prm) + { + min_depth = prm.get("min distance slab top"); + max_depth = prm.get("max distance slab top"); + compositions = prm.get_vector("compositions"); + + const bool set_euler_angles = prm.check_entry("Euler angles z-x-z"); + const bool set_rotation_matrices = prm.check_entry("rotation matrices"); + + WBAssertThrow(!(set_euler_angles == true && set_rotation_matrices == true), + "Only Euler angles or Rotation matrices may be set, but both are set for " << prm.get_full_json_path()); + + + WBAssertThrow(!(set_euler_angles == false && set_rotation_matrices == false), + "Euler angles or Rotation matrices have to be set, but neither are set for " << prm.get_full_json_path()); + + if (set_euler_angles) + { + std::vector > euler_angles_vector = prm.get_vector >("Euler angles z-x-z"); + rotation_matrices.resize(euler_angles_vector.size()); + for (size_t i = 0; i,3> >("rotation matrices"); + } + + operation = prm.get("orientation operation"); + grain_sizes = prm.get_vector("grain sizes"); + + + WBAssertThrow(compositions.size() == rotation_matrices.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and rotation_matrices (" << rotation_matrices.size() << ")."); + WBAssertThrow(compositions.size() == grain_sizes.size(), + "There are not the same amount of compositions (" << compositions.size() + << ") and grain_sizes (" << grain_sizes.size() << ")."); + } + + + WorldBuilder::grains + Uniform::get_grains(const Point<3> & /*position_in_cartesian_coordinates*/, + const double /*depth*/, + const unsigned int composition_number, + WorldBuilder::grains grains_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters & /*additional_parameters*/) const + { + WorldBuilder::grains grains_local = grains_; + if (distance_from_planes.distance_from_plane <= max_depth && distance_from_planes.distance_from_plane >= min_depth) + { + for (unsigned int i =0; i < compositions.size(); ++i) + { + if (compositions[i] == composition_number) + { + std::fill(grains_local.rotation_matrices.begin(),grains_local.rotation_matrices.end(),rotation_matrices[i]); + + const double size = grain_sizes[i] < 0 ? 1.0/static_cast(grains_local.sizes.size()) : grain_sizes[i]; + std::fill(grains_local.sizes.begin(),grains_local.sizes.end(),size); + + return grains_local; + } + } + } + return grains_local; + } + WB_REGISTER_FEATURE_SUBDUCTING_PLATE_GRAINS_MODEL(Uniform, uniform) + } // namespace Grains + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/adiabatic.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/adiabatic.cc.bak new file mode 100644 index 00000000000..4bed92202a4 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/adiabatic.cc.bak @@ -0,0 +1,166 @@ +/* + 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/features/subducting_plate_models/temperature/adiabatic.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace SubductingPlateModels + { + namespace Temperature + { + Adiabatic::Adiabatic(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + potential_mantle_temperature(NaN::DSNAN), + thermal_expansion_coefficient(NaN::DSNAN), + specific_heat(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "adiabatic"; + } + + Adiabatic::~Adiabatic() + = default; + + void + Adiabatic::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + prm.declare_entry("", Types::Object(), + "Adiabatic temperature model. Uses global values by default."); + + // Declare entries of this plugin + prm.declare_entry("min distance slab top", Types::Double(0), + "todo The depth in meters from which the composition of this feature is present."); + + prm.declare_entry("max distance slab top", Types::Double(std::numeric_limits::max()), + "todo The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("potential mantle temperature", Types::Double(-1), + "The potential temperature of the mantle at the surface in Kelvin. " + "If the value is lower then zero, the global value is used."); + + prm.declare_entry("thermal expansion coefficient", Types::Double(-1), + "The thermal expansion coefficient in $K^{-1}$. " + "If the value is lower then zero, the global value is used."); + + prm.declare_entry("specific heat", Types::Double(-1), + "The specific heat in $J kg^{-1} K^{-1}$. " + "If the value is lower then zero, the global value is used."); + + } + + void + Adiabatic::parse_entries(Parameters &prm) + { + + min_depth = prm.get("min distance slab top"); + max_depth = prm.get("max distance slab top"); + operation = string_operations_to_enum(prm.get("operation")); + + potential_mantle_temperature = prm.get("potential mantle temperature"); + if (potential_mantle_temperature < 0) + potential_mantle_temperature = this->world->potential_mantle_temperature; + + + thermal_expansion_coefficient = prm.get("thermal expansion coefficient"); + if (thermal_expansion_coefficient < 0) + thermal_expansion_coefficient = this->world->thermal_expansion_coefficient; + + specific_heat = prm.get("specific heat"); + if (specific_heat < 0) + specific_heat = this->world->specific_heat; + + // Some assertions in debug mode can't hurt and have helped before. + WBAssert(!std::isnan(potential_mantle_temperature), + "potential_mantle_temperature is not a number: " << potential_mantle_temperature << '.'); + WBAssert(std::isfinite(potential_mantle_temperature), + "potential_mantle_temperature is not a finite: " << potential_mantle_temperature << '.'); + + WBAssert(!std::isnan(thermal_expansion_coefficient), + "thermal_expansion_coefficient is not a number: " << thermal_expansion_coefficient << '.'); + WBAssert(std::isfinite(thermal_expansion_coefficient), + "thermal_expansion_coefficient is not a finite: " << thermal_expansion_coefficient << '.'); + + WBAssert(!std::isnan(specific_heat), + "specific_heat is not a number: " << specific_heat << '.'); + WBAssert(std::isfinite(thermal_expansion_coefficient), + "specific_heat is not a finite: " << specific_heat << '.'); + + } + + + double + Adiabatic::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const double depth, + const double gravity_norm, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters & /*additional_parameters*/) const + { + + const double distance_from_plane = distance_from_planes.distance_from_plane; + if (distance_from_plane <= max_depth && distance_from_plane >= min_depth) + { + const double adabatic_temperature = potential_mantle_temperature * + std::exp(((thermal_expansion_coefficient * gravity_norm) / + specific_heat) * depth); + + + WBAssert(!std::isnan(adabatic_temperature), + "adabatic_temperature is not a number: " << adabatic_temperature << ". " + <<"Parameters: potential_mantle_temperature = " << potential_mantle_temperature + <<", thermal_expansion_coefficient = " << thermal_expansion_coefficient + << ", gravity_norm = " << gravity_norm + << ", specific_heat = " << specific_heat + << ", depth = " << depth); + + WBAssert(std::isfinite(adabatic_temperature), + "adabatic_temperature is not a finite: " << adabatic_temperature << '.'); + + return apply_operation(operation,temperature_,adabatic_temperature); + } + + + return temperature_; + } + + WB_REGISTER_FEATURE_SUBDUCTING_PLATE_TEMPERATURE_MODEL(Adiabatic, adiabatic) + } // namespace Temperature + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/interface.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/interface.cc.bak new file mode 100644 index 00000000000..ada29a76574 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/interface.cc.bak @@ -0,0 +1,94 @@ +/* + 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/features/subducting_plate_models/temperature/interface.h" + +#include + +#include "world_builder/types/string.h" + +namespace WorldBuilder +{ + namespace Features + { + namespace SubductingPlateModels + { + namespace Temperature + { + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + void + Interface::declare_entries(Parameters &prm, + const std::string &parent_name, + const std::vector &required_entries) + { + // The type needs to be stored in a separate value, otherwise there are memory issues + const Types::String type = Types::String("replace", std::vector {"replace", "add", "subtract"}); + + prm.declare_model_entries("temperature",parent_name, get_declare_map(),required_entries, + { + std::tuple + { + "operation", type, + "Whether the value should replace any value previously defined at this location (replace), " + "add the value to the previously define value (add) or subtract the value to the previously " + "define value (subtract)." + } + }); + } + + + 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 Temperature + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/linear.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/linear.cc.bak new file mode 100644 index 00000000000..e4c6a70dce8 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/linear.cc.bak @@ -0,0 +1,138 @@ +/* + 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/features/subducting_plate_models/temperature/linear.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace SubductingPlateModels + { + namespace Temperature + { + Linear::Linear(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + top_temperature(NaN::DSNAN), + bottom_temperature(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "linear"; + } + + Linear::~Linear() + = default; + + void + Linear::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `max distance slab top` center to the required parameters. + prm.declare_entry("", Types::Object({"max distance slab top"}), + "Linear temperature model. Can be set to use an adiabatic temperature at the boundaries."); + + // Declare entries of this plugin + prm.declare_entry("min distance slab top", Types::Double(0), + "todo The depth in meters from which the composition of this feature is present."); + + prm.declare_entry("max distance slab top", Types::Double(std::numeric_limits::max()), + "todo The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("top temperature", Types::Double(293.15), + "The temperature at the top in degree Kelvin of this feature." + "If the value is below zero, the an adiabatic temperature is used."); + + prm.declare_entry("bottom temperature", Types::Double(-1), + "The temperature at the bottom in degree Kelvin of this feature. " + "If the value is below zero, an adiabatic temperature is used."); + } + + void + Linear::parse_entries(Parameters &prm) + { + min_depth = prm.get("min distance slab top"); + max_depth = prm.get("max distance slab top"); + WBAssert(max_depth >= min_depth, "max depth needs to be larger or equal to min depth."); + operation = string_operations_to_enum(prm.get("operation")); + top_temperature = prm.get("top temperature"); + bottom_temperature = prm.get("bottom temperature"); + } + + + double + Linear::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const double /*depth*/, + const double gravity_norm, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_plane, + const AdditionalParameters & /*additional_parameters*/) const + { + if (distance_from_plane.distance_from_plane <= max_depth && distance_from_plane.distance_from_plane >= min_depth) + { + const double min_depth_local = min_depth; + const double max_depth_local = max_depth; + + + double top_temperature_local = top_temperature; + if (top_temperature_local < 0) + { + top_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient * gravity_norm) / + this->world->specific_heat) * min_depth_local); + } + + double bottom_temperature_local = bottom_temperature; + if (bottom_temperature_local < 0) + { + bottom_temperature_local = this->world->potential_mantle_temperature * + std::exp(((this->world->thermal_expansion_coefficient * gravity_norm) / + this->world->specific_heat) * max_depth_local); + } + + const double new_temperature = top_temperature_local + + (distance_from_plane.distance_from_plane - min_depth_local) * + ((bottom_temperature_local - top_temperature_local) / (max_depth_local - min_depth_local)); + return apply_operation(operation,temperature_,new_temperature); + + + } + return temperature_; + } + + WB_REGISTER_FEATURE_SUBDUCTING_PLATE_TEMPERATURE_MODEL(Linear, linear) + } // namespace Temperature + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/mass_conserving.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/mass_conserving.cc.bak new file mode 100644 index 00000000000..f2ad576c5c2 --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/mass_conserving.cc.bak @@ -0,0 +1,639 @@ +/* + 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 . + + + Note that the empirical model used to define how Tmin increases with depth + and how the position of Tmin shift with depth is expected to change somewhat + after better calibrating with further tests. +*/ + +#include "world_builder/features/subducting_plate_models/temperature/mass_conserving.h" +#include "world_builder/features/oceanic_plate_models/temperature/plate_model.h" +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/object.h" +#include "world_builder/types/point.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" +#include "world_builder/types/int.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace SubductingPlateModels + { + namespace Temperature + { + MassConserving::MassConserving(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + density(NaN::DSNAN), + mantle_coupling_depth(NaN::DSNAN), + forearc_cooling_factor(NaN::DSNAN), + thermal_conductivity(NaN::DSNAN), + thermal_expansion_coefficient(NaN::DSNAN), + specific_heat(NaN::DSNAN), + thermal_diffusivity(NaN::DSNAN), + potential_mantle_temperature(NaN::DSNAN), + surface_temperature(NaN::DSNAN), + taper_distance(NaN::DSNAN), + adiabatic_heating(true), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "mass conserving"; + } + + MassConserving::~MassConserving() = default; + + void + MassConserving::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `plate velocity` to the required parameters. + prm.declare_entry("", Types::Object({"plate velocity"}), + "Mass conserving temperature model. The temperature " + "model uses the heat content (proportional to to thermal mass anomaly) to " + "define a smooth temperature profile that conserves mass along the slab length. " + "An empirical model, using error functions for smooth transitions, is used to " + " define how the minimum temperature increases with depth and how the location of " + "the minimum temperature shifts into the slab interior. The slab is divided into top " + "and bottom parts, which meet at the location where the minimum temperature occurs in the slab. " + "For the bottom slab, the temperature is defined by a half-space cooling model. " + "For the top of the slab the temperature is defined by one side of a 1D infinite " + "space cooling model: this function was chosen to have a smoother temperature function across " + "the minimum temperature position. The age of the overriding plate is used so the slab temperature " + "at shallow depth smoothly transitions to the temperature of the overriding plate: " + "this is not perfect, and is affected by the value of \"top truncation\" parameter " + "subducting plate. Notes:" + "1) the parameter \"thickness\" for the subducting plate segments needs to be defined but is not used. " + "2) because we use a negative truncation for distance above the slab, it is recommended to use" + "depth method:begin at end segment, in the main part of the world-builder file." + "Other methods may lead to gpas in temperatures at the segment boundaries." + "3)the empirical model used to define how Tmin increases with depth " + "and how the position of Tmin shift with depth is expected to change somewhat " + "after better calibrating with further tests."); + + // Declare entries of this plugin + prm.declare_entry("min distance slab top", Types::Double(0), + "The distance in meters from the top surface of the slab over which the temperature is " + "determined by this feature. This parameter should be negative and should be 1.5-2 times " + "larger than the nominal slab thickness to allow the diffusion of cold " + "temperatures from in the slab into the mantle above the slab surface. " + "Also note that the top truncation value for the slab segment needs to have a value " + "of -1, otherwise the temperature above the slab will be cut off at a distance less than " + "the value set here."); + + prm.declare_entry("max distance slab top", Types::Double(std::numeric_limits::max()), + "The distance in meters from the top surface of the slab over which the temperature is " + "determined by this feature. This parameter should be positive and approximately 2.5-3.0 times " + "larger than the nominal slab thickness to allow the diffusion of cold" + "temperatures from in the slab into the mantle below the slab surface." + "For example if the slab starts with cold temperatures over a 100 km wide region, this" + "parameters should be about 250 km."); + + prm.declare_entry("density", Types::Double(3300), + "The reference density of the subducting plate in $kg/m^3$"); + + prm.declare_entry("plate velocity", Types::OneOf(Types::Double(0.05),Types::Array(Types::ValueAtPoints(0.05, std::numeric_limits::max()))), + "The velocity with which the plate subducts in meters per year. Default is 5 cm/yr"); + + prm.declare_entry("subducting velocity", Types::OneOf(Types::Double(-1), Types::Array(Types::Array(Types::Double(-1), 1), 1)), + "The velocity with which the ridge is moving through time, and how long the ridge " + "has been moving. First value is the velocity, second is the time. Default is [0 cm/yr, 0 yr]"); + + prm.declare_entry("coupling depth", Types::Double(100e3), + "The depth at which the slab surface first comes in contact with the hot mantle wedge " + "in meters. Default is 100 km."); + + prm.declare_entry("forearc cooling factor", Types::Double(1.0), + "Increase the value to create thin (~2 km) cold thermal boundary layer above the slab." + "Any value greater than 1 does NOT meet the instantaneous conservation of mass, but does allow " + "one to account for the history of insulating the forearc from heating up to this point in time. " + "Note younger subducting lithosphere provides less insulation, while thicker, older slabs " + "provide more insulation. Values up to 10 to 30 have been tested and don't cause any other " + "extraneous effects. The larger th value the more you are not meeting the mass conserving criteria, " + "so you don't want to see this affecting the temperature beyond the coupling depth as it will " + "increase the mass of the slab and affect how it sinks. If you use higher values, you will start to " + "see that this creates a very thick cool layer above the entire slab - if you see this extending beyond " + "the coupling zone reduce the value. You should use a value of 1 first and then " + "only increase as little as possible to cool just the forearc region. " + "Please examine the output temperature carefully. "); + + prm.declare_entry("thermal conductivity", Types::Double(3.3), + "The thermal conductivity of the subducting plate material in $W m^{-1} K^{-1}$."); + + prm.declare_entry("thermal expansion coefficient", Types::Double(-1), + "The thermal expansivity of the subducting plate material in $K^{-1}$. If smaller than zero, the global value is used."); + + prm.declare_entry("specific heat", Types::Double(-1), + "The specific heat of the subducting plate material in $J kg^{-1} K^{-1}$. If smaller than zero, the global value is used."); + + prm.declare_entry("thermal diffusivity", Types::Double(-1), + "The thermal conductivity of the subducting plate material in $W m^{-1} K^{-1}$."); + + prm.declare_entry("adiabatic heating", Types::Bool(true), + "Whether adiabatic heating should be used for the slab."); + + prm.declare_entry("taper distance", Types::Double(100e3), + "Distance over which to taper the slab tip." + "tapers the initial heat content to zero and the minimum temperature to the background temperature."); + + prm.declare_entry("potential mantle temperature", Types::Double(-1), + "The potential temperature of the mantle at the surface in Kelvin. If smaller than zero, the global value is used."); + + prm.declare_entry("ridge coordinates", Types::Array(Types::Array(Types::Point<2>(), 2),1), + "An list of ridges. Each ridge is a lists of at least 2 2d points which " + "define the location of the ridge. You need to define at least one ridge." + "So the an example with two ridges is " + "[[[10,20],[20,30],[10,40]],[[50,10],[60,10]]]."); + + prm.declare_entry("reference model name", Types::String("half space model"), + "The type of thermal model to use in the mass conserving model of slab temperature. " + "Options are half space model and plate model"); + + prm.declare_entry("apply spline", Types::Bool(false), + "Whether a spline should be applied on the mass conserving model."); + + prm.declare_entry("number of points in spline", Types::UnsignedInt(5), + "The number of points in the spline"); + + } + + void + MassConserving::parse_entries(Parameters &prm) + { + + min_depth = prm.get("min distance slab top"); + max_depth = prm.get("max distance slab top"); + operation = string_operations_to_enum(prm.get("operation")); + + density = prm.get("density"); + thermal_conductivity = prm.get("thermal conductivity"); + ridge_spreading_velocities = prm.get_value_at_array("plate velocity"); + subducting_velocities = prm.get_vector_or_double("subducting velocity"); + + mantle_coupling_depth = prm.get("coupling depth"); + forearc_cooling_factor = prm.get("forearc cooling factor"); + + taper_distance = prm.get("taper distance"); + + thermal_expansion_coefficient = prm.get("thermal expansion coefficient"); + if (thermal_expansion_coefficient < 0) + thermal_expansion_coefficient = this->world->thermal_expansion_coefficient; + + specific_heat = prm.get("specific heat"); + if (specific_heat < 0) + specific_heat = this->world->specific_heat; + + thermal_diffusivity = prm.get("thermal diffusivity"); + if (thermal_diffusivity < 0) + thermal_diffusivity = this->world->thermal_diffusivity; + + adiabatic_heating = prm.get("adiabatic heating"); + + potential_mantle_temperature = this->world->potential_mantle_temperature >= 0 + ? + this->world->potential_mantle_temperature + : + prm.get("potential mantle temperature"); + + surface_temperature = this->world->surface_temperature; + + mid_oceanic_ridges = prm.get_vector>>("ridge coordinates"); + const double dtr = prm.coordinate_system->natural_coordinate_system() == spherical ? Consts::PI / 180.0 : 1.0; + for (auto &ridge_coordinates : mid_oceanic_ridges) + for (auto &ridge_coordinate : ridge_coordinates) + { + ridge_coordinate *= dtr; + } + + unsigned int ridge_point_index = 0; + for (const auto &mid_oceanic_ridge : mid_oceanic_ridges) + { + std::vector ridge_spreading_velocities_for_ridge; + for (unsigned int index_y = 0; index_y < mid_oceanic_ridge.size(); index_y++) + { + if (ridge_spreading_velocities.second.size() == 1) + { + ridge_spreading_velocities_for_ridge.push_back(ridge_spreading_velocities.second[0]); + } + else + { + ridge_spreading_velocities_for_ridge.push_back(ridge_spreading_velocities.second[ridge_point_index]); + } + ridge_point_index += 1; + } + ridge_spreading_velocities_at_each_ridge_point.push_back(ridge_spreading_velocities_for_ridge); + } + + std::string reference_model_name_str = prm.get("reference model name"); + if (reference_model_name_str=="plate model") + reference_model_name = plate_model; + else if (reference_model_name_str=="half space model") + reference_model_name = half_space_model; + + apply_spline = prm.get("apply spline"); + spline_n_points = prm.get("number of points in spline"); + + if (subducting_velocities[0].size() > 1) + { + for (unsigned int ridge_index = 0; ridge_index < mid_oceanic_ridges.size(); ridge_index++) + { + WBAssertThrow(subducting_velocities.size() == mid_oceanic_ridges.size() && + subducting_velocities[ridge_index].size() == mid_oceanic_ridges[ridge_index].size(), + "subducting velocity must have the same dimension as the ridge coordinates parameter."); + for (unsigned int point_index = 0; point_index < mid_oceanic_ridges[ridge_index].size(); point_index++) + { + WBAssertThrow(Utilities::approx(subducting_velocities[ridge_index][point_index], + ridge_spreading_velocities_at_each_ridge_point[ridge_index][point_index]), + "Currently, subducting velocity must equal the spreading velocity to satisfy conservation of mass. " + "This will be changed in the future to allow for the spreading center to move depending on the relative " + "difference between the spreading velocity and the subducting velocity, thereby conserving mass."); + } + } + } + } + + double + MassConserving::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const double depth, + const double gravity_norm, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const + { + + const double distance_from_plane = distance_from_planes.distance_from_plane; + + if (distance_from_plane <= max_depth && distance_from_plane >= min_depth) + { + + const Point<3> trench_point = distance_from_planes.closest_trench_point; + const Objects::NaturalCoordinate trench_point_natural = Objects::NaturalCoordinate(trench_point, + *(world->parameters.coordinate_system)); + + std::vector ridge_parameters = Utilities::calculate_ridge_distance_and_spreading(mid_oceanic_ridges, + ridge_spreading_velocities_at_each_ridge_point, + world->parameters.coordinate_system, + trench_point_natural, + subducting_velocities, + ridge_spreading_velocities.first); + + constexpr double km2m = 1.0e3; // 1000 m/km + constexpr double cm2m = 100; // 100 cm/m + constexpr double my = 1.0e6; // 1e6 y/my + + /* information about nearest point on the slab segment */ + const double distance_along_plane = distance_from_planes.distance_along_plane; + const double depth_to_reference_surface = distance_from_planes.depth_reference_surface; + const double total_segment_length = additional_parameters.total_local_segment_length; + const double average_angle = distance_from_planes.average_angle; + + std::vector slab_ages = calculate_effective_trench_and_plate_ages(ridge_parameters, distance_along_plane); + + const double seconds_in_year = 60.0 * 60.0 * 24.0 * 365.25; // sec/y + const double spreading_velocity = ridge_parameters[0] * seconds_in_year; // m/yr + double subducting_velocity = ridge_parameters[2] * seconds_in_year; // m/yr + + if (subducting_velocity <= 0) + subducting_velocity = spreading_velocity; + + const double age_at_trench = slab_ages[0]; + const double plate_age_sec = age_at_trench * seconds_in_year; // y --> seconds + // 1. Determine initial heat content of the slab based on age of plate at trench + // This uses the integral of the half-space temperature profile + // The initial heat content is also decided from the type of thermal model to use in the + // mass conserving model + double initial_heat_content; + if (reference_model_name == plate_model) + { + initial_heat_content = thermal_conductivity / thermal_diffusivity * + (surface_temperature - potential_mantle_temperature) * max_depth / 2.0; + for (int i = 0; i< std::floor(plate_model_summation_number/2.0); ++i) + { + // because n < sommation_number + 1 and n = 2k + 1 + // The "spreading_velocity" instead of "spreading_velocity_UI" is used for the last instance as "age_at_trench" has + // a unit of yr. + const double subducting_velocity_UI = subducting_velocity / seconds_in_year; + const double temp_heat_content = thermal_conductivity / thermal_diffusivity * + (surface_temperature - potential_mantle_temperature) * + 4 * max_depth / double(2*i + 1) / double(2*i + 1) / Consts::PI / Consts::PI * + exp((subducting_velocity_UI * max_depth / 2 / thermal_diffusivity - + std::sqrt(subducting_velocity_UI * subducting_velocity_UI * max_depth * max_depth / 4.0 / thermal_diffusivity / thermal_diffusivity + + double(2*i + 1) * double(2*i + 1) * Consts::PI * Consts::PI)) * + subducting_velocity * age_at_trench / max_depth); + initial_heat_content -= temp_heat_content; + } + } + else + { + initial_heat_content = 2 * thermal_conductivity * (surface_temperature - potential_mantle_temperature) * + std::sqrt(plate_age_sec / (thermal_diffusivity * Consts::PI)); + } + + // Plate age increases with distance along the slab in the mantle + double effective_plate_age = slab_ages[1]; + + // Need adiabatic temperature at position of grid point + const double background_temperature = adiabatic_heating ? potential_mantle_temperature * + std::exp(thermal_expansion_coefficient * gravity_norm * depth / specific_heat) + : potential_mantle_temperature; + + WBAssert(!std::isnan(background_temperature), "Internal error: temp is not a number: " << background_temperature << ". In exponent: " + << std::exp(((thermal_expansion_coefficient * gravity_norm) / specific_heat) * depth) + << ", thermal_expansion_coefficient = " << thermal_expansion_coefficient << ", gravity_norm = " << gravity_norm + << ", specific_heat = " << specific_heat << ", depth = " << depth); + + const double adiabatic_gradient = adiabatic_heating ? background_temperature - potential_mantle_temperature : 0; + + // 2. Get Tmin and offset as a function of depth: these depend on plate velocity and plate age_at_trench. + // shallow-dipping slabs will take longer to reach the same depth - this leads to larger effective age at a given depth + // causing these slabs to be broader than steeper dipping slabs + // These equations are empirical based on fitting the temperature profiles from dynamic subduction models. + // and published kinematic models for specific subduction zones. + + // increases Tmin slope for slower relative to slope for maximum plate velocity + // will be between 0.1 (fast) and 0.35 (slow) + const double max_plate_vel = 20/cm2m; // e.g., 20 cm/yr -> 0.2 m/yr + const double vsubfact = std::min( std::max( 0.35 + ((0.1-0.35) / max_plate_vel) * subducting_velocity, 0.1), 0.35); + + // increases Tmin slope for younger plate relative to slope for old place + // will be between 0.1 (old) and 0.35 *(young) + const double max_plate_age = 100*my; // years + const double max_age_fact = 1.0; + const double agefact = std::min( std::max( max_age_fact + ((0.1-max_age_fact) / max_plate_age) * age_at_trench, 0.1), max_age_fact); + + // increases offset relative to slab surface for older plates + // will be between 0.1 (young) and 0.35 (old) + const double agefact2 = std::max( std::min( 0.1 + ((0.35-0.1) / max_plate_age) * age_at_trench, 0.35), 0.1); + + // ranges between 0.5 (old and fast) and 1.0 (young and slow) + const double subfact = 0.3 + vsubfact + agefact; // this has a minimum value of 0.5 for the erfc + // ranges between 0.5 (young and fast) and 1 (old and slow) + const double subfact2 = 0.3 + vsubfact + agefact2; + + // Minimum Temperature + const double min_Tcoup = 10; // 0.3*mantle_coupling_depth/km2m; // deg C: from 0.3deg/km * 100 km = 30 deg + const double max_Tcoup = 350; // deg C: from Cascadia subduction models by Gao and Wang, Gcubd 2017 + const double Tcoup = min_Tcoup + (subfact - 0.5)*(max_Tcoup - min_Tcoup); + + const double min_Tmin660 = 300; //110; // based on syracruse models (with 0.5 deg/km adiabat; (265-30)-0.5*240) + const double max_Tmin660 = 900; + const double Tmin660 = min_Tmin660 + (subfact - 0.5)*(max_Tmin660 - min_Tmin660); + + // Temperature offset + const double min_offset_coup = 2*km2m; // values from syracuse and time-dep Citcom run + const double max_offset_coup = 10*km2m; + const double offset_coup = min_offset_coup + (subfact2)*(max_offset_coup - min_offset_coup); + + const double min_offset660 = 15*km2m; // values from time-dep Citcom run + const double max_offset660 = 25*km2m; + const double offset660 = min_offset660 + (subfact2)*(max_offset660 - min_offset660); + + // For tapering the slab tip temperature to the mantle temperature + const double start_taper_distance = total_segment_length - taper_distance; + + const double upper_mantle_lengthscale = 660e3 - mantle_coupling_depth; // m + + + const double taper_con = 0.8; // controls how close taper gets to end of segment + double theta = 0; + double min_temperature = 0; + double offset = 0; + + if (depth_to_reference_surface < mantle_coupling_depth) + { + // above coupling depth + theta = (mantle_coupling_depth - depth_to_reference_surface) / (subfact * mantle_coupling_depth); // must be scaled depth_coupling to match Tcoup ad Tsurface. + min_temperature = Tcoup * std::erfc(theta); + offset = offset_coup * std::erfc(theta); + } + else if (distance_along_plane >= start_taper_distance) + { + // beyond start taper distance to taper the slab tip + + const double depth_start_taper = depth_to_reference_surface - (distance_along_plane - start_taper_distance) + * std::sin(average_angle * Consts::PI / 180.0); + const double theta_start = (mantle_coupling_depth - depth_start_taper) / (subfact * upper_mantle_lengthscale); + const double Tmin_start_taper = Tcoup + Tmin660 * (std::erfc(theta_start)) - Tmin660; + //keep the offset location constant in the taper + const double offset_start_taper = offset_coup + (offset660) * std::erfc(theta_start) - offset660; + + // taper Tmin to the mantle temperature + theta = (distance_along_plane - start_taper_distance) / (taper_distance); + min_temperature = Tmin_start_taper + (potential_mantle_temperature - Tmin_start_taper) * (1-std::erfc(taper_con*theta)); + offset = offset_start_taper + (2*max_offset660 - offset_start_taper) * (1-std::erfc(taper_con*theta)); + + // Also taper the initial heat content and effective plate age + initial_heat_content = initial_heat_content * std::erfc(1.5*taper_con*theta); + effective_plate_age = effective_plate_age * std::erfc(1.5*taper_con*theta); + } + + else + { + theta = (mantle_coupling_depth - depth_to_reference_surface) / (subfact * upper_mantle_lengthscale); + min_temperature = Tcoup + Tmin660 * std::erfc(theta) - Tmin660; + offset = offset_coup + offset660 * std::erfc(theta) - offset660; + } + + min_temperature = min_temperature + adiabatic_gradient + surface_temperature; + + // Adjust distance for the offset of the minimum temperature from the top of the slab + const double adjusted_distance = distance_from_plane - offset; + + // Base value chosen to insure that even young slabs have some cooling of the top of the slab + // Use forearc_cooling_factor input variable to increase the amount of long-term cooling of the forearc. + const double max_top_heat_content = -1.0e9 * forearc_cooling_factor * background_temperature; // need to multiply by background temperature since it gets divided by something of this scale. + + double temperature = 0.0; // temperature (to be determined) at this location in the mesh + + if (min_temperature < background_temperature) + { + + // 3. Determine the heat content for side 1 (bottom) of the slab + // Comes from integrating the half-space cooling model or the plate model temperature + // The bottom heat content is also decided from the type of thermal model to use in the + // mass conserving model + double bottom_heat_content; + if (reference_model_name == plate_model) + { + bottom_heat_content = thermal_conductivity / thermal_diffusivity * + (min_temperature - potential_mantle_temperature) * max_depth / 2.0; + for (int i = 0; i< std::floor(plate_model_summation_number/2.0); ++i) + { + // because n < sommation_number + 1 and n = 2k + 1 + const double subducting_velocity_UI = subducting_velocity / seconds_in_year; + const double temp_heat_content = thermal_conductivity / thermal_diffusivity * + (min_temperature - potential_mantle_temperature) * + 4 * max_depth / double(2*i + 1) / double(2*i + 1) / Consts::PI / Consts::PI * + exp((subducting_velocity_UI * max_depth / 2.0 / thermal_diffusivity - + std::sqrt(subducting_velocity_UI * subducting_velocity_UI * max_depth * max_depth / 4.0 / thermal_diffusivity / thermal_diffusivity + + double(2*i + 1) * double(2*i + 1) * Consts::PI * Consts::PI)) * + subducting_velocity_UI * effective_plate_age / max_depth); + bottom_heat_content -= temp_heat_content; + } + } + else + { + bottom_heat_content = 2 * thermal_conductivity * (min_temperature - potential_mantle_temperature) * + std::sqrt(effective_plate_age /(thermal_diffusivity * Consts::PI)); + } + + // 4. The difference in heat content goes into the temperature above where Tmin occurs. + // Should not be a positive value + //double top_heat_content = initial_heat_content - bottom_heat_content; + + double top_heat_content = std::min(max_top_heat_content, (initial_heat_content - bottom_heat_content) ); + + // Also need to taper the top_heat_content otherwise slab top will continue to thicken to the tip. + // Can't do this above because need min_temperature to get bottom_heat_content first + if (distance_along_plane > start_taper_distance) + { + top_heat_content = top_heat_content * std::erfc(taper_con*theta); + } + + double nondimensional_adjusted_distance = adjusted_distance / max_depth; + + if (apply_spline) + { + // A total number of (2 * spline_n_points + 1) points are picked, + // spline_n_points points on each side and one at the center. + // These points cover a range of (-1.0, 1.0) in adjusted_distance. + Utilities::interpolation monotone_cubic_spline; + + const double interval_spline_distance = 1.0 / spline_n_points; + std::vector i_temperatures (2*(spline_n_points + 1), 0.0); + + for (size_t i = 0; i < 2 * spline_n_points + 1; ++i) + { + const double i_adjusted_distance = (static_cast(i) * interval_spline_distance - 1.0) * max_depth; + const double i_temperature = get_temperature_analytic(top_heat_content, min_temperature, background_temperature, temperature_, spreading_velocity, effective_plate_age, i_adjusted_distance); + i_temperatures[i] = i_temperature; + } + + monotone_cubic_spline.set_points(i_temperatures); + + const double index_distance = (nondimensional_adjusted_distance + 1.0) / interval_spline_distance; + temperature = monotone_cubic_spline(index_distance); + } + else + { + // Call the analytic solution to compute the temperature + temperature = get_temperature_analytic(top_heat_content, min_temperature, background_temperature, temperature_, spreading_velocity, effective_plate_age, adjusted_distance); + } + } + else + { + // slab temperature anomaly is gone. + temperature = temperature_; + } + + WBAssert(!std::isnan(temperature), "Internal error: temperature is not a number: " << temperature << '.'); + WBAssert(std::isfinite(temperature), "Internal error: temperature is not finite: " << temperature << '.'); + + return apply_operation(operation, temperature_, temperature); + } + + return temperature_; + } + + double + MassConserving::get_temperature_analytic(const double top_heat_content, + const double min_temperature, + const double background_temperature, + const double temperature_, + const double subducting_velocity, + const double effective_plate_age, + const double adjusted_distance) const + { + const double seconds_in_year = 60.0 * 60.0 * 24.0 * 365.25; // sec/y + + double temperature = 0.0; + + // Assign the temperature depending on whether distance is negative (above) or positive (below) the slab + if (adjusted_distance < 0) + { + // use 1D infinite space solution for top (side 2) of slab the slab + // 2 times the "top_heat_content" because all this heat needs to be on one side of the Gaussian + const double time_top_slab = (1/(Consts::PI*thermal_diffusivity)) * + pow(((2 * top_heat_content) / (2 * density * specific_heat * (min_temperature - temperature_ + 1e-16))),2) + 1e-16; + + // for overriding plate region where plate temperature is less the minimum slab temperature + // need to set temperature = temperature_ otherwise end up with temperature less than surface temperature ; + if (temperature_ < min_temperature) + { + temperature = temperature_; + } + else + { + temperature = temperature_ + (2 * top_heat_content / + (2*density*specific_heat * std::sqrt(Consts::PI * thermal_diffusivity * time_top_slab)))* + std::exp(-(adjusted_distance*adjusted_distance)/(4*thermal_diffusivity*time_top_slab)); + } + } + else + { + // use half-space cooling or plate model for the bottom (side 1) of the slab + if (reference_model_name == plate_model) + { + if (adjusted_distance < max_depth) + { + const double subducting_velocity_UI = subducting_velocity / seconds_in_year; + temperature = background_temperature + (min_temperature - background_temperature) * (1 - adjusted_distance / max_depth); + for (int i = 1; i< std::floor(plate_model_summation_number/2.0); ++i) + { + temperature = temperature - (min_temperature - background_temperature) * + ((2 / (double(i) * Consts::PI)) * std::sin((double(i) * Consts::PI * adjusted_distance) / max_depth) * + std::exp((((subducting_velocity_UI * max_depth)/(2 * thermal_diffusivity)) - + std::sqrt(((subducting_velocity_UI*subducting_velocity_UI*max_depth*max_depth) / + (4*thermal_diffusivity*thermal_diffusivity)) + double(i) * double(i) * Consts::PI * Consts::PI)) * + ((subducting_velocity_UI * effective_plate_age) / max_depth))); + } + } + else + { + temperature = background_temperature; + } + } + else + { + temperature = background_temperature + (min_temperature - background_temperature) * + std::erfc(adjusted_distance / (2 * std::sqrt(thermal_diffusivity * effective_plate_age))); + + } + } + return temperature; + } + + WB_REGISTER_FEATURE_SUBDUCTING_PLATE_TEMPERATURE_MODEL(MassConserving, mass conserving) + } // namespace Temperature + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/plate_model.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/plate_model.cc.bak new file mode 100644 index 00000000000..368adcdc09d --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/plate_model.cc.bak @@ -0,0 +1,214 @@ +/* + 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/features/subducting_plate_models/temperature/plate_model.h" + +#include "world_builder/nan.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" + +namespace WorldBuilder +{ + using namespace Utilities; + + namespace Features + { + namespace SubductingPlateModels + { + namespace Temperature + { + PlateModel::PlateModel(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + density(NaN::DSNAN), + plate_velocity(NaN::DSNAN), + thermal_conductivity(NaN::DSNAN), + thermal_expansion_coefficient(NaN::DSNAN), + specific_heat(NaN::DSNAN), + potential_mantle_temperature(NaN::DSNAN), + surface_temperature(NaN::DSNAN), + adiabatic_heating(true), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "plate model"; + } + + PlateModel::~PlateModel() + = default; + + void + PlateModel::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `plate velocity` to the required parameters. + prm.declare_entry("", Types::Object({"plate velocity"}), + "Plate model (based on McKenzie, 1970)."); + + // Declare entries of this plugin + prm.declare_entry("min distance slab top", Types::Double(0), + "todo The depth in meters from which the composition of this feature is present."); + + prm.declare_entry("max distance slab top", Types::Double(std::numeric_limits::max()), + "todo The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("density", Types::Double(3300), + "The reference density of the subducting plate in $kg/m^3$"); + + prm.declare_entry("plate velocity", Types::Double(NaN::DQNAN), + "The velocity in meters per year with which the plate subducts in meters per year."); + + prm.declare_entry("thermal conductivity", Types::Double(2.0), + "The thermal conductivity of the subducting plate material in $W m^{-1} K^{-1}$."); + + prm.declare_entry("thermal expansion coefficient", Types::Double(-1), + "The thermal expansivity of the subducting plate material in $K^{-1}$. If smaller than zero, the global value is used."); + + prm.declare_entry("specific heat", Types::Double(-1), + "The specific heat of the subducting plate material in $J kg^{-1} K^{-1}$. If smaller than zero, the global value is used."); + + prm.declare_entry("adiabatic heating", Types::Bool(true), + "Whether adiabatic heating should be used for the slab. Setting the parameter to false leads to equation 26 from McKenzie (1970)," + "which is the result obtained from McKenzie 1969."); + + prm.declare_entry("potential mantle temperature", Types::Double(-1), + "The potential temperature of the mantle at the surface in Kelvin. If smaller than zero, the global value is used."); + } + + void + PlateModel::parse_entries(Parameters &prm) + { + + min_depth = prm.get("min distance slab top"); + max_depth = prm.get("max distance slab top"); + operation = string_operations_to_enum(prm.get("operation")); + + density = prm.get("density"); + plate_velocity = prm.get("plate velocity"); + thermal_conductivity = prm.get("thermal conductivity"); + thermal_expansion_coefficient = prm.get("thermal expansion coefficient"); + + if (thermal_expansion_coefficient < 0 ) + thermal_expansion_coefficient = this->world->thermal_expansion_coefficient; + + specific_heat = prm.get("specific heat"); + + if (specific_heat < 0) + specific_heat = this->world->specific_heat; + + adiabatic_heating = prm.get("adiabatic heating"); + + potential_mantle_temperature = this->world->potential_mantle_temperature >= 0 + ? + this->world->potential_mantle_temperature + : + prm.get("potential mantle temperature"); + surface_temperature = this->world->surface_temperature; + } + + + double + PlateModel::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const double depth, + const double gravity_norm, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_planes, + const AdditionalParameters &additional_parameters) const + { + const double thickness_local = std::min(additional_parameters.local_thickness, max_depth); + const double distance_from_plane = distance_from_planes.distance_from_plane; + const double distance_along_plane = distance_from_planes.distance_along_plane; + + if (distance_from_plane <= max_depth && distance_from_plane >= min_depth) + { + /* + * We now use the McKenzie (1970) equation to determine the + * temperature inside the slab. The McKenzie equation was + * designed for a straight slab, but we have a potentially + * curved slab. Since the angle is used to compute the depth + * of the point, we directly use the depth. + */ + const double R = (density * specific_heat + * (plate_velocity /(365.25 * 24.0 * 60.0 * 60.0)) + * thickness_local) / (2.0 * thermal_conductivity); + + WBAssert(!std::isnan(R), "Internal error: R is not a number: " << R << '.'); + + const int n_sum = 500; + // distance_from_plane can be zero, so protect division. + const double z_scaled = 1 - (std::fabs(distance_from_plane) < 2.0 * std::numeric_limits::epsilon() ? + 2.0 * std::numeric_limits::epsilon() + : + distance_from_plane/thickness_local); + + // distance_along_plane can be zero, so protect division. + const double x_scaled = (std::fabs(distance_along_plane) < 2.0 * std::numeric_limits::epsilon() ? + 2.0 *std::numeric_limits::epsilon() + : + distance_along_plane/thickness_local); + + // the paper uses `(x_scaled * sin(average_angle) - z_scaled * cos(average_angle))` to compute the + // depth (execpt that you do not use average angles since they only have on angle). On recomputing + // their result it seems to me (Menno) that it should have been `(1-z_scaled)` instead of `z_scaled`. + // To avoid this whole problem we just use the depth directly since we have that. + // todo: get the local thickniss out of H, that prevents an other division. + // If we want to specify the bottom temperature, because we have defined a linear temperature increase in the + // mantle and/or oceanic plate, we have to switch off adiabatic heating for now. + // Todo: there may be a better way to deal with this. + ; + const double temp = adiabatic_heating ? std::exp(((thermal_expansion_coefficient * gravity_norm * depth) / specific_heat)) : 1; + + WBAssert(!std::isnan(temp), "Internal error: temp is not a number: " << temp << ". In exponent: " + << std::exp(((thermal_expansion_coefficient * gravity_norm) / specific_heat) * depth) + << ", thermal_expansion_coefficient = " << thermal_expansion_coefficient << ", gravity_norm = " << gravity_norm + << ", specific_heat = "<< specific_heat << ", depth = " << depth ); + + double sum=0; + for (int i=1; i<=n_sum; i++) + { + sum += (std::pow((-1.0),i)/(i*Consts::PI)) * + (exp((R - std::pow(R * R + i * i * Consts::PI * Consts::PI, 0.5)) * x_scaled)) + * (sin(i * Consts::PI * z_scaled)); + } + // todo: investigate whether this 273.15 should just be the surface temperature. + const double temperature = temp * (potential_mantle_temperature + + 2.0 * (potential_mantle_temperature - 273.15) * sum); + + WBAssert(!std::isnan(temperature), "Internal error: temperature is not a number: " << temperature << '.'); + WBAssert(std::isfinite(temperature), "Internal error: temperature is not finite: " << temperature << '.'); + + + return apply_operation(operation,temperature_,temperature); + } + + return temperature_; + } + + WB_REGISTER_FEATURE_SUBDUCTING_PLATE_TEMPERATURE_MODEL(PlateModel, plate model) + } // namespace Temperature + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/uniform.cc.bak b/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/uniform.cc.bak new file mode 100644 index 00000000000..aa9a904ee7e --- /dev/null +++ b/contrib/world_builder/source/world_builder/features/subducting_plate_models/temperature/uniform.cc.bak @@ -0,0 +1,109 @@ +/* + 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/features/subducting_plate_models/temperature/uniform.h" + + +#include "world_builder/nan.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/utilities.h" + + +namespace WorldBuilder +{ + + using namespace Utilities; + + namespace Features + { + namespace SubductingPlateModels + { + namespace Temperature + { + Uniform::Uniform(WorldBuilder::World *world_) + : + min_depth(NaN::DSNAN), + max_depth(NaN::DSNAN), + temperature(NaN::DSNAN), + operation(Operations::REPLACE) + { + this->world = world_; + this->name = "uniform"; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Document plugin and require entries if needed. + // Add `temperature` and to the required parameters. + prm.declare_entry("", Types::Object({"temperature"}), + "Uniform temperature model. Set the temperature to a constant value."); + + // Declare entries of this plugin + prm.declare_entry("min distance slab top", Types::Double(0), + "todo The depth in meters from which the composition of this feature is present."); + + prm.declare_entry("max distance slab top", Types::Double(std::numeric_limits::max()), + "todo The depth in meters to which the composition of this feature is present."); + + prm.declare_entry("temperature", Types::Double(293.15), + "The temperature in degree Kelvin which this feature should have"); + + } + + void + Uniform::parse_entries(Parameters &prm) + { + + min_depth = prm.get("min distance slab top"); + max_depth = prm.get("max distance slab top"); + operation = string_operations_to_enum(prm.get("operation")); + temperature = prm.get("temperature"); + } + + + double + Uniform::get_temperature(const Point<3> & /*position_in_cartesian_coordinates*/, + const double /*depth*/, + const double /*gravity*/, + double temperature_, + const double /*feature_min_depth*/, + const double /*feature_max_depth*/, + const WorldBuilder::Utilities::PointDistanceFromCurvedPlanes &distance_from_plane, + const AdditionalParameters & /*additional_parameters*/) const + { + + if (distance_from_plane.distance_from_plane <= max_depth && distance_from_plane.distance_from_plane >= min_depth) + { + return apply_operation(operation,temperature_,temperature); + } + + return temperature_; + } + + WB_REGISTER_FEATURE_SUBDUCTING_PLATE_TEMPERATURE_MODEL(Uniform, uniform) + } // namespace Temperature + } // namespace SubductingPlateModels + } // namespace Features +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/grains.cc.bak b/contrib/world_builder/source/world_builder/grains.cc.bak new file mode 100644 index 00000000000..b9e06ad2cde --- /dev/null +++ b/contrib/world_builder/source/world_builder/grains.cc.bak @@ -0,0 +1,80 @@ +/* + 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/grains.h" + +namespace WorldBuilder +{ + + grains::grains() + + + = default; + + + grains::grains(const std::vector &vector, + const size_t number_of_grains, + const size_t start_entry) + { + sizes.resize(number_of_grains); + for (unsigned int i_grain = 0; i_grain < number_of_grains; i_grain++) + { + sizes[i_grain] = vector[start_entry+i_grain]; + } + + rotation_matrices.resize(number_of_grains); + for (unsigned int i_grain = 0; i_grain < number_of_grains; i_grain++) + { + rotation_matrices[i_grain][0][0] = vector[start_entry+number_of_grains+i_grain*9]; + rotation_matrices[i_grain][0][1] = vector[start_entry+number_of_grains+i_grain*9+1]; + rotation_matrices[i_grain][0][2] = vector[start_entry+number_of_grains+i_grain*9+2]; + rotation_matrices[i_grain][1][0] = vector[start_entry+number_of_grains+i_grain*9+3]; + rotation_matrices[i_grain][1][1] = vector[start_entry+number_of_grains+i_grain*9+4]; + rotation_matrices[i_grain][1][2] = vector[start_entry+number_of_grains+i_grain*9+5]; + rotation_matrices[i_grain][2][0] = vector[start_entry+number_of_grains+i_grain*9+6]; + rotation_matrices[i_grain][2][1] = vector[start_entry+number_of_grains+i_grain*9+7]; + rotation_matrices[i_grain][2][2] = vector[start_entry+number_of_grains+i_grain*9+8]; + } + } + + + void + grains::unroll_into(std::vector &vector, const size_t start_entry) const + { + const size_t number_of_grains = sizes.size(); + + for (unsigned int i_grain = 0; i_grain < number_of_grains; i_grain++) + { + vector[start_entry+i_grain] = sizes[i_grain]; + } + + for (unsigned int i_grain = 0; i_grain < number_of_grains; i_grain++) + { + vector[start_entry+number_of_grains+i_grain*9] = rotation_matrices[i_grain][0][0]; + vector[start_entry+number_of_grains+i_grain*9+1] = rotation_matrices[i_grain][0][1]; + vector[start_entry+number_of_grains+i_grain*9+2] = rotation_matrices[i_grain][0][2]; + vector[start_entry+number_of_grains+i_grain*9+3] = rotation_matrices[i_grain][1][0]; + vector[start_entry+number_of_grains+i_grain*9+4] = rotation_matrices[i_grain][1][1]; + vector[start_entry+number_of_grains+i_grain*9+5] = rotation_matrices[i_grain][1][2]; + vector[start_entry+number_of_grains+i_grain*9+6] = rotation_matrices[i_grain][2][0]; + vector[start_entry+number_of_grains+i_grain*9+7] = rotation_matrices[i_grain][2][1]; + vector[start_entry+number_of_grains+i_grain*9+8] = rotation_matrices[i_grain][2][2]; + } + } +} // namespace WorldBuilder \ No newline at end of file diff --git a/contrib/world_builder/source/world_builder/gravity_model/interface.cc.bak b/contrib/world_builder/source/world_builder/gravity_model/interface.cc.bak new file mode 100644 index 00000000000..6a41777631b --- /dev/null +++ b/contrib/world_builder/source/world_builder/gravity_model/interface.cc.bak @@ -0,0 +1,99 @@ +/* + 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/gravity_model/interface.h" + +#include "world_builder/types/object.h" + +#include + +namespace WorldBuilder +{ + namespace GravityModel + { + + Interface::Interface() + = default; + + Interface::~Interface () + = default; + + 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), "gravity model"); + + prm.declare_entry("model",Types::String("",it.first), + "The name of the model for the gravity 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 GravityModel +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/gravity_model/uniform.cc.bak b/contrib/world_builder/source/world_builder/gravity_model/uniform.cc.bak new file mode 100644 index 00000000000..9978af549c5 --- /dev/null +++ b/contrib/world_builder/source/world_builder/gravity_model/uniform.cc.bak @@ -0,0 +1,94 @@ +/* + 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/gravity_model/uniform.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/world.h" + + +namespace WorldBuilder +{ + namespace GravityModel + { + Uniform::Uniform(WorldBuilder::World *world_) + { + this->world = world_; + } + + Uniform::~Uniform() + = default; + + void + Uniform::declare_entries(Parameters &prm, const std::string & /*unused*/) + { + // Add depth method to the required parameters. + prm.declare_entry("", Types::Object(), + "Uniform gravity model. It returns the gravity vector in a Cartesian coordinate system at " + "a given position, which has a constant magitude for the whole domain. The vector points " + "down in cartesian coordinates and to the center of the sphere in spherical coordinates."); + + prm.declare_entry("magnitude", + Types::Double(9.81), "The magnitude of the gravity."); + } + + void + Uniform::parse_entries(Parameters &prm) + { + gravity_magnitude = prm.get("magnitude"); + } + + + Point<3> + Uniform::gravity_vector(Point<3> point) const + { + const CoordinateSystem coordinate_system = world->parameters.coordinate_system->natural_coordinate_system(); + + switch (coordinate_system) + { + case CoordinateSystem::cartesian: + return Point<3>(0.,0.,-gravity_magnitude,CoordinateSystem::cartesian); + break; + + case CoordinateSystem::spherical: + return (point/point.norm())*-gravity_magnitude; + break; + + default: + WBAssertThrow(false, "Invalid coordinate system when using the gravity vector function."); + } + + return Point<3>(NaN::DSNAN,NaN::DSNAN,NaN::DSNAN,CoordinateSystem::invalid); + } + + + double + Uniform::gravity_norm(Point<3> /*point*/) const + { + return gravity_magnitude; + } + + + /** + * Register plugin + */ + WB_REGISTER_GRAVITY_MODEL(Uniform, uniform) + } // namespace GravityModel +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/kd_tree.cc.bak b/contrib/world_builder/source/world_builder/kd_tree.cc.bak new file mode 100644 index 00000000000..6f5a8347fc6 --- /dev/null +++ b/contrib/world_builder/source/world_builder/kd_tree.cc.bak @@ -0,0 +1,211 @@ +/* + 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/kd_tree.h" +#include +#include + +namespace WorldBuilder +{ + namespace KDTree + { + KDTree::KDTree(std::vector point_list) + : nodes(std::move(std::move(point_list))) + {} + + + void + KDTree::create_tree(const size_t left, + const size_t right, + const bool y_axis) + { + const size_t mid=(left+right)>>1; + std::nth_element(nodes.begin()+static_cast(left),nodes.begin()+static_cast(mid),nodes.begin()+static_cast(right)+1, + [y_axis](Node& i, Node& j) -> bool + { + return i[y_axis] < j[y_axis]; + }); + + if (leftmid) + create_tree(mid+1,right,!y_axis); + } + + + const std::vector & + KDTree::get_nodes() const + { + return nodes; + } + + + IndexDistance + KDTree::find_closest_point(const Point<2> &check_point) const + { + const size_t start_node_index = 0; + IndexDistance index_distance = {start_node_index, + std::numeric_limits::max() + }; + + find_closest_point_recursive(check_point,0,nodes.size()-1,false,index_distance); + + return index_distance; + } + + + void + KDTree::find_closest_point_recursive(const Point<2> &check_point, + const size_t left, + const size_t right, + const bool y_axis, + IndexDistance &index_distance) const + { + // Calculate the index of this node + const size_t mid=(left+right)>>1; + const Node &node = nodes[mid]; + if (check_point[static_cast(y_axis)] < node[y_axis]) + { + // Traverse left child + if (left distance) + { + index_distance.index = mid; + index_distance.distance = distance; + } + + // Traverse right child + if (right>mid) + { + if ((node[y_axis]-check_point[static_cast(y_axis)]) < index_distance.distance) + { + find_closest_point_recursive(check_point,mid+1,right,!y_axis,index_distance); + } + } + } + else + { + // Traverse right child + if (right>mid) + find_closest_point_recursive(check_point,mid+1,right,!y_axis,index_distance); + + // Compare node's point to current closest point + const double distance = sqrt((node[false]-check_point[0])*(node[false]-check_point[0]) + +(node[true]-check_point[1])*(node[true]-check_point[1])); + if (index_distance.distance > distance) + { + index_distance.index = mid; + index_distance.distance = distance; + } + + // Traverse left child + if (left(y_axis)]) < index_distance.distance) + find_closest_point_recursive(check_point,left,mid-1,!y_axis,index_distance); + } + } + + + + IndexDistances + KDTree::find_closest_points(const Point<2> &check_point) const + { + const size_t start_node_index = 0; + IndexDistances index_distances = {start_node_index, + std::numeric_limits::max(), + {} + }; + index_distances.vector.reserve(nodes.size()); + + find_closest_points_recursive(check_point,0,nodes.size()-1,false,index_distances); + + return index_distances; + } + + + void + KDTree::find_closest_points_recursive(const Point<2> &check_point, + const size_t left, + const size_t right, + const bool y_axis, + IndexDistances &index_distances) const + { + // Calculate the index of this node + const size_t mid=(left+right)>>1; + const Node &node = nodes[mid]; + if (check_point[static_cast(y_axis)] < node[y_axis]) + { + // Traverse left child + if (left distance) + { + index_distances.min_index = mid; + index_distances.min_distance = distance; + } + + index_distances.vector.emplace_back(IndexDistance {mid, distance}); + + // Traverse right child + if (right>mid) + { + if ((node[y_axis]-check_point[static_cast(y_axis)]) < index_distances.min_distance) + { + find_closest_points_recursive(check_point,mid+1,right,!y_axis,index_distances); + } + } + } + else + { + // Traverse right child + if (right>mid) + find_closest_points_recursive(check_point,mid+1,right,!y_axis,index_distances); + + // Compare node's point to current closest point + const double distance = sqrt((node[false]-check_point[0])*(node[false]-check_point[0]) + +(node[true]-check_point[1])*(node[true]-check_point[1])); + if (index_distances.min_distance > distance) + { + index_distances.min_index = mid; + index_distances.min_distance = distance; + } + + index_distances.vector.emplace_back(IndexDistance {mid, distance}); + + // Traverse left child + if (left(y_axis)]) < index_distances.min_distance) + find_closest_points_recursive(check_point,left,mid-1,!y_axis,index_distances); + } + } + } // namespace KDTree +} // namespace WorldBuilder diff --git a/contrib/world_builder/source/world_builder/objects/bezier_curve.cc.bak b/contrib/world_builder/source/world_builder/objects/bezier_curve.cc.bak new file mode 100644 index 00000000000..74f3b57393d --- /dev/null +++ b/contrib/world_builder/source/world_builder/objects/bezier_curve.cc.bak @@ -0,0 +1,550 @@ +/* + 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/assert.h" +#include "world_builder/nan.h" +#include "world_builder/objects/bezier_curve.h" + +#include +#include +#include +#include +#include + +using namespace WorldBuilder; + +namespace WorldBuilder +{ + namespace Objects + { + BezierCurve::BezierCurve(const std::vector > &p, const std::vector &angle_constrains_input) + { + points = p; + const size_t n_points = p.size(); + control_points.resize(n_points-1, {{p[0],p[0]}}); + lengths.resize(n_points-1,NaN::DSNAN); + angles.resize(n_points,NaN::DSNAN); + std::vector angle_constrains = angle_constrains_input; + angle_constrains.resize(n_points,NaN::DQNAN); + + // if no angle is provided, compute the angle as the average angle between the previous and next point. + // The first angle points at the second point and the last angle points at the second to last point. + // The check points are set at a distance of 1/10th the line length from the point in the direction of the angle. + if (std::isnan(angle_constrains[0])) + { + Point<2> P1P2 = points[1]-points[0]; + angles[0] = atan2(P1P2[1],P1P2[0]); + } + else + { + angles[0] = angle_constrains[0]; + } + + for (size_t p_i = 1; p_i < n_points-1; ++p_i) + { + // first determine the angle + if (std::isnan(angle_constrains[p_i])) + { + // get the average angle + const Point<2> P1P2 = points[p_i-1]-points[p_i]; + const Point<2> P3P2 = points[p_i+1]-points[p_i]; + + const double angle_p1p2 = atan2(P1P2[1],P1P2[0]); + const double angle_p3p1 = atan2(P3P2[1],P3P2[0]); + const double average_angle = (angle_p1p2 + angle_p3p1)*0.5; + angles[p_i] = average_angle; + angles[p_i] -= Consts::PI*0.5; + } + else + { + angles[p_i] = angle_constrains[p_i]; + } + + } + + if (std::isnan(angle_constrains[n_points-1])) + { + Point<2> P1P2 = points[n_points-2]-points[n_points-1]; + angles[n_points-1] = atan2(P1P2[1],P1P2[0]); + } + else + { + angles[n_points-1] = angle_constrains[n_points-1]; + } + + if (points.size() > 2) + { + // next determine the location of the control points + // the location of the control point is 1/10th p1p2 distance in the direction of the angle. + // make sure the angle is pointing away from the next point, e.g. + // the check point is on the other side of the of the line p1p2 compared to p3. + const double fraction_of_length = 0.2; + { + const Point<2> &p1 = points[0]; + const Point<2> &p2 = points[1]; + const Point<2> &p3 = points[2]; + const double length = (points[0]-points[1]).norm(); // can be squared + control_points[0][0][0] = cos(angles[0])*length*fraction_of_length+p1[0]; + control_points[0][0][1] = sin(angles[0])*length*fraction_of_length+p1[1]; + control_points[0][1][0] = cos(angles[1])*length*fraction_of_length+p2[0]; + control_points[0][1][1] = sin(angles[1])*length*fraction_of_length+p2[1]; + { + const bool side_of_line_1 = (p1[0] - p2[0]) * (control_points[0][1][1] - p1[1]) + - (p1[1] - p2[1]) * (control_points[0][1][0] - p1[0]) + < 0; + const bool side_of_line_2 = (p1[0] - p2[0]) * (p3[1] - p1[1]) + - (p1[1] - p2[1]) * (p3[0] - p1[0]) + < 0; + if (side_of_line_1 == side_of_line_2) + { + // use a 180 degree rotated angle to create this control_point + control_points[0][1][0] = cos(angles[1]+Consts::PI)*length*fraction_of_length+p2[0]; + control_points[0][1][1] = sin(angles[1]+Consts::PI)*length*fraction_of_length+p2[1]; + } + } + } + + for (size_t p_i = 1; p_i < n_points-1; ++p_i) + { + const Point<2> &p1 = points[p_i]; + const Point<2> &p2 = points[p_i+1]; + const double length = (points[p_i]-points[p_i+1]).norm(); // can be squared + control_points[p_i][0][0] = cos(angles[p_i])*length*fraction_of_length+p1[0]; + control_points[p_i][0][1] = sin(angles[p_i])*length*fraction_of_length+p1[1]; + + { + const bool side_of_line_1 = (p1[0] - p2[0]) * (control_points[p_i-1][1][1] - p1[1]) + - (p1[1] - p2[1]) * (control_points[p_i-1][1][0] - p1[0]) + < 0; + const bool side_of_line_2 = (p1[0] - p2[0]) * (control_points[p_i][0][1] - p1[1]) + - (p1[1] - p2[1]) * (control_points[p_i][0][0] - p1[0]) + < 0; + if (side_of_line_1 == side_of_line_2) + { + // use a 180 degree rotated angle to create this control_point + control_points[p_i][0][0] = cos(angles[p_i]+Consts::PI)*length*fraction_of_length+p1[0]; + control_points[p_i][0][1] = sin(angles[p_i]+Consts::PI)*length*fraction_of_length+p1[1]; + } + } + + control_points[p_i][1][0] = cos(angles[p_i+1])*length*fraction_of_length+points[p_i+1][0]; + control_points[p_i][1][1] = sin(angles[p_i+1])*length*fraction_of_length+points[p_i+1][1]; + + if (p_i+1 < n_points-1) + { + const Point<2> &p3 = points[p_i+2]; + const bool side_of_line_1 = (p1[0] - p2[0]) * (control_points[p_i][1][1] - p1[1]) + - (p1[1] - p2[1]) * (control_points[p_i][1][0] - p1[0]) + < 0; + const bool side_of_line_2 = (p1[0] - p2[0]) * (p3[1] - p1[1]) + - (p1[1] - p2[1]) * (p3[0] - p1[0]) + < 0; + if (side_of_line_1 == side_of_line_2) + { + // use a 180 degree rotated angle to create this control_point + control_points[p_i][1][0] = cos(angles[p_i+1]+Consts::PI)*length*fraction_of_length+p2[0]; + control_points[p_i][1][1] = sin(angles[p_i+1]+Consts::PI)*length*fraction_of_length+p2[1]; + } + } + } + } + } + + + Point<2> + BezierCurve::operator()(const size_t i, const double t) const + { + WBAssert(i < points.size()-1 && i < control_points.size() , + "Trying to access index " << i << ", but points.size() = " << points.size() << ", and control_points = " << control_points.size() << "."); + return (1-t)*(1-t)*(1-t)*points[i] + 3*(1-t)*(1-t)*t*control_points[i][0] + 3.*(1-t)*t*t*control_points[i][1]+t*t*t*points[i+1]; + } + + + ClosestPointOnCurve + BezierCurve::closest_point_on_curve_segment(const Point<2> &check_point, + const bool verbose) const + { + ClosestPointOnCurve closest_point_on_curve; + const Point<2> &cp = check_point; + double min_squared_distance = std::numeric_limits::infinity(); + if (check_point.get_coordinate_system() == CoordinateSystem::cartesian) + { + for ( size_t cp_i = 0; cp_i < control_points.size(); ++cp_i) + { +#ifndef NDEBUG + std::stringstream output; +#endif + const Point<2> &p1 = points[cp_i]; + const Point<2> &p2 = points[cp_i+1]; + //min_squared_distance = std::min(std::min(min_squared_distance,(check_point-p1).norm_square()),(check_point-p1).norm_square()); + + // Getting an estimate for where the closest point is with a linear approximation + const Point<2> P1P2 = p2-p1; + const Point<2> P1Pc = check_point-p1; + + const double P2P2_dot = P1P2*P1P2; + + double est = P2P2_dot > 0.0 ? std::min(1.,std::max(0.,(P1Pc*P1P2) / P2P2_dot)) : 1.0; // est=estimate of solution + bool found = false; + + // based on https://stackoverflow.com/questions/2742610/closest-point-on-a-cubic-bezier-curve + const double a_0 = 3.*control_points[cp_i][0][0]-3.*control_points[cp_i][1][0]+points[cp_i+1][0]-points[cp_i][0]; + const double a_1 = 3.*control_points[cp_i][0][1]-3.*control_points[cp_i][1][1]+points[cp_i+1][1]-points[cp_i][1]; + const double b_0 = 3.*points[cp_i][0] - 6.*control_points[cp_i][0][0]+3.*control_points[cp_i][1][0]; + const double b_1 = 3.*points[cp_i][1] - 6.*control_points[cp_i][0][1]+3.*control_points[cp_i][1][1]; + const double c_0 = -3.*points[cp_i][0] + 3.*control_points[cp_i][0][0]; + const double c_1 = -3.*points[cp_i][1] + 3.*control_points[cp_i][0][1]; + const double d_0 = points[cp_i][0]; + const double d_1 = points[cp_i][1]; + + const double d_min_cp_0 = d_0-cp[0]; + const double d_min_cp_1 = d_1-cp[1]; + +#ifndef NDEBUG + double estimate_point_min_cp_0_dg = a_0*est*est*est+b_0*est*est+c_0*est+d_min_cp_0; + double estimate_point_min_cp_1_dg = a_1*est*est*est+b_1*est*est+c_1*est+d_min_cp_1; + double min_squared_distance_cartesian_temp_dg = (estimate_point_min_cp_0_dg*estimate_point_min_cp_0_dg)+(estimate_point_min_cp_1_dg*estimate_point_min_cp_1_dg); +#endif + + for (size_t newton_i = 0; newton_i < 150; newton_i++) + { +#ifndef NDEBUG + output << " wolfram alpha: (" << a_0 << "*x^3+" << b_0 << "*x^2+"<< c_0 << "*x+" << d_0 << "-" << cp[0] << ")^2+(" << a_1 << "*x^3+" << b_1 << "*x^2+"<< c_1 << "*x+" << d_1 << "-" << cp[1] << ")^2 with x=" << est << std::endl; +#endif + const double est_sq = est*est; + const double estimate_point_min_cp_0 = a_0*est_sq*est+b_0*est_sq+c_0*est+d_min_cp_0; + const double estimate_point_min_cp_1 = a_1*est_sq*est+b_1*est_sq+c_1*est+d_min_cp_1; + + const double deriv_0 = 3.0*a_0*est_sq+2.0*b_0*est+c_0; + const double deriv_1 = 3.0*a_1*est_sq+2.0*b_1*est+c_1; + const double squared_distance_cartesian = (estimate_point_min_cp_0*estimate_point_min_cp_0)+(estimate_point_min_cp_1*estimate_point_min_cp_1); + + const double squared_distance_cartesian_derivative = 2.0*(deriv_0*estimate_point_min_cp_0 + deriv_1*estimate_point_min_cp_1); + const double squared_distance_cartesian_second_derivative_abs = std::fabs(2.0*((6.0*a_0*est+2.0*b_0)*estimate_point_min_cp_0 + deriv_0*deriv_0 + + (6.0*a_1*est+2.0*b_1)*estimate_point_min_cp_1 + deriv_1*deriv_1)); + + if (squared_distance_cartesian_second_derivative_abs <= 0.0) + { + found = true; + break; + } + + // the local minimum is where squared_distance_cartesian_derivative=0 and squared_distance_cartesian_derivative>=0 + const double update = std::min(0.5,std::max(-0.5,squared_distance_cartesian_derivative/squared_distance_cartesian_second_derivative_abs)); + double line_search = 1.; + + if (std::fabs(update) > 1e-1) + { + double est_test = est-update*line_search; + double squared_distance_cartesian_test = squared_distance_cartesian; + double squared_distance_cartesian_test_previous = squared_distance_cartesian; + + for (unsigned int i = 0; i < 10; i++) + { + est_test = est-update*line_search; + const double est_test_sq = est_test*est_test; + const double estimate_point_min_cp_test_0 = a_0*est_test_sq*est_test+b_0*est_test_sq+c_0*est_test+d_min_cp_0; + const double estimate_point_min_cp_test_1 = a_1*est_test_sq*est_test+b_1*est_test_sq+c_1*est_test+d_min_cp_1; + + squared_distance_cartesian_test = (estimate_point_min_cp_test_0*estimate_point_min_cp_test_0)+(estimate_point_min_cp_test_1*estimate_point_min_cp_test_1); + +#ifndef NDEBUG + const Point<2> a = 3.*control_points[cp_i][0]-3.*control_points[cp_i][1]+points[cp_i+1]-points[cp_i]; + const Point<2> b = 3.*points[cp_i] - 6.*control_points[cp_i][0]+3.*control_points[cp_i][1]; + const Point<2> c = -3.*points[cp_i] + 3.*control_points[cp_i][0]; + const Point<2> d = points[cp_i]; + const double squared_distance_cartesian_derivative_test = 2.0*(3.0*a_0*est_test*est_test+2.0*b_0*est_test+c_0)*(a_0*est_test*est_test*est_test+b_0*est_test*est_test+c_0*est_test+d_0-cp[0]) + + 2.0*(3.0*a_1*est_test*est_test+2.0*b_1*est_test+c_1)*(a_1*est_test*est_test*est_test+b_1*est_test*est_test+c_1*est_test+d_1-cp[1]); + const double squared_distance_cartesian_second_derivative_test = 2.0*(6.0*a_0*est_test + 2.0*b_0)*(a_0*est_test*est_test*est_test+b_0*est_test*est_test+c_0*est_test+d_0-cp[0]) + + 2.0*(3.0*a_0*est_test*est_test + 2.0*b_0*est_test + c_0)*(3.0*a_0*est_test*est_test + 2.0*b_0*est_test + c_0) + + 2.0*(6.0*a_1*est_test + 2.0*b_1)*(a_1*est_test*est_test*est_test+b_1*est_test*est_test+c_1*est_test+d_1-cp[1]) + + 2.0*(3.0*a_1*est_test*est_test + 2.0*b_1*est_test + c_1)*(3.0*a_1*est_test*est_test + 2.0*b_1*est_test + c_1) ; + output << " i: " << cp_i << ", ni: " << newton_i<< ", lsi: " << i << ", line_search_step=" << 2./3. << ": squared_distance_cartesian_test = " << squared_distance_cartesian_test << ", diff= " << squared_distance_cartesian_test-squared_distance_cartesian + << ", tests: " << (squared_distance_cartesian_test_previous < squared_distance_cartesian ? "true" : "false") << ":" << (squared_distance_cartesian_test > squared_distance_cartesian_test_previous ? "true" : "false") << ", est_test=" << est_test + << ", update=" << update << ", ls=" << line_search << ", up*ls=" << update *line_search << ", test deriv =" << squared_distance_cartesian_derivative_test << ", test update=" << squared_distance_cartesian_derivative_test/fabs(squared_distance_cartesian_second_derivative_test) + << ", p1=" << p1 << ", p2= " << p2 << ", poc= " << a *est_test *est_test *est_test + b *est_test *est_test+c *est_test+d << ", cp= " << check_point << ", ds:" << ((a*est_test*est_test*est_test+b*est_test*est_test+c*est_test+d)-check_point).norm_square() << ":" << min_squared_distance_cartesian_temp_dg + << ", diff = " << squared_distance_cartesian_test-min_squared_distance_cartesian_temp_dg << std::endl; +#endif + if (i > 0 && (squared_distance_cartesian_test > squared_distance_cartesian_test_previous)) + { + if (squared_distance_cartesian_test_previous-squared_distance_cartesian < 0) + { + line_search *= 3./2.; + break; + } + } + squared_distance_cartesian_test_previous = squared_distance_cartesian_test; + + line_search *= 2./3.; + } + } + + est -= update*line_search; + + if (std::fabs(update) < 1e-4 || est < -0.1 || est > 1.1) + { + found = true; + break; + } + } +#ifndef NDEBUG + WBAssertThrow(found, "Could not find a good solution. " << output.str()); +#else + WBAssertThrow(found, "Could not find a good solution. Enable debug mode for more info."); +#endif + + const double est_min_cp_end_0 = a_0*est*est*est+b_0*est*est+c_0*est+d_min_cp_0; + const double est_min_cp_end_1 = a_1*est*est*est+b_1*est*est+c_1*est+d_min_cp_1; + const double min_squared_distance_temp = (est_min_cp_end_0*est_min_cp_end_0)+(est_min_cp_end_1*est_min_cp_end_1); + if (min_squared_distance_temp < min_squared_distance) + { + if (est >= -1e-8 && static_cast(cp_i)+est > 0 && est-1. <= 1e-8 && est-1. < static_cast(cp_i)) + { + min_squared_distance = min_squared_distance_temp; + const Point<2> point_on_curve = Point<2>(a_0*est*est*est+b_0*est*est+c_0*est+d_0,a_1*est*est*est+b_1*est*est+c_1*est+d_1,cp.get_coordinate_system()); + WBAssert(!std::isnan(point_on_curve[0]) && !std::isnan(point_on_curve[1]), "Point on curve has NAN entries: " << point_on_curve); + // the sign is rotating the derivative by 90 degrees. + // When moving in the direction of increasing t, left is positive and right is negative. + // https://www.wolframalpha.com/input?i=d%2Fdt+%281-t%29*%281-t%29*%281-t%29*a+%2B+3*%281-t%29*%281-t%29*t*b+%2B+3.*%281-t%29*t*t*c%2Bt*t*t*d + const Point<2> derivative_point = points[cp_i]*((6.-3.*est)*est-3.) + control_points[cp_i][0]*(est*(9*est-12)+3) + + control_points[cp_i][1]*(6.-9.*est)*est + points[cp_i+1]*3.*est*est; + + Point<2> tangent_point = derivative_point - point_on_curve; + // if angle between check point and tangent point is larger than 90 degrees, return a negative distance + const double dot_product = (tangent_point*(check_point-point_on_curve)); + const double sign = dot_product < 0. ? -1. : 1.; + tangent_point = Point<2>(-tangent_point[1],tangent_point[0],tangent_point.get_coordinate_system()); + + closest_point_on_curve.distance = sign*std::sqrt(min_squared_distance); + closest_point_on_curve.parametric_fraction = est; + closest_point_on_curve.interpolation_fraction = NaN::DSNAN; //arc_length(i,real_roots[root_i])/lengths[i]; + closest_point_on_curve.index = cp_i; + closest_point_on_curve.point = point_on_curve; + WBAssert(!std::isnan(point_on_curve[0]) && !std::isnan(point_on_curve[1]), "Point on curve has NAN entries: " << point_on_curve); + Point<2> normal = point_on_curve; + { + Point<2> derivative = Point<2>(a_0*est*est+b_0*est+c_0,a_1*est*est+b_1*est+c_1,cp.get_coordinate_system()); + normal=derivative; + const double normal_size = derivative.norm(); + if (normal_size > 0.) + { + normal[0] = derivative[1]/normal_size; + normal[1] = -derivative[0]/normal_size; + } + } + closest_point_on_curve.normal = normal; + } + } + } + } + else + { + const double cos_cp_lat = cos(cp[1]); + for ( size_t cp_i = 0; cp_i < control_points.size(); ++cp_i) + { + const Point<2> &p1 = points[cp_i]; + const Point<2> &p2 = points[cp_i+1]; + // Getting an estimate for where the closest point is with a linear approximation + const Point<2> P1P2 = p2-p1; + const Point<2> P1Pc = check_point-p1; + + const double P2P2_dot = P1P2*P1P2; + + double est = P2P2_dot > 0.0 ? std::min(1.,std::max(0.,(P1Pc*P1P2) / P2P2_dot)) : 1.0; // est=estimate of solution + bool found = false; + + // only used if verbose is true + std::stringstream output; + + Point<2> a = 3.*control_points[cp_i][0]-3.*control_points[cp_i][1]+points[cp_i+1]-points[cp_i]; + Point<2> b = 3.*points[cp_i] - 6.*control_points[cp_i][0]+3.*control_points[cp_i][1]; + Point<2> c = -3.*points[cp_i] + 3.*control_points[cp_i][0]; + const Point<2> d = points[cp_i]; + + Point<2> estimate_point = a*est*est*est+b*est*est+c*est+d; + + double cos_lat_dg = NaN::DSNAN; + double sin_d_long_h_dg = NaN::DSNAN; + double sin_d_lat_h_dg = NaN::DSNAN; + double min_squared_distance_cartesian_temp_dg = NaN::DSNAN; + if (verbose == true) + { + cos_lat_dg = cos(estimate_point[1]); + sin_d_long_h_dg = sin((estimate_point[0]-cp[0])*0.5); + sin_d_lat_h_dg = sin((estimate_point[1]-cp[1])*0.5); + min_squared_distance_cartesian_temp_dg = sin_d_lat_h_dg*sin_d_lat_h_dg+sin_d_long_h_dg*sin_d_long_h_dg*cos_cp_lat*cos_lat_dg; + output << "cp_i=" << cp_i << ", init est = " << est << ", min_squared_distance = " << min_squared_distance << ", min_squared_distance_cartesian_temp_dg: " << min_squared_distance_cartesian_temp_dg << ", p1: " << p1 << ", p2: " << p2 << std::endl; + output << std::setprecision(6) << " wolfram: sin((" << a[1] << "*x^3+" << b[1] << "*x^2+"<< c[1] << "*x+" << d[1] << "-" << cp[1] << ")*.5)^2+sin((" << a[0] << "*x^3+" << b[0] << "*x^2+"<< c[0] << "*x+" << d[0] << "-" << cp[0] << ")*.5)^2*cos(" << cp[1] << ")*cos(" << a[1] << "*x^3+" << b[1] << "*x^2+"<< c[1] << "*x+" << d[1] << "-" << cp[1] << ") with x=" << est << std::endl; + output << std::setprecision(10) << " python: y=np.sin((" << a[1] << "*x**3+" << b[1] << "*x**2+"<< c[1] << "*x+" << d[1] << "-" << cp[1] << ")*.5)**2+np.sin((" << a[0] << "*x**3+" << b[0] << "*x**2+"<< c[0] << "*x+" << d[0] << "-" << cp[0] << ")*.5)**2*np.cos(" << cp[1] << ")*np.cos(" << a[1] << "*x**3+" << b[1] << "*x**2+"<< c[1] << "*x+" << d[1] << "-" << cp[1] << "); x=" << est << std::endl; + } + for (size_t newton_i = 0; newton_i < 150; newton_i++) + { + // based on https://stackoverflow.com/questions/2742610/closest-point-on-a-cubic-bezier-curve + estimate_point = a*est*est*est+b*est*est+c*est+d; + + double sin_d_long_h = sin((estimate_point[0]-cp[0])*0.5); + double sin_d_lat_h = sin((estimate_point[1]-cp[1])*0.5); + const double cos_d_lat = cos(estimate_point[1]-cp[1]); + const double squared_distance_cartesian = sin_d_lat_h*sin_d_lat_h+sin_d_long_h*sin_d_long_h*cos_cp_lat*cos_d_lat; + + double sin_dlat = sin(estimate_point[1]-cp[1]); + const double cos_dlong_h = cos(0.5*(estimate_point[0]-cp[0])); + double cos_dlat_h = cos(0.5*(estimate_point[1]-cp[1])); + double deriv_long = (3.0*a[0]*est*est+2.0*b[0]*est+c[0]); + double deriv_lat = (3.0*a[1]*est*est+2.0*b[1]*est+c[1]); + + const double squared_distance_cartesian_derivative = cos_cp_lat*(-deriv_lat)*sin_d_long_h*sin_d_long_h*sin_dlat+cos_cp_lat*deriv_long*sin_d_long_h*cos_dlong_h*cos_d_lat+deriv_lat*sin_d_lat_h*cos_dlat_h; + double update = NaN::DSNAN; + if (std::fabs(squared_distance_cartesian_derivative) > 1e-15) + { + const double squared_distance_cartesian_second_derivative = cos_cp_lat*cos_d_lat*(-0.5*deriv_long*deriv_long*sin_d_long_h*sin_d_long_h+0.5*deriv_long*deriv_long*cos_dlong_h*cos_dlong_h+(6.0*a[0]*est+2.0*b[0])*sin_d_long_h*cos_dlong_h)+cos_cp_lat*sin_d_long_h*sin_d_long_h*(deriv_lat*deriv_lat*(-cos_d_lat)-(6.0*a[1]*est+2.0*b[1])*sin_dlat)-2.0*cos_cp_lat*deriv_long*deriv_lat*sin_d_long_h*cos_dlong_h*sin_dlat-0.5*deriv_lat*deriv_lat*sin_d_lat_h*sin_d_lat_h+0.5*deriv_lat*deriv_lat*cos_dlat_h*cos_dlat_h+(6.0*a[1]*est+2.0*b[1])*sin_d_lat_h*cos_dlat_h; + + if (verbose == true) + { + const double squared_distance_cartesian_full = sin((a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])*0.5)*sin((a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])*0.5)+sin((a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0])*0.5)*sin((a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0])*0.5)*cos(cp[1])*cos(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]); + const double squared_distance_cartesian_derivative_full = cos(cp[1])*(-(3.0*a[1]*est*est+2.0*b[1]*est+c[1]))*sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*sin(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])+cos(cp[1])*(3.0*a[0]*est*est+2.0*b[0]*est+c[0])*sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*cos(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*cos(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])+(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*sin(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))*cos(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])); + const double squared_distance_cartesian_second_derivative_full = cos(cp[1])*cos(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])*(-0.5*(3.0*a[0]*est*est+2.0*b[0]*est+c[0])*(3.0*a[0]*est*est+2.0*b[0]*est+c[0])*sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))+0.5*(3.0*a[0]*est*est+2.0*b[0]*est+c[0])*(3.0*a[0]*est*est+2.0*b[0]*est+c[0])*cos(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*cos(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))+(6.0*a[0]*est+2.0*b[0])*sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*cos(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0])))+cos(cp[1])*sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*((3.0*a[1]*est*est+2.0*b[1]*est+c[1])*(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*(-cos(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))-(6.0*a[1]*est+2.0*b[1])*sin(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))-2.0*cos(cp[1])*(3.0*a[0]*est*est+2.0*b[0]*est+c[0])*(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*sin(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*cos(0.5*(a[0]*est*est*est+b[0]*est*est+c[0]*est+d[0]-cp[0]))*sin(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])-0.5*(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*sin(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))*sin(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))+0.5*(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*(3.0*a[1]*est*est+2.0*b[1]*est+c[1])*cos(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))*cos(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))+(6.0*a[1]*est+2.0*b[1])*sin(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1]))*cos(0.5*(a[1]*est*est*est+b[1]*est*est+c[1]*est+d[1]-cp[1])); + output <<"sqd = " << squared_distance_cartesian <<":" << squared_distance_cartesian_full << ", diff=" << squared_distance_cartesian-squared_distance_cartesian_full << ", sqdd: " << squared_distance_cartesian_derivative <<":" << squared_distance_cartesian_derivative_full << ", diff="<< squared_distance_cartesian_derivative-squared_distance_cartesian_derivative_full << ", sqdd: " << squared_distance_cartesian_second_derivative << ":" << squared_distance_cartesian_second_derivative_full << ", diff= " << squared_distance_cartesian_second_derivative-squared_distance_cartesian_second_derivative_full << ", est: " << est << std::endl; + } + // the local minimum is where squared_distance_cartesian_derivative=0 and squared_distance_cartesian_derivative>=0 + update = std::min(0.5,std::max(-0.5,squared_distance_cartesian_derivative/std::fabs(squared_distance_cartesian_second_derivative))); + double line_search = 1.; + double est_test = est-update*line_search; + double squared_distance_cartesian_test = squared_distance_cartesian; + double squared_distance_cartesian_test_previous = squared_distance_cartesian; + double line_search_step = 2./3.; + + for (unsigned int i = 0; i < 10; i++) + { + est_test = est-update*line_search; + estimate_point = a*est_test*est_test*est_test+b*est_test*est_test+c*est_test+d; + + sin_d_long_h = sin((estimate_point[0]-cp[0])*0.5); + sin_d_lat_h = sin((estimate_point[1]-cp[1])*0.5); + squared_distance_cartesian_test = sin_d_lat_h*sin_d_lat_h+sin_d_long_h*sin_d_long_h*cos_cp_lat*cos(estimate_point[1]-cp[1]); + + if (verbose == true) + { + sin_dlat = sin(estimate_point[1]-cp[1]); + deriv_long = (3.0*a[0]*est_test*est_test+2.0*b[0]*est_test+c[0]); + deriv_lat = (3.0*a[1]*est_test*est_test+2.0*b[1]*est_test+c[1]); + const double squared_distance_cartesian_derivative_test = cos_cp_lat*(-deriv_lat)*sin_d_long_h*sin_d_long_h*sin_dlat+cos_cp_lat*deriv_long*sin_d_long_h*cos_dlong_h*cos_d_lat+deriv_lat*sin_d_lat_h*cos_dlat_h; + const double squared_distance_cartesian_second_derivative_test = cos_cp_lat*cos_d_lat*(-0.5*deriv_long*deriv_long*sin_d_long_h*sin_d_long_h+0.5*deriv_long*deriv_long*cos_dlong_h*cos_dlong_h+(6.0*a[0]*est_test+2.0*b[0])*sin_d_long_h*cos_dlong_h)+cos_cp_lat*sin_d_long_h*sin_d_long_h*(deriv_lat*deriv_lat*(-cos_d_lat)-(6.0*a[1]*est_test+2.0*b[1])*sin_dlat)-2.0*cos_cp_lat*deriv_long*deriv_lat*sin_d_long_h*cos_dlong_h*sin_dlat-0.5*deriv_lat*deriv_lat*sin_d_lat_h*sin_d_lat_h+0.5*deriv_lat*deriv_lat*cos_dlat_h*cos_dlat_h+(6.0*a[1]*est_test+2.0*b[1])*sin_d_lat_h*cos_dlat_h; + output << " i: " << cp_i << ", ni: " << newton_i<< ", lsi: " << i << ", line_search_step=" << line_search_step << ": squared_distance_cartesian_test = " << squared_distance_cartesian_test << ", diff= " << squared_distance_cartesian_test-squared_distance_cartesian << ", tests: " << (squared_distance_cartesian_test_previous < squared_distance_cartesian ? "true" : "false") << ":" << (squared_distance_cartesian_test > squared_distance_cartesian_test_previous ? "true" : "false") << ", est_test=" << est_test << ", update=" << update << ", ls=" << line_search << ", up*ls=" << update *line_search << ", test deriv =" << squared_distance_cartesian_derivative_test << ", test update=" << squared_distance_cartesian_derivative_test/fabs(squared_distance_cartesian_second_derivative_test) << ", p1=" << p1 << ", p2= " << p2 << ", poc= " << a *est_test *est_test *est_test+b *est_test *est_test+c *est_test+d << ", cp= " << check_point << ", ds:" << ((a*est_test*est_test*est_test+b*est_test*est_test+c*est_test+d)-check_point).norm_square() << ":" << min_squared_distance_cartesian_temp_dg << ", diff = " << squared_distance_cartesian_test-min_squared_distance_cartesian_temp_dg<< std::endl; + } + if (i > 0 && (squared_distance_cartesian_test > squared_distance_cartesian_test_previous)) + { + if (squared_distance_cartesian_test_previous-squared_distance_cartesian < 0) + { + line_search *= 1/line_search_step; + break; + } + if (i> 1) + { + line_search *= (1/line_search_step)*(1/line_search_step); + est_test = est-update*line_search; + estimate_point = a*est_test*est_test*est_test+b*est_test*est_test+c*est_test+d; + + sin_d_long_h = sin((estimate_point[0]-cp[0])*0.5); + sin_d_lat_h = sin((estimate_point[1]-cp[1])*0.5); + squared_distance_cartesian_test_previous = sin_d_lat_h*sin_d_lat_h+sin_d_long_h*sin_d_long_h*cos_cp_lat*cos(estimate_point[1]-cp[1]); + line_search_step = std::min(line_search_step*(11./10.),0.95); + continue; + } + } + squared_distance_cartesian_test_previous = squared_distance_cartesian_test; + + line_search *= line_search_step; + } + if (verbose == true) + { + output << " i: " << cp_i << ", ni: " << newton_i<< ", est= " << est-update *line_search << ", ls:" << line_search << ": squared_distance_cartesian_test = " << squared_distance_cartesian_test << ", diff= " << squared_distance_cartesian_test-squared_distance_cartesian << std::endl; + } + est -= update*line_search; + } + + if (std::fabs(squared_distance_cartesian_derivative) <= 1e-15 || std::fabs(update) < 1e-4 || est < -0.1 || est > 1.1) + { + found = true; + break; + } + } + + if (verbose == true && found == false) + { + // report the error and print the output + WBAssertThrow(found, "Could not find a good solution. " << output.str()); + } + else if (verbose == false && found == false) + { + // redo the iteration with verbose=true to be able to report the error + return closest_point_on_curve_segment(check_point, true); + } + + estimate_point = a*est*est*est+b*est*est+c*est+d; + + const double sin_d_long_h = sin((estimate_point[0]-cp[0])*0.5); + const double sin_d_lat_h = sin((estimate_point[1]-cp[1])*0.5); + + const double min_squared_distance_cartesian_temp = sin_d_lat_h*sin_d_lat_h+sin_d_long_h*sin_d_long_h*cos_cp_lat*cos(estimate_point[1]-cp[1]); + + if (min_squared_distance_cartesian_temp < min_squared_distance) + { + if (est >= -1e-8 && static_cast(cp_i)+est > 0 && est-1. <= 1e-8 && est-1. < static_cast(cp_i)) + { + min_squared_distance = min_squared_distance_cartesian_temp; + const Point<2> point_on_curve = a*est*est*est+b*est*est+c*est+d; + + // the sign is rotating the derivative by 90 degrees. + // When moving in the direction of increasing t, left is positive and right is negative. + // https://www.wolframalpha.com/input?i=d%2Fdt+%281-t%29*%281-t%29*%281-t%29*a+%2B+3*%281-t%29*%281-t%29*t*b+%2B+3.*%281-t%29*t*t*c%2Bt*t*t*d + const Point<2> derivative_point = points[cp_i]*((6.-3.*est)*est-3.) + control_points[cp_i][0]*(est*(9*est-12)+3) + + control_points[cp_i][1]*(6.-9.*est)*est + points[cp_i+1]*3.*est*est; + + Point<2> tangent_point = derivative_point - point_on_curve; + // if angle between check point and tangent point is larger than 90 degrees, return a negative distance + const double dot_product = (tangent_point*(check_point-point_on_curve)); + const double sign = dot_product < 0. ? -1. : 1.; + tangent_point = Point<2>(-tangent_point[1],tangent_point[0],tangent_point.get_coordinate_system()); + + closest_point_on_curve.distance = sign*std::sqrt(min_squared_distance); + closest_point_on_curve.parametric_fraction = est; + closest_point_on_curve.interpolation_fraction = NaN::DSNAN; //arc_length(i,real_roots[root_i])/lengths[i]; + closest_point_on_curve.index = cp_i; + closest_point_on_curve.point = point_on_curve; + Point<2> normal = point_on_curve; + { + Point<2> derivative = a*est*est+b*est+c; + normal=derivative; + const double normal_size = derivative.norm(); + if (normal_size > 0.) + { + normal[0] = derivative[1]/normal_size; + normal[1] = -derivative[0]/normal_size; + } + } + closest_point_on_curve.normal = normal; + } + } + } + + } + return closest_point_on_curve; + } + } // namespace Objects +} // namespace WorldBuilder diff --git a/contrib/world_builder/source/world_builder/objects/distance_from_surface.cc.bak b/contrib/world_builder/source/world_builder/objects/distance_from_surface.cc.bak new file mode 100644 index 00000000000..5024c3692da --- /dev/null +++ b/contrib/world_builder/source/world_builder/objects/distance_from_surface.cc.bak @@ -0,0 +1,36 @@ +/* + 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/objects/distance_from_surface.h" + +namespace WorldBuilder +{ + namespace Objects + { + double PlaneDistances::get_distance_from_surface() const + { + return this->distance_from_surface; + } + + double PlaneDistances::get_distance_along_surface() const + { + return this->distance_along_surface; + } + } // namespace Objects +} // namespace WorldBuilder \ No newline at end of file diff --git a/contrib/world_builder/source/world_builder/objects/natural_coordinate.cc.bak b/contrib/world_builder/source/world_builder/objects/natural_coordinate.cc.bak new file mode 100644 index 00000000000..b02ddc9beb1 --- /dev/null +++ b/contrib/world_builder/source/world_builder/objects/natural_coordinate.cc.bak @@ -0,0 +1,121 @@ +/* + 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/objects/natural_coordinate.h" + +namespace WorldBuilder +{ + namespace Objects + { + NaturalCoordinate::NaturalCoordinate(const std::array &position, + const CoordinateSystems::Interface &coordinate_system_) + { + coordinate_system = coordinate_system_.natural_coordinate_system(); + coordinates = coordinate_system_.cartesian_to_natural_coordinates(position); + } + + + // todo, should be possible to make this without the interface, since the Point knows the coord system. + NaturalCoordinate::NaturalCoordinate(const Point<3> &position, + const CoordinateSystems::Interface &coordinate_system_) + { + coordinate_system = coordinate_system_.natural_coordinate_system(); + coordinates = coordinate_system_.cartesian_to_natural_coordinates(position.get_array()); + } + + + const std::array &NaturalCoordinate::get_coordinates() const + { + return coordinates; + } + + + std::array NaturalCoordinate::get_surface_coordinates() const + { + std::array coordinate; + + switch (coordinate_system) + { + case CoordinateSystem::cartesian: + coordinate[0] = coordinates[0]; + coordinate[1] = coordinates[1]; + break; + + case CoordinateSystem::spherical: + coordinate[0] = coordinates[1]; + coordinate[1] = coordinates[2]; + break; + + default: + WBAssertThrow (false, "Coordinate system not implemented."); + } + + return coordinate; + } + + + Point<2> NaturalCoordinate::get_surface_point() const + { + Point<2> coordinate(0,0,coordinate_system); + + switch (coordinate_system) + { + case CoordinateSystem::cartesian: + coordinate[0] = coordinates[0]; + coordinate[1] = coordinates[1]; + break; + + case CoordinateSystem::spherical: + coordinate[0] = coordinates[1]; + coordinate[1] = coordinates[2]; + break; + + default: + WBAssertThrow (false, "Coordinate system not implemented."); + } + + return coordinate; + } + + + CoordinateSystem + NaturalCoordinate::get_coordinate_system() const + { + return coordinate_system; + } + + + double &NaturalCoordinate::get_ref_depth_coordinate() + { + switch (coordinate_system) + { + case CoordinateSystem::cartesian: + return coordinates[2]; + + case CoordinateSystem::spherical: + return coordinates[0]; + + default: + WBAssertThrow (false, "Coordinate system not implemented."); + } + + return coordinates[2]; + } + } // namespace Objects +} // namespace WorldBuilder \ No newline at end of file diff --git a/contrib/world_builder/source/world_builder/objects/segment.cc.bak b/contrib/world_builder/source/world_builder/objects/segment.cc.bak new file mode 100644 index 00000000000..368a034ad52 --- /dev/null +++ b/contrib/world_builder/source/world_builder/objects/segment.cc.bak @@ -0,0 +1,126 @@ +/* + 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 + +#include "world_builder/objects/segment.h" + + +namespace WorldBuilder +{ + + namespace Features + { + namespace FaultModels + { + namespace Composition + { + class Interface; + } // namespace Composition + namespace Grains + { + class Interface; + } // namespace Grains + namespace Temperature + { + class Interface; + } // namespace Temperature + } // namespace FaultModels + namespace SubductingPlateModels + { + namespace Composition + { + class Interface; + } // namespace Composition + namespace Grains + { + class Interface; + } // namespace Grains + namespace Temperature + { + class Interface; + } // namespace Temperature + } // namespace SubductingPlateModels + } // namespace Features + + + namespace Objects + { + // todo update function + template + Segment::Segment(const double default_length_, + const WorldBuilder::Point<2> &default_thickness_, + const WorldBuilder::Point<2> &default_top_truncation_, + const WorldBuilder::Point<2> &default_angle_, + const std::vector > temperature_systems_, + const std::vector > composition_systems_, + const std::vector > grains_systems_) + : + value_length(default_length_), + default_length(default_length_), + value_thickness(default_thickness_), + value_top_truncation(default_top_truncation_), + value_angle(default_angle_), + temperature_systems(std::move(temperature_systems_)), + composition_systems(std::move(composition_systems_)), + grains_systems(std::move(grains_systems_)) + { + } + + template + Segment::Segment(Segment const &other) + : + value_length(other.value_length), + default_length(other.default_length), + value_thickness(other.value_thickness), + value_top_truncation(other.value_top_truncation), + value_angle(other.value_angle), + temperature_systems(other.temperature_systems), + composition_systems(other.composition_systems), + grains_systems(other.grains_systems) + { + } + + template + Segment::~Segment () + = default; + + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template class + Segment; + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template class + Segment; + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + //template class + //Segment; + + } // namespace Objects +} // namespace WorldBuilder \ No newline at end of file diff --git a/contrib/world_builder/source/world_builder/objects/surface.cc.bak b/contrib/world_builder/source/world_builder/objects/surface.cc.bak new file mode 100644 index 00000000000..e509703313c --- /dev/null +++ b/contrib/world_builder/source/world_builder/objects/surface.cc.bak @@ -0,0 +1,227 @@ +/* + 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/assert.h" +#include "world_builder/objects/surface.h" + +#include + +#include "delaunator-cpp/delaunator.hpp" + + +namespace WorldBuilder +{ + namespace Objects + { + + namespace + { + /** + * Test whether a point is in a triangle. If that is the case is stores the interpolated + * value of the triangle into `interpolated_value` and returns true. + */ + bool in_triangle(const std::array,3> &points, + const std::array &precomputed, + const Point<2> &check_point, + double &interpolate_value, + double &interpolator_s, + double &interpolator_t) + { + double factor = 1e4; + // based on https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle + // compute s, t and area + const double s_no_area = -(precomputed[0] + precomputed[1]*check_point[0] + precomputed[2]*check_point[1]); + const double t_no_area = -(precomputed[3] + precomputed[4]*check_point[0] + precomputed[5]*check_point[1]); + + if (s_no_area >= -factor*std::numeric_limits::epsilon() && t_no_area >= -factor*std::numeric_limits::epsilon() && s_no_area+t_no_area-precomputed[6]<=precomputed[6]*factor*std::numeric_limits::epsilon()) + { + // point is in this triangle + interpolator_s = precomputed[7]*s_no_area; + interpolator_t = precomputed[7]*t_no_area; + interpolate_value = points[0][2]*(1-interpolator_s-interpolator_t)+points[1][2]*interpolator_s+points[2][2]*interpolator_t; + return true; + } + return false; + } + } + + Surface::Surface() + = default; + + + Surface::Surface(std::pair,std::vector> values_at_points) + { + // first find the min and max. This need always to be done; + WBAssertThrow(!values_at_points.first.empty(), "internal error: no values in values_at_points.first."); + minimum = values_at_points.first[0]; + maximum = values_at_points.first[0]; + + for (const auto &value: values_at_points.first) + { + if (value < minimum) + { + minimum = value; + } + if (value > maximum) + { + maximum = value; + } + } + + // if there are points defined there is not a constant value, + // if there are no points defined there is a constant value. + if (!values_at_points.second.empty()) + { + constant_value = false; + + // Next make the triangulation and the kd-tree. + // Feed the delaunator + delaunator::Delaunator triangulation(values_at_points.second); + + // now loop over all the triangles and add them to the correct vectors + triangles.resize(triangulation.triangles.size()/3); + std::vector node_list; + for (std::size_t i = 0; i < triangulation.triangles.size(); i+=3) + { + delaunator::Delaunator &t = triangulation; + // 1. We need to create a triangle list where each entry contains the coordinates + // and value of the points of the triangle: + // [[[x0,y0,v0],[x1,y1,v1],[x2,y2,v2]],[[x1,y1,v1],[x0,y0,v0],[x3,y3,v3]],...] + // 2. we need to compute the centeroid locations and add those to the KD-tree + // with the index stored on the triangle list + triangles[i/3][0][0] = t.coords[2 * t.triangles[i]]; // tx0 + triangles[i/3][0][1] = t.coords[2 * t.triangles[i]+1]; // ty0 + triangles[i/3][0][2] = values_at_points.first[t.triangles[i]]; // v0 + triangles[i/3][1][0] = t.coords[2 * t.triangles[i+1]]; // tx1 + triangles[i/3][1][1] = t.coords[2 * t.triangles[i+1]+1]; // ty1 + triangles[i/3][1][2] = values_at_points.first[t.triangles[i+1]]; // v1 + triangles[i/3][2][0] = t.coords[2 * t.triangles[i+2]]; // tx2 + triangles[i/3][2][1] = t.coords[2 * t.triangles[i+2]+1]; // ty2 + triangles[i/3][2][2] = values_at_points.first[t.triangles[i+2]]; // v2 + + node_list.emplace_back(i/3, + (t.coords[2*t.triangles[i]]+t.coords[2*t.triangles[i+1]]+t.coords[2*t.triangles[i+2]])/3., + (t.coords[2*t.triangles[i]+1]+t.coords[2*t.triangles[i+1]+1]+t.coords[2*t.triangles[i+2]+1])/3.); + + } + // now feed and create the KD-tree + tree = KDTree::KDTree(node_list); + tree.create_tree(0, node_list.size()-1, false); + + + // precompute values for in_triangle + in_triangle_precomputed.resize(tree.get_nodes().size()); + for (size_t iii = 0; iii < tree.get_nodes().size(); iii++) + { + in_triangle_precomputed[iii][0] = triangles[iii][0][1]*triangles[iii][2][0] - triangles[iii][0][0]*triangles[iii][2][1]; + in_triangle_precomputed[iii][1] = triangles[iii][2][1] - triangles[iii][0][1]; + in_triangle_precomputed[iii][2] = triangles[iii][0][0] - triangles[iii][2][0]; + in_triangle_precomputed[iii][3] = triangles[iii][0][0]*triangles[iii][1][1] - triangles[iii][0][1]*triangles[iii][1][0]; + in_triangle_precomputed[iii][4] = triangles[iii][0][1] - triangles[iii][1][1]; + in_triangle_precomputed[iii][5] = triangles[iii][1][0] - triangles[iii][0][0]; + in_triangle_precomputed[iii][6] = -(-triangles[iii][1][1]*triangles[iii][2][0] + triangles[iii][0][1]*(-triangles[iii][1][0] + triangles[iii][2][0]) + triangles[iii][0][0]*(triangles[iii][1][1] - triangles[iii][2][1]) + triangles[iii][1][0]*triangles[iii][2][1]); + in_triangle_precomputed[iii][7] = 1./in_triangle_precomputed[iii][6]; + } + } + else + { + constant_value = true; + } + + } + + SurfaceValueInfo + Surface::local_value(const Point<2> &check_point) const + { + if (constant_value) + { + // just min and max are the same since it is constant. Just return min. + return minimum; + } + // first find the closest centeroids + const KDTree::IndexDistances index_distances = tree.find_closest_points(check_point); + + // try triangle of the closest centroid + double interpolated_value = 0; + double interpolator_s = NaN::DQNAN; + double interpolator_t = NaN::DQNAN; + + if (in_triangle(triangles[tree.get_nodes()[index_distances.min_index].index],in_triangle_precomputed[tree.get_nodes()[index_distances.min_index].index],check_point,interpolated_value,interpolator_s,interpolator_t)) + { + return SurfaceValueInfo {tree.get_nodes()[index_distances.min_index].index,interpolated_value,interpolator_s,interpolator_t}; + } + + Point<2> other_point = check_point; + KDTree::IndexDistances index_distances_other; + const bool spherical = check_point.get_coordinate_system() == CoordinateSystem::spherical; + if (spherical) + { + other_point[0] += check_point[0] < 0 ? 2.0 * WorldBuilder::Consts::PI : -2.0 * WorldBuilder::Consts::PI; + index_distances_other = tree.find_closest_points(other_point); + + if (in_triangle(triangles[tree.get_nodes()[index_distances_other.min_index].index],in_triangle_precomputed[tree.get_nodes()[index_distances_other.min_index].index],other_point,interpolated_value,interpolator_s,interpolator_t)) + { + return SurfaceValueInfo {tree.get_nodes()[index_distances_other.min_index].index,interpolated_value,interpolator_s,interpolator_t}; + } + } + + + { + // if not found go to closets nodes + // Todo: could remove the cosest node, because it was already tested. Could also sort based no distance. + for (const auto &index_distance: index_distances.vector) + { + if (in_triangle(triangles[tree.get_nodes()[index_distance.index].index],in_triangle_precomputed[tree.get_nodes()[index_distance.index].index],check_point,interpolated_value,interpolator_s,interpolator_t)) + { + return SurfaceValueInfo {tree.get_nodes()[index_distance.index].index,interpolated_value,interpolator_s,interpolator_t}; + } + } + if (spherical) + { + for (auto &index_distance: index_distances_other.vector) + { + if (in_triangle(triangles[tree.get_nodes()[index_distance.index].index],in_triangle_precomputed[tree.get_nodes()[index_distance.index].index],other_point,interpolated_value,interpolator_s,interpolator_t)) + { + return SurfaceValueInfo {tree.get_nodes()[index_distance.index].index,interpolated_value,interpolator_s,interpolator_t}; + } + } + } + + // if still not found, go through all nodes + // Todo: Although this shouldonly very rearly happen, could remove already tested nodes. + for (const auto &nodes: tree.get_nodes()) + { + if (in_triangle(triangles[nodes.index],in_triangle_precomputed[nodes.index],check_point,interpolated_value,interpolator_s,interpolator_t)) + { + return SurfaceValueInfo {nodes.index,interpolated_value,interpolator_s,interpolator_t}; + } + if (spherical && in_triangle(triangles[nodes.index],in_triangle_precomputed[nodes.index],other_point,interpolated_value,interpolator_s,interpolator_t)) + { + return SurfaceValueInfo {nodes.index,interpolated_value,interpolator_s,interpolator_t}; + } + } + WBAssertThrow(false, "Internal error: The requested point was not in any triangle. " + << "This could be due to rounding errors if the difference between the check point and triangle points are small, " + << "or you are requesting a point outside the boundaries defined by the additional points. The check point was " + << check_point[0] << ":" << check_point[1] << "."); + } + return 0; + } + } // namespace Objects +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/parameters.cc.bak b/contrib/world_builder/source/world_builder/parameters.cc.bak new file mode 100644 index 00000000000..a7b1afc63b9 --- /dev/null +++ b/contrib/world_builder/source/world_builder/parameters.cc.bak @@ -0,0 +1,2229 @@ +/* + 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/features/continental_plate_models/composition/interface.h" +#include "world_builder/features/continental_plate_models/grains/interface.h" +#include "world_builder/features/continental_plate_models/temperature/interface.h" +#include "world_builder/features/fault.h" +#include "world_builder/features/mantle_layer_models/composition/interface.h" +#include "world_builder/features/mantle_layer_models/grains/interface.h" +#include "world_builder/features/mantle_layer_models/temperature/interface.h" +#include "world_builder/features/oceanic_plate_models/composition/interface.h" +#include "world_builder/features/oceanic_plate_models/grains/interface.h" +#include "world_builder/features/oceanic_plate_models/temperature/interface.h" +#include "world_builder/features/plume_models/composition/interface.h" +#include "world_builder/features/plume_models/grains/interface.h" +#include "world_builder/features/plume_models/temperature/interface.h" +#include "world_builder/features/subducting_plate.h" +#include "world_builder/gravity_model/interface.h" +#include "world_builder/types/object.h" +#include "world_builder/utilities.h" + +#include "rapidjson/error/en.h" +#include "rapidjson/istreamwrapper.h" +#include "rapidjson/latexwriter.h" +#include "rapidjson/mystwriter.h" +#include "rapidjson/prettywriter.h" + +#include +#include + +using namespace rapidjson; + +namespace +{ + void remove_key(rapidjson::Value &value, const char *key) + { + if (value.IsObject()) + { + auto it = value.FindMember(key); + if (it != value.MemberEnd()) + value.RemoveMember(it); + + for (auto &member : value.GetObject()) + remove_key(member.value, key); + + } + else if (value.IsArray()) + { + for (auto &element : value.GetArray()) + remove_key(element, key); + } + } +} + +namespace WorldBuilder +{ + Parameters::Parameters(World &world_) + : + world(world_) + { + } + + Parameters::~Parameters() + = default; + + void Parameters::initialize(std::string &filename, bool has_output_dir, const std::string &output_dir) + { + + if (has_output_dir) + { + StringBuffer buffer; + std::ofstream file; + + // write out json schema + file.open (output_dir + "world_builder_declarations.schema.json"); + WBAssertThrow(file.is_open(), "Error: Could not open file '" + output_dir + "world_builder_declarations.schema.json' for string the json declarations."); + PrettyWriter, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> json_writer(buffer); + declarations.Accept(json_writer); + file << buffer.GetString(); + file.close(); + buffer.Clear(); + + // remove Snippets so they don't appear in the documentation: + remove_key(declarations, "defaultSnippets"); + + // write out declarations + file.open (output_dir + "world_builder_declarations.tex"); + WBAssertThrow(file.is_open(), "Error: Could not open file '" + output_dir + "world_builder_declarations.tex' for string the tex declarations."); + + LatexWriter, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> tex_writer(buffer); + declarations.Accept(tex_writer); + file << buffer.GetString(); + file.close(); + buffer.Clear(); + + // write out declarations (open) + file.open (output_dir + "world_builder_declarations_open.md"); + WBAssertThrow(file.is_open(), "Error: Could not open file '" + output_dir + "world_builder_declarations_open.md' for string the tex declarations."); + + MySTWriter, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> myst_writer_open(buffer, true); + declarations.Accept(myst_writer_open); + file << buffer.GetString(); + file.close(); + buffer.Clear(); + + // write out declarations (closed) + file.open (output_dir + "world_builder_declarations_closed.md"); + WBAssertThrow(file.is_open(), "Error: Could not open file '" + output_dir + "world_builder_declarations_closed.md' for string the tex declarations."); + + MySTWriter, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> myst_writer_closed(buffer, false); + declarations.Accept(myst_writer_closed); + file << buffer.GetString(); + file.close(); + buffer.Clear(); + } + + path_level =0; + // Now read in the world builder file into a stringstream and + // put it into a the rapidjson document + std::stringstream json_input_stream(WorldBuilder::Utilities::read_and_distribute_file_content(filename)); + rapidjson::IStreamWrapper isw(json_input_stream); + + // relaxing syntax by allowing comments () for now, maybe also allow trailing commas and (kParseTrailingCommasFlag) and nan's, inf etc (kParseNanAndInfFlag)? + //WBAssertThrow(!parameters.ParseStream(isw).HasParseError(), "Parsing errors world builder file"); + + WBAssertThrowExc(!(parameters.ParseStream(isw).HasParseError()), std::ifstream json_input_stream_error(filename.c_str()); , + "Parsing errors world builder file: Error(offset " << static_cast(parameters.GetErrorOffset()) + << "): " << GetParseError_En(parameters.GetParseError()) << std::endl << std::endl + << " Showing 50 chars before and after: " + << std::string((std::istreambuf_iterator(json_input_stream_error.seekg(0, json_input_stream_error.beg))), + std::istreambuf_iterator()).substr(static_cast(parameters.GetErrorOffset()) <= 50 + ? + 0 + : + static_cast(parameters.GetErrorOffset()) - 50, 100 + ) << std::endl << std::endl + << " Showing 5 chars before and after: " + << std::string((std::istreambuf_iterator(json_input_stream_error.seekg(0, json_input_stream_error.beg))), + std::istreambuf_iterator()).substr(static_cast(parameters.GetErrorOffset()) <= 5 + ? 0 + : + static_cast(parameters.GetErrorOffset())-5, + (static_cast(parameters.GetErrorOffset()) + 10 > json_input_stream_error.seekg(0,std::ios::end).tellg() + ? + static_cast(json_input_stream.tellg())-static_cast(parameters.GetErrorOffset()) + : + 10) + )); + + WBAssertThrow(parameters.IsObject(), "World builder file is is not an object."); + + + const SchemaDocument schema(declarations); + SchemaValidator validator(schema); + + if (!parameters.Accept(validator)) + { + // Input JSON is invalid according to the schema + // Output diagnostic information + StringBuffer buffer; + std::stringstream string; + validator.GetInvalidSchemaPointer().StringifyUriFragment(buffer); + string << "Invalid schema: " << buffer.GetString() << std::endl; + string << "Invalid keyword: " << validator.GetInvalidSchemaKeyword(); + buffer.Clear(); + validator.GetInvalidDocumentPointer().StringifyUriFragment(buffer); + string << "Invalid schema: " << buffer.GetString() << std::endl; + PrettyWriter writer(buffer); + validator.GetError().Accept(writer); + WBAssertThrow(false, string.str() << "Error document: " << std::endl << buffer.GetString()); + } + } + + void + Parameters::declare_entry(const std::string &name, + const Types::Interface &type, + const std::string &documentation) + { + type.write_schema(*this,name,documentation); + } + + bool + Parameters::check_entry(const std::string &name) const + { + return Pointer((this->get_full_json_path() + "/" + name).c_str()).Get(parameters) != nullptr; + } + + + template<> + std::string + Parameters::get(const std::string &name) + { + const std::string base = this->get_full_json_path(); + const Value *value = Pointer((base + "/" + name).c_str()).Get(parameters); + +#ifdef debug + bool required = false; + if (Pointer((base + "/required").c_str()).Get(declarations) != NULL) + { + for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray()) + { + if (v.GetString() == name) + { + required = true; + } + } + } + + WBAssert(value != NULL || required == false, + "Internal error: Value \"" << base << '/' << name << "/type\" not found in the input file, while it was set as required."); +#endif + if (value == nullptr) + { + value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the default value at: " + << base + "/" + name + "/default value"); + } + + return value->GetString(); + } + + template<> + double + Parameters::get(const std::string &name) + { + const std::string base = this->get_full_json_path(); + const Value *value = Pointer((base + "/" + name).c_str()).Get(parameters); + +#ifdef debug + bool required = false; + if (Pointer((base + "/required").c_str()).Get(declarations) != NULL) + { + for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray()) + { + if (v.GetString() == name) + { + required = true; + } + } + } + + WBAssert(value != NULL || required == false, + "Internal error: Value \"" << base << '/' << name << "/type\" not found in the input file, while it was set as required."); +#endif + if (value == nullptr) + { + value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the default value at: " + << get_full_json_schema_path() + "/" + name + "/default value, for value: " << base + "/" + name); + } + + double return_value; + try + { + return_value = value->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << base << " into doubles."); + } + return return_value; + } + + template<> + size_t + Parameters::get(const std::string &name) + { + const std::string base = this->get_full_json_path(); + const Value *value = Pointer((base + "/" + name).c_str()).Get(parameters); + +#ifdef debug + bool required = false; + if (Pointer((base + "/required").c_str()).Get(declarations) != NULL) + { + for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray()) + { + if (v.GetString() == name) + { + required = true; + } + } + } + + WBAssert(value != NULL || required == false, + "Internal error: Value \"" << base << '/' << name << "/type\" not found in the input file, while it was set as required."); +#endif + if (value == nullptr) + { + value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the default value at: " + << base + "/" + name + "/default value"); + } + + return value->GetUint(); + } + + template<> + unsigned int + Parameters::get(const std::string &name) + { + const std::string base = this->get_full_json_path(); + const Value *value = Pointer((base + "/" + name).c_str()).Get(parameters); + +#ifdef debug + bool required = false; + if (Pointer((base + "/required").c_str()).Get(declarations) != NULL) + { + for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray()) + { + if (v.GetString() == name) + { + required = true; + } + } + } + + WBAssert(value != NULL || required == false, + "Internal error: Value \"" << base << '/' << name << "/type\" not found in the input file, while it was set as required."); +#endif + if (value == nullptr) + { + value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the default value at: " + << base + "/" + name + "/default value"); + } + + return value->GetUint(); + } + + template<> + int + Parameters::get(const std::string &name) + { + const std::string base = this->get_full_json_path(); + const Value *value = Pointer((base + "/" + name).c_str()).Get(parameters); + +#ifdef debug + bool required = false; + if (Pointer((base + "/required").c_str()).Get(declarations) != NULL) + { + for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray()) + { + if (v.GetString() == name) + { + required = true; + } + } + } + + WBAssert(value != NULL || required == false, + "Internal error: Value \"" << base << '/' << name << "/type\" not found in the input file, while it was set as required."); +#endif + if (value == nullptr) + { + value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the default value at: " + << base + "/" + name + "/default value"); + } + + return value->GetInt(); + } + + template<> + bool + Parameters::get(const std::string &name) + { + const std::string base = this->get_full_json_path(); + const Value *value = Pointer((base + "/" + name).c_str()).Get(parameters); + +#ifdef debug + bool required = false; + if (Pointer((base + "/required").c_str()).Get(declarations) != NULL) + { + for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray()) + { + if (v.GetString() == name) + { + required = true; + } + } + } + + WBAssert(value != NULL || required == false, + "Internal error: Value \"" << base << '/' << name << "/type\" not found in the input file, while it was set as required."); +#endif + if (value == nullptr) + { + value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the default value at: " + << base + "/" + name + "/default value"); + } + + return value->GetBool(); + } + + + template<> + Point<2> + Parameters::get(const std::string &name) + { + + const std::string strict_base = this->get_full_json_path(); + const Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + +#ifdef debug + bool required = false; + if (Pointer((strict_base + "/required").c_str()).Get(declarations) != NULL) + { + for (auto &v : Pointer((strict_base + "/required").c_str()).Get(declarations)->GetArray()) + { + if (v.GetString() == name) + { + required = true; + } + } + } + + WBAssert(array != NULL || required == false, + "Internal error: Value \"" << strict_base << '/' << name << "/type\" not found in the input file, while it was set as required."); +#endif + if (array != nullptr) + { + const std::string base = strict_base + "/" + name; + //let's assume that the file is correct, because it has been checked with the json schema. + // So there are exactly two values. + double value1; + double value2; + + try + { + value1 = Pointer((base + "/0").c_str()).Get(parameters)->GetDouble(); + value2 = Pointer((base + "/1").c_str()).Get(parameters)->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << base << " into Point<2>, because it could not convert the sub-elements into doubles."); + } + return Point<2>(value1,value2,this->coordinate_system->natural_coordinate_system()); + } + WBAssertThrow(false, "default values not implemented in get >. Looked in: " + strict_base + "/" << name); + + return {invalid};; + } + + template<> + std::vector + Parameters::get_vector(const std::string &name) + { + std::vector vector; + const std::string strict_base = this->get_full_json_path(); + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr) + { + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + for (size_t i = 0; i < array->Size(); ++i ) + { + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + + vector.push_back(Pointer(base.c_str()).Get(parameters)->GetBool()); + } + } + else + { + const Value *value = Pointer((this->get_full_json_schema_path() + "/" + name + "/minItems").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the minItems value at: " + << this->get_full_json_schema_path() + "/" + name + "/minItems value"); + + const size_t min_size = value->GetUint(); + + const bool default_value = Pointer((this->get_full_json_schema_path() + "/" + name + "/items/default value").c_str()).Get(declarations)->GetBool(); + + // set to min size + for (size_t i = 0; i < min_size; ++i) + { + vector.push_back(default_value); + } + } + return vector; + } + + + std::pair,std::vector> + Parameters::get(const std::string &name, + const std::vector > &addition_points) + { + // There are four cases: + // 1. No value provided: use the default value everywhere. Return first with one value and second with size 0. + // 2. One double provided: use the default value everywhere. Return first with one value and second with size 0. + // 3. One value in a double array and no points provided: use that value everywhere. Return first with one value and second with size 0. + // 4. Other: fill the vectors with the default value and addition points and then add new point. + // If a value without points is encountered, the additional points are used. + std::pair,std::vector> result; + + const std::string strict_base = this->get_full_json_path(); + + // start with adding the additional points with the default value + // to do this we need the default value + double default_value = 0; + bool is_array = true; + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr && Pointer((strict_base + "/" + name).c_str()).Get(parameters)->IsArray()) + { + const std::string value_def_path = get_full_json_schema_path() + "/" + name + "/oneOf/1/items/items/anyOf/0/default value"; + Value *value_def = Pointer(value_def_path.c_str()).Get(declarations); + WBAssertThrow(value_def != nullptr, + "internal error: could not retrieve the default value at: " + << value_def_path); + + // Since the default value is set in the code, if it fails it is an internal error, not a user error. + // So no try/catch needed. + default_value = value_def->GetDouble(); + } + else + { + is_array = false; + Value *value_def = Pointer((get_full_json_schema_path() + "/" + name + "/oneOf/0/default value").c_str()).Get(declarations); + WBAssertThrow(value_def != nullptr, + "internal error: could not retrieve the default value at: " + <GetDouble(); + } + + + // check if there is a user defined value + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr) + { + // there is a user defined value, so either case 2, 3 or 4. + if (is_array) + { + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + if (array->Size() == 1 + && Pointer((strict_base + "/" + name + "/0/1").c_str()).Get(parameters) == nullptr) + { + // case 2: Return first with one value and second with size 0. + double value = 0; + try + { + value = Pointer((strict_base + "/" + name + "/0/0").c_str()).Get(parameters)->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << strict_base << "/" << name << "/0/0 into a double. " + << "The provided value was \"" << Pointer((strict_base + "/" + name + "/0/0").c_str()).Get(parameters)->GetString() << "\"."); + } + result.first.emplace_back(value); + } + else + { + // case 3: fill the vectors with the default value and addition points and then add new point. + // If a value without points is encountered, the additional points are used. + + // first fill with additional points at default value + for (const auto &addition_point : addition_points) + { + result.first.emplace_back(default_value); + result.second.emplace_back(addition_point[0]); + result.second.emplace_back(addition_point[1]); + } + + // second, go through all the points in order + for (size_t i = 0; i < array->Size(); ++i ) + { + // now parse a single value_at_point. + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + // Let's assume that the file is correct, because it has been checked with the json schema. + // So there are exactly two values, the first value is a double, the second an array of 2d arrays (points). + + // Get the double + double value; + Value *value_pointer = Pointer((base + "/0").c_str()).Get(parameters); + + WBAssertThrow(value_pointer != nullptr, "internal error: this should not happen."); + + try + { + value = value_pointer->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << base << "/0 into doubles. " + << "The provided value was \"" << Pointer((base + "/0").c_str()).Get(parameters)->GetString() << "\"."); + } + + // now get the array of points. + Value *coordinates_array = Pointer((base + "/1").c_str()).Get(parameters); + if (coordinates_array != nullptr) + { + for (size_t coordinate_i = 0; coordinate_i < coordinates_array->Size(); ++coordinate_i ) + { + // Let's assume that the file is correct, because it has been checked with the json schema. + // That means that there are exactly two values per item + double coordinate_0; + double coordinate_1; + try + { + coordinate_0 = Pointer((base + "/1/" + std::to_string(coordinate_i) + "/0").c_str()).Get(parameters)->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << base + "/1/" + std::to_string(coordinate_i) + "/0" + << " into a Point<2> array, because it could not convert the 1st sub-elements into doubles. " + << "The provided value was \"" + << Pointer((base + "/1/" + std::to_string(coordinate_i) + "/0").c_str()).Get(parameters)->GetString() + << "\"."); + } + try + { + coordinate_1 = Pointer((base + "/1/" + std::to_string(coordinate_i) + "/1").c_str()).Get(parameters)->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << base + "/1/" + std::to_string(coordinate_i) + "/1" + << " into a Point<2> array, because it could not convert the 2nd sub-elements into doubles. " + << "The provided value was \"" + << Pointer((base + "/1/" + std::to_string(coordinate_i) + "/1").c_str()).Get(parameters)->GetString() + << "\"."); + } + + coordinate_0 *= (coordinate_system->natural_coordinate_system() == CoordinateSystem::spherical ? Consts::PI / 180.0 : 1.); + coordinate_1 *= (coordinate_system->natural_coordinate_system() == CoordinateSystem::spherical ? Consts::PI / 180.0 : 1.); + + bool found_same_point = false; + unsigned int coordinate_pair_i = 0; + for (; coordinate_pair_i < result.second.size(); coordinate_pair_i+=2) + { + if (Utilities::approx(result.second[coordinate_pair_i],coordinate_0) && Utilities::approx(result.second[coordinate_pair_i+1],coordinate_1)) + { + found_same_point = true; + break; + } + } + if (found_same_point) + { + // set the value to the new value + result.first[coordinate_pair_i/2] = value; + } + else + { + // add a new point + result.first.emplace_back(value); + result.second.emplace_back(coordinate_0); + result.second.emplace_back(coordinate_1); + } + } + + } + else + { + // no points are provided, so use the value to fill put in the additional points + // at that value. Since we know that all the additional points are at the start + // we can easily overwrite the values. + for (unsigned int addition_point_i = 0; addition_point_i < addition_points.size(); ++addition_point_i) + { + result.first[addition_point_i] = value; + } + } + } + } + } + else + { + // case 2: there one value, not an array + double value = 0; + try + { + value = Pointer((strict_base + "/" + name).c_str()).Get(parameters)->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << strict_base << "/" << name << " into a double. " + << "The provided value was \"" << Pointer((strict_base + "/" + name).c_str()).Get(parameters)->GetString() << "\"."); + } + result.first.emplace_back(value); + } + } + else + { + // there is no user defined value. Case one: return the default value and no points + result.first.emplace_back(default_value); + } + + return result; + } + + + std::pair,std::vector> Parameters::get_value_at_array(const std::string &name) + { + // There are two cases: + // 1. One double provided: use the default value everywhere. Return first with one value and second with size 0. + // 2. Other: fill the vectors with the default value and addition points and then add new point. + // If a value without points is encountered, the additional points are used. + std::pair,std::vector> result; + + const std::string strict_base = this->get_full_json_path(); + + // start with adding the additional points with the default value + // to do this we need the default value + double default_value = 0; + bool is_array = true; + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr && Pointer((strict_base + "/" + name).c_str()).Get(parameters)->IsArray()) + { + const std::string value_def_path = get_full_json_schema_path() + "/" + name + "/oneOf/1/items/items/anyOf/0/default value"; + Value *value_def = Pointer(value_def_path.c_str()).Get(declarations); + WBAssertThrow(value_def != nullptr, + "internal error: could not retrieve the default value at: " + << value_def_path); + + // Since the default value is set in the code, if it fails it is an internal error, not a user error. + // So no try/catch needed. + default_value = value_def->GetDouble(); + } + else + { + is_array = false; + Value *value_def = Pointer((get_full_json_schema_path() + "/" + name + "/oneOf/0/default value").c_str()).Get(declarations); + WBAssertThrow(value_def != nullptr, + "internal error: could not retrieve the default value at: " + <GetDouble(); + } + + + // check if there is a user defined value + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr) + { + // there is a user defined value, so either case 2, 3 or 4. + if (is_array) + { + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + // go through all the points in order + for (size_t i = 0; i < array->Size(); ++i ) + { + // now parse a single value_at_point. + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + // Let's assume that the file is correct, because it has been checked with the json schema. + // So there are exactly two values, the first value is a double, the second an array of 2d arrays (points). + + // Get the double + double value; + Value *value_pointer = Pointer((base + "/0").c_str()).Get(parameters); + + WBAssertThrow(value_pointer != nullptr, "internal error: this should not happen."); + + try + { + value = value_pointer->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << base << "/0 into doubles. " + << "The provided value was \"" << Pointer((base + "/0").c_str()).Get(parameters)->GetString() << "\"."); + } + + // now get the array of points. + Value *array_of_doubles = Pointer((base + "/1").c_str()).Get(parameters); + double value_in_array; + if (array_of_doubles != nullptr) + { + for (size_t coordinate_i = 0; coordinate_i < array_of_doubles->Size(); ++coordinate_i ) + { + Value *coordinate_j_array = Pointer((base + "/1/" + std::to_string(coordinate_i)).c_str()).Get(parameters); + for (size_t coordinate_j = 0; coordinate_j < coordinate_j_array->Size(); ++coordinate_j) + { + // Let's assume that the file is correct, because it has been checked with the json schema. + // That means that there are exactly two values per item + try + { + value_in_array = Pointer((base + "/1/" + std::to_string(coordinate_i) + "/" + std::to_string(coordinate_j)).c_str()).Get(parameters)->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << base + "/1/" + std::to_string(coordinate_i) + "/" + std::to_string(coordinate_j) + << " into a Point<2> array, because it could not convert the 1st sub-elements into doubles. " + << "The provided value was \"" + << Pointer((base + "/1/" + std::to_string(coordinate_i) + "/" + std::to_string(coordinate_j)).c_str()).Get(parameters)->GetString() + << "\"."); + } + + result.second.emplace_back(value_in_array); + } + } + result.first.emplace_back(value); + } + } + } + else + { + // case 1: there one value, not an array + double value = 0; + try + { + value = Pointer((strict_base + "/" + name).c_str()).Get(parameters)->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << strict_base << "/" << name << " into a double. " + << "The provided value was \"" << Pointer((strict_base + "/" + name).c_str()).Get(parameters)->GetString() << "\"."); + } + result.first.emplace_back(0.0); + result.second.emplace_back(value); + } + } + else + { + // there is no user defined value. Case one: return the default value and no points + result.first.emplace_back(0.0); + result.second.emplace_back(default_value); + } + + return result; + } + + + template<> + std::vector > + Parameters::get_vector(const std::string &name) + { + std::vector > vector; + const std::string strict_base = this->get_full_json_path(); + WBAssertThrow(Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr,"Error: " << name + << " was not defined in " << strict_base << ", schema path: " << this->get_full_json_schema_path() << "."); + + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + for (size_t i = 0; i < array->Size(); ++i ) + { + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + //let's assume that the file is correct, because it has been checked with the json schema. + // So there are exactly two values. + double value1; + double value2; + + try + { + value1 = Pointer((base + "/0").c_str()).Get(parameters)->GetDouble(); + value2 = Pointer((base + "/1").c_str()).Get(parameters)->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << base << " into a Point<2> array, because it could not convert the sub-elements into doubles."); + } + vector.emplace_back(value1,value2,this->coordinate_system->natural_coordinate_system()); + } + + return vector; + } + + template<> + std::vector > + Parameters::get_vector(const std::string &name) + { + std::vector > vector; + const std::string strict_base = this->get_full_json_path(); + WBAssertThrow(Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr,"Error: " << name + << " was not defined in " << strict_base << ", schema path: " << this->get_full_json_schema_path() << "."); + + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + for (size_t i = 0; i < array->Size(); ++i ) + { + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + //let's assume that the file is correct, because it has been checked with the json schema. + // So there are exactly three values. + try + { + const double value1 = Pointer((base + "/0").c_str()).Get(parameters)->GetDouble(); + const double value2 = Pointer((base + "/1").c_str()).Get(parameters)->GetDouble(); + const double value3 = Pointer((base + "/2").c_str()).Get(parameters)->GetDouble(); + vector.push_back({{value1,value2,value3}}); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << base << " into doubles."); + } + } + + + return vector; + } + + std::vector> + Parameters::get_vector_or_double(const std::string &name) + { + // There are two cases: + // 1. One double provided: use the default value everywhere. Return first with one value and second with size 0. + // 2. std::vector> provided: output this array. + std::vector> result; + + const std::string strict_base = this->get_full_json_path(); + + // start with adding the additional points with the default value + // to do this we need the default value + double default_value = 0; + bool is_array = true; + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr && Pointer((strict_base + "/" + name).c_str()).Get(parameters)->IsArray()) + { + const std::string value_def_path = get_full_json_schema_path() + "/" + name + "/oneOf/1/items/items/default value"; + Value *value_def = Pointer(value_def_path.c_str()).Get(declarations); + WBAssertThrow(value_def != nullptr, + "internal error: could not retrieve the default value at: " + << value_def_path); + + // Since the default value is set in the code, if it fails it is an internal error, not a user error. + // So no try/catch needed. + default_value = value_def->GetDouble(); + } + else + { + is_array = false; + Value *value_def = Pointer((get_full_json_schema_path() + "/" + name + "/oneOf/0/default value").c_str()).Get(declarations); + WBAssertThrow(value_def != nullptr, + "internal error: could not retrieve the default value at: " + <GetDouble(); + } + + + // check if there is a user defined value + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr) + { + // there is a user defined value, so either case 2, 3 or 4. + if (is_array) + { + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + // go through all the 1d-arrays within the 2d-array + for (size_t i = 0; i < array->Size(); ++i ) + { + // now parse a single value_at_point. + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + + // now get the array of points. + // Value *coordinates_array = Pointer((base + "/0").c_str()).Get(parameters); + Value *coordinates_array = Pointer((base).c_str()).Get(parameters); + double value_in_array; + std::vector array_of_values; + if (coordinates_array != nullptr) + { + for (size_t coordinate_i = 0; coordinate_i < coordinates_array->Size(); ++coordinate_i ) + { + // Let's assume that the file is correct, because it has been checked with the json schema. + // That means that there are exactly two values per item + try + { + value_in_array = Pointer(((base + "/") + std::to_string(coordinate_i)).c_str()).Get(parameters)->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << base + "/" + std::to_string(i) + "/" + std::to_string(coordinate_i) + "/" + std::to_string(coordinate_i) + << " into a Point<2> array, because it could not convert the 1st sub-elements into doubles. " + << "The provided value was \"" + << Pointer((base + "/" + std::to_string(i) + "/" + std::to_string(coordinate_i)).c_str()).Get(parameters)->GetString() + << "\"."); + } + array_of_values.emplace_back(value_in_array); + } + result.emplace_back(array_of_values); + + } + } + } + else + { + // case 1: there's one value, not an array + double value = 0; + try + { + value = Pointer((strict_base + "/" + name).c_str()).Get(parameters)->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << strict_base << "/" << name << " into a double. " + << "The provided value was \"" << Pointer((strict_base + "/" + name).c_str()).Get(parameters)->GetString() << "\"."); + } + result.emplace_back(std::vector {value}); + } + } + else + { + // there is no user defined value. Case one: return the default value and no points + result.emplace_back(std::vector {default_value}); + } + + return result; + } + + + + template<> + std::vector,3> > + Parameters::get_vector(const std::string &name) + { + std::vector,3> > vector; + const std::string strict_base = this->get_full_json_path(); + WBAssertThrow(Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr,"Error: " << name + << " was not defined in " << strict_base << ", schema path: " << this->get_full_json_schema_path() << "."); + + Value *array1 = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + for (size_t i = 0; i < array1->Size(); ++i ) + { + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + Value *array2 = Pointer((base).c_str()).Get(parameters); + + // Not sure why cppcheck it is generating the warning + // Filed a question at: https://sourceforge.net/p/cppcheck/discussion/general/thread/429759f85e/ + // cppcheck-suppress constStatement + std::array,3> array; + WBAssertThrow(array2->Size() == 3, "Array " << i << " is supposed to be a 3x3 array, but the outer array dimensions is " + << array2->Size() << '.'); + for (size_t j = 0; j < array2->Size(); ++j ) + { + const std::string base_extended = base + "/" + std::to_string(j); + + WBAssertThrow(Pointer((base_extended).c_str()).Get(parameters)->Size() == 3, + "Array " << i << " is supposed to be a 3x3 array, but the inner array dimensions of " + << j << " is " << Pointer((base_extended).c_str()).Get(parameters)->Size() << '.'); + double value1; + double value2; + double value3; + + try + { + value1 = Pointer((base_extended + "/0").c_str()).Get(parameters)->GetDouble(); + value2 = Pointer((base_extended + "/1").c_str()).Get(parameters)->GetDouble(); + value3 = Pointer((base_extended + "/2").c_str()).Get(parameters)->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << base << " into doubles."); + } + array[j][0] = value1; + array[j][1] = value2; + array[j][2] = value3; + } + vector.push_back(array); + } + + return vector; + } + + + template<> + std::vector > > + Parameters::get_vector(const std::string &name) + { + std::vector > > vector; + const std::string strict_base = this->get_full_json_path(); + WBAssertThrow(Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr,"Error: " << name + << " was not defined in " << strict_base << ", schema path: " << this->get_full_json_schema_path() << "."); + + Value *array1 = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + for (size_t i = 0; i < array1->Size(); ++i ) + { + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + Value *array2 = Pointer((base).c_str()).Get(parameters); + + // Not sure why cppcheck it is generating the warning + // Filed a question at: https://sourceforge.net/p/cppcheck/discussion/general/thread/429759f85e/ + // cppcheck-suppress constStatement + std::vector > sub_vector(array2->Size(),Point<2>(NaN::DSNAN,NaN::DSNAN,coordinate_system->natural_coordinate_system())); + for (size_t j = 0; j < array2->Size(); ++j ) + { + const std::string base_extended = base + "/" + std::to_string(j); + + WBAssertThrow(Pointer((base_extended).c_str()).Get(parameters)->Size() == 2, + "Array " << i << " is supposed to be a 2d point, but the inner array dimensions of " + << j << " is " << Pointer((base_extended).c_str()).Get(parameters)->Size() << '.'); + double value1; + double value2; + + try + { + value1 = Pointer((base_extended + "/0").c_str()).Get(parameters)->GetDouble(); + value2 = Pointer((base_extended + "/1").c_str()).Get(parameters)->GetDouble(); + } + catch (...) + { + WBAssertThrow(false, "Could not convert values of " << base << " into doubles, because it could not covert the sub-elements into doubles."); + } + sub_vector[j][0] = value1; + sub_vector[j][1] = value2; + } + vector.push_back(sub_vector); + } + + return vector; + } + + + template<> + std::vector > + Parameters::get_vector(const std::string &name, + std::vector > &default_temperature_models, + std::vector > &default_composition_models, + std::vector > &default_grains_models) + { + using namespace Features::SubductingPlateModels; + std::vector > vector; + this->enter_subsection(name); + const std::string strict_base = this->get_full_json_path(); + WBAssertThrow(Pointer((strict_base).c_str()).Get(parameters) != nullptr,"Error: " << name + << " was not defined in " << strict_base << ", schema path: " << this->get_full_json_schema_path() << "."); + + // get the array of segments + Value *array = Pointer((strict_base).c_str()).Get(parameters); + + for (size_t i = 0; i < array->Size(); ++i ) + { + this->enter_subsection(std::to_string(i)); + const std::string base = this->get_full_json_path(); + // get one segment + // length + const double length = Pointer((base + "/length").c_str()).Get(parameters)->GetDouble(); + + // get thickness + Value *point_array = Pointer((base + "/thickness").c_str()).Get(parameters); + Point<2> thickness(invalid); + WBAssertThrow(point_array != nullptr,"error: " << name + << " was not defined in " << strict_base << "/thickness, schema path: " << this->get_full_json_schema_path() << "/thickness."); + + if (point_array->Size() == 1) + { + // There is only one value, set it for both elements + const double local0 = Pointer((base + "/thickness/0").c_str()).Get(parameters)->GetDouble(); + thickness = Point<2>(local0,local0,invalid); + } + else + { + const double local0 = Pointer((base + "/thickness/0").c_str()).Get(parameters)->GetDouble(); + const double local1 = Pointer((base + "/thickness/1").c_str()).Get(parameters)->GetDouble(); + thickness = Point<2>(local0,local1,invalid); + } + + + // get top truncation (default is 0,0) + point_array = Pointer((base + "/top truncation").c_str()).Get(parameters); + Point<2> top_truncation(invalid); + if (point_array != nullptr) + { + if (point_array->Size() == 1) + { + // There is only one value, set it for both elements + const double local0 = Pointer((base + "/top truncation/0").c_str()).Get(parameters)->GetDouble(); + top_truncation = Point<2>(local0,local0,invalid); + } + else + { + const double local0 = Pointer((base + "/top truncation/0").c_str()).Get(parameters)->GetDouble(); + const double local1 = Pointer((base + "/top truncation/1").c_str()).Get(parameters)->GetDouble(); + top_truncation = Point<2>(local0,local1,invalid); + } + } + // get thickness + point_array = Pointer((base + "/angle").c_str()).Get(parameters); + Point<2> angle(invalid); + WBAssertThrow(point_array != nullptr,"error: " << name + << " was not defined in " << strict_base << "/angle, schema path: " << this->get_full_json_schema_path() << "/angle."); + + if (point_array->Size() == 1) + { + // There is only one value, set it for both elements + const double local0 = Pointer((base + "/angle/0").c_str()).Get(parameters)->GetDouble(); + angle = Point<2>(local0,local0,invalid); + } + else + { + const double local0 = Pointer((base + "/angle/0").c_str()).Get(parameters)->GetDouble(); + const double local1 = Pointer((base + "/angle/1").c_str()).Get(parameters)->GetDouble(); + angle = Point<2>(local0,local1,invalid); + } + + + // Get temperature models + std::vector > temperature_models; + + //This is a value to look back in the path elements. + size_t searchback = 0; + if (!this->get_shared_pointers("temperature models", temperature_models) || + Pointer((base + "/temperature model default entry").c_str()).Get(parameters) != nullptr) + { + temperature_models = default_temperature_models; + + // find the default value, which is the closest to the current path + for (searchback = 0; searchback < path.size(); ++searchback) + { + if (Pointer((this->get_full_json_path(path.size()-searchback) + "/temperature models").c_str()).Get(parameters) != nullptr) + { + break; + } + } + + // if we can not find default value for the temperature model, skip it + if (searchback < path.size()) + { + + // copy the value, this unfortunately removes it. + Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/temperature models").c_str()).Get(parameters)->GetArray()); + + // now copy it + Value value2; + value2.CopyFrom(value1, parameters.GetAllocator()); + + // now we should have 2x the same value, so put it back and place it in the correct location. + Pointer((this->get_full_json_path(path.size()-searchback) + "/temperature models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator()); + + Pointer((base).c_str()).Get(parameters)->AddMember("temperature models", value2, parameters.GetAllocator()); + Pointer((base + "/temperature model default entry").c_str()).Set(parameters,true); + } + } + + // now do the same for compositions + std::vector > composition_models; + if (!this->get_shared_pointers("composition models", composition_models) || + Pointer((base + "/composition model default entry").c_str()).Get(parameters) != nullptr) + { + composition_models = default_composition_models; + + + // find the default value, which is the closest to the current path + for (searchback = 0; searchback < path.size(); ++searchback) + { + if (Pointer((this->get_full_json_path(path.size()-searchback) + "/composition models").c_str()).Get(parameters) != nullptr) + { + break; + } + } + + // if we can not find default value for the temperature model, skip it + if (searchback < path.size()) + { + + // copy the value, this unfortunately removes it. + Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/composition models").c_str()).Get(parameters)->GetArray()); + + // now copy it + Value value2; + value2.CopyFrom(value1, parameters.GetAllocator()); + + // now we should have 2x the same value, so put it back and place it in the correct location. + Pointer((this->get_full_json_path(path.size()-searchback) + "/composition models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator()); + + Pointer((base).c_str()).Get(parameters)->AddMember("composition models", value2, parameters.GetAllocator()); + Pointer((base + "/composition model default entry").c_str()).Set(parameters,true); + } + } + + // now do the same for grains + std::vector > grains_models; + if (!this->get_shared_pointers("grains models", grains_models) || + Pointer((base + "/grains model default entry").c_str()).Get(parameters) != nullptr) + { + grains_models = default_grains_models; + + + // find the default value, which is the closest to the current path + for (searchback = 0; searchback < path.size(); ++searchback) + { + if (Pointer((this->get_full_json_path(path.size()-searchback) + "/grains models").c_str()).Get(parameters) != nullptr) + { + break; + } + } + + // if we can not find default value for the temperature model, skip it + if (searchback < path.size()) + { + + // copy the value, this unfortunately removes it. + Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/grains models").c_str()).Get(parameters)->GetArray()); + + // now copy it + Value value2; + value2.CopyFrom(value1, parameters.GetAllocator()); + + // now we should have 2x the same value, so put it back and place it in the correct location. + Pointer((this->get_full_json_path(path.size()-searchback) + "/grains models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator()); + + Pointer((base).c_str()).Get(parameters)->AddMember("grains models", value2, parameters.GetAllocator()); + Pointer((base + "/grains model default entry").c_str()).Set(parameters,true); + } + } + vector.emplace_back(length, thickness, top_truncation, angle, temperature_models, composition_models, grains_models); + + this->leave_subsection(); + } + + this->leave_subsection(); + return vector; + } + + + template<> + std::vector > + Parameters::get_vector(const std::string &name, + std::vector > &default_temperature_models, + std::vector > &default_composition_models, + std::vector > &default_grains_models) + { + using namespace Features::FaultModels; + std::vector > vector; + this->enter_subsection(name); + const std::string strict_base = this->get_full_json_path(); + WBAssertThrow(Pointer((strict_base).c_str()).Get(parameters) != nullptr,"error: " << name + << " was not defined in " << strict_base << ", schema path: " << this->get_full_json_schema_path() << "."); + + // get the array of segments + Value *array = Pointer((strict_base).c_str()).Get(parameters); + + for (size_t i = 0; i < array->Size(); ++i ) + { + this->enter_subsection(std::to_string(i)); + const std::string base = this->get_full_json_path(); + // get one segment + // length + const double length = Pointer((base + "/length").c_str()).Get(parameters)->GetDouble(); + + // get thickness + Value *point_array = Pointer((base + "/thickness").c_str()).Get(parameters); + Point<2> thickness(invalid); + WBAssertThrow(point_array != nullptr,"error: " << name + << " was not defined in " << strict_base << "/thickness, schema path: " << this->get_full_json_schema_path() << "/thickness."); + + if (point_array->Size() == 1) + { + // There is only one value, set it for both elements + const double local0 = Pointer((base + "/thickness/0").c_str()).Get(parameters)->GetDouble(); + thickness = Point<2>(local0,local0,invalid); + } + else + { + const double local0 = Pointer((base + "/thickness/0").c_str()).Get(parameters)->GetDouble(); + const double local1 = Pointer((base + "/thickness/1").c_str()).Get(parameters)->GetDouble(); + thickness = Point<2>(local0,local1,invalid); + } + + + // get top truncation (default is 0,0) + point_array = Pointer((base + "/top truncation").c_str()).Get(parameters); + Point<2> top_truncation(invalid); + if (point_array != nullptr) + { + if (point_array->Size() == 1) + { + // There is only one value, set it for both elements + const double local0 = Pointer((base + "/top truncation/0").c_str()).Get(parameters)->GetDouble(); + top_truncation = Point<2>(local0,local0,invalid); + } + else + { + const double local0 = Pointer((base + "/top truncation/0").c_str()).Get(parameters)->GetDouble(); + const double local1 = Pointer((base + "/top truncation/1").c_str()).Get(parameters)->GetDouble(); + top_truncation = Point<2>(local0,local1,invalid); + } + } + // get thickness + point_array = Pointer((base + "/angle").c_str()).Get(parameters); + Point<2> angle(invalid); + WBAssertThrow(point_array != nullptr,"error: " << name + << " was not defined in " << strict_base << "/angle, schema path: " << this->get_full_json_schema_path() << "/angle."); + + if (point_array->Size() == 1) + { + // There is only one value, set it for both elements + const double local0 = Pointer((base + "/angle/0").c_str()).Get(parameters)->GetDouble(); + angle = Point<2>(local0,local0,invalid); + } + else + { + const double local0 = Pointer((base + "/angle/0").c_str()).Get(parameters)->GetDouble(); + const double local1 = Pointer((base + "/angle/1").c_str()).Get(parameters)->GetDouble(); + angle = Point<2>(local0,local1,invalid); + } + + + // Get temperature models + std::vector > temperature_models; + + //This is a value to look back in the path elements. + size_t searchback = 0; + if (!this->get_shared_pointers("temperature models", temperature_models) || + Pointer((base + "/temperature model default entry").c_str()).Get(parameters) != nullptr) + { + temperature_models = default_temperature_models; + + // find the default value, which is the closest to the current path + for (searchback = 0; searchback < path.size(); ++searchback) + { + if (Pointer((this->get_full_json_path(path.size()-searchback) + "/temperature models").c_str()).Get(parameters) != nullptr) + { + break; + } + } + + // if we can not find default value for the temperature model, skip it + if (searchback < path.size()) + { + + // copy the value, this unfortunately removes it. + Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/temperature models").c_str()).Get(parameters)->GetArray()); + + // now copy it + Value value2; + value2.CopyFrom(value1, parameters.GetAllocator()); + + // now we should have 2x the same value, so put it back and place it in the correct location. + Pointer((this->get_full_json_path(path.size()-searchback) + "/temperature models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator()); + + Pointer((base).c_str()).Get(parameters)->AddMember("temperature models", value2, parameters.GetAllocator()); + Pointer((base + "/temperature model default entry").c_str()).Set(parameters,true); + } + } + + // now do the same for compositions + std::vector > composition_models; + if (!this->get_shared_pointers("composition models", composition_models) || + Pointer((base + "/composition model default entry").c_str()).Get(parameters) != nullptr) + { + composition_models = default_composition_models; + + + // find the default value, which is the closest to the current path + for (searchback = 0; searchback < path.size(); ++searchback) + { + if (Pointer((this->get_full_json_path(path.size()-searchback) + "/composition models").c_str()).Get(parameters) != nullptr) + { + break; + } + } + + // if we can not find default value for the temperature model, skip it + if (searchback < path.size()) + { + + // copy the value, this unfortunately removes it. + Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/composition models").c_str()).Get(parameters)->GetArray()); + + // now copy it + Value value2; + value2.CopyFrom(value1, parameters.GetAllocator()); + + // now we should have 2x the same value, so put it back and place it in the correct location. + Pointer((this->get_full_json_path(path.size()-searchback) + "/composition models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator()); + + Pointer((base).c_str()).Get(parameters)->AddMember("composition models", value2, parameters.GetAllocator()); + Pointer((base + "/composition model default entry").c_str()).Set(parameters,true); + } + } + + // now do the same for grains + std::vector > grains_models; + if (!this->get_shared_pointers("grains models", grains_models) || + Pointer((base + "/grains model default entry").c_str()).Get(parameters) != nullptr) + { + grains_models = default_grains_models; + + + // find the default value, which is the closest to the current path + for (searchback = 0; searchback < path.size(); ++searchback) + { + if (Pointer((this->get_full_json_path(path.size()-searchback) + "/grains models").c_str()).Get(parameters) != nullptr) + { + break; + } + } + + // if we can not find default value for the temperature model, skip it + if (searchback < path.size()) + { + + // copy the value, this unfortunately removes it. + Value value1 = Value(Pointer((this->get_full_json_path(path.size()-searchback) + "/grains models").c_str()).Get(parameters)->GetArray()); + + // now copy it + Value value2; + value2.CopyFrom(value1, parameters.GetAllocator()); + + // now we should have 2x the same value, so put it back and place it in the correct location. + Pointer((this->get_full_json_path(path.size()-searchback) + "/grains models").c_str()).Set(parameters, value1);//.Get(parameters)->Set("temperature models", value1, parameters.GetAllocator()); + + Pointer((base).c_str()).Get(parameters)->AddMember("grains models", value2, parameters.GetAllocator()); + Pointer((base + "/grains model default entry").c_str()).Set(parameters,true); + } + } + vector.emplace_back(length, thickness, top_truncation, angle, temperature_models, composition_models, grains_models); + + this->leave_subsection(); + } + + this->leave_subsection(); + return vector; + } + + template<> + std::vector + Parameters::get_vector(const std::string &name) + { + std::vector vector; + const std::string strict_base = this->get_full_json_path(); + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr) + { + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + for (size_t i = 0; i < array->Size(); ++i ) + { + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + + vector.push_back(Pointer(base.c_str()).Get(parameters)->GetDouble()); + } + } + else + { + const Value *value = Pointer((this->get_full_json_schema_path() + "/" + name + "/minItems").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the minItems value at: " + << this->get_full_json_schema_path() + "/" + name + "/minItems"); + + const size_t min_size = value->GetUint(); + + value = Pointer((this->get_full_json_schema_path() + "/" + name + "/items/default value").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the default value at: " + << this->get_full_json_schema_path() + "/" + name + "/default value"); + + const double default_value = value->GetDouble(); + + // set to min size + for (size_t i = 0; i < min_size; ++i) + { + vector.push_back(default_value); + } + } + return vector; + } + + template<> + std::vector + Parameters::get_vector(const std::string &name) + { + std::vector vector; + const std::string strict_base = this->get_full_json_path(); + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr) + { + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + for (size_t i = 0; i < array->Size(); ++i ) + { + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + + vector.push_back(Pointer(base.c_str()).Get(parameters)->GetUint()); + } + } + else + { + const Value *value = Pointer((this->get_full_json_schema_path() + "/" + name + "/minItems").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the minItems value at: " + << this->get_full_json_schema_path() + "/" + name + "/minItems"); + + const size_t min_size = value->GetUint(); + + value = Pointer((this->get_full_json_schema_path() + "/" + name + "/items/default value").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the default value at: " + << this->get_full_json_schema_path() + "/" + name + "/default value"); + + const size_t default_value = value->GetUint(); + + // set to min size + for (size_t i = 0; i < min_size; ++i) + { + vector.push_back(default_value); + } + } + return vector; + } + + template<> + std::vector + Parameters::get_vector(const std::string &name) + { + std::vector vector; + const std::string strict_base = this->get_full_json_path(); + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr) + { + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + for (size_t i = 0; i < array->Size(); ++i ) + { + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + + vector.push_back(Pointer(base.c_str()).Get(parameters)->GetUint()); + } + } + else + { + const Value *value = Pointer((this->get_full_json_schema_path() + "/" + name + "/minItems").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the minItems value at: " + << this->get_full_json_schema_path() + "/" + name + "/minItems value"); + + const size_t min_size = value->GetUint(); + + const unsigned int default_value = Pointer((this->get_full_json_schema_path() + "/" + name + "/items/default value").c_str()).Get(declarations)->GetUint(); + + // set to min size + for (size_t i = 0; i < min_size; ++i) + { + vector.push_back(default_value); + } + } + return vector; + } + + template + std::unique_ptr + Parameters::get_unique_pointer(const std::string &name) + { + const std::string base = this->get_full_json_path(); + Value *value = Pointer((base + "/" + name + "/model").c_str()).Get(parameters); + +#ifdef debug + bool required = false; + if (Pointer((base + "/required").c_str()).Get(declarations) != NULL) + for (auto &v : Pointer((base + "/required").c_str()).Get(declarations)->GetArray()) + { + if (v.GetString() == name) + { + required = true; + } + } + + WBAssert(value != NULL || required == false, + "Internal error: Value \"" << base << '/' << name << "/model\" not found in the input file, while it was set as required."); +#endif + if (value == nullptr) + { + value = Pointer((get_full_json_schema_path() + "/" + name + "/default value").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the default value at: " + << base + "/" + name + "/default value. Make sure the value has been declared."); + } + + return T::create(value->GetString(),&world); + } + + template + bool + Parameters::get_unique_pointers(const std::string &name, std::vector > &vector) + { + vector.resize(0); + const std::string strict_base = this->get_full_json_path(); + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr) + { + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + for (size_t i = 0; i < array->Size(); ++i ) + { + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + + const std::string value = Pointer((base + "/model").c_str()).Get(parameters)->GetString(); + + vector.push_back(std::move(T::create(value, &world))); + } + } + else + { + return false; + } + + return true; + } + + template<> + bool + Parameters::get_unique_pointers(const std::string &name, std::vector > &vector) + { + vector.resize(0); + const std::string strict_base = this->get_full_json_path(); + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr) + { + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + for (size_t i = 0; i < array->Size(); ++i ) + { + vector.push_back(std::make_unique(&world)); + } + } + else + { + return false; + } + + return true; + } + + template<> + bool + Parameters::get_unique_pointers(const std::string &name, std::vector > &vector) + { + vector.resize(0); + const std::string strict_base = this->get_full_json_path(); + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr) + { + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + for (size_t i = 0; i < array->Size(); ++i ) + { + vector.push_back(std::make_unique(&world)); + } + } + else + { + return false; + } + + return true; + } + + + + template + bool + Parameters::get_shared_pointers(const std::string &name, std::vector > &vector) + { + vector.resize(0); + const std::string strict_base = this->get_full_json_path(); + if (Pointer((strict_base + "/" + name).c_str()).Get(parameters) != nullptr) + { + Value *array = Pointer((strict_base + "/" + name).c_str()).Get(parameters); + + for (size_t i = 0; i < array->Size(); ++i ) + { + const std::string base = (strict_base + "/").append(name).append("/").append(std::to_string(i)); + + const std::string value = Pointer((base + "/model").c_str()).Get(parameters)->GetString(); + + vector.push_back(std::move(T::create(value, &world))); + } + } + else + { + return false; + } + + return true; + } + + void + Parameters::enter_subsection(const std::string &name) + { + path.push_back(name); + //TODO: WBAssert(is path valid?) + } + + void + Parameters::leave_subsection() + { + path.pop_back(); + } + + + + void + Parameters::declare_model_entries(const std::string &model_group_name, + const std::string &parent_name, + const std::map &declare_map, + const std::vector &required_entries, + const std::vector > &extra_declarations) + { + unsigned int counter = 0; + for (const auto &it : declare_map) + { + typedef std::tuple DeclareEntry; + // prevent infinite recursion + if (it.first != parent_name) + { + enter_subsection("oneOf"); + { + enter_subsection(std::to_string(counter)); + { + enter_subsection("properties"); + { + declare_entry("", Types::Object(required_entries), model_group_name + " object"); + + declare_entry("model", Types::String("",it.first), + "The name of the " + model_group_name + " model."); + + for (DeclareEntry extra_declaration : extra_declarations) + { + declare_entry(std::get<0>(extra_declaration),std::get<1>(extra_declaration),std::get<2>(extra_declaration)); + } + + + it.second(*this, parent_name); + } + leave_subsection(); + } + leave_subsection(); + } + leave_subsection(); + + counter++; + + } + } + } + + + + std::string + Parameters::get_full_json_path(size_t max_size) const + { + std::string collapse; + for (size_t i = 0; i < path.size() && i < max_size; i++) + { + collapse += "/" + path[i]; + } + return collapse; + } + + std::string + Parameters::get_full_json_schema_path() const + { + std::string collapse = "/properties"; + for (size_t i = 0; i < path.size(); i++) + { + // first get the type + //WBAssert(Pointer((collapse + "/" + path[i] + "/type").c_str()).Get(declarations) != NULL, "Internal error: could not find " << collapse + "/" + path[i] + "/type"); + + const std::string base_path = Pointer((collapse + "/" + path[i] + "/type").c_str()).Get(declarations) != nullptr + ? + collapse + "/" + path[i] + : + collapse; + + const std::string type = Pointer((base_path + "/type").c_str()).Get(declarations)->GetString(); + + if (type == "array") + { + // the type is an array. Arrays always have an items, but can also + // have a oneOf (todo: or anyOf ...). Find out whether this is the case + //collapse += path[i] + "/items"; + if (Pointer((base_path + "/items/oneOf").c_str()).Get(declarations) != nullptr) + { + // it has a structure with oneOf. Find out which of the entries is needed. + // This means we have to take a sneak peak to figure out how to get to the + // next value. + const size_t size = Pointer((base_path + "/items/oneOf").c_str()).Get(declarations)->Size(); +#ifdef debug + bool found = false; +#endif + size_t index = 0; + for (; index < size; ++index) + { + const std::string declarations_string = Pointer((base_path + "/items/oneOf/" + std::to_string(index) + + "/properties/model/enum/0").c_str()).Get(declarations)->GetString(); + + // we need to get the json path relevant for the current declaration string + // we are interested in, which requires an offset of 2. + WBAssert(Pointer((get_full_json_path(i+2) + "/model").c_str()).Get(parameters) != nullptr, "Could not find model in: " << get_full_json_path(i+2) + "/model"); + const std::string parameters_string = Pointer((get_full_json_path(i+2) + "/model").c_str()).Get(parameters)->GetString(); + + // currently in our case these are always objects, so go directly to find the option we need. + if (declarations_string == parameters_string) + { + // found it for index i; +#ifdef debug + found = true; +#endif + break; + } + } +#ifdef debug + WBAssert(found == true, + "Internal error: This is an array with several possible values, " + "but could not find the correct value " << collapse + "/" + path[i] + "/items/oneOf"); +#endif + collapse += "/" + path[i] + "/items/oneOf/" + std::to_string(index) + "/properties"; + // add one to i, to skip the array + ++i; + } + else + { + collapse = base_path + "/items"; + } + } + else if (type == "object") + { + // normal objects just have properties, but some have oneOf + if (Pointer((base_path + "/oneOf").c_str()).Get(declarations) != nullptr) + { + // it has a structure with oneOf. Find out which of the entries is needed. + // This means we have to take a sneak peak to figure out how to get to the + // next value. + const size_t size = Pointer((base_path + "/oneOf").c_str()).Get(declarations)->Size(); +#ifdef debug + bool found = false; +#endif + size_t index = 0; + for (; index < size; ++index) + { + const std::string declarations_string = Pointer((base_path + "/oneOf/" + std::to_string(index) + + "/properties/model/enum/0").c_str()).Get(declarations)->GetString(); + + // we need to get the json path relevant for the current declaration string + // we are interested in, which requires an offset of 2. + const Value *value = Pointer((get_full_json_path(i+2) + "/model").c_str()).Get(parameters); + + + if (value == nullptr) + { + value = Pointer((collapse + "/" + path[i] + "/default value").c_str()).Get(declarations); + WBAssertThrow(value != nullptr, + "internal error: could not retrieve the default value at: " + << collapse + "/" + path[i] + "/default value, for value: "); + } + + const std::string parameters_string = value->GetString(); + + // currently in our case these are always objects, so go directly to find the option we need. + if (declarations_string == parameters_string) + { + // found it for index i; +#ifdef debug + found = true; +#endif + break; + } + } +#ifdef debug + WBAssert(found == true, + "Internal error: This is an array with several possible values, " + "but could not find the correct value " << collapse + "/" + path[i] + "/items/oneOf"); +#endif + collapse += "/" + path[i] + "/oneOf/" + std::to_string(index) + "/properties"; + // add one to i, to skip the array + ++i; + + } + else + { + collapse += "/properties"; + } + } + else + { + collapse += "/" + path[i]; + } + } + return collapse; + } + + + + + + /** + * Todo: Returns a vector of pointers to the Point<3> Type 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); + + + /** + * Returns a vector of pointers to the Gravity 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. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_unique_pointers(const std::string &name, + std::vector > &vector); + + + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_shared_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_shared_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_shared_pointers(const std::string &name, + std::vector > &vector); + + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_shared_pointers(const std::string &name, + std::vector > &vector); + + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_shared_pointers(const std::string &name, + std::vector > &vector); + /** + * Todo: Returns a vector of pointers to the Point<3> Type based on the provided name. + * Note that the variable with this name has to be loaded before this function is called. + */ + template bool + Parameters::get_shared_pointers(const std::string &name, + std::vector > &vector); + + + + + +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/point.cc.bak b/contrib/world_builder/source/world_builder/point.cc.bak new file mode 100644 index 00000000000..e04402d4158 --- /dev/null +++ b/contrib/world_builder/source/world_builder/point.cc.bak @@ -0,0 +1,108 @@ +/* + 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/point.h" + +#include + +namespace WorldBuilder +{ + + template<> + Point<2>::Point(const double x, const double y, const CoordinateSystem coordinate_system_) + : + point({{x,y}}), + coordinate_system(coordinate_system_) + {} + + template<> + Point<3>::Point(const double /*x*/, const double /*y*/, CoordinateSystem coordinate_system_) + : + point({{std::numeric_limits::signaling_NaN(),std::numeric_limits::signaling_NaN(), std::numeric_limits::signaling_NaN()}}), + coordinate_system(coordinate_system_) + { + WBAssertThrow(false,"Can't use the 2d constructor in 3d."); + } + + + template<> + Point<2>::Point(const double /*x*/, const double /*y*/, const double /*z*/, CoordinateSystem coordinate_system_) + : + point({{std::numeric_limits::signaling_NaN(),std::numeric_limits::signaling_NaN()}}), + coordinate_system(coordinate_system_) + { + WBAssertThrow(false,"Can't use the 3d constructor in 2d."); + } + + + template<> + Point<3>::Point(const double x, const double y, const double z, CoordinateSystem coordinate_system_) + : + point({{x,y,z}}), + coordinate_system(coordinate_system_) + {} + + + + + + + + template + double + Point::distance(const Point<2> &two) const + { + if (this->coordinate_system == spherical) + { + // spherical + const double d_longitude = two[0] - this->point[0]; + const double d_latitude = two[1] - this->point[1]; + const double sin_d_lat = std::sin(d_latitude * 0.5); + const double sin_d_long = std::sin(d_longitude * 0.5); + return 2.0 * asin(sqrt((sin_d_lat * sin_d_lat) + (sin_d_long*sin_d_long) * std::cos(this->point[1]) * std::cos(two[1]))); + } + + // cartesian + const double x_distance_to_reference_point = point[0]-two[0]; + const double y_distance_to_reference_point = point[1]-two[1]; + return sqrt((x_distance_to_reference_point*x_distance_to_reference_point) + (y_distance_to_reference_point*y_distance_to_reference_point)); + + } + + /** + * The 2d version of the point class. + */ + template class Point<2>; + + + /** + * The 3d version of the point class. + */ + template class Point<3>; + + /** + * Multiplies a 2d point with a scalar. + */ + template Point<2> operator*(const double scalar, const Point<2> &point); + + /** + * Multiplies a 3d point with a scalar. + */ + template Point<3> operator*(const double scalar, const Point<3> &point); +} // namespace WorldBuilder diff --git a/contrib/world_builder/source/world_builder/types/array.cc.bak b/contrib/world_builder/source/world_builder/types/array.cc.bak new file mode 100644 index 00000000000..7c62626a976 --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/array.cc.bak @@ -0,0 +1,84 @@ +/* + 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/types/array.h" + +#include "world_builder/parameters.h" + +namespace WorldBuilder +{ + namespace Types + { + Array::Array(const Interface &type, + const unsigned int min_items_, + const unsigned int max_items_, + const bool unique_items_) + : + inner_type(type.get_type()), + inner_type_ptr(type.clone()), + required(false), + min_items(min_items_), + max_items(max_items_), + unique_items(unique_items_) + { + this->type_name = Types::type::Array; + } + + Array::Array(Array const &other) + : + inner_type(other.inner_type), + inner_type_ptr(other.inner_type_ptr->clone()), + required(other.required), + min_items(other.min_items), + max_items(other.max_items), + unique_items(other.unique_items) + { + this->type_name = Types::type::Array; + } + + Array::~Array () + = default; + + + void + Array::write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const + { + using namespace rapidjson; + Document &declarations = prm.declarations; + const std::string &base = prm.get_full_json_path() + "/" + name; + + Pointer((base + "/type").c_str()).Set(declarations,"array"); + Pointer((base + "/minItems").c_str()).Set(declarations,min_items); + Pointer((base + "/maxItems").c_str()).Set(declarations,max_items); + Pointer((base + "/uniqueItems").c_str()).Set(declarations,unique_items); + Pointer((base + "/description").c_str()).Set(declarations,documentation.c_str()); + + prm.enter_subsection(name); + { + WBAssertThrow(this->inner_type_ptr != nullptr, "Internal error, inner pointer is NULL."); + this->inner_type_ptr->write_schema(prm, "items", ""); + } + prm.leave_subsection(); + + + } + } // namespace Types +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/types/bool.cc.bak b/contrib/world_builder/source/world_builder/types/bool.cc.bak new file mode 100644 index 00000000000..94ee122cbfb --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/bool.cc.bak @@ -0,0 +1,62 @@ +/* + 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/types/bool.h" + +#include "world_builder/parameters.h" + +namespace WorldBuilder +{ + namespace Types + { + Bool::Bool(const bool default_value_) + : + default_value(default_value_) + { + this->type_name = Types::type::Bool; + } + + + Bool::Bool(Bool const &other) + : + default_value(other.default_value) + { + this->type_name = Types::type::Bool; + } + + + Bool::~Bool () + = default; + + + void + Bool::write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const + { + using namespace rapidjson; + Document &declarations = prm.declarations; + const std::string base = prm.get_full_json_path() + "/" + name; + + Pointer((base + "/default value").c_str()).Set(declarations,default_value); + Pointer((base + "/type").c_str()).Set(declarations,"boolean"); + Pointer((base + "/description").c_str()).Set(declarations,documentation.c_str()); + } + } // namespace Types +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/types/double.cc.bak b/contrib/world_builder/source/world_builder/types/double.cc.bak new file mode 100644 index 00000000000..3d1e1f2a48b --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/double.cc.bak @@ -0,0 +1,68 @@ +/* + 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/types/double.h" + +#include "world_builder/parameters.h" +#include + +namespace WorldBuilder +{ + namespace Types + { + Double::Double(const double default_value_) + : + default_value(default_value_) + { + this->type_name = Types::type::Double; + } + + + Double::Double(Double const &other) + : + default_value(other.default_value) + { + this->type_name = Types::type::Double; + } + + + + Double::~Double () + = default; + + + void + Double::write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const + { + using namespace rapidjson; + Document &declarations = prm.declarations; + const std::string base = prm.get_full_json_path() + "/" + name; + + if (std::isnan(default_value)) + Pointer((base + "/default value").c_str()).Set(declarations,"NaN"); + else + Pointer((base + "/default value").c_str()).Set(declarations,default_value); + + Pointer((base + "/type").c_str()).Set(declarations,"number"); + Pointer((base + "/description").c_str()).Set(declarations,documentation.c_str()); + } + } // namespace Types +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/types/int.cc.bak b/contrib/world_builder/source/world_builder/types/int.cc.bak new file mode 100644 index 00000000000..a18c7ef3882 --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/int.cc.bak @@ -0,0 +1,64 @@ +/* + 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/types/int.h" + +#include "world_builder/parameters.h" + +namespace WorldBuilder +{ + namespace Types + { + Int::Int(int default_value_) + : + + default_value(default_value_) + { + this->type_name = Types::type::Int; + } + + + Int::Int(Int const &other) + : + value(other.value), + default_value(other.default_value) + { + this->type_name = Types::type::Int; + } + + Int::~Int () + = default; + + + void + Int::write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const + { + using namespace rapidjson; + Document &declarations = prm.declarations; + + const std::string base = prm.get_full_json_path() + "/" + name; + Pointer((base + "/default value").c_str()).Set(declarations,default_value); + Pointer((base + "/type").c_str()).Set(declarations,"integer"); + Pointer((base + "/description").c_str()).Set(declarations,documentation.c_str()); + + } + } // namespace Types +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/types/interface.cc.bak b/contrib/world_builder/source/world_builder/types/interface.cc.bak new file mode 100644 index 00000000000..c1bd9560ae4 --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/interface.cc.bak @@ -0,0 +1,45 @@ +/* + 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/types/interface.h" + + + +namespace WorldBuilder +{ + + namespace Types + { + Interface::Interface() + + + = default; + + Interface::~Interface () + = default; + + + type + Interface::get_type() const + { + return type_name; + } + } // namespace Types +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/types/object.cc.bak b/contrib/world_builder/source/world_builder/types/object.cc.bak new file mode 100644 index 00000000000..fce574bd90e --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/object.cc.bak @@ -0,0 +1,91 @@ +/* + 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/types/object.h" + + +#include "world_builder/parameters.h" + +namespace WorldBuilder +{ + namespace Types + { + Object::Object(std::vector required_, + const bool additional_properties_) + : + required(std::move(required_)), + additional_properties(additional_properties_) + { + this->type_name = Types::type::Object; + } + + Object::Object(Object const &other) + : + required(other.required), + additional_properties(other.additional_properties) + { + this->type_name = Types::type::Object; + } + + Object::~Object () + = default; + + void + Object::write_schema(Parameters &prm, + const std::string & /*name*/, + const std::string &documentation) const + { + // The object has to be defined just above the properties section. + // because it is very inconvenient to make this object there, we + // take care here to do that. + WBAssertThrow(!prm.path.empty() && prm.path.back() == "properties", + "The Object must be defined in a subsection called properties."); + prm.leave_subsection(); + { + using namespace rapidjson; + Document &declarations = prm.declarations; + const std::string path = prm.get_full_json_path(); + + Pointer((path + "/type").c_str()).Set(declarations,"object"); + Pointer((path + "/description").c_str()).Set(declarations,documentation.c_str()); + Pointer((path + "/additionalProperties").c_str()).Set(declarations,additional_properties); + + if (!required.empty()) + { + for (unsigned int i = 0; i < required.size(); ++i) + { + if (i == 0 && Pointer((path + "/required").c_str()).Get(declarations) == nullptr) + { + // The required array doesn't exist yet, so we create it and fill it. + Pointer((path + "/required/0").c_str()).Create(declarations); + Pointer((path + "/required/0").c_str()).Set(declarations, required[i].c_str()); + } + else + { + // The required array already exist yet, so we add an element to the end. + Pointer((path + "/required/-").c_str()).Set(declarations, required[i].c_str()); + } + } + } + } + prm.enter_subsection("properties"); + } + } // namespace Types +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/types/one_of.cc.bak b/contrib/world_builder/source/world_builder/types/one_of.cc.bak new file mode 100644 index 00000000000..8ee982bb1c1 --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/one_of.cc.bak @@ -0,0 +1,77 @@ +/* + 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/types/one_of.h" + +#include "world_builder/parameters.h" + +namespace WorldBuilder +{ + namespace Types + { + OneOf::OneOf(const Interface &type_1, + const Interface &type_2) + { + this->type_name = Types::type::OneOf; + inner_types_ptr.emplace_back(type_1.clone()); + inner_types_ptr.emplace_back(type_2.clone()); + + } + + OneOf::OneOf(OneOf const &other) + { + this->type_name = Types::type::OneOf; + for (const auto &i : other.inner_types_ptr) + { + inner_types_ptr.emplace_back(i->clone()); + } + } + + OneOf::~OneOf () + = default; + + + void + OneOf::write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const + { + using namespace rapidjson; + Document &declarations = prm.declarations; + const std::string &base = prm.get_full_json_path() + "/" + name; + + prm.enter_subsection(name); + { + Pointer((base + "/description").c_str()).Set(declarations,documentation.c_str()); + prm.enter_subsection("oneOf"); + { + for (size_t i = 0; i < inner_types_ptr.size(); i++) + { + WBAssertThrow(inner_types_ptr[i] != nullptr, "Internal error, inner pointer is NULL."); + inner_types_ptr[i]->write_schema(prm, std::to_string(i), ""); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + + } + } // namespace Types +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/types/plugin_system.cc.bak b/contrib/world_builder/source/world_builder/types/plugin_system.cc.bak new file mode 100644 index 00000000000..4e5d23d1c33 --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/plugin_system.cc.bak @@ -0,0 +1,95 @@ +/* + 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/types/plugin_system.h" + + + +namespace WorldBuilder +{ + namespace Types + { + PluginSystem::PluginSystem(std::string default_value_, + void ( *declare_entries_)(Parameters &, const std::string &, const std::vector &), + std::vector required_entries_, + const bool allow_multiple_) + : + default_value(std::move(default_value_)), + declare_entries(declare_entries_), + required_entries(std::move(required_entries_)), + allow_multiple(allow_multiple_) + { + this->type_name = Types::type::PluginSystem; + + WBAssert(declare_entries_ != nullptr, "declare entries may not be a null pointer."); + } + + + PluginSystem::PluginSystem(PluginSystem const &plugin_system) + : + default_value(plugin_system.default_value), + declare_entries(plugin_system.declare_entries), + required_entries(plugin_system.required_entries), + allow_multiple(plugin_system.allow_multiple) + { + this->type_name = Types::type::PluginSystem; + } + + PluginSystem::~PluginSystem () + = default; + + void + PluginSystem::write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const + { + using namespace rapidjson; + + prm.enter_subsection(name); + { + const std::string path = prm.get_full_json_path(); + Pointer((path + "/description").c_str()).Set(prm.declarations,documentation.c_str()); + Pointer((path + "/default value").c_str()).Set(prm.declarations,default_value.c_str()); + + if (allow_multiple) + { + Pointer((path + "/type").c_str()).Set(prm.declarations,"array"); + + prm.enter_subsection("items"); + { + WBAssert(this->declare_entries != nullptr, "No declare entries given."); + + this->declare_entries(prm, name, required_entries); + } + prm.leave_subsection(); + } + else + { + Pointer((path + "/type").c_str()).Set(prm.declarations,"object"); + + WBAssert(this->declare_entries != nullptr, "No declare entries given."); + this->declare_entries(prm, name, required_entries); + + + } + } + prm.leave_subsection(); + } + } // namespace Types +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/types/point.cc.bak b/contrib/world_builder/source/world_builder/types/point.cc.bak new file mode 100644 index 00000000000..977fe601183 --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/point.cc.bak @@ -0,0 +1,185 @@ +/* + 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/types/point.h" + + +#include "world_builder/parameters.h" + +namespace WorldBuilder +{ + namespace Types + { + + template + Point::Point() + : + value(WorldBuilder::Point(CoordinateSystem::cartesian)), + default_value(WorldBuilder::Point(CoordinateSystem::cartesian)) + + { + this->type_name = dim == 2 ? Types::type::Point2D : Types::type::Point3D; + } + + template + Point::Point(const WorldBuilder::Point &default_value_, + std::string description_) + : + value(default_value_), + default_value(default_value_), + description(std::move(description_)) + { + this->type_name = dim == 2 ? Types::type::Point2D : Types::type::Point3D; + } + + template + Point::Point(const WorldBuilder::Point &value_, + const WorldBuilder::Point &default_value_, + std::string description_) + : + value(value_), + default_value(default_value_), + description(std::move(description_)) + { + this->type_name = dim == 2 ? Types::type::Point2D : Types::type::Point3D; + } + + template + Point::Point(Point const &other) + : + value(other.value), + default_value(other.default_value), + description(other.description) + { + this->type_name = dim == 2 ? Types::type::Point2D : Types::type::Point3D; + } + + template + Point::~Point () + = default; + + template + void + Point::write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const + { + using namespace rapidjson; + Document &declarations = prm.declarations; + const std::string base = prm.get_full_json_path() + "/" + name; + + Pointer((base + "/type").c_str()).Set(declarations,"array"); + Pointer((base + "/minItems").c_str()).Set(declarations,dim); + Pointer((base + "/maxItems").c_str()).Set(declarations,dim); + Pointer((base + "/description").c_str()).Set(declarations,documentation.c_str()); + Pointer((base + "/items/type").c_str()).Set(declarations,"number"); + // todo: default value + } + + + template + double Point::operator*(const Point &point_) const + { + const std::array array = point_.value.get_array(); + double dot_product = 0; + for (unsigned int i = 0; i < dim; ++i) + dot_product += value[i] * array[i]; + return dot_product; + } + + + template + WorldBuilder::Point + Point::operator*(const double scalar) const + { + // initialize the array to zero. + std::array array = WorldBuilder::Point(value.get_coordinate_system()).get_array(); + for (unsigned int i = 0; i < dim; ++i) + array[i] += value[i] * scalar; + return WorldBuilder::Point(array,value.get_coordinate_system()); + } + + template + WorldBuilder::Point + Point::operator+(const Point &point_) const + { + WorldBuilder::Point point_tmp(value); + point_tmp += point_.value; + + return point_tmp; + } + + template + WorldBuilder::Point + Point::operator-(const Point &point_) const + { + WorldBuilder::Point point_tmp(value); + point_tmp -= point_.value; + + return point_tmp; + } + + /** + * access index + */ + template + double & + Point::operator[](const unsigned int index) + { + return value[index]; + } + + /** + * access index + */ + template + const double & + Point::operator[](const unsigned int index) const + { + return value[index]; + } + + /** + * Multiplies a Types::Point with a scalr and returns a + * WorldBuilder::Point. + */ + template + WorldBuilder::Point + operator*(const double scalar, const Point &point) + { + return point.value*scalar; + } + + template class Point<2>; + template class Point<3>; + + /** + * Multiplies a Types::Point<2> with a scalr and returns a + * WorldBuilder::Point<2>. + */ + template WorldBuilder::Point<2> operator*(const double scalar, const Point<2> &point); + + + /** + * Multiplies a Types::Point<3> with a scalr and returns a + * WorldBuilder::Point<3>. + */ + template WorldBuilder::Point<3> operator*(const double scalar, const Point<3> &point); + } // namespace Types +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/types/segment.cc.bak b/contrib/world_builder/source/world_builder/types/segment.cc.bak new file mode 100644 index 00000000000..b51c63c1a7a --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/segment.cc.bak @@ -0,0 +1,170 @@ +/* + 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/types/segment.h" + + +namespace WorldBuilder +{ + namespace Features + { + namespace FaultModels + { + namespace Composition + { + class Interface; + } // namespace Composition + namespace Grains + { + class Interface; + } // namespace Grains + namespace Temperature + { + class Interface; + } // namespace Temperature + } // namespace FaultModels + namespace SubductingPlateModels + { + namespace Composition + { + class Interface; + } // namespace Composition + namespace Grains + { + class Interface; + } // namespace Grains + namespace Temperature + { + class Interface; + } // namespace Temperature + } // namespace SubductingPlateModels + } // namespace Features + + namespace Types + { + Segment::Segment(const double default_length_, + const WorldBuilder::Point<2> &default_thickness_, + const WorldBuilder::Point<2> &default_top_truncation_, + const WorldBuilder::Point<2> &default_angle_, + const Types::Interface &temperature_plugin_system_, + const Types::Interface &composition_plugin_system_, + const Types::Interface &grains_plugin_system_) + : + value_length(default_length_), + default_length(default_length_), + value_thickness(default_thickness_), + default_thickness(default_thickness_), + default_top_truncation(default_top_truncation_), + value_angle(default_angle_), + default_angle(default_angle_), + temperature_plugin_system(temperature_plugin_system_.clone()), + composition_plugin_system(composition_plugin_system_.clone()), + grains_plugin_system(grains_plugin_system_.clone()) + { + this->type_name = Types::type::Segment; + } + + + Segment::Segment(Segment const &other) + : + value_length(other.default_length), + default_length(other.default_length), + value_thickness(other.default_thickness), + default_thickness(other.default_thickness), + default_top_truncation(other.default_top_truncation), + value_angle(other.default_angle), + default_angle(other.default_angle), + temperature_plugin_system(other.temperature_plugin_system->clone()), + composition_plugin_system(other.composition_plugin_system->clone()), + grains_plugin_system(other.grains_plugin_system->clone()) + { + this->type_name = Types::type::Segment; + } + + + Segment::~Segment () + = default; + + + + void + Segment::write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const + { + using namespace rapidjson; + prm.enter_subsection(name); + { + Document &declarations = prm.declarations; + std::string base = prm.get_full_json_path(); + + Pointer((base + "/type").c_str()).Set(declarations,"object"); + Pointer((base + "/additionalProperties").c_str()).Set(declarations,false); + Pointer((base + "/description").c_str()).Set(declarations,documentation.c_str()); + std::vector restricted_values = {"length", "thickness", "angle"}; + for (unsigned int i = 0; i < restricted_values.size(); ++i) + { + if (!restricted_values[i].empty()) + { + if (i == 0 && Pointer((base + "/required").c_str()).Get(declarations) == nullptr) + { + // The enum array doesn't exist yet, so we create it and fill it. + Pointer((base + "/required/0").c_str()).Create(declarations); + Pointer((base + "/required/0").c_str()).Set(declarations, restricted_values[i].c_str()); + } + else + { + // The enum array already exist yet, so we add an element to the end. + Pointer((base + "/required/-").c_str()).Set(declarations, restricted_values[i].c_str()); + } + } + } + + prm.enter_subsection("properties"); + { + base = prm.get_full_json_path(); + Pointer((base + "/length/type").c_str()).Set(declarations,"number"); + + Pointer((base + "/thickness/type").c_str()).Set(declarations,"array"); + Pointer((base + "/thickness/minItems").c_str()).Set(declarations,1); + Pointer((base + "/thickness/maxItems").c_str()).Set(declarations,2); + Pointer((base + "/thickness/items/type").c_str()).Set(declarations,"number"); + + Pointer((base + "/top truncation/type").c_str()).Set(declarations,"array"); + Pointer((base + "/top truncation/minItems").c_str()).Set(declarations,1); + Pointer((base + "/top truncation/maxItems").c_str()).Set(declarations,2); + Pointer((base + "/top truncation/items/type").c_str()).Set(declarations,"number"); + + Pointer((base + "/angle/type").c_str()).Set(declarations,"array"); + Pointer((base + "/angle/minItems").c_str()).Set(declarations,1); + Pointer((base + "/angle/maxItems").c_str()).Set(declarations,2); + Pointer((base + "/angle/items/type").c_str()).Set(declarations,"number"); + + temperature_plugin_system->write_schema(prm, "temperature models", ""); + composition_plugin_system->write_schema(prm, "composition models", ""); + grains_plugin_system->write_schema(prm, "grains models", ""); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + } + } // namespace Types +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/types/string.cc.bak b/contrib/world_builder/source/world_builder/types/string.cc.bak new file mode 100644 index 00000000000..903f9ed4c24 --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/string.cc.bak @@ -0,0 +1,120 @@ +/* + 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/types/string.h" + + +#include "world_builder/parameters.h" + +namespace WorldBuilder +{ + namespace Types + { + + String::String(std::string default_value_) + : + default_value(std::move(default_value_)), + + restricted_values({}) + { + this->type_name = Types::type::String; + } + + String::String(std::string default_value_, + const std::string &restricted_value_) + : + default_value(std::move(default_value_)), + restricted_values({restricted_value_}) + { + this->type_name = Types::type::String; + } + + String::String(String const &other) + : + value(other.value), + default_value(other.default_value) + { + this->type_name = Types::type::String; + } + + + String::String(std::string default_value_, + std::vector restricted_values_) + : + default_value(std::move(default_value_)), + restricted_values(std::move(restricted_values_)) + { + this->type_name = Types::type::String; + } + + /*String::String(std::string default_value, std::string description) + : + value(default_value), + default_value(default_value), + description(description) + { + this->type_name = Types::type::String; + }*/ + + String::String(std::string value_, + std::string default_value_, + std::string description_) + : + value(std::move(value_)), + default_value(std::move(default_value_)), + description(std::move(description_)) + { + this->type_name = Types::type::String; + } + + String::~String () + = default; + + void + String::write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const + { + using namespace rapidjson; + Document &declarations = prm.declarations; + const std::string base = prm.get_full_json_path() + "/" + name; + Pointer((base + "/default value").c_str()).Set(declarations,default_value.c_str()); + Pointer((base + "/type").c_str()).Set(declarations,"string"); + Pointer((base + "/description").c_str()).Set(declarations,documentation.c_str()); + for (unsigned int i = 0; i < restricted_values.size(); ++i) + { + if (!restricted_values[i].empty()) + { + if (i == 0 && Pointer((base + "/enum").c_str()).Get(declarations) == nullptr) + { + // The enum array doesn't exist yet, so we create it and fill it. + Pointer((base + "/enum/0").c_str()).Create(declarations); + Pointer((base + "/enum/0").c_str()).Set(declarations, restricted_values[i].c_str()); + } + else + { + // The enum array already exist yet, so we add an element to the end. + Pointer((base + "/enum/-").c_str()).Set(declarations, restricted_values[i].c_str()); + } + } + } + } + + } // namespace Types +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/types/unsigned_int.cc.bak b/contrib/world_builder/source/world_builder/types/unsigned_int.cc.bak new file mode 100644 index 00000000000..9109cb72b1b --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/unsigned_int.cc.bak @@ -0,0 +1,64 @@ +/* + 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/types/unsigned_int.h" + +#include "world_builder/parameters.h" + +namespace WorldBuilder +{ + namespace Types + { + UnsignedInt::UnsignedInt(unsigned int default_value_) + : + + default_value(default_value_) + { + this->type_name = Types::type::UnsignedInt; + } + + + UnsignedInt::UnsignedInt(UnsignedInt const &other) + : + value(other.value), + default_value(other.default_value) + { + this->type_name = Types::type::UnsignedInt; + } + + UnsignedInt::~UnsignedInt () + = default; + + + void + UnsignedInt::write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const + { + using namespace rapidjson; + Document &declarations = prm.declarations; + + const std::string base = prm.get_full_json_path() + "/" + name; + Pointer((base + "/default value").c_str()).Set(declarations,default_value); + Pointer((base + "/type").c_str()).Set(declarations,"integer"); + Pointer((base + "/description").c_str()).Set(declarations,documentation.c_str()); + + } + } // namespace Types +} // namespace WorldBuilder + diff --git a/contrib/world_builder/source/world_builder/types/value_at_points.cc.bak b/contrib/world_builder/source/world_builder/types/value_at_points.cc.bak new file mode 100644 index 00000000000..ad51d48ed97 --- /dev/null +++ b/contrib/world_builder/source/world_builder/types/value_at_points.cc.bak @@ -0,0 +1,96 @@ +/* + 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 + +#include "world_builder/types/value_at_points.h" + +#include "world_builder/parameters.h" + + +namespace WorldBuilder +{ + namespace Types + { + + ValueAtPoints::ValueAtPoints(const double default_value_, + uint64_t max_values_in_array_, + std::vector> default_points_) + : + default_value(default_value_), + max_values_in_array(max_values_in_array_), + default_points(std::move(std::move(default_points_))) + { + this->type_name = Types::type::ValueAtPoints; + + WBAssert(default_points_.size() == 0, "default points are not implemented."); + } + + ValueAtPoints::ValueAtPoints(ValueAtPoints const &other) + : + default_value(other.default_value), + max_values_in_array(other.max_values_in_array), + default_points(other.default_points) + { + this->type_name = Types::type::ValueAtPoints; + } + + + ValueAtPoints::~ValueAtPoints () + = default; + + + void + ValueAtPoints::write_schema(Parameters &prm, + const std::string &name, + const std::string &documentation) const + { + using namespace rapidjson; + prm.enter_subsection(name); + { + Document &declarations = prm.declarations; + const std::string base = prm.get_full_json_path(); + + Pointer((base + "/type").c_str()).Set(declarations,"array"); + Pointer((base + "/additionalProperties").c_str()).Set(declarations,false); + Pointer((base + "/minItems").c_str()).Set(declarations,1); + Pointer((base + "/maxItems").c_str()).Set(declarations, max_values_in_array); + Pointer((base + "/description").c_str()).Set(declarations,documentation.c_str()); + + { + Pointer((base + "/items/anyOf/0/type").c_str()).Set(declarations,"number"); + Pointer((base + "/items/anyOf/0/default value").c_str()).Set(declarations,default_value); + + Pointer((base + "/items/anyOf/1/type").c_str()).Set(declarations,"array"); + Pointer((base + "/items/anyOf/1/minItems").c_str()).Set(declarations,1); + Pointer((base + "/items/anyOf/1/maxItems").c_str()).Set(declarations,std::numeric_limits::max()); + + Pointer((base + "/items/anyOf/1/items/type").c_str()).Set(declarations,"array"); + Pointer((base + "/items/anyOf/1/items/minItems").c_str()).Set(declarations,1); + Pointer((base + "/items/anyOf/1/items/maxItems").c_str()).Set(declarations, max_values_in_array); + + Pointer((base + "/items/anyOf/1/items/items/type").c_str()).Set(declarations,"number"); + } + } + prm.leave_subsection(); + } + + } // namespace Types +} // namespace WorldBuilder + + diff --git a/contrib/world_builder/source/world_builder/utilities.cc.bak b/contrib/world_builder/source/world_builder/utilities.cc.bak new file mode 100644 index 00000000000..90ecdf099fe --- /dev/null +++ b/contrib/world_builder/source/world_builder/utilities.cc.bak @@ -0,0 +1,1510 @@ +/* + 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/assert.h" +#include +#include +#include +#include +#include +#include +#include + +#ifdef WB_WITH_MPI +// we don't need the c++ MPI wrappers +#define OMPI_SKIP_MPICXX 1 +#define MPICH_SKIP_MPICXX +#include +#endif + +#include "world_builder/nan.h" +#include "world_builder/utilities.h" +#include + + +namespace WorldBuilder +{ + namespace Utilities + { + bool + polygon_contains_point(const std::vector > &point_list, + const Point<2> &point) + { + if (point.get_coordinate_system() == CoordinateSystem::spherical) + { + Point<2> other_point = point; + other_point[0] += point[0] < 0 ? 2.0 * Consts::PI : -2.0 * Consts::PI; + + return (polygon_contains_point_implementation(point_list, point) || + polygon_contains_point_implementation(point_list, other_point)); + } + + return polygon_contains_point_implementation(point_list, point); + + } + + bool + polygon_contains_point_implementation(const std::vector > &point_list, + const Point<2> &point) + { + /** + * This code has been based on http://geomalgorithms.com/a03-_inclusion.html, + * and therefore requires the following copyright notice: + * + * Copyright 2000 softSurfer, 2012 Dan Sunday + * This code may be freely used and modified for any purpose + * providing that this copyright notice is included with it. + * SoftSurfer makes no warranty for this code, and cannot be held + * liable for any real or imagined damage resulting from its use. + * Users of this code must verify correctness for their application. + * + * The main functional difference between the original code and this + * code is that all the boundaries are considered to be inside the + * polygon. One should of course realize that with floating point + * arithmetic no guarantees can be made for the borders, but for + * exact arithmetic this algorithm would work (also see polygon + * in point test). + */ + const size_t pointNo = point_list.size(); + size_t wn = 0; // the winding number counter + size_t j=pointNo-1; + + // loop through all edges of the polygon + for (size_t i=0; i= point[1]) // an upward crossing + { + const double is_left = (point_list[i][0] - point_list[j][0]) * (point[1] - point_list[j][1]) + - (point[0] - point_list[j][0]) * (point_list[i][1] - point_list[j][1]); + + if ( is_left > 0 && point_list[i][1] > point[1]) + { + // P left of edge + ++wn; // have a valid up intersect + } + else if ( std::abs(is_left) < std::numeric_limits::epsilon()) + { + // The point is exactly on the infinite line. + // determine if it is on the segment + const double dot_product = (point - point_list[j])*(point_list[i] - point_list[j]); + + if (dot_product >= 0) + { + const double squaredlength = (point_list[i] - point_list[j]).norm_square(); + + if (dot_product <= squaredlength) + { + return true; + } + } + } + } + } + else + { + // start y > P.y (no test needed) + if (point_list[i][1] <= point[1]) // a downward crossing + { + const double is_left = (point_list[i][0] - point_list[j][0]) * (point[1] - point_list[j][1]) + - (point[0] - point_list[j][0]) * (point_list[i][1] - point_list[j][1]); + + if ( is_left < 0) + { + // P right of edge + --wn; // have a valid down intersect + } + else if (std::abs(is_left) < std::numeric_limits::epsilon()) + { + // This code is to make sure that the boundaries are included in the polygon. + // The point is exactly on the infinite line. + // determine if it is on the segment + const double dot_product = (point - point_list[j])*(point_list[i] - point_list[j]); + + if (dot_product >= 0) + { + const double squaredlength = (point_list[i] - point_list[j]).norm_square(); + + if (dot_product <= squaredlength) + { + return true; + } + } + } + } + } + j=i; + } + + return (wn != 0); + } + + + + double + fraction_from_ellipse_center(const Point<2> &ellipse_center, + const double semi_major_axis, + const double eccentricity, + const double theta, + const Point<2> &point) + { + const double x_rotated = (point[0] - ellipse_center[0]) * std::cos(theta) + (point[1] - ellipse_center[1])* std::sin(theta); + const double y_rotated = -(point[0] - ellipse_center[0]) * std::sin(theta) + (point[1] - ellipse_center[1])* std::cos(theta); + + const double semi_minor_axis = semi_major_axis * std::sqrt(1 - std::pow(eccentricity, 2)); + + if (semi_major_axis < 10 * std::numeric_limits::min() + || semi_minor_axis < 10 * std::numeric_limits::min()) + return false; + + const double ellipse = std::pow((x_rotated), 2) / std::pow(semi_major_axis, 2) + + std::pow((y_rotated), 2) / std::pow(semi_minor_axis, 2); + + return ellipse; + } + + + + double + signed_distance_to_polygon(const std::vector > &point_list, + const Point<2> &point) + { + // If the point lies outside polygon, we give it a negative sign, + // inside a positive sign. + const double sign = polygon_contains_point(point_list, point) ? 1.0 : -1.0; + + /** + * This code is based on http://geomalgorithms.com/a02-_lines.html#Distance-to-Infinite-Line, + * and therefore requires the following copyright notice: + * + * Copyright 2000 softSurfer, 2012 Dan Sunday + * This code may be freely used and modified for any purpose + * providing that this copyright notice is included with it. + * SoftSurfer makes no warranty for this code, and cannot be held + * liable for any real or imagined damage resulting from its use. + * Users of this code must verify correctness for their application. + * + */ + + const size_t n_poly_points = point_list.size(); + WBAssertThrow(n_poly_points >= 3, "Not enough polygon points were specified."); + + // Initialize a vector of distances for each point of the polygon with a very large distance + std::vector distances(n_poly_points, 1e23); + + // Create another polygon but with all points shifted 1 position to the right + std::vector > shifted_point_list(n_poly_points, Point<2>(point.get_coordinate_system())); + shifted_point_list[0] = point_list[n_poly_points-1]; + + for (size_t i = 0; i < n_poly_points-1; ++i) + shifted_point_list[i+1] = point_list[i]; + + for (size_t i = 0; i < n_poly_points; ++i) + { + // Create vector along the polygon line segment + const Point<2> vector_segment = shifted_point_list[i] - point_list[i]; + // Create vector from point to the second segment point + const Point<2> vector_point_segment = point - point_list[i]; + + // Compute dot products to get angles + const double c1 = vector_point_segment * vector_segment; + const double c2 = vector_segment * vector_segment; + + // point lies closer to not-shifted polygon point, but perpendicular base line lies outside segment + if (c1 <= 0.0) + distances[i] = (Point<2> (point_list[i] - point)).norm(); + // point lies closer to shifted polygon point, but perpendicular base line lies outside segment + else if (c2 <= c1) + distances[i] = (Point<2> (shifted_point_list[i] - point)).norm(); + // perpendicular base line lies on segment + else + { + const Point<2> point_on_segment = point_list[i] + (c1/c2) * vector_segment; + distances[i] = (Point<2> (point - point_on_segment)).norm(); + } + } + + // Return the minimum of the distances of the point to all polygon segments + return *std::min_element(distances.begin(),distances.end()) * sign; + } + + + std::array + cartesian_to_spherical_coordinates(const Point<3> &position) + { + std::array scoord; + + scoord[0] = position.norm(); // R + scoord[1] = std::atan2(position[1],position[0]); // Phi/long -> The result is always between -180 and 180 degrees: [-pi,pi] + //if (scoord[1] < 0.0) + //scoord[1] += 2.0*Consts::PI; // correct phi to [0,2*pi] + + //lat + if (scoord[0] > std::numeric_limits::min()) + scoord[2] = 0.5 * Consts::PI - std::acos(position[2]/scoord[0]); + else + scoord[2] = 0.0; + + return scoord; + } + + Point<3> + spherical_to_cartesian_coordinates(const std::array &scoord) + { + const double cos_lat = scoord[0] * std::sin(0.5 * Consts::PI - scoord[2]); + + return Point<3>(cos_lat * std::cos(scoord[1]), // X + cos_lat * std::sin(scoord[1]), // Y + scoord[0] * std::cos(0.5 * Consts::PI - scoord[2]), // Z + cartesian);; + } + + + + CoordinateSystem + string_to_coordinate_system(const std::string &coordinate_system) + { + if (coordinate_system == "cartesian") + return CoordinateSystem::cartesian; + if (coordinate_system == "spherical") + return CoordinateSystem::spherical; + WBAssertThrow(false, "Coordinate system not implemented."); + + return invalid; + } + + + template + std::array + convert_point_to_array(const Point &point_) + { + std::array array; + for (size_t i = 0; i < dim; ++i) + array[i] = point_[i]; + return array; + } + + double + string_to_double(const std::string &string) + { + // trim whitespace on either side of the text if necessary + std::string s = string; + while ((!s.empty()) && (s[0] == ' ')) + s.erase(s.begin()); + while ((!s.empty()) && (s[s.size() - 1] == ' ')) + s.erase(s.end() - 1); + + std::istringstream i(s); + double d; + char c; + if (!(i >> d) || i.get(c)) + WBAssertThrow(false, "Could not convert \"" + s + "\" to a double."); + + return d; + } + + int + string_to_int(const std::string &string) + { + // trim whitespace on either side of the text if necessary + std::string s = string; + while ((!s.empty()) && (s[0] == ' ')) + s.erase(s.begin()); + while ((!s.empty()) && (s[s.size() - 1] == ' ')) + s.erase(s.end() - 1); + + std::istringstream i(s); + int d; + char c; + if (!(i >> d) || i.get(c)) + WBAssertThrow(false, "Could not convert \"" + s + "\" to an int."); + + return d; + } + + + unsigned int + string_to_unsigned_int(const std::string &string) + { + // trim whitespace on either side of the text if necessary + std::string s = string; + while ((!s.empty()) && (s[0] == ' ')) + s.erase(s.begin()); + while ((!s.empty()) && (s[s.size() - 1] == ' ')) + s.erase(s.end() - 1); + + + std::istringstream i(s); + unsigned int d; + char c; + if (!(i >> d) || i.get(c)) + WBAssertThrow(false, "Could not convert \"" + s + "\" to an unsigned int."); + + return d; + } + + + Point<3> + cross_product(const Point<3> &a, const Point<3> &b) + { + WBAssert(a.get_coordinate_system() == b.get_coordinate_system(), "Trying to do a cross product of points of a different coordinate system."); + const double x = a[1] * b[2] - b[1] * a[2]; + const double y = a[2] * b[0] - b[2] * a[0]; + const double z = a[0] * b[1] - b[0] * a[1]; + return Point<3>(x,y,z,a.get_coordinate_system()); + } + + PointDistanceFromCurvedPlanes + distance_point_from_curved_planes(const Point<3> &check_point, // cartesian point in cartesian and spherical system + const Objects::NaturalCoordinate &natural_coordinate, // cartesian point cartesian system, spherical point in spherical system + const Point<2> &reference_point, // in (rad) spherical coordinates in spherical system + const std::vector > &point_list, // in (rad) spherical coordinates in spherical system + const std::vector > &plane_segment_lengths, + const std::vector > > &plane_segment_angles, + const double start_radius, + const std::unique_ptr &coordinate_system, + const bool only_positive, + const Objects::BezierCurve &bezier_curve) + { + double distance = std::numeric_limits::infinity(); + double new_distance = std::numeric_limits::infinity(); + double along_plane_distance = std::numeric_limits::infinity(); + double new_along_plane_distance = std::numeric_limits::infinity(); + double new_depth_reference_surface = std::numeric_limits::infinity(); + + const CoordinateSystem natural_coordinate_system = coordinate_system->natural_coordinate_system(); + const bool bool_cartesian = natural_coordinate_system == cartesian; + + const std::array &check_point_surface_2d_array = natural_coordinate.get_coordinates(); + const Point<3> check_point_surface(bool_cartesian ? check_point_surface_2d_array[0] : start_radius, + check_point_surface_2d_array[1], + bool_cartesian ? start_radius : check_point_surface_2d_array[2], + natural_coordinate_system); + const Point<2> check_point_surface_2d(natural_coordinate.get_surface_coordinates(), + natural_coordinate_system); + + // The section which is checked. + size_t section = 0; + + // The 'horizontal' fraction between the points at the surface. + double section_fraction = 0.0; + + // What segment the point on the line is in. + size_t segment = 0; + + // The 'vertical' fraction, indicates how far in the current segment the + // point on the line is. + double segment_fraction = 0.0; + double total_average_angle = 0.0; + double depth_reference_surface = 0.0; + + const DepthMethod depth_method = coordinate_system->depth_method(); + + size_t i_section_min_distance = 0; + double fraction_CPL_P1P2 = std::numeric_limits::infinity(); + + // get an estimate for the closest point between P1 and P2. + //constexpr double parts = 1; + //constexpr double one_div_parts = 1./parts; + //double minimum_distance_to_reference_point = std::numeric_limits::infinity(); + //const size_t number_of_points = point_list.size(); + + const 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; + + // 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). + const Point<3> closest_point_on_line_surface(bool_cartesian ? closest_point_on_line_2d[0] : start_radius, + bool_cartesian ? closest_point_on_line_2d[1] : closest_point_on_line_2d[0], + bool_cartesian ? start_radius : closest_point_on_line_2d[1], + natural_coordinate_system); + + const Point<3> closest_point_on_line_cartesian(coordinate_system->natural_to_cartesian_coordinates(closest_point_on_line_surface.get_array()),cartesian); + + if (!std::isnan(closest_point_on_line_2d[0])) + { + i_section_min_distance = closest_point_on_curve.index; + fraction_CPL_P1P2 = closest_point_on_curve.parametric_fraction; + + Point<3> closest_point_on_line_bottom = closest_point_on_line_surface; + closest_point_on_line_bottom[bool_cartesian ? 2 : 0] = 0; + + WBAssert(!std::isnan(closest_point_on_line_bottom[0]) + && + !std::isnan(closest_point_on_line_bottom[1]) + && + !std::isnan(closest_point_on_line_bottom[2]), + "Internal error: The closest_point_on_line_bottom variables variable contains not a number: " << closest_point_on_line_bottom); + + // Now that we have both the check point and the + // closest_point_on_line, we need to push them to cartesian. + const Point<3> closest_point_on_line_bottom_cartesian(coordinate_system->natural_to_cartesian_coordinates(closest_point_on_line_bottom.get_array()),cartesian); + const Point<3> check_point_surface_cartesian(coordinate_system->natural_to_cartesian_coordinates(check_point_surface.get_array()),cartesian); + + + WBAssert(!std::isnan(closest_point_on_line_bottom_cartesian[0]), + "Internal error: The closest_point_on_line_bottom_cartesian[0] variable is not a number: " << closest_point_on_line_bottom_cartesian[0]); + WBAssert(!std::isnan(closest_point_on_line_bottom_cartesian[1]), + "Internal error: The closest_point_on_line_bottom_cartesian[1] variable is not a number: " << closest_point_on_line_bottom_cartesian[1]); + WBAssert(!std::isnan(closest_point_on_line_bottom_cartesian[2]), + "Internal error: The closest_point_on_line_bottom_cartesian[2] variable is not a number: " << closest_point_on_line_bottom_cartesian[2]); + + + // translate to original coordinates current and next section + const size_t original_current_section = i_section_min_distance; + const size_t original_next_section = original_current_section + 1; + + + // These are the mostly likely cases for the x and y axis, so initialize them to these values. They will be checked + // in the else statement or replaced in the if statement. + Point<3> y_axis = closest_point_on_line_cartesian - closest_point_on_line_bottom_cartesian; + Point<3> x_axis = closest_point_on_line_cartesian - check_point_surface_cartesian; + + // This are accounting for corner cases. + // If the point to check is exactly on or below the line, we can not compute the x-axis with this method. + // We could use an other method where we use the two point before and after it, but we can also + // just nudge it into a direction, which seems to work very well. + if (std::fabs((check_point_surface - closest_point_on_line_surface).norm()) < 2e-14) + { + // If the point to check is on the line, we don't need to search any further, because we know the distance is zero. + if (std::fabs((check_point - closest_point_on_line_cartesian).norm()) > 2e-14) + { + const Point<2> &P1(point_list[i_section_min_distance]); + const Point<2> &P2(point_list[i_section_min_distance+1]); + + const Point<2> P1P2 = P2 - P1; + const Point<2> unit_normal_to_plane_spherical = P1P2 / P1P2.norm(); + const Point<2> closest_point_on_line_plus_normal_to_plane_spherical = closest_point_on_line_2d + 1e-8 * (closest_point_on_line_2d.norm() > 1.0 ? closest_point_on_line_2d.norm() : 1.0) * unit_normal_to_plane_spherical; + + WBAssert(std::fabs(closest_point_on_line_plus_normal_to_plane_spherical.norm()) > std::numeric_limits::epsilon(), + "Internal error: The norm of variable 'closest_point_on_line_plus_normal_to_plane_spherical' " + "is zero, while this may not happen."); + + const Point<3> closest_point_on_line_plus_normal_to_plane_surface_spherical(bool_cartesian ? closest_point_on_line_plus_normal_to_plane_spherical[0] : start_radius, + bool_cartesian ? closest_point_on_line_plus_normal_to_plane_spherical[1] : closest_point_on_line_plus_normal_to_plane_spherical[0], + bool_cartesian ? start_radius : closest_point_on_line_plus_normal_to_plane_spherical[1], + natural_coordinate_system); + const Point<3> closest_point_on_line_plus_normal_to_plane_cartesian(coordinate_system->natural_to_cartesian_coordinates(closest_point_on_line_plus_normal_to_plane_surface_spherical.get_array()),cartesian); + Point<3> normal_to_plane = closest_point_on_line_plus_normal_to_plane_cartesian - closest_point_on_line_cartesian; + normal_to_plane = normal_to_plane / normal_to_plane.norm(); + + // The y-axis is from the bottom/center to the closest_point_on_line, + // the x-axis is 90 degrees rotated from that, so we rotate around + // the line P1P2. + // Todo: Assert that the norm of the axis are not equal to zero. + y_axis = closest_point_on_line_cartesian - closest_point_on_line_bottom_cartesian; + + WBAssert(std::abs(y_axis.norm()) > std::numeric_limits::epsilon(), + "World Builder error: Cannot determine the up direction in the model. This is most likely due to the provided start radius being zero." + << " Technical details: The y_axis.norm() is zero. Y_axis is " << y_axis[0] << ':' << y_axis[1] << ':' << y_axis[2] + << ". closest_point_on_line_cartesian = " << closest_point_on_line_cartesian[0] << ':' << closest_point_on_line_cartesian[1] << ':' << closest_point_on_line_cartesian[2] + << ", closest_point_on_line_bottom_cartesian = " << closest_point_on_line_bottom_cartesian[0] << ':' << closest_point_on_line_bottom_cartesian[1] << ':' << closest_point_on_line_bottom_cartesian[2]); + + WBAssert(!std::isnan(y_axis[0]), + "Internal error: The y_axis variable is not a number: " << y_axis[0]); + WBAssert(!std::isnan(y_axis[1]), + "Internal error: The y_axis variable is not a number: " << y_axis[1]); + WBAssert(!std::isnan(y_axis[2]), + "Internal error: The y_axis variable is not a number: " << y_axis[2]); + + y_axis = y_axis / y_axis.norm(); + + WBAssert(!std::isnan(y_axis[0]), + "Internal error: The y_axis variable is not a number: " << y_axis[0]); + WBAssert(!std::isnan(y_axis[1]), + "Internal error: The y_axis variable is not a number: " << y_axis[1]); + WBAssert(!std::isnan(y_axis[2]), + "Internal error: The y_axis variable is not a number: " << y_axis[2]); + + + // shorthand notation for computing the x_axis + const double vx = y_axis[0]; + const double vy = y_axis[1]; + const double vz = y_axis[2]; + const double ux = normal_to_plane[0]; + const double uy = normal_to_plane[1]; + const double uz = normal_to_plane[2]; + + x_axis = Point<3>(ux*ux*vx + ux*uy*vy - uz*vy + uy*uz*vz + uy*vz, + uy*ux*vx + uz*vx + uy*uy*vy + uy*uz*vz - ux*vz, + uz*ux*vx - uy*vx + uz*uy*vy + ux*vy + uz*uz*vz, + cartesian); + + // see on what side the line P1P2 reference point is. This is based on the determinant + const Point<2> reference_p = ((closest_point_on_curve.normal-closest_point_on_line_2d)*1e2)+closest_point_on_line_2d; + const double reference_on_side_of_line = (closest_point_on_line_2d-reference_p).norm_square() < (check_point_surface_2d-reference_p).norm_square() ? -1 : 1; + + WBAssert(!std::isnan(x_axis[0]), + "Internal error: The x_axis variable is not a number: " << x_axis[0]); + WBAssert(!std::isnan(x_axis[1]), + "Internal error: The x_axis variable is not a number: " << x_axis[1]); + WBAssert(!std::isnan(x_axis[2]), + "Internal error: The x_axis variable is not a number: " << x_axis[2]); + + x_axis = x_axis *(reference_on_side_of_line / x_axis.norm()); + + WBAssert(!std::isnan(x_axis[0]), + "Internal error: The x_axis variable is not a number: " << x_axis[0]); + WBAssert(!std::isnan(x_axis[1]), + "Internal error: The x_axis variable is not a number: " << x_axis[1]); + WBAssert(!std::isnan(x_axis[2]), + "Internal error: The x_axis variable is not a number: " << x_axis[2]); + } + else + { + total_average_angle = plane_segment_angles[original_current_section][0][0] + + fraction_CPL_P1P2 * (plane_segment_angles[original_next_section][0][0] + - plane_segment_angles[original_current_section][0][0]); + + PointDistanceFromCurvedPlanes return_values(natural_coordinate.get_coordinate_system()); + return_values.distance_from_plane = 0.0; + return_values.distance_along_plane = 0.0; + return_values.fraction_of_section = fraction_CPL_P1P2; + return_values.fraction_of_segment = 0.0; + return_values.section = i_section_min_distance; + return_values.segment = 0; + return_values.average_angle = total_average_angle; + return_values.depth_reference_surface = 0.0; + return_values.closest_trench_point = closest_point_on_line_cartesian; + return return_values; + } + } + else + { + WBAssert(std::abs(y_axis.norm()) > std::numeric_limits::epsilon(), + "World Builder error: Cannot determine the up direction in the model. This is most likely due to the provided start radius being zero." + << " Technical details: The y_axis.norm() is zero. Y_axis is " << y_axis + << ". closest_point_on_line_cartesian = " << closest_point_on_line_cartesian + << ", closest_point_on_line_bottom_cartesian = " << closest_point_on_line_bottom_cartesian); + + WBAssert(!std::isnan(y_axis[0]), + "Internal error: The y_axis variable is not a number: " << y_axis[0]); + WBAssert(!std::isnan(y_axis[1]), + "Internal error: The y_axis variable is not a number: " << y_axis[1]); + WBAssert(!std::isnan(y_axis[2]), + "Internal error: The y_axis variable is not a number: " << y_axis[2]); + + y_axis = y_axis / y_axis.norm(); + + WBAssert(!std::isnan(y_axis[0]), + "Internal error: The y_axis variable is not a number: " << y_axis[0]); + WBAssert(!std::isnan(y_axis[1]), + "Internal error: The y_axis variable is not a number: " << y_axis[1]); + WBAssert(!std::isnan(y_axis[2]), + "Internal error: The y_axis variable is not a number: " << y_axis[2]); + + + Point<2> check_point_surface_2d_temp = check_point_surface_2d; + + if (!bool_cartesian) + { + const double normal = std::fabs(point_list[i_section_min_distance+static_cast((std::round(fraction_CPL_P1P2)))][0]-check_point_surface_2d[0]); + const double plus = std::fabs(point_list[i_section_min_distance+static_cast((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((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[0]+= 2*Consts::PI; + } + else if (min < normal) + { + check_point_surface_2d_temp[0]-= 2*Consts::PI; + } + } + + // 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 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; + + WBAssert(!std::isnan(x_axis[0]), + "Internal error: The x_axis variable is not a number: " << x_axis[0]); + WBAssert(!std::isnan(x_axis[1]), + "Internal error: The x_axis variable is not a number: " << x_axis[1]); + WBAssert(!std::isnan(x_axis[2]), + "Internal error: The x_axis variable is not a number: " << x_axis[2]); + + WBAssert(x_axis.norm() > 0.0, "x_axis norm is zero"); + + x_axis = x_axis *(reference_on_side_of_line / x_axis.norm()); + + WBAssert(!std::isnan(x_axis[0]), + "Internal error: The x_axis variable is not a number: " << x_axis[0]); + WBAssert(!std::isnan(x_axis[1]), + "Internal error: The x_axis variable is not a number: " << x_axis[1]); + WBAssert(!std::isnan(x_axis[2]), + "Internal error: The x_axis variable is not a number: " << x_axis[2]); + + } + + WBAssert(!std::isnan(x_axis[0]), + "Internal error: The x_axis[0] variable is not a number: " << x_axis[0] << ". Relevant values: check_point = " << check_point << '.'); + WBAssert(!std::isnan(x_axis[1]), + "Internal error: The x_axis[1] variable is not a number: " << x_axis[1]); + WBAssert(!std::isnan(x_axis[2]), + "Internal error: The x_axis[2] variable is not a number: " << x_axis[2]); + + // now that we have the x and y axes computed, convert the 3d check point into a 2d one. + Point<2> check_point_2d(x_axis * (check_point - closest_point_on_line_bottom_cartesian), + y_axis * (check_point - closest_point_on_line_bottom_cartesian), + cartesian); + + Point<2> begin_segment(x_axis * (closest_point_on_line_cartesian - closest_point_on_line_bottom_cartesian), + y_axis * (closest_point_on_line_cartesian - closest_point_on_line_bottom_cartesian), + cartesian); + + WBAssert(!std::isnan(check_point_2d[0]), + "Internal error: The check_point_2d variable is not a number: " << check_point_2d[0]); + WBAssert(!std::isnan(check_point_2d[1]), + "Internal error: The check_point_2d variable is not a number: " << check_point_2d[1]); + + + WBAssert(!std::isnan(begin_segment[0]), + "Internal error: The begin_segment variable is not a number: " << begin_segment[0]); + WBAssert(!std::isnan(begin_segment[1]), + "Internal error: The begin_segment variable is not a number: " << begin_segment[1]); + + Point<2> end_segment = begin_segment; + + double total_length = 0.0; + double add_angle = 0.0; + double add_angle_correction = 0.0; + double average_angle = 0.0; + for (size_t i_segment = 0; i_segment < plane_segment_lengths[original_current_section].size(); i_segment++) + { + const size_t current_segment = i_segment; + + // compute the angle between the previous begin and end if + // the depth method is angle_at_begin_segment_with_surface. + if (i_segment != 0 + && + (depth_method == DepthMethod::angle_at_begin_segment_with_surface + || + depth_method == DepthMethod::angle_at_begin_segment_applied_to_end_segment_with_surface)) + { + double add_angle_inner = (begin_segment * end_segment) / (begin_segment.norm() * end_segment.norm()); + + WBAssert(!std::isnan(add_angle_inner), + "Internal error: The add_angle_inner variable is not a number: " << add_angle_inner + << ". Variables: begin_segment = " << begin_segment + << ", end_segment = " << end_segment + << ", begin_segment * end_segment / (begin_segment.norm() * end_segment.norm()) = " + << std::setprecision(32) << begin_segment * end_segment / (begin_segment.norm() * end_segment.norm()) + << '.'); + + // there could be round of error problems here is the inner part is close to one + if (add_angle_inner < 0. && add_angle_inner >= -1e-14) + add_angle_inner = 0.; + if (add_angle_inner > 1. && add_angle_inner <= 1.+1e-14) + add_angle_inner = 1.; + + WBAssert(add_angle_inner >= 0 && add_angle_inner <= 1, + "Internal error: The variable add_angle_inner is smaller than zero or larger then one," + "which causes the std::acos to return nan. If it is only a little bit larger then one, " + "this is probably caused by that begin and end segment are the same and round off error. " + "The value of add_angle_inner = " << add_angle_inner); + + add_angle_correction = std::acos(add_angle_inner); + add_angle += add_angle_correction; + + WBAssert(!std::isnan(add_angle), + "Internal error: The add_angle variable is not a number: " << add_angle + << ". Variables: begin_segment = " << begin_segment + << ", end_segment = " << end_segment + << ", begin_segment * end_segment / (begin_segment.norm() * end_segment.norm()) = " + << std::setprecision(32) << begin_segment * end_segment / (begin_segment.norm() * end_segment.norm()) + << ", std::acos(begin_segment * end_segment / (begin_segment.norm() * end_segment.norm())) = " + << std::acos(begin_segment * end_segment / (begin_segment.norm() * end_segment.norm()))); + } + + + + + begin_segment = end_segment; + + WBAssert(!std::isnan(begin_segment[0]), + "Internal error: The begin_segment variable is not a number: " << begin_segment[0]); + WBAssert(!std::isnan(begin_segment[1]), + "Internal error: The begin_segment variable is not a number: " << begin_segment[1]); + + + // This interpolates different properties between P1 and P2 (the + // points of the plane at the surface) + const double degree_90_to_rad = 0.5 * Consts::PI; + + WBAssert(plane_segment_angles.size() > original_next_section, + "Error: original_next_section = " << original_next_section + << ", and plane_segment_angles.size() = " << plane_segment_angles.size()); + + + WBAssert(plane_segment_angles[original_next_section].size() > current_segment, + "Error: current_segment = " << current_segment + << ", and current_segment.size() = " << plane_segment_angles[original_next_section].size()); + + const double interpolated_angle_top = plane_segment_angles[original_current_section][current_segment][0] + + fraction_CPL_P1P2 * (plane_segment_angles[original_next_section][current_segment][0] + - plane_segment_angles[original_current_section][current_segment][0]) + + add_angle + + (depth_method == DepthMethod::angle_at_begin_segment_applied_to_end_segment_with_surface + && i_segment != 0 ? -add_angle_correction: 0); + + const double interpolated_angle_bottom = plane_segment_angles[original_current_section][current_segment][1] + + fraction_CPL_P1P2 * (plane_segment_angles[original_next_section][current_segment][1] + - plane_segment_angles[original_current_section][current_segment][1]) + + add_angle; + + + const double interpolated_segment_length = plane_segment_lengths[original_current_section][current_segment] + + fraction_CPL_P1P2 * (plane_segment_lengths[original_next_section][current_segment] + - plane_segment_lengths[original_current_section][current_segment]); + + if (interpolated_segment_length < 1e-14) + continue; + + WBAssert(!std::isnan(interpolated_angle_top), + "Internal error: The interpolated_angle_top variable is not a number: " << interpolated_angle_top); + + // We want to know where the end point of this segment is (and + // the start of the next segment). There are two cases which we + // will deal with separately. The first one is if the angle is + // constant. The second one is if the angle changes. + const double difference_in_angle_along_segment = interpolated_angle_top - interpolated_angle_bottom; + + if (std::fabs(difference_in_angle_along_segment) < 1e-8) + { + // The angle is constant. It is easy find find the end of + // this segment and the distance. + if (std::fabs(interpolated_segment_length) > std::numeric_limits::epsilon()) + { + end_segment[0] += interpolated_segment_length * std::sin(degree_90_to_rad - interpolated_angle_top); + end_segment[1] -= interpolated_segment_length * std::cos(degree_90_to_rad - interpolated_angle_top); + + Point<2> begin_end_segment = end_segment - begin_segment; + Point<2> normal_2d_plane(-begin_end_segment[0],begin_end_segment[1], cartesian); + WBAssert(std::fabs(normal_2d_plane.norm()) > std::numeric_limits::epsilon(), "Internal Error: normal_2d_plane.norm() is zero, which should not happen. " + << "Extra info: begin_end_segment[0] = " << begin_end_segment[0] + << ", begin_end_segment[1] = " << begin_end_segment[1] + << ", end_segment: [" << end_segment[0] << ',' << end_segment[1] << ']' + << ", begin_segment: [" << begin_segment[0] << ',' << begin_segment[1] << ']' + ); + normal_2d_plane /= normal_2d_plane.norm(); + + // Now find the distance of a point to this line. + // Based on http://geomalgorithms.com/a02-_lines.html. + const Point<2> BSP_ESP = end_segment - begin_segment; + const Point<2> BSP_CP = check_point_2d - begin_segment; + + const double c1 = BSP_ESP * BSP_CP; + const double c2 = BSP_ESP * BSP_ESP; + + if (c1 < 0 || c2 < c1) + { + new_distance = std::numeric_limits::infinity(); + new_along_plane_distance = std::numeric_limits::infinity(); + new_depth_reference_surface = std::numeric_limits::infinity(); + } + else + { + const Point<2> Pb = begin_segment + (c1/c2) * BSP_ESP; + const double side_of_line = (begin_segment[0] - end_segment[0]) * (check_point_2d[1] - begin_segment[1]) + - (begin_segment[1] - end_segment[1]) * (check_point_2d[0] - begin_segment[0]) + < 0 ? -1.0 : 1.0; + + new_distance = side_of_line * (check_point_2d - Pb).norm(); + new_along_plane_distance = (begin_segment - Pb).norm(); + new_depth_reference_surface = start_radius - Pb[1]; + + WBAssert(!std::isnan(new_depth_reference_surface), + "new_depth_reference_surface is not a number: " << new_depth_reference_surface << ". " + << "start_radius = " << start_radius << ",Pb[1] = " << Pb[1] << "."); + } + } + } + else + { + // The angle is not constant. This means that we need to + // define a circle. First find the center of the circle. + const double radius_angle_circle = std::fabs(interpolated_segment_length/difference_in_angle_along_segment); + + WBAssert(!std::isnan(radius_angle_circle), + "Internal error: The radius_angle_circle variable is not a number: " << radius_angle_circle + << ". interpolated_segment_length = " << interpolated_segment_length + << ", difference_in_angle_along_segment = " << difference_in_angle_along_segment); + + const double cos_angle_top = std::cos(interpolated_angle_top); + + WBAssert(!std::isnan(cos_angle_top), + "Internal error: The radius_angle_circle variable is not a number: " << cos_angle_top + << ". interpolated_angle_top = " << interpolated_angle_top); + + Point<2> center_circle(cartesian); + if (std::fabs(interpolated_angle_top - 0.5 * Consts::PI) < 1e-8) + { + // if interpolated_angle_top is 90 degrees, the tan function + // is undefined (1/0). What we really want in this case is + // set the center to the correct location which is x = the x + //begin point + radius and y = the y begin point. + center_circle[0] = difference_in_angle_along_segment > 0 ? begin_segment[0] + radius_angle_circle : begin_segment[0] - radius_angle_circle; + center_circle[1] = begin_segment[1]; + } + else if (std::fabs(interpolated_angle_top - 1.5 * Consts::PI) < 1e-8) + { + // if interpolated_angle_top is 270 degrees, the tan function + // is undefined (-1/0). What we really want in this case is + // set the center to the correct location which is x = the x + //begin point - radius and y = the y begin point. + center_circle[0] = difference_in_angle_along_segment > 0 ? begin_segment[0] - radius_angle_circle : begin_segment[0] + radius_angle_circle; + center_circle[1] = begin_segment[1]; + } + else + { + const double tan_angle_top = std::tan(interpolated_angle_top); + + WBAssert(!std::isnan(tan_angle_top), + "Internal error: The tan_angle_top variable is not a number: " << tan_angle_top); + const double center_circle_y = difference_in_angle_along_segment < 0 ? + begin_segment[1] - radius_angle_circle * cos_angle_top + : begin_segment[1] + radius_angle_circle * cos_angle_top; + + WBAssert(!std::isnan(center_circle_y), + "Internal error: The center_circle_y variable is not a number: " << center_circle_y + << ". begin_segment[1] = " << begin_segment[1] + << ", radius_angle_circle = " << radius_angle_circle + << ", cos_angle_top = " << cos_angle_top); + + // to prevent round off errors becoming dominant, we check + // whether center_circle_y - begin_segment[1] should be zero. + // TODO: improve this to some kind of relative difference. + const double CCYBS = center_circle_y - begin_segment[1]; + + WBAssert(!std::isnan(CCYBS), + "Internal error: The CCYBS variable is not a number: " << CCYBS); + + + + center_circle[0] = begin_segment[0] + tan_angle_top * (CCYBS); + center_circle[1] = center_circle_y; + } + + WBAssert(!std::isnan(center_circle[0]) || !std::isnan(center_circle[1]), + "Internal error: The center variable contains not a number: " << center_circle[0] << ':' << center_circle[0]); + WBAssert(std::fabs((begin_segment-center_circle).norm() - std::fabs(radius_angle_circle)) + < 1e-8 * std::fabs((begin_segment-center_circle).norm() + std::fabs(radius_angle_circle)), + "Internal error: The center of the circle is not a radius away from the begin point. " << std::endl + << "The center is located at " << center_circle[0] << ':' << center_circle[1] << std::endl + << "The begin point is located at " << begin_segment[0] << ':' << begin_segment[1] << std::endl + << "The computed radius is " << std::fabs((begin_segment-center_circle).norm()) + << ", and it should be " << radius_angle_circle << '.'); + + + // Now compute the location of the end of the segment by + // rotating P1 around the center_circle + Point<2> BSPC = begin_segment - center_circle; + const double sin_angle_diff = sin(difference_in_angle_along_segment); + const double cos_angle_diff = cos(difference_in_angle_along_segment); + end_segment[0] = cos_angle_diff * BSPC[0] - sin_angle_diff * BSPC[1] + center_circle[0]; + end_segment[1] = sin_angle_diff * BSPC[0] + cos_angle_diff * BSPC[1] + center_circle[1]; + + + + WBAssert(std::fabs((end_segment-center_circle).norm() - std::fabs(radius_angle_circle)) + < 1e-8 * std::fabs((end_segment-center_circle).norm() + std::fabs(radius_angle_circle)) , + "Internal error: The center of the circle is not a radius away from the end point. " << std::endl + << "The center is located at " << center_circle[0] << ':' << center_circle[1] << std::endl + << "The end point is located at " << end_segment[0] << ':' << end_segment[1] << std::endl + << "The computed radius is " << std::fabs((end_segment-center_circle).norm()) + << ", and it should be " << radius_angle_circle << '.'); + + // Now check if the angle of the check point in this circle + // is larger then the angle of P1 and smaller then P1 + angle + // difference. If that is the case then the distance from the + // plane is radius - (center - check_point).norm(). Otherwise + // it is infinity. + // The angle of the check point is computed with the help of + // dot product. But before that we need to adjust the check + // point 2d. + const Point<2> CPCR = check_point_2d - center_circle; + const double CPCR_norm = CPCR.norm(); + + const double dot_product = CPCR * Point<2>(0, radius_angle_circle, cartesian); + // If the x of the check point is larger then the x of center + // the circle, the angle is more than 180 degree, but the dot + // product will decrease instead of increase from 180 degrees. + // To fix this we make a special case for this. + // Furthermore, when the check point is at the same location as + // the center of the circle, we count that point as belonging + // to the top of the top segment (0 degree). + double check_point_angle = std::fabs(CPCR_norm) < std::numeric_limits::epsilon() ? 2.0 * Consts::PI : (check_point_2d[0] <= center_circle[0] + ? std::acos(dot_product/(CPCR_norm * radius_angle_circle)) + : 2.0 * Consts::PI - std::acos(dot_product/(CPCR_norm * radius_angle_circle))); + check_point_angle = difference_in_angle_along_segment >= 0 ? Consts::PI - check_point_angle : 2.0 * Consts::PI - check_point_angle; + + // In the case that it is exactly 2 * pi, bring it back to zero + check_point_angle = (std::fabs(check_point_angle - 2 * Consts::PI) < 1e-14 ? 0 : check_point_angle); + + if ((difference_in_angle_along_segment > 0 && (check_point_angle <= interpolated_angle_top || std::fabs(check_point_angle - interpolated_angle_top) < 1e-12) + && (check_point_angle >= interpolated_angle_bottom || std::fabs(check_point_angle - interpolated_angle_bottom) < 1e-12)) + || (difference_in_angle_along_segment < 0 && (check_point_angle >= interpolated_angle_top || std::fabs(check_point_angle - interpolated_angle_top) < 1e-12) + && (check_point_angle <= interpolated_angle_bottom || std::fabs(check_point_angle - interpolated_angle_bottom) < 1e-12))) + { + new_distance = (radius_angle_circle - CPCR_norm) * (difference_in_angle_along_segment < 0 ? 1 : -1); + new_along_plane_distance = (radius_angle_circle * check_point_angle - radius_angle_circle * interpolated_angle_top) * (difference_in_angle_along_segment < 0 ? 1 : -1); + // compute the new depth by rotating the begin point to the check point location. + new_depth_reference_surface = start_radius-(sin(check_point_angle + interpolated_angle_top) * BSPC[0] + cos(check_point_angle + interpolated_angle_top) * BSPC[1] + center_circle[1]); + + WBAssert(!std::isnan(new_depth_reference_surface), + "new_depth_reference_surface is not a number: " << new_depth_reference_surface << ". " + << "start_radius = " << start_radius << ", check_point_angle = " << check_point_angle << ", interpolated_angle_top = " << interpolated_angle_top + << ", BSPC[0] = " << BSPC[0] << "."); + } + + } + + // Now we need to see whether we need to update the information + // based on whether this segment is the closest one to the point + // up to now. To do this we first look whether the point falls + // within the bound of the segment and if it is actually closer. + // TODO: find out whether the fabs() are needed. + if (new_along_plane_distance >= -1e-10 && + new_along_plane_distance <= std::fabs(interpolated_segment_length) && + std::fabs(new_distance) < std::fabs(distance)) + { + // There are two specific cases we are concerned with. The + // first case is that we want to have both the positive and + // negative distances (above and below the line). The second + // case is that we only want positive distances. + distance = only_positive ? std::fabs(new_distance) : new_distance; + along_plane_distance = new_along_plane_distance + total_length; + section = i_section_min_distance; + section_fraction = fraction_CPL_P1P2; + segment = i_segment; + segment_fraction = new_along_plane_distance / interpolated_segment_length; + total_average_angle = (average_angle * total_length + + 0.5 * (interpolated_angle_top + interpolated_angle_bottom - 2 * add_angle) * new_along_plane_distance); + total_average_angle = (std::fabs(total_average_angle) < std::numeric_limits::epsilon() ? 0 : total_average_angle / + (total_length + new_along_plane_distance)); + depth_reference_surface = new_depth_reference_surface; + } + + // increase average angle + average_angle = (average_angle * total_length + + 0.5 * (interpolated_angle_top + interpolated_angle_bottom - 2 * add_angle) * interpolated_segment_length); + average_angle = (std::fabs(average_angle) < std::numeric_limits::epsilon() ? 0 : average_angle / + (total_length + interpolated_segment_length)); + // increase the total length for the next segment. + total_length += interpolated_segment_length; + } + } + + WBAssert(!std::isnan(depth_reference_surface), "depth_reference_surface is not a number: " << depth_reference_surface << "."); + + PointDistanceFromCurvedPlanes return_values(natural_coordinate.get_coordinate_system()); + return_values.distance_from_plane = distance; + return_values.distance_along_plane = along_plane_distance; + return_values.fraction_of_section = section_fraction; + return_values.fraction_of_segment = segment_fraction; + return_values.section = section; + return_values.segment = segment; + return_values.average_angle = total_average_angle; + return_values.depth_reference_surface = depth_reference_surface; + return_values.closest_trench_point = closest_point_on_line_cartesian; + return return_values; + } + + void interpolation::set_points(const std::vector &y) + { + const size_t n = y.size(); + mx_size_min = n; + m.resize(n); + for (unsigned int i = 0; i < n; ++i) + { + m[i][3] = y[i]; + } + + /** + * This monotone spline algorithm is based on the javascript version + * at https://en.wikipedia.org/wiki/Monotone_cubic_interpolation. The + * parameters from this algorithm prevent overshooting in the + * interpolation spline. + */ + + // get m_a parameter + m[0][2] = 0; + + for (size_t i = 0; i < n-2; i++) + { + const double m0 = y[i+1]-y[i]; + const double m1 = y[i+2]-y[i+1]; + + if (m0 * m1 <= 0) + { + m[i+1][2] = 0; + } + else + { + m[i+1][2] = 2*m0*m1/(m0+m1); + } + } + m[n-1][2] = y[n-1]-y[n-2]; + + // Get b and c coefficients + //m_a.resize(n); + //m_b.resize(n); + for (size_t i = 0; i < n-1; i++) + { + const double c1 = m[i][2]; + const double m0 = y[i+1]-y[i]; + + const double common0 = c1 + m[i+1][2] - m0 - m0; + m[i][1] = (m0 - c1 - common0); + m[i][0] = common0; + } + } + + double wrap_angle(const double angle) + { + return angle - 360.0*std::floor(angle/360.0); + } + + double interpolate_angle_across_zero(const double angle_1, + const double angle_2, + const double fraction) + { + double theta_1 = angle_1; + double theta_2 = angle_2; + double rotation_angle; + + if (std::abs(theta_2 - theta_1) > Consts::PI) + { + if (theta_2 > theta_1) + theta_1 += 2.*Consts::PI; + else + theta_2 += 2.*Consts::PI; + } + rotation_angle = (1-fraction) * theta_1 + fraction * theta_2; + + // make sure angle is between 0 and 360 degrees + rotation_angle = rotation_angle - 2*Consts::PI*std::floor(rotation_angle/(2 * Consts::PI)); + + return rotation_angle; + } + + std::array + euler_angles_from_rotation_matrix(const std::array,3> &rotation_matrix) + { + const double rad_to_degree = 180.0/Consts::PI; + std::array euler_angles; + //const double s2 = std::sqrt(rotation_matrix[2][1] * rotation_matrix[2][1] + rotation_matrix[2][0] * rotation_matrix[2][0]); + const std::ostringstream os; + for (size_t i = 0; i < 3; i++) + for (size_t j = 0; j < 3; j++) + WBAssert(std::fabs(rotation_matrix[i][j]) <= 1.0, + "rotation_matrix[" + std::to_string(i) + "][" + std::to_string(j) + + "] is larger than one: " + std::to_string(rotation_matrix[i][j]) + ". rotation_matrix = \n" + + std::to_string(rotation_matrix[0][0]) + " " + std::to_string(rotation_matrix[0][1]) + " " + std::to_string(rotation_matrix[0][2]) + "\n" + + std::to_string(rotation_matrix[1][0]) + " " + std::to_string(rotation_matrix[1][1]) + " " + std::to_string(rotation_matrix[1][2]) + "\n" + + std::to_string(rotation_matrix[2][0]) + " " + std::to_string(rotation_matrix[2][1]) + " " + std::to_string(rotation_matrix[2][2])); + + + const double theta = std::acos(rotation_matrix[2][2]); + const double phi1 = std::atan2(rotation_matrix[2][0]/-sin(theta),rotation_matrix[2][1]/-sin(theta)); + const double phi2 = std::atan2(rotation_matrix[0][2]/-sin(theta),rotation_matrix[1][2]/sin(theta)); + + euler_angles[0] = wrap_angle(phi1 * rad_to_degree); + euler_angles[1] = wrap_angle(theta * rad_to_degree); + euler_angles[2] = wrap_angle(phi2 * rad_to_degree); + + return euler_angles; + } + + std::array,3> + euler_angles_to_rotation_matrix(double phi1_d, double theta_d, double phi2_d) + { + + const double degree_to_rad = Consts::PI/180.0; + const double phi1 = phi1_d * degree_to_rad; + const double theta = theta_d * degree_to_rad; + const double phi2 = phi2_d * degree_to_rad; + std::array,3> rot_matrix; + + + rot_matrix[0][0] = cos(phi2)*cos(phi1) - cos(theta)*sin(phi1)*sin(phi2); + rot_matrix[0][1] = -cos(phi2)*sin(phi1) - cos(theta)*cos(phi1)*sin(phi2); + rot_matrix[0][2] = -sin(phi2)*sin(theta); + + rot_matrix[1][0] = sin(phi2)*cos(phi1) + cos(theta)*sin(phi1)*cos(phi2); + rot_matrix[1][1] = -sin(phi2)*sin(phi1) + cos(theta)*cos(phi1)*cos(phi2); + rot_matrix[1][2] = cos(phi2)*sin(theta); + + rot_matrix[2][0] = -sin(theta)*sin(phi1); + rot_matrix[2][1] = -sin(theta)*cos(phi1); + rot_matrix[2][2] = cos(theta); + return rot_matrix; + } + + std::string + read_and_distribute_file_content(const std::string &filename) + { + std::string data_string; + +#ifdef WB_WITH_MPI + int mpi_initialized; + MPI_Initialized(&mpi_initialized); + if (mpi_initialized != 0) + { + const MPI_Comm comm = MPI_COMM_WORLD; + int my_rank = 0; + MPI_Comm_rank(comm, &my_rank); + if (my_rank == 0) + { + int filesize; + std::ifstream filestream; + filestream.open(filename.c_str()); + WBAssertThrow (filestream.is_open(), std::string("Could not open file <") + filename + ">."); + + // Need to convert to unsigned int, because MPI_Bcast does not support + // size_t or const unsigned int + int invalid_file_size = -1; + + if (!filestream) + { + // broadcast failure state, then throw + const int ierr = MPI_Bcast(&invalid_file_size, 1, MPI_UNSIGNED, 0, comm); + WBAssertThrow (ierr, + std::string("Could not open file <") + filename + ">."); + } + + // Read data from disk + std::stringstream datastream; + + try + { + datastream << filestream.rdbuf(); + } + catch (const std::ios::failure &) + { + // broadcast failure state, then throw + const int ierr = MPI_Bcast(&invalid_file_size, 1, MPI_UNSIGNED, 0, comm); + WBAssertThrow(ierr == 0, "MPI_Bcast failed."); + WBAssertThrow (false, + std::string("Could not read file content from <") + filename + ">."); + } + + data_string = datastream.str(); + WBAssertThrow(static_cast(data_string.size()) < std::numeric_limits::max(), + "File is too large to be send with MPI."); + filesize = static_cast(data_string.size()); + + // Distribute data_size and data across processes + int ierr = MPI_Bcast(&filesize, 1, MPI_UNSIGNED, 0, comm); + WBAssertThrow(ierr == 0, "MPI_Bcast failed."); + + // Receive and store data + ierr = MPI_Bcast(&data_string[0], + filesize, + MPI_CHAR, + 0, + comm); + WBAssertThrow(ierr == 0, "MPI_Bcast failed."); + } + else + { + // Prepare for receiving data + int filesize = 0; + int ierr = MPI_Bcast(&filesize, 1, MPI_UNSIGNED, 0, comm); + WBAssertThrow(ierr == 0, "MPI_Bcast failed."); + WBAssertThrow(filesize != -1, + std::string("Could not open file <") + filename + ">."); + + data_string.resize(static_cast(filesize)); + + // Receive and store data + ierr = MPI_Bcast(&data_string[0], + filesize, + MPI_CHAR, + 0, + comm); + WBAssertThrow(ierr == 0, "MPI_Bcast failed."); + } + } + else + { + std::ifstream filestream; + filestream.open(filename.c_str()); + if (!filestream) + { + WBAssertThrow (false, + std::string("Could not open file <") + filename + ">."); + } + std::stringstream datastream; + datastream << filestream.rdbuf(); + data_string = datastream.str(); + } +#else + std::ifstream filestream; + filestream.open(filename.c_str()); + if (!filestream) + { + WBAssertThrow (false, + std::string("Could not open file <") + filename + ">."); + } + std::stringstream datastream; + datastream << filestream.rdbuf(); + data_string = datastream.str(); +#endif + + return data_string; + } + + template std::array convert_point_to_array<2>(const Point<2> &point_); + template std::array convert_point_to_array<3>(const Point<3> &point_); + + + std::vector + calculate_ridge_distance_and_spreading(std::vector>> mid_oceanic_ridges, + std::vector> mid_oceanic_spreading_velocities, + const std::unique_ptr &coordinate_system, + const Objects::NaturalCoordinate &position_in_natural_coordinates_at_min_depth, + const std::vector> &subducting_plate_velocities, + const std::vector &ridge_migration_times) + { + const double seconds_in_year = 60.0 * 60.0 * 24.0 * 365.25; // sec/y + + double distance_ridge = std::numeric_limits::max(); + double spreading_velocity_at_ridge = 0; + double subducting_velocity_at_trench = 0; + double ridge_migration_time = 0; + + // first find if the coordinate is on this side of a ridge + unsigned int relevant_ridge = 0; + const Point<2> check_point(position_in_natural_coordinates_at_min_depth.get_surface_coordinates(), + position_in_natural_coordinates_at_min_depth.get_coordinate_system()); + + Point<2> other_check_point = check_point; + if (check_point.get_coordinate_system() == CoordinateSystem::spherical) + other_check_point[0] += check_point[0] < 0 ? 2.0 * WorldBuilder::Consts::PI : -2.0 * WorldBuilder::Consts::PI; + + // if there is only one ridge, there is no transform + if (mid_oceanic_ridges[0].size() > 1) + { + // There are more than one ridge, so there are transform faults + // Find the first which is on the same side + for (relevant_ridge = 0; relevant_ridge < mid_oceanic_ridges.size()-1; relevant_ridge++) + { + const Point<2> transform_point_0 = mid_oceanic_ridges[relevant_ridge+1][0]; + const Point<2> transform_point_1 = mid_oceanic_ridges[relevant_ridge][mid_oceanic_ridges[relevant_ridge].size()-1]; + const Point<2> reference_point = mid_oceanic_ridges[relevant_ridge][0]; + const bool reference_on_side_of_line = (transform_point_1[0] - transform_point_0[0]) + * (reference_point[1] - transform_point_0[1]) + - (transform_point_1[1] - transform_point_0[1]) + * (reference_point[0] - transform_point_0[0]) + < 0; + const bool checkpoint_on_side_of_line = (transform_point_1[0] - transform_point_0[0]) + * (check_point[1] - transform_point_0[1]) + - (transform_point_1[1] - transform_point_0[1]) + * (check_point[0] - transform_point_0[0]) + < 0; + + + if (reference_on_side_of_line == checkpoint_on_side_of_line) + { + break; + } + + } + } + + for (unsigned int i_coordinate = 0; i_coordinate < mid_oceanic_ridges[relevant_ridge].size() - 1; i_coordinate++) + { + const Point<2> segment_point0 = mid_oceanic_ridges[relevant_ridge][i_coordinate]; + const Point<2> segment_point1 = mid_oceanic_ridges[relevant_ridge][i_coordinate + 1]; + + const double spreading_velocity_point0 = mid_oceanic_spreading_velocities[relevant_ridge][i_coordinate]; + const double spreading_velocity_point1 = mid_oceanic_spreading_velocities[relevant_ridge][i_coordinate + 1]; + + // When subducting_velocities is not input by the user, default value is 0, which + // results in subducting velocity == spreading_velocity. When a single value is + // input by the user, subducting velocity != spreading_velocity, but + // subducting velocity is spatially constant. + double subducting_velocity_point0 = subducting_plate_velocities[0][0]; + double subducting_velocity_point1 = subducting_plate_velocities[0][0]; + + // When subducting_velocities is input as an array, spatial variation + if (subducting_plate_velocities[0].size() > 1) + { + WBAssert(subducting_plate_velocities.size() == mid_oceanic_ridges.size() && \ + subducting_plate_velocities[relevant_ridge].size() == mid_oceanic_ridges[relevant_ridge].size(), + "subducting velocity and ridge coordinates must be the same dimension"); + WBAssert(ridge_migration_times.size() == mid_oceanic_ridges.size(), + "the times for ridge migration specified in 'spreading velocity' must be the same dimension " + "as ridge coordinates."); + subducting_velocity_point0 = subducting_plate_velocities[relevant_ridge][i_coordinate]; + subducting_velocity_point1 = subducting_plate_velocities[relevant_ridge][i_coordinate + 1]; + ridge_migration_time = ridge_migration_times[relevant_ridge]; + } + + { + // based on http://geomalgorithms.com/a02-_lines.html + const Point<2> v = segment_point1 - segment_point0; + const Point<2> w1 = check_point - segment_point0; + const Point<2> w2 = other_check_point - segment_point0; + + const double c1 = (w1[0] * v[0] + w1[1] * v[1]); + const double c = (v[0] * v[0] + v[1] * v[1]); + const double c2 = (w2[0] * v[0] + w2[1] * v[1]); + + + Point<2> Pb1(coordinate_system->natural_coordinate_system()); + // This part is needed when we want to consider segments instead of lines + // If you want to have infinite lines, use only the else statement. + + // First, compare the results from the two compare points + double spreading_velocity_at_ridge_pt1 = 0.0; + double subducting_velocity_at_trench_pt1 = 0.0; + double spreading_velocity_at_ridge_pt2 = 0.0; + double subducting_velocity_at_trench_pt2 = 0.0; + + if (c1 <= 0) + { + Pb1=segment_point0; + spreading_velocity_at_ridge_pt1 = spreading_velocity_point0; + subducting_velocity_at_trench_pt1 = subducting_velocity_point0; + } + else if (c <= c1) + { + Pb1=segment_point1; + spreading_velocity_at_ridge_pt1 = spreading_velocity_point1; + subducting_velocity_at_trench_pt1 = subducting_velocity_point1; + } + else + { + Pb1=segment_point0 + (c1 / c) * v; + spreading_velocity_at_ridge_pt1 = spreading_velocity_point0 + (spreading_velocity_point1 - spreading_velocity_point0) * (c1 / c); + subducting_velocity_at_trench_pt1 = subducting_velocity_point0 + (subducting_velocity_point1 - subducting_velocity_point0) * (c1 / c); + } + + Point<2> Pb2(coordinate_system->natural_coordinate_system()); + if (c2 <= 0) + { + Pb2=segment_point0; + spreading_velocity_at_ridge_pt2 = spreading_velocity_point0; + subducting_velocity_at_trench_pt2 = subducting_velocity_point0; + } + else if (c <= c2) + { + Pb2=segment_point1; + spreading_velocity_at_ridge_pt2 = spreading_velocity_point1; + subducting_velocity_at_trench_pt2 = spreading_velocity_point1; + } + else + { + Pb2=segment_point0 + (c2 / c) * v; + spreading_velocity_at_ridge_pt2 = spreading_velocity_point0 + (spreading_velocity_point1 - spreading_velocity_point0) * (c2 / c); + subducting_velocity_at_trench_pt2 = subducting_velocity_point0 + (subducting_velocity_point1 - subducting_velocity_point0) * (c2 / c); + } + + Point<3> compare_point1(coordinate_system->natural_coordinate_system()); + Point<3> compare_point2(coordinate_system->natural_coordinate_system()); + + compare_point1[0] = coordinate_system->natural_coordinate_system() == cartesian ? Pb1[0] : position_in_natural_coordinates_at_min_depth.get_depth_coordinate(); + compare_point1[1] = coordinate_system->natural_coordinate_system() == cartesian ? Pb1[1] : Pb1[0]; + compare_point1[2] = coordinate_system->natural_coordinate_system() == cartesian ? position_in_natural_coordinates_at_min_depth.get_depth_coordinate() : Pb1[1]; + + compare_point2[0] = coordinate_system->natural_coordinate_system() == cartesian ? Pb2[0] : position_in_natural_coordinates_at_min_depth.get_depth_coordinate(); + compare_point2[1] = coordinate_system->natural_coordinate_system() == cartesian ? Pb2[1] : Pb2[0]; + compare_point2[2] = coordinate_system->natural_coordinate_system() == cartesian ? position_in_natural_coordinates_at_min_depth.get_depth_coordinate() : Pb2[1]; + + const double compare_distance1 = coordinate_system->distance_between_points_at_same_depth(Point<3>(position_in_natural_coordinates_at_min_depth.get_coordinates(), + position_in_natural_coordinates_at_min_depth.get_coordinate_system()), + compare_point1); + + const double compare_distance2 = coordinate_system->distance_between_points_at_same_depth(Point<3>(position_in_natural_coordinates_at_min_depth.get_coordinates(), + position_in_natural_coordinates_at_min_depth.get_coordinate_system()), + compare_point2); + + double compare_distance = compare_distance1; + double spreading_velocity_at_ridge_pt = spreading_velocity_at_ridge_pt1; + double subducting_velocity_at_trench_pt = subducting_velocity_at_trench_pt1; + + // This is required in spherical coordinates to ensure that the distance + // returned is the shortest distance around the sphere. + if (compare_distance2 < compare_distance1) + { + compare_distance = compare_distance2; + spreading_velocity_at_ridge_pt = spreading_velocity_at_ridge_pt2; + subducting_velocity_at_trench_pt = subducting_velocity_at_trench_pt2; + } + + // Then, the distance and velocities are taken from the nearest point on the ridge + if (i_coordinate == 0 || compare_distance < distance_ridge) + { + distance_ridge = compare_distance; + spreading_velocity_at_ridge = spreading_velocity_at_ridge_pt; + subducting_velocity_at_trench = subducting_velocity_at_trench_pt; + } + } + } + std::vector result; + result.push_back(spreading_velocity_at_ridge / seconds_in_year); // m/s + result.push_back(distance_ridge); + result.push_back(subducting_velocity_at_trench / seconds_in_year); // m/s + result.push_back(ridge_migration_time); + return result; + } + + // TODO: implement method for modifying the age of the slab based on ridge/trench migration. + std::vector + calculate_effective_trench_and_plate_ages(std::vector ridge_parameters, double distance_along_plane) + { + WBAssert(ridge_parameters.size() == 4, "Internal error: ridge_parameters have the wrong size: " << ridge_parameters.size() << " instead of 4."); + const double seconds_in_year = 60.0 * 60.0 * 24.0 * 365.25; // sec/y + const double spreading_velocity = ridge_parameters[0] * seconds_in_year; // m/yr + double subducting_velocity = ridge_parameters[2] * seconds_in_year; // m/yr + + if (subducting_velocity <= 0) + subducting_velocity = spreading_velocity; + + const double age_at_trench = ridge_parameters[1] / spreading_velocity; // m/(m/y) = yr + const double plate_age_sec = age_at_trench * seconds_in_year; // y --> seconds + + // Plate age increases with distance along the slab in the mantle + double effective_plate_age = plate_age_sec + (distance_along_plane / subducting_velocity) * seconds_in_year; // m/(m/y) = y(seconds_in_year) + WBAssertThrow(effective_plate_age >= 0, "The age of the subducting plate is less than or equal to 0. " + "Effective plate age: " << effective_plate_age); + std::vector result; + result.push_back(age_at_trench); + result.push_back(effective_plate_age); + return result; + + } + } // namespace Utilities +} // namespace WorldBuilder + + + diff --git a/contrib/world_builder/source/world_builder/world.cc.bak b/contrib/world_builder/source/world_builder/world.cc.bak new file mode 100644 index 00000000000..6871f29ea9c --- /dev/null +++ b/contrib/world_builder/source/world_builder/world.cc.bak @@ -0,0 +1,498 @@ +/* + 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/world.h" + + +#include "world_builder/config.h" +#include "world_builder/features/subducting_plate.h" +#include "world_builder/gravity_model/interface.h" +#include "world_builder/nan.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/object.h" +#include "world_builder/types/plugin_system.h" +#include "world_builder/types/point.h" +#include "world_builder/types/int.h" + +#include +#include +#include + +#ifdef WB_WITH_MPI +// we don't need the c++ MPI wrappers +#define OMPI_SKIP_MPICXX 1 +#define MPICH_SKIP_MPICXX +#include +#endif + +#ifndef NDEBUG +#ifdef WB_USE_FP_EXCEPTIONS +#include +#endif +#endif + +namespace WorldBuilder +{ + using namespace Utilities; + + World::World(std::string filename, bool has_output_dir, const std::string &output_dir, unsigned long random_number_seed, const bool limit_debug_consistency_checks_) + : + parameters(*this), + surface_coord_conversions(invalid), + dim(NaN::ISNAN), + random_number_engine(random_number_seed), + limit_debug_consistency_checks(limit_debug_consistency_checks_) + { + +#ifndef NDEBUG +#ifdef WB_USE_FP_EXCEPTIONS + // Some implementations seem to not initialize the floating point exception + // bits to zero. Make sure we start from a clean state. + feclearexcept(FE_DIVBYZERO|FE_INVALID); + + // enable floating point exceptions + feenableexcept(FE_DIVBYZERO|FE_INVALID); +#endif +#endif + +#ifdef WB_WITH_MPI + int mpi_initialized; + MPI_Initialized(&mpi_initialized); + if (mpi_initialized == 0) + { + MPI_RANK = 0; + MPI_SIZE = 1; + } + else + { + MPI_Comm_rank(MPI_COMM_WORLD, &MPI_RANK); + MPI_Comm_size(MPI_COMM_WORLD, &MPI_SIZE); + } +#else + MPI_RANK = 0; + MPI_SIZE = 1; +#endif + + WorldBuilder::World::declare_entries(parameters); + + parameters.initialize(filename, has_output_dir, output_dir); + + this->parse_entries(parameters); + } + + World::~World() + = default; + + void World::declare_entries(Parameters &prm) + { + prm.enter_subsection("properties"); + { + prm.declare_entry("", Types::Object({"version", "features"}), "Root object"); + + prm.declare_entry("version", Types::String(""),"The major and minor version number for which the input file was written."); + + prm.declare_entry("$schema", Types::String(""),"The optional filename or https address to a JSON schema file"); + + prm.declare_entry("cross section", Types::Array(Types::Point<2>(),2,2),"This is an array of two points along where the cross section is taken"); + + prm.declare_entry("potential mantle temperature", Types::Double(1600), + "The potential temperature of the mantle at the surface in Kelvin."); + prm.declare_entry("surface temperature", Types::Double(293.15), + "The temperature at the surface in Kelvin."); + prm.declare_entry("force surface temperature", Types::Bool(false), + "Force the provided surface temperature to be set at the surface"); + prm.declare_entry("thermal expansion coefficient", Types::Double(3.5e-5), + "The thermal expansion coefficient in $K^{-1}$."); + prm.declare_entry("specific heat", Types::Double(1250), + "The specific heat in $J kg^{-1} K^{-1}.$"); + prm.declare_entry("thermal diffusivity", Types::Double(0.804e-6), + "The thermal diffusivity in $m^{2} s^{-1}$."); + + prm.declare_entry("maximum distance between coordinates",Types::Double(0), + "This enforces a maximum distance (in degree for spherical coordinates " + "or meter in cartesian coordinates) between coordinates in the model. " + "If the distance is larger, extra points are added by interpolation. " + "Requires interpolation to be not 'none'."); + + prm.declare_entry("interpolation",Types::String("continuous monotone spline"), + "What type of interpolation should be used to enforce the minimum points per " + "distance parameter. Options are none, linear, monotone spline and " + "continuous monotone spline interpolation."); + + + prm.declare_entry("coordinate system", Types::PluginSystem("cartesian", CoordinateSystems::Interface::declare_entries, {"model"}, false),"A coordinate system. Cartesian or spherical."); + + prm.declare_entry("gravity model", Types::PluginSystem("uniform", GravityModel::Interface::declare_entries, {"model"}, false),"A gravity 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), + "This allows the input of a preferred random number seed to generate random numbers." + " If no input is given, this value is -1 and triggers the use of default seed = 1."); + + } + prm.leave_subsection(); + + } + + + void World::parse_entries(Parameters &prm) + { + using namespace rapidjson; + + /** + * First load the major version number in the file and check the major + * version number of the program. + */ + + WBAssertThrow((Version::MAJOR == "0" + && prm.get("version") == Version::MAJOR + "." + Version::MINOR) + || (Version::MAJOR != "0" + && prm.get("version") == Version::MAJOR), + "The major and minor version combination (for major version 0) or the major " + "version (for major versions after 0) for which is input file was written " + "is not the same as the version of the World Builder you are running. This means " + "That there may have been incompatible changes made between the versions. \n\n" + "Verify those changes and whether they affect your model. If this is not " + "the case, adjust the version number in the input file. \n\nThe provided version " + "number is \"" << prm.get("version") << "\", while the used world builder " + "has (major.minor) version \"" << Version::MAJOR << "." << Version::MINOR << "\". " + "If you created this file from scratch, fill set the version number to \"" << + Version::MAJOR << "." << Version::MINOR << "\" to continue. If you got the world builder " + "file from somewhere, make sure that the output is what you expect it to be, because " + "backwards incompatible changes may have been made to the code."); + + /** + * Secondly load the coordinate system parameters. + */ + prm.coordinate_system = prm.get_unique_pointer("coordinate system"); + prm.coordinate_system->parse_entries(prm); + + /** + * Thirdly load the gravity model parameters. + */ + prm.gravity_model = prm.get_unique_pointer("gravity model"); + + prm.enter_subsection("gravity model"); + { + prm.gravity_model->parse_entries(prm); + } + prm.leave_subsection(); + + prm.get_unique_pointers("features",prm.features); + + const bool set_cross_section = prm.check_entry("cross section"); + + const CoordinateSystem coordinate_system = prm.coordinate_system->natural_coordinate_system(); + + if (set_cross_section) + { + dim = 2; + const std::vector > cross_section_natural = prm.get_vector >("cross section"); + + WBAssertThrow(cross_section_natural.size() == 2, "The cross section should contain two points, but it contains " + << cross_section.size() << " points."); + + for (const auto &it : cross_section_natural) + cross_section.push_back(it * (coordinate_system == spherical ? Consts::PI / 180.0 : 1.0)); + + + /** + * pre-compute stuff for the cross section + */ + surface_coord_conversions = cross_section[0]-cross_section[1]; + surface_coord_conversions *= -1/(surface_coord_conversions.norm()); + + + } + else + { + dim = 3; + } + + /** + * Temperature parameters. + */ + potential_mantle_temperature = prm.get("potential mantle temperature"); + surface_temperature = prm.get("surface temperature"); + surface_temperature = prm.get("surface temperature"); + force_surface_temperature = prm.get("force surface temperature"); + thermal_expansion_coefficient = prm.get("thermal expansion coefficient"); + specific_heat = prm.get("specific heat"); + thermal_diffusivity = prm.get("thermal diffusivity"); + + /** + * Model discretization parameters + */ + maximum_distance_between_coordinates = prm.get("maximum distance between coordinates"); + interpolation = prm.get("interpolation"); + + /** + * Local random number seed parameter + */ + const int local_seed = prm.get("random number seed"); + + if (local_seed>=0) + random_number_engine.seed(static_cast(local_seed+MPI_RANK)); + + /** + * Now load the features. Some features use for example temperature values, + * so it is important that this is parsed the last. + */ + prm.enter_subsection("features"); + { + for (unsigned int i = 0; i < prm.features.size(); ++i) + { + prm.enter_subsection(std::to_string(i)); + { + prm.features[i]->parse_entries(prm); + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + } + + + + std::vector + World::properties(const std::array &point, + const double depth, + const std::vector> &properties) const + { + // turn it into a 3d coordinate and call the 3d temperature function + WBAssertThrow(dim == 2, "This function can only be called when the cross section " + "variable in the world builder file has been set. Dim is " + << dim << '.'); + + const CoordinateSystem coordinate_system = this->parameters.coordinate_system->natural_coordinate_system(); + + Point<2> point_natural(point[0], point[1],coordinate_system); + if (coordinate_system == spherical) + { + point_natural[1] = std::sqrt(point[0]*point[0]+point[1]*point[1]); + point_natural[0] = std::atan2(point[1],point[0]); + } + + Point<3> coord_3d(coordinate_system); + if (coordinate_system == spherical) + { + coord_3d[0] = point_natural[1]; + coord_3d[1] = cross_section[0][0] + point_natural[0] * surface_coord_conversions[0]; + coord_3d[2] = cross_section[0][1] + point_natural[0] * surface_coord_conversions[1]; + } + else + { + coord_3d[0] = cross_section[0][0] + point_natural[0] * surface_coord_conversions[0]; + coord_3d[1] = cross_section[0][1] + point_natural[0] * surface_coord_conversions[1]; + coord_3d[2] = point_natural[1]; + } + + + const std::array point_3d_cartesian = this->parameters.coordinate_system->natural_to_cartesian_coordinates(coord_3d.get_array()); + + return this->properties(point_3d_cartesian, depth, properties); + } + + + std::vector + World::properties(const std::array &point_, + const double depth, + const std::vector> &properties) const + { + // We receive the cartesian points from the user. + const Point<3> point(point_,cartesian); + (void) this->limit_debug_consistency_checks; + 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 spherical coordinates is consistent with the radius of the planet as defined " + << "in the program that uses the Geodynamic World Builder. This is a debug check in GWB and can be disabled by setting " + << "limit_debug_consistency_checks to true. " + << "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])); + + const Objects::NaturalCoordinate natural_coordinate = Objects::NaturalCoordinate(point,*(this->parameters.coordinate_system)); + + // create output vector + std::vector output; + std::vector entry_in_output; + std::vector> properties_local; + const double gravity_norm = this->parameters.gravity_model->gravity_norm(point); + for (unsigned int i_property = 0; i_property < properties.size(); ++i_property) + { + switch (properties[i_property][0]) + { + case 1: // Temperature + if (std::fabs(depth) < 2.0 * std::numeric_limits::epsilon() && force_surface_temperature) + { + entry_in_output.emplace_back(output.size()); + output.emplace_back(this->surface_temperature); + if (properties.size() == 1) + return output; + } + else + { + entry_in_output.emplace_back(output.size()); + output.emplace_back(potential_mantle_temperature * std::exp(((thermal_expansion_coefficient * gravity_norm) / specific_heat) * depth)); + } + properties_local.emplace_back(properties[i_property]); + break; + case 2: // composition + entry_in_output.emplace_back(output.size()); + output.emplace_back(0.); + properties_local.emplace_back(properties[i_property]); + break; + case 3: // grains (10 entries per grain) + { + entry_in_output.emplace_back(output.size()); + const std::vector tmp_vector(properties[i_property][2]*10,0.); + output.insert(output.end(), tmp_vector.begin(), tmp_vector.end()); + properties_local.emplace_back(properties[i_property]); + break; + } + case 4: // tag + { + entry_in_output.emplace_back(output.size()); + output.emplace_back(-1); + properties_local.emplace_back(properties[i_property]); + break; + } + default: + WBAssertThrow(false, + "Internal error: Unimplemented property provided. " << + "Only temperature (1), composition (2), grains (3) or tag (4) are allowed. " + "Provided property number was: " << properties[i_property][0]); + } + } + for (auto &&it : parameters.features) + { + it->properties(point, natural_coordinate, depth, properties_local, gravity_norm, entry_in_output, output); + } + + return output; + } + + double + World::temperature(const std::array &point, + const double depth) const + { + return properties(point, depth, {{{1,0,0}}})[0]; + } + + double + World::temperature(const std::array &point, + const double depth, + const double /*gravity_norm*/) const + { + return properties(point, depth, {{{1,0,0}}})[0]; + } + + double + World::temperature(const std::array &point, + const double depth) const + { + return properties(point, depth, {{{1,0,0}}})[0]; + } + + double + World::temperature(const std::array &point, + const double depth, + const double /*gravity_norm*/) const + { + return properties(point, depth, {{{1,0,0}}})[0]; + } + + double + World::composition(const std::array &point, + const double depth, + const unsigned int composition_number) const + { + return properties(point, depth, {{{2,composition_number,0}}})[0]; + } + + double + World::composition(const std::array &point, + const double depth, + const unsigned int composition_number) const + { + return properties(point, depth, {{{2,composition_number,0}}})[0]; + } + + + + WorldBuilder::grains + World::grains(const std::array &point, + const double depth, + const unsigned int composition_number, + size_t number_of_grains) const + { + return WorldBuilder::grains(properties(point, depth, {{{3,composition_number,static_cast(number_of_grains)}}}),static_cast(number_of_grains),0); + } + + WorldBuilder::grains + World::grains(const std::array &point, + const double depth, + const unsigned int composition_number, + size_t number_of_grains) const + { + return WorldBuilder::grains(properties(point, depth, {{{3,composition_number,static_cast(number_of_grains)}}}),static_cast(number_of_grains),0); + } + + std::mt19937 & + World::get_random_number_engine() + { + 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. + const 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 spherical coordinates is consistent with the radius of the planet as defined " + << "in the program that uses the Geodynamic World Builder. This is a debug check in GWB and can be disabled by setting " + << "limit_debug_consistency_checks to true. " + << "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])); + + const 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/contrib/world_builder/source/world_builder/wrapper_c.cc.bak b/contrib/world_builder/source/world_builder/wrapper_c.cc.bak new file mode 100644 index 00000000000..e0b95e6e47a --- /dev/null +++ b/contrib/world_builder/source/world_builder/wrapper_c.cc.bak @@ -0,0 +1,108 @@ +/* + 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/wrapper_c.h" + +#include "world_builder/world.h" + +extern "C" { + /** + * This function creates an object of the world builder and returns a pointer + * to it. This pointer can then be used to call the temperature and composition + * functions. When done call the release world function to destroy the object. + */ + void create_world(void **ptr_ptr_world, const char *world_builder_file, const bool *has_output_dir_, const char *output_dir_, const unsigned long random_number_seed) + { + bool has_output_dir = false; + + if (has_output_dir_ != nullptr) + { + has_output_dir = *has_output_dir_; + } + + std::string output_dir; + if (output_dir_ != nullptr) + { + output_dir = *output_dir_; + } + + WorldBuilder::World *a = new WorldBuilder::World(std::string(world_builder_file), has_output_dir, output_dir,random_number_seed); + + *ptr_ptr_world = reinterpret_cast(a); + } + + + /** + * This function return the temperature at a specific location given x, z, depth and + * gravity. + */ + void temperature_2d(void *ptr_ptr_world, double x, double z, double depth, double *temperature) + { + WorldBuilder::World *a = reinterpret_cast(ptr_ptr_world); + const std::array position = {{x,z}}; + *temperature = a->temperature(position,depth); + } + + + /** + * This function return the temperature at a specific location given x, y, z, depth and + * gravity. + */ + void temperature_3d(void *ptr_ptr_world, double x, double y, double z, double depth, double *temperature) + { + WorldBuilder::World *a = reinterpret_cast(ptr_ptr_world); + const std::array position = {{x,y,z}}; + *temperature = a->temperature(position,depth); + } + + + /** + * This function return the composition at a specific location given x, z, depth and + * composition number. + */ + void composition_2d(void *ptr_ptr_world, double x, double z, double depth, unsigned int composition_number, double *composition) + { + WorldBuilder::World *a = reinterpret_cast(ptr_ptr_world); + const std::array position = {{x,z}}; + *composition = a->composition(position,depth,composition_number); + } + + + /** + * This function return the composition at a specific location given x, y, z, depth and + * composition number. + */ + void composition_3d(void *ptr_ptr_world, double x, double y, double z, double depth, unsigned int composition_number, double *composition) + { + WorldBuilder::World *a = reinterpret_cast(ptr_ptr_world); + const std::array position = {{x,y,z}}; + *composition = a->composition(position,depth,composition_number); + } + + + /** + * The destructor for the world builder class. Call this function when done with the + * world builder. + */ + void release_world(void *ptr_ptr_world) + { + WorldBuilder::World *a = reinterpret_cast(ptr_ptr_world); + delete a; + } +} diff --git a/contrib/world_builder/source/world_builder/wrapper_cpp.cc.bak b/contrib/world_builder/source/world_builder/wrapper_cpp.cc.bak new file mode 100644 index 00000000000..d4764ab2413 --- /dev/null +++ b/contrib/world_builder/source/world_builder/wrapper_cpp.cc.bak @@ -0,0 +1,77 @@ +/* + 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/wrapper_cpp.h" + +#include "world_builder/world.h" + +using namespace WorldBuilder; +namespace wrapper_cpp +{ + WorldBuilderWrapper::WorldBuilderWrapper(std::string filename, bool has_output_dir, const std::string &output_dir, const unsigned long random_number_seed) + : ptr_ptr_world(nullptr) + { + WorldBuilder::World *a = new WorldBuilder::World(std::move(filename), has_output_dir, output_dir, random_number_seed); + ptr_ptr_world = reinterpret_cast(a); + } + + + WorldBuilderWrapper::~WorldBuilderWrapper() + { + WorldBuilder::World *a = reinterpret_cast(ptr_ptr_world); + delete a; + } + + + double + WorldBuilderWrapper::temperature_2d(double x, double z, double depth) + { + const std::array position = {{x,z}}; + return reinterpret_cast(ptr_ptr_world)->temperature(position,depth); + } + + double + WorldBuilderWrapper::temperature_2d(double x, double z, double depth, double /*gravity*/) + { + return temperature_2d(x,z,depth); + } + + double WorldBuilderWrapper::temperature_3d(double x, double y, double z, double depth) + { + const std::array position = {{x,y,z}}; + return reinterpret_cast(ptr_ptr_world)->temperature(position,depth); + } + + double WorldBuilderWrapper::temperature_3d(double x, double y, double z, double depth, double /*gravity*/) + { + return temperature_3d(x,y,z,depth); + } + + double WorldBuilderWrapper::composition_2d(double x, double z, double depth, unsigned int composition_number) + { + const std::array position = {{x,z}}; + return reinterpret_cast(ptr_ptr_world)->composition(position,depth,composition_number); + } + + double WorldBuilderWrapper::composition_3d(double x, double y, double z, double depth, unsigned int composition_number) + { + const std::array position = {{x,y,z}}; + return reinterpret_cast(ptr_ptr_world)->composition(position,depth,composition_number); + } +} // namespace wrapper_cpp diff --git a/contrib/world_builder/tests/unit_tests/bounding_box.cc.bak b/contrib/world_builder/tests/unit_tests/bounding_box.cc.bak new file mode 100644 index 00000000000..a438f3ceb42 --- /dev/null +++ b/contrib/world_builder/tests/unit_tests/bounding_box.cc.bak @@ -0,0 +1,87 @@ +/* + Copyright (C) 2021 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 . + */ + +#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#include "doctest/doctest.h" + +#include "world_builder/bounding_box.h" + +using namespace WorldBuilder; +using doctest::Approx; + + +TEST_CASE("bounding box 2D") +{ + // Check default constructor + const BoundingBox<2> bb1; + CHECK(bb1.center().distance(Point<2>(0,0,CoordinateSystem::cartesian)) < 1e-12); + CHECK(BoundingBox<2>().center().distance(Point<2>(0,0,CoordinateSystem::cartesian)) < 1e-12); + + CHECK(bb1.point_inside(Point<2>(2,2.5,CoordinateSystem::cartesian)) == true); + const Point<2> p1 ({{1,1}}, CoordinateSystem::cartesian); + const Point<2> p2 ({{2,3}}, CoordinateSystem::cartesian); + + + CHECK(BoundingBox<2>().center().distance(Point<2>(0,0,CoordinateSystem::cartesian)) < 1e-12); + const BoundingBox<2> bb2({p1, p2}); + CHECK(bb2.center().distance(Point<2>(1.5,2.,CoordinateSystem::cartesian)) < 1e-12); + + // Check that the function point_inside works as expected + CHECK(bb2.point_inside(Point<2>(1.5,2,CoordinateSystem::cartesian)) == true); + CHECK(bb2.point_inside(Point<2>(-1.5,2,CoordinateSystem::cartesian)) == false); + CHECK(bb2.point_inside(Point<2>(1.5,-2,CoordinateSystem::cartesian)) == false); + CHECK(bb2.point_inside(Point<2>(-1.5,-2,CoordinateSystem::cartesian)) == false); +} + + +TEST_CASE("bounding box 3D") +{ + // Check default constructor + const BoundingBox<3> bb1; + CHECK(bb1.center().distance(Point<2>(0,0,CoordinateSystem::cartesian)) < 1e-12); + CHECK(BoundingBox<3>().center().distance(Point<2>(0,0,CoordinateSystem::cartesian)) < 1e-12); + + CHECK(bb1.point_inside(Point<3>(2,2.5,2.5,CoordinateSystem::cartesian)) == true); + + // Check constructor with provided points + const Point<3> p1 ( + { + { + 1,1,1 + } + }, CoordinateSystem::cartesian); + const Point<3> p2 ( + { + { + 2,3,4 + } + }, CoordinateSystem::cartesian); + const BoundingBox<3> bb2({p1, p2}); + + // Check the center function + CHECK(bb2.center().distance(Point<2>(1.5,2,CoordinateSystem::cartesian)) < 1e-12); + + // Check that the function point_inside works as expected + CHECK(bb2.point_inside(Point<3>(1.5,2,2.5,CoordinateSystem::cartesian)) == true); + CHECK(bb2.point_inside(Point<3>(-1.5,2,2.5,CoordinateSystem::cartesian)) == false); + CHECK(bb2.point_inside(Point<3>(1.5,-2,2.5,CoordinateSystem::cartesian)) == false); + CHECK(bb2.point_inside(Point<3>(1.5,2,-2.5,CoordinateSystem::cartesian)) == false); + +} diff --git a/contrib/world_builder/tests/unit_tests/gwb_gravity.cc.bak b/contrib/world_builder/tests/unit_tests/gwb_gravity.cc.bak new file mode 100644 index 00000000000..c6a586a6267 --- /dev/null +++ b/contrib/world_builder/tests/unit_tests/gwb_gravity.cc.bak @@ -0,0 +1,68 @@ +/* + Copyright (C) 2021 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 . + */ + +#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#include "doctest/doctest.h" + +#include "world_builder/config.h" +#include "world_builder/coordinate_systems/invalid.h" +#include "world_builder/gravity_model/uniform.h" +#include "world_builder/parameters.h" +#include "world_builder/point.h" +#include "world_builder/world.h" + +using namespace WorldBuilder; +using doctest::Approx; +using doctest::Contains; + +TEST_CASE("Gravity uniform") +{ + + const std::string file_name = Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/subducting_plate_different_angles_cartesian.wb"; + World world(file_name); + + CHECK(world.parameters.gravity_model->gravity_norm(Point<3>(10,10,10,CoordinateSystem::cartesian)) == Approx(10.)); + + auto vector_cartesian = world.parameters.gravity_model->gravity_vector(Point<3>(10,10,10,CoordinateSystem::cartesian)); + + CHECK(vector_cartesian[0] == Approx(0)); + CHECK(vector_cartesian[1] == Approx(0)); + CHECK(vector_cartesian[2] == Approx(-10.)); + + + const std::string file_name_spherical = Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/subducting_plate_different_angles_spherical.wb"; + World world_spherical(file_name_spherical); + + auto vector_spherical = world_spherical.parameters.gravity_model->gravity_vector(Point<3>(1,2,4,CoordinateSystem::spherical)); + + CHECK(vector_spherical[0] == Approx(-2.1821789024)); + CHECK(vector_spherical[1] == Approx(-4.3643578047)); + CHECK(vector_spherical[2] == Approx(-8.7287156094)); + CHECK(std::sqrt(vector_spherical[0]*vector_spherical[0]+ + vector_spherical[1]*vector_spherical[1]+ + vector_spherical[2]*vector_spherical[2]) == Approx(10.)); + + world_spherical.parameters.coordinate_system = + std::unique_ptr(new CoordinateSystems::Invalid(nullptr)); + + CHECK_THROWS_WITH(world_spherical.parameters.gravity_model->gravity_vector(Point<3>(1,2,4,CoordinateSystem::invalid)), + Contains("Invalid coordinate system when using the gravity vector function.")); + +} \ No newline at end of file diff --git a/contrib/world_builder/tests/unit_tests/kd_tree.cc.bak b/contrib/world_builder/tests/unit_tests/kd_tree.cc.bak new file mode 100644 index 00000000000..154144bebb0 --- /dev/null +++ b/contrib/world_builder/tests/unit_tests/kd_tree.cc.bak @@ -0,0 +1,214 @@ +/* + Copyright (C) 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 . + */ + +#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#include "doctest/doctest.h" +#include "world_builder/coordinate_system.h" +#include "world_builder/kd_tree.h" + +#include + +using namespace WorldBuilder::KDTree; +using doctest::Approx; + +/** + * Compare the given two std::array entries with an epsilon (using Catch::Approx) + */ +inline void compare_node_trees( + const std::vector &computed, + const std::vector &expected) +{ + for (size_t i = 0; i < computed.size(); ++i) + { + CHECK(computed[i].index == expected[i].index); + CHECK(computed[i].x == Approx(expected[i].x)); + CHECK(computed[i].y == Approx(expected[i].y)); + } +} + +TEST_CASE("create kd-tree: 15 nodes") +{ + const std::vector reference = {Node(8,2,3),Node(4,4,4),Node(9,5,2), + Node(2,1,5),Node(10,2,9),Node(5,5,8), + Node(11,6,7),Node(1,7,3),Node(12,9,2.5), + Node(6,10,2),Node(13,11.5,1),Node(3,11,4), + Node(14,8,6),Node(7,9,7),Node(15,11,8) + }; + { + const std::vector nodes = {Node(1,7,3),Node(2,1,5),Node(3,11,4), + Node(4,4,4),Node(5,5,8),Node(6,10,2), + Node(7,9,7),Node(8,2,3),Node(9,5,2), + Node(10,2,9),Node(11,6,7),Node(12,9,2.5), + Node(13,11.5,1),Node(14,8,6),Node(15,11,8) + }; + + KDTree tree = KDTree(nodes); + + tree.create_tree(0, nodes.size()-1, false); + + compare_node_trees(tree.get_nodes(), reference); + } + + { + // shuffle nodes + const std::vector nodes = {Node(2,1,5),Node(3,11,4),Node(9,5,2), + Node(4,4,4),Node(1,7,3),Node(5,5,8), + Node(7,9,7),Node(8,2,3),Node(11,6,7), + Node(10,2,9),Node(12,9,2.5),Node(14,8,6), + Node(13,11.5,1),Node(6,10,2),Node(15,11,8) + }; + + KDTree tree = KDTree(nodes); + + tree.create_tree(0, nodes.size()-1, false); + + compare_node_trees(tree.get_nodes(), reference); + } +} + + +TEST_CASE("create kd-tree: 6 nodes") +{ + const std::vector reference = {Node(4,4,2),Node(5,2,6),Node(2,7,6), + Node(1,9,2),Node(6,12,3),Node(3,11,6) + }; + { + const std::vector nodes = {Node(1,9,2),Node(2,7,6),Node(3,11,6), + Node(4,4,2),Node(5,2,6),Node(6,12,3) + }; + + KDTree tree = KDTree(nodes); + + tree.create_tree(0, nodes.size()-1, false); + + compare_node_trees(tree.get_nodes(), reference); + } + + { + // shuffle nodes + const std::vector nodes = {Node(5,2,6),Node(2,7,6),Node(1,9,2), + Node(6,12,3),Node(4,4,2),Node(3,11,6) + }; + + KDTree tree = KDTree(nodes); + + tree.create_tree(0, nodes.size()-1, false); + + compare_node_trees(tree.get_nodes(), reference); + } +} + + +TEST_CASE("create kd-tree: 10 nodes") +{ + const std::vector reference = {Node(3,2,1),Node(1,4,2),Node(4,1,4), + Node(7,3,6),Node(0,7,3),Node(5,9,2), + Node(8,11,1),Node(2,12,3),Node(9,10,5), + Node(6,11,6) + }; + { + const std::vector nodes = {Node(0,7,3),Node(1,4,2),Node(2,12,3), + Node(3,2,1),Node(4,1,4),Node(5,9,2), + Node(7,3,6),Node(6,11,6),Node(9,10,5), + Node(8,11,1) + }; + + KDTree tree = KDTree(nodes); + + tree.create_tree(0, nodes.size()-1, false); + + compare_node_trees(tree.get_nodes(), reference); + + // check some values + using namespace WorldBuilder; + std::vector> check_points = {Point<2>(7,2,CoordinateSystem::cartesian), + Point<2>(8,2,CoordinateSystem::cartesian), + Point<2>(9,2,CoordinateSystem::cartesian), + Point<2>(8,2.5001,CoordinateSystem::cartesian), + Point<2>(8,2.4999,CoordinateSystem::cartesian), + Point<2>(7,3,CoordinateSystem::cartesian), + Point<2>(11,1.5,CoordinateSystem::cartesian), + Point<2>(10,2,CoordinateSystem::cartesian), + Point<2>(12,2,CoordinateSystem::cartesian), + Point<2>(11,0.5,CoordinateSystem::cartesian), + Point<2>(9.25,1.75,CoordinateSystem::cartesian), + Point<2>(11,3.5,CoordinateSystem::cartesian), + Point<2>(10.5,4,CoordinateSystem::cartesian), + Point<2>(9.5,4,CoordinateSystem::cartesian), + Point<2>(9.5,5.5,CoordinateSystem::cartesian), + Point<2>(10.75,5.5,CoordinateSystem::cartesian), + Point<2>(11.75,5.5,CoordinateSystem::cartesian), + Point<2>(5,1,CoordinateSystem::cartesian), + Point<2>(3,1,CoordinateSystem::cartesian), + Point<2>(1,1,CoordinateSystem::cartesian), + Point<2>(2,3,CoordinateSystem::cartesian), + Point<2>(0.5,3,CoordinateSystem::cartesian), + Point<2>(0.5,5,CoordinateSystem::cartesian), + Point<2>(2,4.5,CoordinateSystem::cartesian), + Point<2>(3,5,CoordinateSystem::cartesian), + Point<2>(3,7,CoordinateSystem::cartesian) + }; + + std::vector index_results = {4,5,5,4,5,4,6,5,7,6,5,7,8,8,8,9,9,1,0,0,2,2,2,2,3,3}; + + for (size_t i = 0; i < check_points.size(); ++i) + { + IndexDistance const index_distance = tree.find_closest_point(check_points[i]); + + CHECK(index_distance.index == index_results[i]); + } + + std::vector > index_distances_results = + { + {5,7,8,4,3,2,1,0},{5,7,4,3,2,1,0},{6,5,7,4,3,2,1},{5,6,7,8,4,3,2,1,0}, + {5,6,7,8,4,3,2,1,0},{8,9,7,5,6,4,},{6,5,7,4,0,1},{6,5,7,4,3,2,1,0}, + {6,5,7,4,3,2,1,0},{6,5,7,4,0,1},{6,5,7,4,0,1,3,2},{9,8,7,6,5,4,3,2,1,0}, + {9,8,7,6,5,4,3,2,1,0},{8,9,7,6,5,4,3,2,1,0},{8,9,7,6,5,4,3,2,1,0}, + {9,8,7,6,5,4,3,2,1,0},{9,8,7,6,5,4,3,2,1,0},{0,1,3,2,4},{0,1,4},{0,1,4}, + {3,2,1,0,4},{2,3,1,0,4},{2,3,1,0,4},{3,2,1,0,4},{3,2,1,0,4},{3,2,1,0,4} + }; + + for (size_t i = 0; i < check_points.size(); ++i) + { + IndexDistances index_distances = tree.find_closest_points(check_points[i]); + CHECK(index_distances.min_index == index_results[i]); + + for (size_t j = 0; j < index_distances.vector.size(); ++j) + { + CHECK(index_distances.vector[j].index == index_distances_results[i][j]); + } + } + } + + { + // shuffle nodes + const std::vector nodes = {Node(3,2,1),Node(4,1,4),Node(5,9,2), + Node(0,7,3),Node(6,11,6),Node(2,12,3), + Node(7,3,6),Node(9,10,5),Node(1,4,2), + Node(8,11,1) + }; + + KDTree tree = KDTree(nodes); + + tree.create_tree(0, nodes.size()-1, false); + + compare_node_trees(tree.get_nodes(), reference); + } +} \ No newline at end of file diff --git a/contrib/world_builder/tests/unit_tests/main.cc.bak b/contrib/world_builder/tests/unit_tests/main.cc.bak new file mode 100644 index 00000000000..64fe8ac9bad --- /dev/null +++ b/contrib/world_builder/tests/unit_tests/main.cc.bak @@ -0,0 +1,25 @@ + +/* + Copyright (C) 2018 - 2021 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 . + */ + +#define APPROVALS_DOCTEST // This tells Approval Tests to provide a main() - only do this in one cpp file +#include "ApprovalTests/ApprovalTests.hpp" + +auto directoryDisposer = ApprovalTests::Approvals::useApprovalsSubdirectory("approval_tests"); +auto default_namer_disposer = ApprovalTests::SeparateApprovedAndReceivedDirectoriesNamer::useAsDefaultNamer(); \ No newline at end of file diff --git a/contrib/world_builder/tests/unit_tests/unit_test_wb_glm.cc.bak b/contrib/world_builder/tests/unit_tests/unit_test_wb_glm.cc.bak new file mode 100644 index 00000000000..f37dddd01a8 --- /dev/null +++ b/contrib/world_builder/tests/unit_tests/unit_test_wb_glm.cc.bak @@ -0,0 +1,253 @@ +/* + Copyright (C) 2020 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 . + */ + +#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#include "doctest/doctest.h" + +#include "glm/glm.h" + +#include "world_builder/coordinate_system.h" +#include "world_builder/utilities.h" + +#include + +using namespace WorldBuilder; +using doctest::Approx; + + +/** + * Compare the given two std::array entries with an epsilon (using Catch::Approx) + */ +inline void compare_3d_arrays_approx( + const std::array &computed, + const std::array &expected) +{ + CHECK(computed.size() == expected.size()); + for (unsigned int i=0; i< computed.size(); ++i) + { + INFO("vector index i=" << i << ": "); + CHECK(computed[i] == Approx(expected[i])); + } +} + +/** + * Compare two rotation matrices + */ +inline void compare_rotation_matrices_approx( + const std::array,3> &computed, + const std::array,3> &expected) +{ + // sign of eigenvector is not important + INFO("rotation matrices are not the same: \n" << + "expected = " << expected[0][0] << ' ' << expected[0][1] << ' ' << expected[0][2] << "\n" << + " " << expected[1][0] << ' ' << expected[1][1] << ' ' << expected[1][2] << "\n" << + " " << expected[2][0] << ' ' << expected[2][1] << ' ' << expected[2][2] << "\n" << + "computed = " << computed[0][0] << ' ' << computed[0][1] << ' ' << computed[0][2] << "\n" << + " " << computed[1][0] << ' ' << computed[1][1] << ' ' << computed[1][2] << "\n" << + " " << computed[2][0] << ' ' << computed[2][1] << ' ' << computed[2][2] << "\n" ); + CHECK(( + (computed[0][0] == Approx(expected[0][0]) && computed[0][1] == Approx(expected[0][1]) && computed[0][2] == Approx(expected[0][2]) && + computed[1][0] == Approx(expected[1][0]) && computed[1][1] == Approx(expected[1][1]) && computed[1][2] == Approx(expected[1][2]) && + computed[2][0] == Approx(expected[2][0]) && computed[2][1] == Approx(expected[2][1]) && computed[2][2] == Approx(expected[2][2])) + || + (computed[0][0] == Approx(-expected[0][0]) && computed[0][1] == Approx(-expected[0][1]) && computed[0][2] == Approx(-expected[0][2]) && + computed[1][0] == Approx(-expected[1][0]) && computed[1][1] == Approx(-expected[1][1]) && computed[1][2] == Approx(-expected[1][2]) && + computed[2][0] == Approx(-expected[2][0]) && computed[2][1] == Approx(-expected[2][1]) && computed[2][2] == Approx(-expected[2][2])))); +} + +inline +void +compare_quaternions( + const glm::quaternion::quat &computed, + const glm::quaternion::quat &expected +) +{ + CHECK(computed.w == Approx(expected.w)); + CHECK(computed.x == Approx(expected.x)); + CHECK(computed.y == Approx(expected.y)); + CHECK(computed.z == Approx(expected.z)); +} + +TEST_CASE("glm quat basic functions") +{ + typedef glm::quaternion::quat QT; + QT q1(2,3,4,5); + QT const q2(6,7,8,9); + QT const q3(9,8,7,6); + + + QT q_res = -q1; + compare_quaternions(q_res, QT(-2,-3,-4,-5)); + + q_res = q1 + q2; + compare_quaternions(q_res, QT(8,10,12,14)); + + q_res = q2 - q1; + compare_quaternions(q_res, QT(-4,-4,-4,-4)); + q_res = q3 - q1; + compare_quaternions(q_res, QT(-7,-5,-3,-1)); + + + q_res = q1 * 2.0; + compare_quaternions(q_res, QT(4,6,8,10)); + q_res = 2.0 * q1; + compare_quaternions(q_res, QT(4,6,8,10)); + + + q_res = (2.0 * q1) / 2.0; + compare_quaternions(q_res, q1); + + CHECK(glm::quaternion::dot(q1,q2) == Approx(110.0)); + CHECK(glm::quaternion::dot(q2,q3) == Approx(220.0)); + CHECK(glm::quaternion::dot(q2,-q3) == Approx(-220.0)); + CHECK(glm::quaternion::dot(-q2,-q3) == Approx(220.0)); + + double res = glm::quaternion::mix(0.0,1.0,0.0); + CHECK(res == Approx(0.0)); + + res = glm::quaternion::mix(0.0,1.0,0.25); + CHECK(res == Approx(Approx(0.25))); + + res = glm::quaternion::mix(0.0,1.0,0.5); + CHECK(res == Approx(0.5)); + + res = glm::quaternion::mix(0.0,1.0,0.75); + CHECK(res == Approx(0.75)); + + res = glm::quaternion::mix(0.0,1.0,1.0); + CHECK(res == Approx(1.0)); + + + res = glm::quaternion::mix(1.0,0.0,0.0); + CHECK(res == Approx(1.0)); + + res = glm::quaternion::mix(1.0,0.0,0.25); + CHECK(res == Approx(0.75)); + + res = glm::quaternion::mix(1.0,0.0,0.5); + CHECK(res == Approx(0.5)); + + res = glm::quaternion::mix(1.0,0.0,0.75); + CHECK(res == Approx(0.25)); + + res = glm::quaternion::mix(1.0,0.0,1.0); + CHECK(res == Approx(0.0)); + + + res = glm::quaternion::mix(-3.0,1.0,0.0); + CHECK(res == Approx(-3.0)); + + res = glm::quaternion::mix(-3.0,1.0,0.25); + CHECK(res == Approx(-2.0)); + + res = glm::quaternion::mix(-3.0,1.0,0.5); + CHECK(res == Approx(-1.0)); + + res = glm::quaternion::mix(-3.0,1.0,0.75); + CHECK(res == Approx(0.0)); + + res = glm::quaternion::mix(-3.0,1.0,1.0); + CHECK(res == Approx(1.0)); + +} + +TEST_CASE("glm quat slerp functions") +{ + { + // This shows that two equal rotation matrices average in the same rotation matrix + const std::array,3> rot1 = {{{{0.36,0.48,-0.8}},{{-0.8,0.6,0}}, {{0.48,0.64, 0.6}}}}; //{{normalize({{1,2,3}}),normalize({{4,5,6}}),normalize({{7,8,9}})}}; + const glm::quaternion::quat quat_current = glm::quaternion::quat_cast(rot1); + const glm::quaternion::quat quat_next = glm::quaternion::quat_cast(rot1); + + const glm::quaternion::quat quat_average = glm::quaternion::slerp(quat_current,quat_next,0.5); + + const std::array,3> result1 = glm::quaternion::mat3_cast(quat_average); + + auto ea1 = Utilities::euler_angles_from_rotation_matrix(rot1); + auto ear = Utilities::euler_angles_from_rotation_matrix(result1); + + compare_rotation_matrices_approx(result1, rot1); + compare_3d_arrays_approx(ea1,ear); + } + + { + // This shows that a very small difference in the rotation matrix causes a very small difference in the resulting rotation matrix. + const std::array,3> rot1 = {{{{0.360000,0.480000,-0.800000}},{{-0.800000,0.600000,0.000000000}}, {{0.480000,0.640000, 0.600000}}}}; + const std::array,3> rot2 = {{{{0.350000,0.480000,-0.800000}},{{-0.800000,0.600000,0.000000000}}, {{0.480000,0.640000, 0.600000}}}}; + const std::array,3> expt = {{{{0.358571,0.479818,-0.800533}},{{-0.800533,0.599107,0.000627009}}, {{0.479818,0.640802, 0.599107}}}}; + + const glm::quaternion::quat quat_current = glm::quaternion::quat_cast(rot1); + const glm::quaternion::quat quat_next = glm::quaternion::quat_cast(rot2); + + const glm::quaternion::quat quat_average = glm::quaternion::slerp(quat_current,quat_next,0.5); + + const std::array,3> result1 = glm::quaternion::mat3_cast(quat_average); + + compare_rotation_matrices_approx(result1, expt); + } + + { + // This shows that a small difference in the rotation matrix causes a small difference in the resulting rotation matrix. + const std::array,3> rot1 = {{{{0.360000,0.480000,-0.800000}},{{-0.800000,0.600000,0.000000000}}, {{0.480000,0.640000, 0.600000}}}}; + const std::array,3> rot2 = {{{{0.300000,0.480000,-0.800000}},{{-0.800000,0.600000,0.000000000}}, {{0.480000,0.640000, 0.600000}}}}; + const std::array,3> expt = {{{{0.351289,0.478886,-0.803242}},{{-0.803242,0.594555,0.00382358}}, {{0.478886,0.644888, 0.594555}}}}; + + const glm::quaternion::quat quat_current = glm::quaternion::quat_cast(rot1); + const glm::quaternion::quat quat_next = glm::quaternion::quat_cast(rot2); + + const glm::quaternion::quat quat_average = glm::quaternion::slerp(quat_current,quat_next,0.5); + + const std::array,3> result1 = glm::quaternion::mat3_cast(quat_average); + + compare_rotation_matrices_approx(result1, expt); + } + + { + // This shows that a small difference in the rotation matrix causes a small difference in the resulting rotation matrix. + const std::array,3> rot1 = {{{{0.360000,0.480000,-0.800000}},{{-0.800000,0.600000,0.000000000}}, {{0.480000,0.640000, 0.600000}}}}; + const std::array,3> rot2 = {{{{0.300000,0.450000,-0.800000}},{{-0.800000,0.600000,0.000000000}}, {{0.480000,0.640000, 0.600000}}}}; + const std::array,3> expt = {{{{0.35767,0.472227,-0.802856}},{{-0.7972,0.6014,0.000000000}}, {{0.481714,0.642285, 0.593783}}}}; + + const glm::quaternion::quat quat_current = glm::quaternion::quat_cast(rot1); + const glm::quaternion::quat quat_next = glm::quaternion::quat_cast(rot2); + + const glm::quaternion::quat quat_average = glm::quaternion::slerp(quat_current,quat_next,0.5); + + const std::array,3> result1 = glm::quaternion::mat3_cast(quat_average); + + compare_rotation_matrices_approx(result1, expt); + } + + { + // This shows that a significant difference in the rotation matrix causes a significant difference in the resulting rotation matrix. + const std::array,3> rot1 = {{{{0.360000,0.480000,-0.800000}},{{-0.800000,0.600000,0.000000000}}, {{0.480000,0.640000, 0.600000}}}}; + const std::array,3> rot2 = {{{{0.200000,0.250000,-0.400000}},{{-0.500000,0.200000,0.300000000}}, {{0.380000,0.840000, 0.500000}}}}; + const std::array,3> expt = {{{{0.493495,0.403007,-0.707894}},{{-0.70133,0.664351,-0.0720395}}, {{0.414325,0.578479, 0.656215}}}}; + + const glm::quaternion::quat quat_current = glm::quaternion::quat_cast(rot1); + const glm::quaternion::quat quat_next = glm::quaternion::quat_cast(rot2); + + const glm::quaternion::quat quat_average = glm::quaternion::slerp(quat_current,quat_next,0.5); + + const std::array,3> result1 = glm::quaternion::mat3_cast(quat_average); + + compare_rotation_matrices_approx(result1, expt); + } +} \ No newline at end of file diff --git a/contrib/world_builder/tests/unit_tests/unit_test_world_builder.cc.bak b/contrib/world_builder/tests/unit_tests/unit_test_world_builder.cc.bak new file mode 100644 index 00000000000..c3fe430775a --- /dev/null +++ b/contrib/world_builder/tests/unit_tests/unit_test_world_builder.cc.bak @@ -0,0 +1,7780 @@ +/* + Copyright (C) 2018 - 2021 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 . + */ + +#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#include "ApprovalTests/ApprovalTests.hpp" +#include "doctest/doctest.h" + +#include "world_builder/config.h" +#include "world_builder/consts.h" +#include "world_builder/coordinate_system.h" +#include "world_builder/coordinate_systems/cartesian.h" +#include "world_builder/coordinate_systems/interface.h" +#include "world_builder/coordinate_systems/invalid.h" +#include "world_builder/features/continental_plate.h" +#include "world_builder/features/interface.h" +#include "world_builder/grains.h" +#include "world_builder/objects/natural_coordinate.h" +#include "world_builder/objects/segment.h" +#include "world_builder/objects/surface.h" +#include "world_builder/parameters.h" +#include "world_builder/point.h" +#include "world_builder/types/array.h" +#include "world_builder/types/bool.h" +#include "world_builder/types/double.h" +#include "world_builder/types/interface.h" +#include "world_builder/types/object.h" +#include "world_builder/types/one_of.h" +#include "world_builder/types/plugin_system.h" +#include "world_builder/types/point.h" +#include "world_builder/types/segment.h" +#include "world_builder/types/string.h" +#include "world_builder/types/unsigned_int.h" +#include "world_builder/types/value_at_points.h" +#include "world_builder/utilities.h" +#include "world_builder/world.h" + + +extern "C" { +#include "world_builder/wrapper_c.h" +} +#include "world_builder/wrapper_cpp.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace WorldBuilder +{ + namespace Features + { + namespace FaultModels + { + namespace Composition + { + class Interface; + } // namespace Composition + namespace Grains + { + class Interface; + } // namespace Grains + namespace Temperature + { + class Interface; + } // namespace Temperature + } // namespace FaultModels + } // namespace Features +} // namespace WorldBuilder + +using namespace WorldBuilder; +using doctest::Approx; +using doctest::Contains; + +/** + * normalize 3d array + */ +inline +std::array normalize(std::array array) +{ + const double norm = sqrt(array[0] * array[0] + array[1] * array[1] + array[2] * array[2]); + return {{array[0]/norm,array[1]/norm,array[2]/norm}}; +} + +/** + * Compare the given two std::vector entries with an epsilon (using Catch::Approx) + */ +inline void compare_vectors_approx( + const std::vector &computed, + const std::vector &expected) +{ + CHECK(computed.size() == expected.size()); + for (unsigned int i=0; i< computed.size(); ++i) + { + INFO("vector index i=" << i << ": "); + CHECK(computed[i] == Approx(expected[i])); + } +} + +/** + * Compare the given two std::array entries with an epsilon (using Catch::Approx) + */ +inline void compare_3d_arrays_approx( + const std::array &computed, + const std::array &expected) +{ + CHECK(computed.size() == expected.size()); + for (unsigned int i=0; i< computed.size(); ++i) + { + INFO("vector index i=" << i << ": "); + CHECK(computed[i] == Approx(expected[i])); + } +} + +/** + * Compare the given two std::vector,3> > entries with an epsilon (using Catch::Approx) + */ +inline void compare_vectors_array3_array3_approx( + const std::vector,3> > &computed, + const std::vector,3> > &expected) +{ + CHECK(computed.size() == expected.size()); + for (unsigned int i=0; i< computed.size(); ++i) + { + CHECK(computed[i].size() == expected[i].size()); + for (unsigned int j=0; j< computed[i].size(); ++j) + { + CHECK(computed[i][j].size() == expected[i][j].size()); + for (unsigned int k=0; k< computed[i][j].size(); ++k) + { + INFO("vector index i:j:k = " << i << ':' << j << ':' << k << std::setprecision(10) + << " = computed: " << computed[i][j][k] << ", expected: " << expected[i][j][k] + << ", diff = " << computed[i][j][k] - expected[i][j][k] << ", eps = " << 1e-10); + CHECK(std::fabs(computed[i][j][k] - expected[i][j][k]) <= 1e-10); + } + } + } +} + +/** + * Compare two rotation matrices + */ +inline void compare_rotation_matrices_approx( + const std::array,3> &computed, + const std::array,3> &expected) +{ + // sign of eigenvector is not important + INFO("rotation matrices are not the same: \n" << + "expected = " << expected[0][0] << ' ' << expected[0][1] << ' ' << expected[0][2] << "\n" << + " " << expected[1][0] << ' ' << expected[1][1] << ' ' << expected[1][2] << "\n" << + " " << expected[2][0] << ' ' << expected[2][1] << ' ' << expected[2][2] << "\n" << + "computed = " << computed[0][0] << ' ' << computed[0][1] << ' ' << computed[0][2] << "\n" << + " " << computed[1][0] << ' ' << computed[1][1] << ' ' << computed[1][2] << "\n" << + " " << computed[2][0] << ' ' << computed[2][1] << ' ' << computed[2][2] << "\n"); + CHECK(( + (computed[0][0] == Approx(expected[0][0]) && computed[0][1] == Approx(expected[0][1]) && computed[0][2] == Approx(expected[0][2]) && + computed[1][0] == Approx(expected[1][0]) && computed[1][1] == Approx(expected[1][1]) && computed[1][2] == Approx(expected[1][2]) && + computed[2][0] == Approx(expected[2][0]) && computed[2][1] == Approx(expected[2][1]) && computed[2][2] == Approx(expected[2][2])) + || + (computed[0][0] == Approx(-expected[0][0]) && computed[0][1] == Approx(-expected[0][1]) && computed[0][2] == Approx(-expected[0][2]) && + computed[1][0] == Approx(-expected[1][0]) && computed[1][1] == Approx(-expected[1][1]) && computed[1][2] == Approx(-expected[1][2]) && + computed[2][0] == Approx(-expected[2][0]) && computed[2][1] == Approx(-expected[2][1]) && computed[2][2] == Approx(-expected[2][2])))); +} + + +TEST_CASE("WorldBuilder Point: Testing initialize and operators") +{ + std::vector approval_tests; + + // Test initialization of the Point class + Point<2> p2(cartesian); + Point<3> p3(cartesian); + + CHECK(p2.get_array() == std::array {{0,0}}); + CHECK(p3.get_array() == std::array {{0,0,0}}); + + const Point<2> p2_array(std::array {{1,2}},cartesian); + const Point<3> p3_array(std::array {{1,2,3}},cartesian); + + CHECK(p2_array.get_array() == std::array {{1,2}}); + CHECK(p3_array.get_array() == std::array {{1,2,3}}); + + const Point<2> &p2_point(p2_array); + const Point<3> &p3_point(p3_array); + + CHECK(p2_point.get_array() == std::array {{1,2}}); + CHECK(p3_point.get_array() == std::array {{1,2,3}}); + + const Point<2> p2_explicit(3,4,cartesian); + const Point<3> p3_explicit(4,5,6,cartesian); + + CHECK(p2_explicit.get_array() == std::array {{3,4}}); + CHECK(p3_explicit.get_array() == std::array {{4,5,6}}); + + + // Test Point operators + + // Test assign operator + p2 = p2_array; + p3 = p3_array; + + CHECK(p2.get_array() == std::array {{1,2}}); + CHECK(p3.get_array() == std::array {{1,2,3}}); + + // Test multiply operator + p2 = 2 * p2 * 1.0; + p3 = 2 * p3 * 1.0; + + CHECK(p2.get_array() == std::array {{2,4}}); + CHECK(p3.get_array() == std::array {{2,4,6}}); + + p2 *= 2; + p3 *= 2; + + CHECK(p2.get_array() == std::array {{4,8}}); + CHECK(p3.get_array() == std::array {{4,8,12}}); + + // Test dot operator + approval_tests.emplace_back(p2_array * p2_explicit); + approval_tests.emplace_back(p3_array * p3_explicit); + + // Test add operator + p2 = p2 + p2; + p3 = p3 + p3; + + CHECK(p2.get_array() == std::array {{8,16}}); + CHECK(p3.get_array() == std::array {{8,16,24}}); + + p2 += p2; + p3 += p3; + + CHECK(p2.get_array() == std::array {{16,32}}); + CHECK(p3.get_array() == std::array {{16,32,48}}); + + // Test subtract operator + p2 = p2 - (0.5 * p2); + p3 = p3 - (0.5 * p3); + + CHECK(p2.get_array() == std::array {{8,16}}); + CHECK(p3.get_array() == std::array {{8,16,24}}); + + p2 -= (0.5 * p2); + p3 -= (0.5 * p3); + + CHECK(p2.get_array() == std::array {{4,8}}); + CHECK(p3.get_array() == std::array {{4,8,12}}); + + // Test coordinate system + //approval_tests.emplace_back(p2.get_coordinate_system()); + //approval_tests.emplace_back(p3.get_coordinate_system()); + + // Test norm and norm_square + approval_tests.emplace_back(p2.norm_square()); + approval_tests.emplace_back(p3.norm_square()); + + approval_tests.emplace_back(p2.norm()); + approval_tests.emplace_back(p3.norm()); + + // Test Point utility classes + const std::array an2 = Utilities::convert_point_to_array(p2_point); + const std::array an3 = Utilities::convert_point_to_array(p3_point); + + CHECK(an2 == std::array {{1,2}}); + CHECK(an3 == std::array {{1,2,3}}); + + CHECK_THROWS_WITH(Point<2>(1,2,3,cartesian),Contains("Can't use the 3d constructor in 2d.")); + CHECK_THROWS_WITH(Point<3>(1,2,cartesian),Contains("Can't use the 2d constructor in 3d.")); + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + + +TEST_CASE("WorldBuilder Utilities: string to conversions") +{ + // Test string to number conversion + CHECK(Utilities::string_to_double("1") == Approx(1.0)); + CHECK(Utilities::string_to_double(" 1 ") == Approx(1.0)); + CHECK(Utilities::string_to_double(" 1.01 ") == Approx(1.01)); + + CHECK_THROWS_WITH(Utilities::string_to_double("1a"), + Contains("Could not convert \"1a\" to a double.")); + CHECK_THROWS_WITH(Utilities::string_to_double("a1"), + Contains("Could not convert \"a1\" to a double.")); + CHECK_THROWS_WITH(Utilities::string_to_double("a"), + Contains("Could not convert \"a\" to a double.")); + + CHECK(Utilities::string_to_int("2") == Approx(2.0)); + CHECK(Utilities::string_to_int(" 2 ") == Approx(2.0)); + + CHECK_THROWS_WITH(Utilities::string_to_int(" 2.02 "), + Contains("Could not convert \"2.02\" to an int.")); + CHECK_THROWS_WITH(Utilities::string_to_int("2b"), + Contains("Could not convert \"2b\" to an int.")); + CHECK_THROWS_WITH(Utilities::string_to_int("b2"), + Contains("Could not convert \"b2\" to an int.")); + CHECK_THROWS_WITH(Utilities::string_to_int("b"), + Contains("Could not convert \"b\" to an int.")); + + CHECK(Utilities::string_to_unsigned_int("3") == Approx(3.0)); + CHECK(Utilities::string_to_unsigned_int(" 3 ") == Approx(3.0)); + + CHECK_THROWS_WITH(Utilities::string_to_unsigned_int(" 3.03 "), + Contains("Could not convert \"3.03\" to an unsigned int.")); + CHECK_THROWS_WITH(Utilities::string_to_unsigned_int("3c"), + Contains("Could not convert \"3c\" to an unsigned int.")); + CHECK_THROWS_WITH(Utilities::string_to_unsigned_int("c3"), + Contains("Could not convert \"c3\" to an unsigned int.")); + CHECK_THROWS_WITH(Utilities::string_to_unsigned_int("c"), + Contains("Could not convert \"c\" to an unsigned int.")); + + // Test point to array conversion + const Point<2> p2(1,2,cartesian); + const Point<3> p3(1,2,3,cartesian); + + CHECK(Utilities::convert_point_to_array(p2) == std::array {{1,2}}); + CHECK(Utilities::convert_point_to_array(p3) == std::array {{1,2,3}}); + + // Test coordinate system + CHECK(Utilities::string_to_coordinate_system("cartesian") == CoordinateSystem::cartesian); + CHECK(Utilities::string_to_coordinate_system("spherical") == CoordinateSystem::spherical); + CHECK_THROWS_WITH(Utilities::string_to_coordinate_system("other"), Contains("Coordinate system not implemented.")); +} + + +TEST_CASE("WorldBuilder Utilities: interpolation") +{ + std::vector approval_tests; + + std::vector x = {{0,1,2,3}}; + std::vector y = {{10,5,5,35}}; + + Utilities::interpolation monotone_cubic_spline; + monotone_cubic_spline.set_points(y); + + approval_tests.emplace_back(monotone_cubic_spline(-1)); + approval_tests.emplace_back(monotone_cubic_spline(-0.9)); + approval_tests.emplace_back(monotone_cubic_spline(-0.7)); + approval_tests.emplace_back(monotone_cubic_spline(-0.5)); + approval_tests.emplace_back(monotone_cubic_spline(-0.3)); + approval_tests.emplace_back(monotone_cubic_spline(-0.1)); + approval_tests.emplace_back(monotone_cubic_spline(0)); + approval_tests.emplace_back(monotone_cubic_spline(0.1)); + approval_tests.emplace_back(monotone_cubic_spline(0.3)); + approval_tests.emplace_back(monotone_cubic_spline(0.5)); + approval_tests.emplace_back(monotone_cubic_spline(0.7)); + approval_tests.emplace_back(monotone_cubic_spline(0.9)); + approval_tests.emplace_back(monotone_cubic_spline(1)); + approval_tests.emplace_back(monotone_cubic_spline(1.1)); + approval_tests.emplace_back(monotone_cubic_spline(1.3)); + approval_tests.emplace_back(monotone_cubic_spline(1.5)); + approval_tests.emplace_back(monotone_cubic_spline(1.7)); + approval_tests.emplace_back(monotone_cubic_spline(1.9)); + approval_tests.emplace_back(monotone_cubic_spline(2)); + approval_tests.emplace_back(monotone_cubic_spline(2.025)); + approval_tests.emplace_back(monotone_cubic_spline(2.075)); + approval_tests.emplace_back(monotone_cubic_spline(2.125)); + approval_tests.emplace_back(monotone_cubic_spline(2.175)); + approval_tests.emplace_back(monotone_cubic_spline(2.225)); + approval_tests.emplace_back(monotone_cubic_spline(2.25)); + approval_tests.emplace_back(monotone_cubic_spline(2.275)); + approval_tests.emplace_back(monotone_cubic_spline(2.325)); + approval_tests.emplace_back(monotone_cubic_spline(2.375)); + approval_tests.emplace_back(monotone_cubic_spline(2.425)); + approval_tests.emplace_back(monotone_cubic_spline(2.475)); + approval_tests.emplace_back(monotone_cubic_spline(2.5)); + approval_tests.emplace_back(monotone_cubic_spline(2.625)); + approval_tests.emplace_back(monotone_cubic_spline(2.75)); + approval_tests.emplace_back(monotone_cubic_spline(2.875)); + approval_tests.emplace_back(monotone_cubic_spline(3)); + approval_tests.emplace_back(monotone_cubic_spline(3.125)); + approval_tests.emplace_back(monotone_cubic_spline(3.25)); + + Utilities::interpolation monotone_cubic_spline2; + y[1] = -5; + y[3] = -35; + monotone_cubic_spline2.set_points(y); + approval_tests.emplace_back(monotone_cubic_spline2(-1)); + approval_tests.emplace_back(monotone_cubic_spline2(-0.5)); + approval_tests.emplace_back(monotone_cubic_spline2(0)); + approval_tests.emplace_back(monotone_cubic_spline2(0.5)); + approval_tests.emplace_back(monotone_cubic_spline2(1)); + approval_tests.emplace_back(monotone_cubic_spline2(1.5)); + approval_tests.emplace_back(monotone_cubic_spline2(2)); + approval_tests.emplace_back(monotone_cubic_spline2(2.125) == Approx(3.828125)); + approval_tests.emplace_back(monotone_cubic_spline2(2.25)); + approval_tests.emplace_back(monotone_cubic_spline2(2.375) == Approx(-4.140625)); + approval_tests.emplace_back(monotone_cubic_spline2(2.5)); + approval_tests.emplace_back(monotone_cubic_spline2(2.625)); + approval_tests.emplace_back(monotone_cubic_spline2(2.75)); + approval_tests.emplace_back(monotone_cubic_spline2(2.875)); + approval_tests.emplace_back(monotone_cubic_spline2(3)); + approval_tests.emplace_back(monotone_cubic_spline2(3.125)); + approval_tests.emplace_back(monotone_cubic_spline2(3.25)); + + Utilities::interpolation monotone_cubic_spline3; + y[0] = 10; + y[1] = -5; + y[2] = -10; + y[3] = -35; + monotone_cubic_spline3.set_points(y); + approval_tests.emplace_back(monotone_cubic_spline3(-1)); + approval_tests.emplace_back(monotone_cubic_spline3(-0.5)); + approval_tests.emplace_back(monotone_cubic_spline3(0)); + approval_tests.emplace_back(monotone_cubic_spline3(0.5)); + approval_tests.emplace_back(monotone_cubic_spline3(1)); + approval_tests.emplace_back(monotone_cubic_spline3(1.5)); + approval_tests.emplace_back(monotone_cubic_spline3(2)); + approval_tests.emplace_back(monotone_cubic_spline3(2.125)); + approval_tests.emplace_back(monotone_cubic_spline3(2.25) == Approx(-13.90625)); + approval_tests.emplace_back(monotone_cubic_spline3(2.375)); + approval_tests.emplace_back(monotone_cubic_spline3(2.5)); + approval_tests.emplace_back(monotone_cubic_spline3(2.625)); + approval_tests.emplace_back(monotone_cubic_spline3(2.75)); + approval_tests.emplace_back(monotone_cubic_spline3(2.875)); + approval_tests.emplace_back(monotone_cubic_spline3(3)); + approval_tests.emplace_back(monotone_cubic_spline3(3.125)); + approval_tests.emplace_back(monotone_cubic_spline3(3.25)); + + // bi monotone cubic spline + Utilities::interpolation monotone_cubic_spline_x; + Utilities::interpolation monotone_cubic_spline_y; + x[0] = 0; + x[1] = 1; + x[2] = 2; + x[3] = 3; + y[0] = 10; + y[1] = 10; + y[2] = 5; + y[3] = 0; + monotone_cubic_spline_x.set_points(y); + y[0] = 0; + y[1] = 5; + y[2] = 10; + y[3] = 10; + monotone_cubic_spline_y.set_points(y); + + approval_tests.emplace_back(monotone_cubic_spline_x(0)); + approval_tests.emplace_back(monotone_cubic_spline_x(0.25)); + approval_tests.emplace_back(monotone_cubic_spline_x(0.5)); + approval_tests.emplace_back(monotone_cubic_spline_x(0.75)); + approval_tests.emplace_back(monotone_cubic_spline_x(1)); + approval_tests.emplace_back(monotone_cubic_spline_x(1.25) == Approx(9.453125)); + approval_tests.emplace_back(monotone_cubic_spline_x(1.5)); + approval_tests.emplace_back(monotone_cubic_spline_x(1.75)); + approval_tests.emplace_back(monotone_cubic_spline_x(2)); + approval_tests.emplace_back(monotone_cubic_spline_x(2.25)); + approval_tests.emplace_back(monotone_cubic_spline_x(2.5)); + approval_tests.emplace_back(monotone_cubic_spline_x(2.75)); + approval_tests.emplace_back(monotone_cubic_spline_x(3)); + + approval_tests.emplace_back(monotone_cubic_spline_y(0)); + approval_tests.emplace_back(monotone_cubic_spline_y(0.25)); + approval_tests.emplace_back(monotone_cubic_spline_y(0.5)); + approval_tests.emplace_back(monotone_cubic_spline_y(0.75) == Approx(3.515625)); + approval_tests.emplace_back(monotone_cubic_spline_y(1)); + approval_tests.emplace_back(monotone_cubic_spline_y(1.25)); + approval_tests.emplace_back(monotone_cubic_spline_y(1.5)); + approval_tests.emplace_back(monotone_cubic_spline_y(1.75) == Approx(9.453125)); + approval_tests.emplace_back(monotone_cubic_spline_y(2)); + approval_tests.emplace_back(monotone_cubic_spline_y(2.25)); + approval_tests.emplace_back(monotone_cubic_spline_y(2.5)); + approval_tests.emplace_back(monotone_cubic_spline_y(2.75)); + approval_tests.emplace_back(monotone_cubic_spline_y(3)); + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("WorldBuilder Utilities: Point in polygon") +{ + std::vector > point_list_4_elements(4, Point<2>(cartesian)); + point_list_4_elements[0] = Point<2>(0,0,cartesian); + point_list_4_elements[1] = Point<2>(5,0,cartesian); + point_list_4_elements[2] = Point<2>(5,5,cartesian); + point_list_4_elements[3] = Point<2>(0,5,cartesian); + + std::vector > point_list_3_elements(3, Point<2>(cartesian)); + point_list_3_elements[0] = Point<2>(10,10,cartesian); + point_list_3_elements[1] = Point<2>(10,15,cartesian); + point_list_3_elements[2] = Point<2>(15,15,cartesian); + + std::vector > check_points(9, Point<2>(cartesian)); + check_points[0] = Point<2>(-1,-1,cartesian); + check_points[1] = Point<2>(0,0,cartesian); + check_points[2] = Point<2>(0,5,cartesian); + check_points[3] = Point<2>(5,0,cartesian); + check_points[4] = Point<2>(5,5,cartesian); + check_points[5] = Point<2>(5,5.01,cartesian); + check_points[6] = Point<2>(1,1,cartesian); + check_points[7] = Point<2>(12.5,12,cartesian); + check_points[8] = Point<2>(11.5,12,cartesian); + + std::vector > answers(9); + answers[0] = {{false,false}}; + answers[1] = {{true,false}}; + answers[2] = {{true,false}}; + answers[3] = {{true,false}}; + answers[4] = {{true,false}}; + answers[5] = {{false,false}}; + answers[6] = {{true,false}}; + answers[7] = {{false,false}}; + answers[8] = {{false,true}}; + + std::vector > answers_signed_distance(9); + answers_signed_distance[0] = {{-std::sqrt(2), -std::sqrt(11 * 11 + 11 * 11)}}; + answers_signed_distance[1] = {{0,-std::sqrt(10 * 10 + 10 * 10)}}; + answers_signed_distance[2] = {{0,-std::sqrt(125)}}; + answers_signed_distance[3] = {{0,-std::sqrt(125)}}; + answers_signed_distance[4] = {{0,-std::sqrt(50)}}; + answers_signed_distance[5] = {{-std::sqrt(0.01 * 0.01),-std::sqrt(5 * 5 + 4.99 * 4.99)}}; + answers_signed_distance[6] = {{1,-std::sqrt(9 * 9 + 9 * 9)}}; + answers_signed_distance[7] = {{-10.2591422643,-0.3535533906}}; + answers_signed_distance[8] = {{-9.5524865873,0.3535533906}}; + + for (unsigned int i = 0; i < check_points.size(); ++i) + { + INFO("checking point " << i << " = (" << check_points[i][0] << ':' << check_points[i][1] << ')'); + CHECK(Utilities::polygon_contains_point(point_list_4_elements,check_points[i]) == answers[i][0]); + CHECK(Utilities::polygon_contains_point(point_list_3_elements,check_points[i]) == answers[i][1]); + CHECK(Utilities::signed_distance_to_polygon(point_list_4_elements,check_points[i]) == Approx(answers_signed_distance[i][0])); + CHECK(Utilities::signed_distance_to_polygon(point_list_3_elements,check_points[i]) == Approx(answers_signed_distance[i][1])); + } + + const std::vector > point_list_2_elements(2, Point<2>(cartesian)); + CHECK_THROWS_WITH(Utilities::signed_distance_to_polygon(point_list_2_elements,check_points[0]), + Contains("Not enough polygon points were specified.")); + + const std::vector > point_list_1_elements(1, Point<2>(cartesian)); + CHECK_THROWS_WITH(Utilities::signed_distance_to_polygon(point_list_1_elements,check_points[0]), + Contains("Not enough polygon points were specified.")); + + const std::vector > point_list_0_elements(0, Point<2>(cartesian)); + CHECK_THROWS_WITH(Utilities::signed_distance_to_polygon(point_list_0_elements,check_points[0]), + Contains("Not enough polygon points were specified.")); +} + + +TEST_CASE("WorldBuilder Utilities: Natural Coordinate") +{ + std::vector approval_tests; + + // Cartesian + const std::unique_ptr cartesian(CoordinateSystems::Interface::create("cartesian",nullptr)); + + // Test the natural coordinate system + const Objects::NaturalCoordinate nca1(std::array {{1,2,3}},*cartesian); + CHECK(nca1.get_coordinates() == std::array {{1,2,3}}); + CHECK(nca1.get_surface_coordinates() == std::array {{1,2}}); + approval_tests.emplace_back(nca1.get_depth_coordinate()); + + const Objects::NaturalCoordinate ncp1(Point<3>(1,2,3,CoordinateSystem::cartesian),*cartesian); + CHECK(ncp1.get_coordinates() == std::array {{1,2,3}}); + CHECK(ncp1.get_surface_coordinates() == std::array {{1,2}}); + approval_tests.emplace_back(ncp1.get_depth_coordinate()); + + + const std::unique_ptr spherical(CoordinateSystems::Interface::create("spherical",nullptr)); + + // Test the natural coordinate system + const Objects::NaturalCoordinate nsa1(std::array {{1,2,3}},*spherical); + std::array nsa1_array = nsa1.get_coordinates(); + approval_tests.emplace_back(nsa1_array[0]); + approval_tests.emplace_back(nsa1_array[1]); + approval_tests.emplace_back(nsa1_array[2]); + std::array nsa1_surface_array = nsa1.get_surface_coordinates(); + approval_tests.emplace_back(nsa1_surface_array[0]); + approval_tests.emplace_back(nsa1_surface_array[1]); + approval_tests.emplace_back(nsa1.get_depth_coordinate()); + + + const Objects::NaturalCoordinate nsp1(Point<3>(1,2,3,CoordinateSystem::spherical),*spherical); + std::array nsp1_array = nsp1.get_coordinates(); + approval_tests.emplace_back(nsp1_array[0]); + approval_tests.emplace_back(nsp1_array[1]); + approval_tests.emplace_back(nsp1_array[2]); + std::array nsp1_surface_array = nsp1.get_surface_coordinates(); + approval_tests.emplace_back(nsp1_surface_array[0]); + approval_tests.emplace_back(nsp1_surface_array[1]); + approval_tests.emplace_back(nsp1.get_depth_coordinate()); + + // Invalid tests + const std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/subducting_plate_different_angles_cartesian.wb"; + WorldBuilder::World world(file_name); + Parameters prm(world); + std::unique_ptr invalid(new CoordinateSystems::Invalid(nullptr)); + invalid->parse_entries(prm); + Objects::NaturalCoordinate ivp1(Point<3>(1,2,3,CoordinateSystem::invalid),*invalid); + std::array ivp1_array = ivp1.get_coordinates(); + CHECK(std::isnan(ivp1_array[0])); + CHECK(std::isnan(ivp1_array[1])); + CHECK(std::isnan(ivp1_array[2])); + CHECK_THROWS_WITH(ivp1.get_surface_coordinates(),Contains("Coordinate system not implemented.")); + CHECK_THROWS_WITH(ivp1.get_surface_point(),Contains("Coordinate system not implemented.")); + CHECK_THROWS_WITH(ivp1.get_depth_coordinate(),Contains("Coordinate system not implemented.")); + CHECK_THROWS_WITH(ivp1.get_depth_coordinate(),Contains("Coordinate system not implemented.")); + CHECK_THROWS_WITH(ivp1.get_ref_depth_coordinate(),Contains("Coordinate system not implemented.")); + CHECK(std::isnan(invalid->distance_between_points_at_same_depth(Point<3>(1,2,3,CoordinateSystem::invalid), + Point<3>(1,2,3,CoordinateSystem::invalid)))); + approval_tests.emplace_back(invalid->depth_method()); + + std::array iv_array = invalid->natural_to_cartesian_coordinates({{1,2,3}}); + CHECK(std::isnan(iv_array[0])); + CHECK(std::isnan(iv_array[1])); + CHECK(std::isnan(iv_array[2])); + + CHECK(std::isnan(invalid->max_model_depth())); + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("WorldBuilder Utilities: Coordinate systems transformations") +{ + std::vector approval_tests; + + // Test coordinate system transformation + { + const Point<3> cartesian(3,4,5,CoordinateSystem::cartesian); + + const Point<3> spherical(Utilities::cartesian_to_spherical_coordinates(Point<3>(cartesian.get_array(),CoordinateSystem::cartesian)), CoordinateSystem::spherical); + + compare_vectors_approx(std::vector(std::begin(spherical.get_array()), std::end(spherical.get_array())), + std::vector {{std::sqrt(3*3+4*4+5*5),0.927295218001613,0.7853982}}); + + const Point<3> cartesian_back(Utilities::spherical_to_cartesian_coordinates(spherical.get_array()), CoordinateSystem::cartesian); + + compare_vectors_approx(std::vector(std::begin(cartesian_back.get_array()), std::end(cartesian_back.get_array())), + std::vector {{3,4,5}}); + } + + { + const Point<3> cartesian(-2,-1,6,CoordinateSystem::cartesian); + + const Point<3> spherical(Utilities::cartesian_to_spherical_coordinates(Point<3>(cartesian.get_array(),CoordinateSystem::cartesian)), CoordinateSystem::spherical); + + compare_vectors_approx(std::vector(std::begin(spherical.get_array()), std::end(spherical.get_array())), + std::vector {{std::sqrt(2*2+1*1+6*6),-2.6779450446,1.2140629383}}); + + const Point<3> cartesian_back(Utilities::spherical_to_cartesian_coordinates(spherical.get_array()), CoordinateSystem::cartesian); + + approval_tests.insert(approval_tests.end(), std::begin(cartesian_back.get_array()), std::end(cartesian_back.get_array())); + } + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); + +} + +TEST_CASE("WorldBuilder Utilities: cross product") +{ + const std::vector approval_tests; + + const Point<3> unit_x(1,0,0,cartesian); + const Point<3> unit_y(0,1,0,cartesian); + const Point<3> unit_z(0,0,1,cartesian); + + compare_3d_arrays_approx(Utilities::cross_product(unit_x, unit_x).get_array(), std::array {{0,0,0}}); + compare_3d_arrays_approx(Utilities::cross_product(unit_x, unit_y).get_array(), std::array {{0,0,1}}); + compare_3d_arrays_approx(Utilities::cross_product(unit_x, unit_z).get_array(), std::array {{0,-1,0}}); + + compare_3d_arrays_approx(Utilities::cross_product(unit_y, unit_x).get_array(), std::array {{0,0,-1}}); + compare_3d_arrays_approx(Utilities::cross_product(unit_y, unit_y).get_array(), std::array {{0,0,0}}); + compare_3d_arrays_approx(Utilities::cross_product(unit_y, unit_z).get_array(), std::array {{1,0,0}}); + + compare_3d_arrays_approx(Utilities::cross_product(unit_z, unit_x).get_array(), std::array {{0,1,0}}); + compare_3d_arrays_approx(Utilities::cross_product(unit_z, unit_y).get_array(), std::array {{-1,0,0}}); + compare_3d_arrays_approx(Utilities::cross_product(unit_z, unit_z).get_array(), std::array {{0,0,0}}); + + + const double sqrt2 = sqrt(0.5); + const Point<3> sqrt2_x(sqrt2,0,0,cartesian); + const Point<3> sqrt2_y(0,sqrt2,0,cartesian); + const Point<3> sqrt2_z(0,0,sqrt2,cartesian); + + const Point<3> unit_xy(sqrt2,sqrt2,0,cartesian); + const Point<3> unit_xz(sqrt2,0,sqrt2,cartesian); + const Point<3> unit_yz(0,sqrt2,sqrt2,cartesian); + + compare_3d_arrays_approx(Utilities::cross_product(unit_xy, sqrt2_x).get_array(), std::array {{0,0,-0.5}}); + compare_3d_arrays_approx(Utilities::cross_product(unit_xy, sqrt2_y).get_array(), std::array {{0,0,0.5}}); + compare_3d_arrays_approx(Utilities::cross_product(unit_xy, sqrt2_z).get_array(), std::array {{0.5,-0.5,0}}); + + compare_3d_arrays_approx(Utilities::cross_product(unit_xz, sqrt2_x).get_array(), std::array {{0,0.5,0}}); + compare_3d_arrays_approx(Utilities::cross_product(unit_xz, sqrt2_y).get_array(), std::array {{-0.5,0,0.5}}); + compare_3d_arrays_approx(Utilities::cross_product(unit_xz, sqrt2_z).get_array(), std::array {{0,-0.5,0}}); + + compare_3d_arrays_approx(Utilities::cross_product(unit_yz, sqrt2_x).get_array(), std::array {{0,0.5,-0.5}}); + compare_3d_arrays_approx(Utilities::cross_product(unit_yz, sqrt2_y).get_array(), std::array {{-0.5,0,0}}); + compare_3d_arrays_approx(Utilities::cross_product(unit_yz, sqrt2_z).get_array(), std::array {{0.5,0,0}}); + + const Point<3> point1(2,3,4,cartesian); + const Point<3> point2(5,6,7,cartesian); + + compare_3d_arrays_approx(Utilities::cross_product(point1, point2).get_array(), std::array {{-3,6,-3}}); + compare_3d_arrays_approx(Utilities::cross_product(point2, point1).get_array(), std::array {{3,-6,3}}); +} + +TEST_CASE("WorldBuilder C wrapper") +{ + std::vector approval_tests; + + // First test a world builder file with a cross section defined + std::string file = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/simple_wb1.json"; + void *ptr_world = nullptr; + void **ptr_ptr_world = &ptr_world; + const char *world_builder_file = file.c_str(); + bool has_output_dir = false; + + create_world(ptr_ptr_world, world_builder_file, &has_output_dir, "", 1); + + double temperature = 0.; + + temperature_2d(*ptr_ptr_world, 1, 2, 0, &temperature); + approval_tests.emplace_back(temperature); + temperature_3d(*ptr_ptr_world, 1, 2, 3, 0, &temperature); + approval_tests.emplace_back(temperature); + temperature_2d(*ptr_ptr_world, 550e3, 0, 0, &temperature); + approval_tests.emplace_back(temperature); + temperature_3d(*ptr_ptr_world, 120e3, 500e3, 0, 0, &temperature); + approval_tests.emplace_back(temperature); + + // Test the compositions + double composition = 0.0; + + composition_2d(*ptr_ptr_world, 1, 2, 0, 2, &composition); + approval_tests.emplace_back(composition); + composition_3d(*ptr_ptr_world, 1, 2, 3, 0, 2, &composition); + approval_tests.emplace_back(composition); + composition_2d(*ptr_ptr_world, 550e3, 0, 0, 3, &composition); + approval_tests.emplace_back(composition); + composition_3d(*ptr_ptr_world, 120e3, 500e3, 0, 0, 3, &composition); + approval_tests.emplace_back(composition); + + release_world(*ptr_ptr_world); + + // Now test a world builder file without a cross section defined + file = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/simple_wb2.json"; + ptr_world = nullptr; + ptr_ptr_world = &ptr_world; + const char *world_builder_file2 = file.c_str(); + has_output_dir = false; + + create_world(ptr_ptr_world, world_builder_file2, &has_output_dir, "", 1); + + + CHECK_THROWS_WITH(temperature_2d(*ptr_ptr_world, 1, 2, 0, &temperature), + Contains("This function can only be called when the cross section " + "variable in the world builder file has been set. Dim is 3.")); + temperature_3d(*ptr_ptr_world, 1, 2, 3, 0, &temperature); + approval_tests.emplace_back(temperature); + temperature_3d(*ptr_ptr_world, 120e3, 500e3, 0, 0, &temperature); + approval_tests.emplace_back(temperature); + + // Test the compositions + CHECK_THROWS_WITH(composition_2d(*ptr_ptr_world, 1, 2, 0, 2, &composition), + Contains("This function can only be called when the cross section " + "variable in the world builder file has been set. Dim is 3.")); + + composition_3d(*ptr_ptr_world, 1, 2, 3, 0, 2, &composition); + approval_tests.emplace_back(composition); + composition_3d(*ptr_ptr_world, 120e3, 500e3, 0, 0, 3, &composition); + approval_tests.emplace_back(composition); + + release_world(*ptr_ptr_world); + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("WorldBuilder CPP wrapper") +{ + std::vector approval_tests; + + // First test a world builder file with a cross section defined + std::string file = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/simple_wb1.json"; + + wrapper_cpp::WorldBuilderWrapper world(file); + + double temperature = 0; + + temperature = world.temperature_2d(1, 2, 0); + approval_tests.emplace_back(temperature); + temperature = world.temperature_3d(1, 2, 3, 0); + approval_tests.emplace_back(temperature); + temperature = world.temperature_2d(550e3, 0, 0); + approval_tests.emplace_back(temperature); + temperature = world.temperature_3d(120e3, 500e3, 0, 0); + approval_tests.emplace_back(temperature); + + // Test the compositions + double composition = 0.0; + + composition = world.composition_2d(1, 2, 0, 2); + approval_tests.emplace_back(composition); + composition = world.composition_3d(1, 2, 3, 0, 2); + approval_tests.emplace_back(composition); + composition = world.composition_2d(550e3, 0, 0, 3); + approval_tests.emplace_back(composition); + composition = world.composition_3d(120e3, 500e3, 0, 0, 3); + approval_tests.emplace_back(composition); + + + // Now test a world builder file without a cross section defined + file = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/simple_wb2.json"; + + wrapper_cpp::WorldBuilderWrapper world2(file); + + + CHECK_THROWS_WITH(world2.temperature_2d(1, 2, 0), + Contains("This function can only be called when the cross section " + "variable in the world builder file has been set. Dim is 3.")); + temperature = world2.temperature_3d(1, 2, 3, 0); + approval_tests.emplace_back(temperature); + temperature = world2.temperature_3d(120e3, 500e3, 0, 0); + approval_tests.emplace_back(temperature); + + // Test the compositions + CHECK_THROWS_WITH(world2.composition_2d(1, 2, 0, 2), + Contains("This function can only be called when the cross section " + "variable in the world builder file has been set. Dim is 3.")); + + composition = world2.composition_3d(1, 2, 3, 0, 2); + approval_tests.emplace_back(composition); + composition = world2.composition_3d(120e3, 500e3, 0, 0, 3); + approval_tests.emplace_back(composition); + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("WorldBuilder interface") +{ + + std::vector approval_tests_grains; + const std::string file = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/continental_plate.wb"; + const WorldBuilder::World world(file); + + CHECK_THROWS_WITH(world.properties({{1,2,3}},1., {{{{0,0,0}}}}),Contains("Unimplemented property provided. Only ")); + CHECK_THROWS_WITH(world.properties({{1,2,3}},1., {{{{5,0,0}}}}),Contains("Unimplemented property provided. Only ")); + + approval_tests_grains.emplace_back(world.grains(std::array {{750e3,250e3,100e3}},10e3,0,3)); + approval_tests_grains.emplace_back(world.grains(std::array {{750e3,100e3}},10e3,0,3)); + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests_grains); +} + +TEST_CASE("Worldbuilder grains") +{ + // creat a grains object + const WorldBuilder::grains grains; + + CHECK(grains.sizes.size() == 0); + CHECK(grains.rotation_matrices.size() == 0); +} + +TEST_CASE("WorldBuilder World random") +{ + std::vector approval_tests; + + // The world builder uses a deterministic random number generator. This is on prorpose + // because even though you might want to use random numbers, the result should be + // reproducible. Note that when the world builder is used in for example MPI programs + // you should supply the world builder created each MPI process a different seed. You + // can use the MPI RANK for this (seed is seed + MPI_RANK). Because the generator is + // deterministic (known and documented algorithm), we can test the results and they + // should be the same even for different compilers and machines. + const std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/oceanic_plate_spherical.wb"; + WorldBuilder::World world1(file_name, false, "", 1); + // same result as https://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine/seed + approval_tests.emplace_back(world1.get_random_number_engine()()); + approval_tests.emplace_back(world1.get_random_number_engine()()); + std::uniform_real_distribution<> dist(1.0,2.0); + approval_tests.emplace_back(dist(world1.get_random_number_engine())); + approval_tests.emplace_back(dist(world1.get_random_number_engine())); + + // test whether the seed indeed changes the resuls + WorldBuilder::World world2(file_name, false, "", 2); + approval_tests.emplace_back(world2.get_random_number_engine()()); + approval_tests.emplace_back(world2.get_random_number_engine()()); + approval_tests.emplace_back(dist(world2.get_random_number_engine())); + approval_tests.emplace_back(dist(world2.get_random_number_engine())); + + // Test reproducibility with the same seed. + WorldBuilder::World world3(file_name, false, "", 1); + approval_tests.emplace_back(world3.get_random_number_engine()()); + approval_tests.emplace_back(world3.get_random_number_engine()()); + approval_tests.emplace_back(dist(world3.get_random_number_engine())); + approval_tests.emplace_back(dist(world3.get_random_number_engine())); + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("WorldBuilder Coordinate Systems: Interface") +{ + std::vector approval_tests; + + const std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/oceanic_plate_spherical.wb"; + WorldBuilder::World world(file_name); + + CHECK_THROWS_WITH(CoordinateSystems::Interface::create("!not_implemented_coordinate_system!",&world), + Contains("Internal error: Plugin with name '!not_implemented_coordinate_system!' is not found. " + "The size of factories is ")); + + std::unique_ptr interface(CoordinateSystems::Interface::create("cartesian",&world)); + + interface->declare_entries(world.parameters, "", {}); + + CHECK(interface->cartesian_to_natural_coordinates(std::array {{1,2,3}}) == std::array {{1,2,3}}); + CHECK(interface->natural_to_cartesian_coordinates(std::array {{1,2,3}}) == std::array {{1,2,3}}); + + approval_tests.emplace_back(interface->natural_coordinate_system()); + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("WorldBuilder Coordinate Systems: Cartesian") +{ + std::vector approval_tests; + + std::unique_ptr cartesian(CoordinateSystems::Interface::create("cartesian",nullptr)); + + //todo:fix + //cartesian->declare_entries(); + + CHECK(cartesian->cartesian_to_natural_coordinates(std::array {{1,2,3}}) == std::array {{1,2,3}}); + CHECK(cartesian->natural_to_cartesian_coordinates(std::array {{1,2,3}}) == std::array {{1,2,3}}); + + approval_tests.emplace_back(cartesian->natural_coordinate_system()); + + // distance between two points at the same depth + const Point<3> point_1(0.0,0.0,10.0, CoordinateSystem::cartesian); + const Point<3> point_2(1.0,2.0,10.0, CoordinateSystem::cartesian); + const Point<3> point_3(3.0,2.0,10.0, CoordinateSystem::cartesian); + const Point<3> point_4(3.0,3.0,10.0, CoordinateSystem::cartesian); + + approval_tests.emplace_back(cartesian->distance_between_points_at_same_depth(point_1, point_2)); + approval_tests.emplace_back(cartesian->distance_between_points_at_same_depth(point_2, point_3)); + approval_tests.emplace_back(cartesian->distance_between_points_at_same_depth(point_2, point_4)); + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("WorldBuilder Coordinate Systems: Spherical") +{ + std::vector approval_tests; + + // TODO: make test where a cartesian wb file is loaded into a spherical coordinate system. + const std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/oceanic_plate_spherical.wb"; + + WorldBuilder::World world(file_name); + + std::unique_ptr spherical(CoordinateSystems::Interface::create("spherical", &world)); + + world.parameters.enter_subsection("coordinate system"); + { + world.parameters.enter_subsection("spherical"); + { + spherical->declare_entries(world.parameters,"", {}); + } + world.parameters.leave_subsection(); + } + world.parameters.leave_subsection(); + + std::array spherical_array = spherical->cartesian_to_natural_coordinates(std::array {{1,2,3}}); + approval_tests.emplace_back(spherical_array[0]); + approval_tests.emplace_back(spherical_array[1]); + approval_tests.emplace_back(spherical_array[2]); + std::array cartesian_array = spherical->natural_to_cartesian_coordinates(std::array {{std::sqrt(1.0 * 1.0 + 2.0 * 2.0 + 3.0 * 3.0),1.1071487178,0.9302740141}}); + approval_tests.emplace_back(cartesian_array[0]); + approval_tests.emplace_back(cartesian_array[1]); + approval_tests.emplace_back(cartesian_array[2]); + + approval_tests.emplace_back(spherical->natural_coordinate_system()); + + // distance between two points at the same depth + const double dtr = Consts::PI / 180.0; + // first check unit radius, this the central angle + const Point<3> unit_point_1(1.0, 0.0 * dtr, 0.0 * dtr, CoordinateSystem::spherical); + const Point<3> unit_point_2(1.0, 1.0 * dtr, 0.0 * dtr, CoordinateSystem::spherical); + const Point<3> unit_point_3(1.0, 0.0 * dtr, 1.0 * dtr, CoordinateSystem::spherical); + const Point<3> unit_point_4(1.0, 1.0 * dtr, 1.0 * dtr, CoordinateSystem::spherical); + const Point<3> unit_point_5(1.0, 90.0 * dtr, 90.0 * dtr, CoordinateSystem::spherical); + const Point<3> unit_point_6(1.0, -90.0 * dtr, 0.0 * dtr, CoordinateSystem::spherical); + const Point<3> unit_point_7(1.0, 90.0 * dtr, 180.0 * dtr, CoordinateSystem::spherical); + + approval_tests.emplace_back(spherical->distance_between_points_at_same_depth(unit_point_1, unit_point_2)); + approval_tests.emplace_back(spherical->distance_between_points_at_same_depth(unit_point_1, unit_point_3)); + CHECK(spherical->distance_between_points_at_same_depth(unit_point_1, unit_point_4) == + Approx(std::acos(std::sin(0) * std::sin(1*dtr) + + std::cos(0) * std::cos(1*dtr) * std::cos(1*dtr)))); + approval_tests.emplace_back(spherical->distance_between_points_at_same_depth(unit_point_1, unit_point_5)); + approval_tests.emplace_back(spherical->distance_between_points_at_same_depth(unit_point_6, unit_point_7)); + + // secondly check non-unit radius + const Point<3> point_1(10.0, 0.0 * dtr, 0.0 * dtr, CoordinateSystem::spherical); + const Point<3> point_2(10.0, 1.0 * dtr, 0.0 * dtr, CoordinateSystem::spherical); + const Point<3> point_3(10.0, 0.0 * dtr, 1.0 * dtr, CoordinateSystem::spherical); + const Point<3> point_4(10.0, 1.0 * dtr, 1.0 * dtr, CoordinateSystem::spherical); + const Point<3> point_5(10.0, 90.0 * dtr, 90.0 * dtr, CoordinateSystem::spherical); + const Point<3> point_6(10.0, -90.0 * dtr, 0.0 * dtr, CoordinateSystem::spherical); + const Point<3> point_7(10.0, 90.0 * dtr, 180.0 * dtr, CoordinateSystem::spherical); + + approval_tests.emplace_back(spherical->distance_between_points_at_same_depth(point_1, point_2)); + approval_tests.emplace_back(spherical->distance_between_points_at_same_depth(point_1, point_3)); + CHECK(spherical->distance_between_points_at_same_depth(point_1, point_4) == + Approx(10 * std::acos(std::sin(0) * std::sin(1*dtr) + + std::cos(0) * std::cos(1*dtr) * std::cos(1*dtr)))); + approval_tests.emplace_back(spherical->distance_between_points_at_same_depth(point_1, point_5)); + approval_tests.emplace_back(spherical->distance_between_points_at_same_depth(point_6, point_7)); + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("WorldBuilder Features: Interface") +{ + const std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/simple_wb1.json"; + + WorldBuilder::World world(file_name); + CHECK_THROWS_WITH(Features::Interface::create("!not_implemented_feature!", &world), + Contains("Internal error: Plugin with name '!not_implemented_feature!' is not found. " + "The size of factories is ")); + + const std::unique_ptr interface = Features::Interface::create("continental plate", &world); + +} + +TEST_CASE("WorldBuilder Features: Distance to Feature Plane") +{ + std::vector approval_tests; + + // call the distance_to_plane to a subducting plate feature, + const 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()); + + } + + // call the distance_to_plane to a fault feature. + const 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 point1 = {{250e3,495e3,800e3}}; + const double depth1 = 5.1e3; + auto plane_distances1 = world2.distance_to_plane(point1, depth1, "First fault"); + 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 = world2.distance_to_plane(point2, depth2, "First fault"); + 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 = world2.distance_to_plane(point3, depth3, "First fault"); + 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); + } +} + + +TEST_CASE("WorldBuilder Features: Continental Plate") +{ + std::vector approval_tests; + std::vector approval_tests_grains; + + const std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/continental_plate.wb"; + WorldBuilder::World world1(file_name); + + // Check continental plate directly + { + std::unique_ptr continental_plate = Features::Interface::create("continental plate", &world1); + + world1.parameters.enter_subsection("features"); + world1.parameters.enter_subsection("2"); + continental_plate->parse_entries(world1.parameters); + world1.parameters.leave_subsection(); + world1.parameters.leave_subsection(); + auto point = Point<3>(250e3,750e3,400e3,cartesian); + std::vector vector(1,0.); + auto nat_coord = Objects::NaturalCoordinate(point,*(world1.parameters.coordinate_system)); + CHECK_THROWS_WITH(continental_plate->properties(point,nat_coord,10e3, {{{5,0,0}}},10, {0},vector), + Contains("Internal error: Unimplemented property provided")); + } + + // Check continental plate through the world + std::array position = {{0,0,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + + // the feature with composition 3 + position = {{250e3,500e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 74e3)); + approval_tests.emplace_back(world1.temperature(position, 76e3)); + approval_tests.emplace_back(world1.temperature(position, 149e3)); + approval_tests.emplace_back(world1.temperature(position, 151e3)); + approval_tests.emplace_back(world1.temperature(position, 224e3)); + approval_tests.emplace_back(world1.temperature(position, 226e3)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 240e3, 0)); + approval_tests.emplace_back(world1.composition(position, 240e3, 1)); + approval_tests.emplace_back(world1.composition(position, 240e3, 2)); + approval_tests.emplace_back(world1.composition(position, 240e3, 3)); + approval_tests.emplace_back(world1.composition(position, 240e3, 4)); + approval_tests.emplace_back(world1.composition(position, 240e3, 5)); + approval_tests.emplace_back(world1.composition(position, 260e3, 0)); + approval_tests.emplace_back(world1.composition(position, 260e3, 1)); + approval_tests.emplace_back(world1.composition(position, 260e3, 2)); + approval_tests.emplace_back(world1.composition(position, 260e3, 3)); + approval_tests.emplace_back(world1.composition(position, 260e3, 4)); + approval_tests.emplace_back(world1.composition(position, 260e3, 5)); + + // check grains + { + const WorldBuilder::grains grains = world1.grains(position, 0, 0, 3); + approval_tests_grains.emplace_back(grains); + } + + // the feature with composition 2 + position = {{1500e3,1500e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 240e3, 0)); + approval_tests.emplace_back(world1.composition(position, 240e3, 1)); + approval_tests.emplace_back(world1.composition(position, 240e3, 2)); + approval_tests.emplace_back(world1.composition(position, 240e3, 3)); + approval_tests.emplace_back(world1.composition(position, 240e3, 4)); + approval_tests.emplace_back(world1.composition(position, 240e3, 5)); + approval_tests.emplace_back(world1.composition(position, 260e3, 0)); + approval_tests.emplace_back(world1.composition(position, 260e3, 1)); + approval_tests.emplace_back(world1.composition(position, 260e3, 2)); + approval_tests.emplace_back(world1.composition(position, 260e3, 3)); + approval_tests.emplace_back(world1.composition(position, 260e3, 4)); + approval_tests.emplace_back(world1.composition(position, 260e3, 5)); + + // check grains + { + const WorldBuilder::grains grains = world1.grains(position, 0, 0, 3); + approval_tests_grains.emplace_back(grains); + } + + position = {{250e3,1750e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 240e3, 0)); + approval_tests.emplace_back(world1.composition(position, 240e3, 1)); + approval_tests.emplace_back(world1.composition(position, 240e3, 2)); + approval_tests.emplace_back(world1.composition(position, 240e3, 3)); + approval_tests.emplace_back(world1.composition(position, 240e3, 4)); + approval_tests.emplace_back(world1.composition(position, 240e3, 5)); + approval_tests.emplace_back(world1.composition(position, 260e3, 0)); + approval_tests.emplace_back(world1.composition(position, 260e3, 1)); + approval_tests.emplace_back(world1.composition(position, 260e3, 2)); + approval_tests.emplace_back(world1.composition(position, 260e3, 3)); + approval_tests.emplace_back(world1.composition(position, 260e3, 4)); + approval_tests.emplace_back(world1.composition(position, 260e3, 5)); + + position = {{750e3,250e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + approval_tests.emplace_back(world1.composition(position, 240e3, 0)); + approval_tests.emplace_back(world1.composition(position, 240e3, 1)); + approval_tests.emplace_back(world1.composition(position, 240e3, 2)); + approval_tests.emplace_back(world1.composition(position, 240e3, 3)); + approval_tests.emplace_back(world1.composition(position, 240e3, 4)); + approval_tests.emplace_back(world1.composition(position, 240e3, 5)); + approval_tests.emplace_back(world1.composition(position, 240e3, 6)); + approval_tests.emplace_back(world1.composition(position, 260e3, 0)); + approval_tests.emplace_back(world1.composition(position, 260e3, 1)); + approval_tests.emplace_back(world1.composition(position, 260e3, 2)); + approval_tests.emplace_back(world1.composition(position, 260e3, 3)); + approval_tests.emplace_back(world1.composition(position, 260e3, 4)); + approval_tests.emplace_back(world1.composition(position, 260e3, 5)); + + // check grains layer 1 + { + const WorldBuilder::grains grains = world1.grains(position, 0, 0, 2); + approval_tests_grains.emplace_back(grains); + } + + // check grains layer 2 + { + const WorldBuilder::grains grains = world1.grains(position, 150e3, 0, 2); + approval_tests_grains.emplace_back(grains); + + } + + // the constant layers test + position = {{1500e3,250e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 1)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 249.5e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + approval_tests.emplace_back(world1.composition(position, 0, 7)); + approval_tests.emplace_back(world1.composition(position, 0, 8)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 0)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 1)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 2)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 3)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 4)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 5)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 6)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 7)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 8)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 0)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 1)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 2)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 3)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 4)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 5)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 6)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 7)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 8)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 0)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 1)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 2)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 3)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 4)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 5)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 6)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 7)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 8)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 0)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 1)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 2)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 3)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 4)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 5)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 6)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 7)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 8)); + approval_tests.emplace_back(world1.composition(position, 240e3, 0)); + approval_tests.emplace_back(world1.composition(position, 240e3, 1)); + approval_tests.emplace_back(world1.composition(position, 240e3, 2)); + approval_tests.emplace_back(world1.composition(position, 240e3, 3)); + approval_tests.emplace_back(world1.composition(position, 240e3, 4)); + approval_tests.emplace_back(world1.composition(position, 240e3, 5)); + approval_tests.emplace_back(world1.composition(position, 240e3, 6)); + approval_tests.emplace_back(world1.composition(position, 240e3, 7)); + approval_tests.emplace_back(world1.composition(position, 240e3, 8)); + approval_tests.emplace_back(world1.composition(position, 260e3, 0)); + approval_tests.emplace_back(world1.composition(position, 260e3, 1)); + approval_tests.emplace_back(world1.composition(position, 260e3, 2)); + approval_tests.emplace_back(world1.composition(position, 260e3, 3)); + approval_tests.emplace_back(world1.composition(position, 260e3, 4)); + approval_tests.emplace_back(world1.composition(position, 260e3, 5)); + approval_tests.emplace_back(world1.composition(position, 260e3, 6)); + approval_tests.emplace_back(world1.composition(position, 260e3, 7)); + approval_tests.emplace_back(world1.composition(position, 260e3, 8)); + + + std::vector approvals; + for (auto&& value : approval_tests) + { + std::stringstream s; + s << value; + approvals.emplace_back(s.str()); + } + for (auto&& value : approval_tests_grains) + { + std::stringstream s; + s << value; + approvals.emplace_back(s.str()); + } + ApprovalTests::Approvals::verifyAll("Test", approvals); +} + +TEST_CASE("WorldBuilder Features: Mantle layer") +{ + std::vector approval_tests; + std::vector approval_tests_grains; + const std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/mantle_layer_cartesian.wb"; + WorldBuilder::World world1(file_name); + + // Check mantle layer directly + { + std::unique_ptr mantle_layer = Features::Interface::create("mantle layer", &world1); + + world1.parameters.enter_subsection("features"); + world1.parameters.enter_subsection("2"); + mantle_layer->parse_entries(world1.parameters); + world1.parameters.leave_subsection(); + world1.parameters.leave_subsection(); + auto point = Point<3>(250e3,750e3,400e3,cartesian); + std::vector vector(1,0.); + auto nat_coord = Objects::NaturalCoordinate(point,*(world1.parameters.coordinate_system)); + CHECK_THROWS_WITH(mantle_layer->properties(point,nat_coord,260e3, {{{5,0,0}}},10, {0},vector), + Contains("Internal error: Unimplemented property provided")); + } + // Check continental plate through the world + std::array position = {{0,0,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + + position = {{250e3,501e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0+100e3)); + approval_tests.emplace_back(world1.temperature(position, 240e3+100e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3+100e3)); + + approval_tests.emplace_back(world1.composition(position, 0+200e3, 0)); + approval_tests.emplace_back(world1.composition(position, 0+200e3, 1)); + approval_tests.emplace_back(world1.composition(position, 0+200e3, 2)); + approval_tests.emplace_back(world1.composition(position, 0+200e3, 3)); + approval_tests.emplace_back(world1.composition(position, 0+200e3, 4)); + approval_tests.emplace_back(world1.composition(position, 0+200e3, 5)); + approval_tests.emplace_back(world1.composition(position, 240e3+200e3, 0)); + approval_tests.emplace_back(world1.composition(position, 240e3+200e3, 1)); + approval_tests.emplace_back(world1.composition(position, 240e3+200e3, 2)); + approval_tests.emplace_back(world1.composition(position, 240e3+200e3, 3)); + approval_tests.emplace_back(world1.composition(position, 240e3+200e3, 4)); + approval_tests.emplace_back(world1.composition(position, 240e3+200e3, 5)); + approval_tests.emplace_back(world1.composition(position, 260e3+200e3, 0)); + approval_tests.emplace_back(world1.composition(position, 260e3+200e3, 1)); + approval_tests.emplace_back(world1.composition(position, 260e3+200e3, 2)); + approval_tests.emplace_back(world1.composition(position, 260e3+200e3, 3)); + approval_tests.emplace_back(world1.composition(position, 260e3+200e3, 4)); + approval_tests.emplace_back(world1.composition(position, 260e3+200e3, 5)); + + // check grains + { + const WorldBuilder::grains grains = world1.grains(position, 200e3, 0, 3); + approval_tests_grains.emplace_back(grains); + } + + position = {{1500e3,1500e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0+150e3)); + approval_tests.emplace_back(world1.temperature(position, 240e3+150e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3+150e3)); + + approval_tests.emplace_back(world1.composition(position, 0+150e3, 0)); + approval_tests.emplace_back(world1.composition(position, 0+150e3, 1)); + approval_tests.emplace_back(world1.composition(position, 0+150e3, 2)); + approval_tests.emplace_back(world1.composition(position, 0+150e3, 3)); + approval_tests.emplace_back(world1.composition(position, 0+150e3, 4)); + approval_tests.emplace_back(world1.composition(position, 0+150e3, 5)); + approval_tests.emplace_back(world1.composition(position, 240e3+150e3, 0)); + approval_tests.emplace_back(world1.composition(position, 240e3+150e3, 1)); + approval_tests.emplace_back(world1.composition(position, 240e3+150e3, 2)); + approval_tests.emplace_back(world1.composition(position, 240e3+150e3, 3)); + approval_tests.emplace_back(world1.composition(position, 240e3+150e3, 4)); + approval_tests.emplace_back(world1.composition(position, 240e3+150e3, 5)); + approval_tests.emplace_back(world1.composition(position, 260e3+150e3, 0)); + approval_tests.emplace_back(world1.composition(position, 260e3+150e3, 1)); + approval_tests.emplace_back(world1.composition(position, 260e3+150e3, 2)); + approval_tests.emplace_back(world1.composition(position, 260e3+150e3, 3)); + approval_tests.emplace_back(world1.composition(position, 260e3+150e3, 4)); + approval_tests.emplace_back(world1.composition(position, 260e3+150e3, 5)); + + // check grains + { + const WorldBuilder::grains grains = world1.grains(position, 150e3, 0, 3); + approval_tests_grains.emplace_back(grains); + } + + position = {{250e3,1750e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0+250e3)); + approval_tests.emplace_back(world1.temperature(position, 240e3+250e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3+250e3)); + + approval_tests.emplace_back(world1.composition(position, 0+250e3, 0)); + approval_tests.emplace_back(world1.composition(position, 0+250e3, 1)); + approval_tests.emplace_back(world1.composition(position, 0+250e3, 2)); + approval_tests.emplace_back(world1.composition(position, 0+250e3, 3)); + approval_tests.emplace_back(world1.composition(position, 0+250e3, 4)); + approval_tests.emplace_back(world1.composition(position, 0+250e3, 5)); + approval_tests.emplace_back(world1.composition(position, 240e3+250e3, 0)); + approval_tests.emplace_back(world1.composition(position, 240e3+250e3, 1)); + approval_tests.emplace_back(world1.composition(position, 240e3+250e3, 2)); + approval_tests.emplace_back(world1.composition(position, 240e3+250e3, 3)); + approval_tests.emplace_back(world1.composition(position, 240e3+250e3, 4)); + approval_tests.emplace_back(world1.composition(position, 240e3+250e3, 5)); + approval_tests.emplace_back(world1.composition(position, 260e3+250e3, 0)); + approval_tests.emplace_back(world1.composition(position, 260e3+250e3, 1)); + approval_tests.emplace_back(world1.composition(position, 260e3+250e3, 2)); + approval_tests.emplace_back(world1.composition(position, 260e3+250e3, 3)); + approval_tests.emplace_back(world1.composition(position, 260e3+250e3, 4)); + approval_tests.emplace_back(world1.composition(position, 260e3+250e3, 5)); + + position = {{750e3,250e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0+300e3)); + approval_tests.emplace_back(world1.temperature(position, 95e3+300e3)); + approval_tests.emplace_back(world1.temperature(position, 105e3+300e3)); + approval_tests.emplace_back(world1.temperature(position, 145e3+300e3)); + approval_tests.emplace_back(world1.temperature(position, 155e3+300e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3+300e3)); + + approval_tests.emplace_back(world1.composition(position, 0+300e3, 0)); + approval_tests.emplace_back(world1.composition(position, 0+300e3, 1)); + approval_tests.emplace_back(world1.composition(position, 0+300e3, 2)); + approval_tests.emplace_back(world1.composition(position, 0+300e3, 3)); + approval_tests.emplace_back(world1.composition(position, 0+300e3, 4)); + approval_tests.emplace_back(world1.composition(position, 0+300e3, 5)); + approval_tests.emplace_back(world1.composition(position, 0+300e3, 6)); + approval_tests.emplace_back(world1.composition(position, 240e3+300e3, 0)); + approval_tests.emplace_back(world1.composition(position, 240e3+300e3, 1)); + approval_tests.emplace_back(world1.composition(position, 240e3+300e3, 2)); + approval_tests.emplace_back(world1.composition(position, 240e3+300e3, 3)); + approval_tests.emplace_back(world1.composition(position, 240e3+300e3, 4)); + approval_tests.emplace_back(world1.composition(position, 240e3+300e3, 5)); + approval_tests.emplace_back(world1.composition(position, 240e3+300e3, 6)); + approval_tests.emplace_back(world1.composition(position, 260e3+300e3, 0)); + approval_tests.emplace_back(world1.composition(position, 260e3+300e3, 1)); + approval_tests.emplace_back(world1.composition(position, 260e3+300e3, 2)); + approval_tests.emplace_back(world1.composition(position, 260e3+300e3, 3)); + approval_tests.emplace_back(world1.composition(position, 260e3+300e3, 4)); + approval_tests.emplace_back(world1.composition(position, 260e3+300e3, 5)); + + // check grains layer 1 + { + const WorldBuilder::grains grains = world1.grains(position, 0+300e3, 0, 2); + approval_tests_grains.emplace_back(grains); + } + + // check grains layer 2 + { + const WorldBuilder::grains grains = world1.grains(position, 150e3+300e3, 0, 2); + approval_tests_grains.emplace_back(grains); + + } + + // the constant layers test + position = {{1500e3,250e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0+350e3)); + approval_tests.emplace_back(world1.temperature(position, 240e3+350e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3+350e3)); + + approval_tests.emplace_back(world1.composition(position, 0+350e3, 0)); + approval_tests.emplace_back(world1.composition(position, 0+350e3, 1)); + approval_tests.emplace_back(world1.composition(position, 0+350e3, 2)); + approval_tests.emplace_back(world1.composition(position, 0+350e3, 3)); + approval_tests.emplace_back(world1.composition(position, 0+350e3, 4)); + approval_tests.emplace_back(world1.composition(position, 0+350e3, 5)); + approval_tests.emplace_back(world1.composition(position, 0+350e3, 6)); + approval_tests.emplace_back(world1.composition(position, 0+350e3, 7)); + approval_tests.emplace_back(world1.composition(position, 0+350e3, 8)); + approval_tests.emplace_back(world1.composition(position, 0+350e3, 9)); + approval_tests.emplace_back(world1.composition(position, 75e3-1+350e3, 0)); + approval_tests.emplace_back(world1.composition(position, 75e3-1+350e3, 1)); + approval_tests.emplace_back(world1.composition(position, 75e3-1+350e3, 2)); + approval_tests.emplace_back(world1.composition(position, 75e3-1+350e3, 3)); + approval_tests.emplace_back(world1.composition(position, 75e3-1+350e3, 4)); + approval_tests.emplace_back(world1.composition(position, 75e3-1+350e3, 5)); + approval_tests.emplace_back(world1.composition(position, 75e3-1+350e3, 6)); + approval_tests.emplace_back(world1.composition(position, 75e3-1+350e3, 7)); + approval_tests.emplace_back(world1.composition(position, 75e3-1+350e3, 8)); + approval_tests.emplace_back(world1.composition(position, 75e3-1+350e3, 9)); + approval_tests.emplace_back(world1.composition(position, 75e3+1+350e3, 0)); + approval_tests.emplace_back(world1.composition(position, 75e3+1+350e3, 1)); + approval_tests.emplace_back(world1.composition(position, 75e3+1+350e3, 2)); + approval_tests.emplace_back(world1.composition(position, 75e3+1+350e3, 3)); + approval_tests.emplace_back(world1.composition(position, 75e3+1+350e3, 4)); + approval_tests.emplace_back(world1.composition(position, 75e3+1+350e3, 5)); + approval_tests.emplace_back(world1.composition(position, 75e3+1+350e3, 6)); + approval_tests.emplace_back(world1.composition(position, 75e3+1+350e3, 7)); + approval_tests.emplace_back(world1.composition(position, 75e3+1+350e3, 8)); + approval_tests.emplace_back(world1.composition(position, 75e3+1+350e3, 9)); + approval_tests.emplace_back(world1.composition(position, 150e3-1+350e3, 0)); + approval_tests.emplace_back(world1.composition(position, 150e3-1+350e3, 1)); + approval_tests.emplace_back(world1.composition(position, 150e3-1+350e3, 2)); + approval_tests.emplace_back(world1.composition(position, 150e3-1+350e3, 3)); + approval_tests.emplace_back(world1.composition(position, 150e3-1+350e3, 4)); + approval_tests.emplace_back(world1.composition(position, 150e3-1+350e3, 5)); + approval_tests.emplace_back(world1.composition(position, 150e3-1+350e3, 6)); + approval_tests.emplace_back(world1.composition(position, 150e3-1+350e3, 7)); + approval_tests.emplace_back(world1.composition(position, 150e3-1+350e3, 8)); + approval_tests.emplace_back(world1.composition(position, 150e3-1+350e3, 9)); + approval_tests.emplace_back(world1.composition(position, 150e3+1+350e3, 0)); + approval_tests.emplace_back(world1.composition(position, 150e3+1+350e3, 1)); + approval_tests.emplace_back(world1.composition(position, 150e3+1+350e3, 2)); + approval_tests.emplace_back(world1.composition(position, 150e3+1+350e3, 3)); + approval_tests.emplace_back(world1.composition(position, 150e3+1+350e3, 4)); + approval_tests.emplace_back(world1.composition(position, 150e3+1+350e3, 5)); + approval_tests.emplace_back(world1.composition(position, 150e3+1+350e3, 6)); + approval_tests.emplace_back(world1.composition(position, 150e3+1+350e3, 7)); + approval_tests.emplace_back(world1.composition(position, 150e3+1+350e3, 8)); + approval_tests.emplace_back(world1.composition(position, 150e3+1+350e3, 9)); + approval_tests.emplace_back(world1.composition(position, 240e3+350e3, 0)); + approval_tests.emplace_back(world1.composition(position, 240e3+350e3, 1)); + approval_tests.emplace_back(world1.composition(position, 240e3+350e3, 2)); + approval_tests.emplace_back(world1.composition(position, 240e3+350e3, 3)); + approval_tests.emplace_back(world1.composition(position, 240e3+350e3, 4)); + approval_tests.emplace_back(world1.composition(position, 240e3+350e3, 5)); + approval_tests.emplace_back(world1.composition(position, 240e3+350e3, 6)); + approval_tests.emplace_back(world1.composition(position, 240e3+350e3, 7)); + approval_tests.emplace_back(world1.composition(position, 240e3+350e3, 8)); + approval_tests.emplace_back(world1.composition(position, 240e3+350e3, 9)); + approval_tests.emplace_back(world1.composition(position, 260e3+350e3, 0)); + approval_tests.emplace_back(world1.composition(position, 260e3+350e3, 1)); + approval_tests.emplace_back(world1.composition(position, 260e3+350e3, 2)); + approval_tests.emplace_back(world1.composition(position, 260e3+350e3, 3)); + approval_tests.emplace_back(world1.composition(position, 260e3+350e3, 4)); + approval_tests.emplace_back(world1.composition(position, 260e3+350e3, 5)); + approval_tests.emplace_back(world1.composition(position, 260e3+350e3, 6)); + approval_tests.emplace_back(world1.composition(position, 260e3+350e3, 7)); + approval_tests.emplace_back(world1.composition(position, 260e3+350e3, 8)); + approval_tests.emplace_back(world1.composition(position, 260e3+350e3, 9)); + + std::vector approvals; + for (auto&& value : approval_tests) + { + std::stringstream s; + s << value; + approvals.emplace_back(s.str()); + } + for (auto&& value : approval_tests_grains) + { + std::stringstream s; + s << value; + approvals.emplace_back(s.str()); + } + ApprovalTests::Approvals::verifyAll("Test", approvals); +} + +TEST_CASE("WorldBuilder Features: Oceanic Plate") +{ + std::vector approval_tests; + std::vector approval_tests_grains; + + // Cartesian + std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/oceanic_plate_cartesian.wb"; + WorldBuilder::World world1(file_name); + + // Check continental plate directly + { + std::unique_ptr oceanic_plate = Features::Interface::create("oceanic plate", &world1); + + world1.parameters.enter_subsection("features"); + world1.parameters.enter_subsection("2"); + oceanic_plate->parse_entries(world1.parameters); + world1.parameters.leave_subsection(); + world1.parameters.leave_subsection(); + auto point = Point<3>(250e3,750e3,400e3,cartesian); + std::vector vector(1,0.); + auto nat_coord = Objects::NaturalCoordinate(point,*(world1.parameters.coordinate_system)); + CHECK_THROWS_WITH(oceanic_plate->properties(point,nat_coord,10e3, {{{5,0,0}}},10, {0},vector), + Contains("Internal error: Unimplemented property provided")); + } + + // Check continental plate through the world + // 2d + std::array position_2d = {{0,0}}; + approval_tests.emplace_back(world1.temperature(position_2d, 0)); + approval_tests.emplace_back(world1.temperature(position_2d, 240e3)); + approval_tests.emplace_back(world1.temperature(position_2d, 260e3)); + approval_tests.emplace_back(world1.composition(position_2d, 0, 0)); + approval_tests.emplace_back(world1.composition(position_2d, 0, 1)); + approval_tests.emplace_back(world1.composition(position_2d, 0, 2)); + approval_tests.emplace_back(world1.composition(position_2d, 0, 3)); + approval_tests.emplace_back(world1.composition(position_2d, 0, 4)); + approval_tests.emplace_back(world1.composition(position_2d, 0, 5)); + approval_tests.emplace_back(world1.composition(position_2d, 0, 6)); + // 3d + std::array position = {{0,0,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + position = {{250e3,500e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 240e3, 3)); + approval_tests.emplace_back(world1.composition(position, 260e3, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + position = {{1500e3,1500e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 240e3, 2)); + approval_tests.emplace_back(world1.composition(position, 260e3, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + position = {{250e3,1750e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 240e3, 4)); + approval_tests.emplace_back(world1.composition(position, 260e3, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + position = {{750e3,250e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 195e3)); + approval_tests.emplace_back(world1.temperature(position, 205e3)); + approval_tests.emplace_back(world1.temperature(position, 247e3)); + approval_tests.emplace_back(world1.temperature(position, 249e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + approval_tests.emplace_back(world1.composition(position, 240e3, 5)); + approval_tests.emplace_back(world1.composition(position, 240e3, 6)); + approval_tests.emplace_back(world1.composition(position, 260e3, 5)); + approval_tests.emplace_back(world1.composition(position, 260e3, 6)); + + position = {{1500e3, 0, 0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + // test symmetry + position = {{1600e3, 0, 0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + + position = {{1400e3, 0, 0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + + // the constant layers test + position = {{200e3,200e3,0}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + approval_tests.emplace_back(world1.composition(position, 0, 7)); + approval_tests.emplace_back(world1.composition(position, 0, 8)); + approval_tests.emplace_back(world1.composition(position, 0, 9)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 0)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 1)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 2)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 3)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 4)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 5)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 6)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 7)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 8)); + approval_tests.emplace_back(world1.composition(position, 75e3-1, 9)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 0)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 1)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 2)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 3)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 4)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 5)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 6)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 7)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 8)); + approval_tests.emplace_back(world1.composition(position, 75e3+1, 9)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 0)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 1)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 2)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 3)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 4)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 5)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 6)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 7)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 8)); + approval_tests.emplace_back(world1.composition(position, 150e3-1, 9)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 0)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 1)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 2)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 3)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 4)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 5)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 6)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 7)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 8)); + approval_tests.emplace_back(world1.composition(position, 150e3+1, 9)); + approval_tests.emplace_back(world1.composition(position, 240e3, 0)); + approval_tests.emplace_back(world1.composition(position, 240e3, 1)); + approval_tests.emplace_back(world1.composition(position, 240e3, 2)); + approval_tests.emplace_back(world1.composition(position, 240e3, 3)); + approval_tests.emplace_back(world1.composition(position, 240e3, 4)); + approval_tests.emplace_back(world1.composition(position, 240e3, 5)); + approval_tests.emplace_back(world1.composition(position, 240e3, 6)); + approval_tests.emplace_back(world1.composition(position, 240e3, 7)); + approval_tests.emplace_back(world1.composition(position, 240e3, 8)); + approval_tests.emplace_back(world1.composition(position, 240e3, 9)); + approval_tests.emplace_back(world1.composition(position, 260e3, 0)); + approval_tests.emplace_back(world1.composition(position, 260e3, 1)); + approval_tests.emplace_back(world1.composition(position, 260e3, 2)); + approval_tests.emplace_back(world1.composition(position, 260e3, 3)); + approval_tests.emplace_back(world1.composition(position, 260e3, 4)); + approval_tests.emplace_back(world1.composition(position, 260e3, 5)); + approval_tests.emplace_back(world1.composition(position, 260e3, 6)); + approval_tests.emplace_back(world1.composition(position, 260e3, 7)); + approval_tests.emplace_back(world1.composition(position, 260e3, 8)); + approval_tests.emplace_back(world1.composition(position, 260e3, 9)); + + // spherical + file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/oceanic_plate_spherical.wb"; + WorldBuilder::World world2(file_name); + + // Check continental plate directly + const std::unique_ptr oceanic_plate = Features::Interface::create("oceanic plate", &world2); + + // Check continental plate through the world + const double dtr = Consts::PI / 180.0; + std::unique_ptr &coordinate_system = world2.parameters.coordinate_system; + + // 2d + position_2d = {{6371000,0}}; + approval_tests.emplace_back(world2.temperature(position_2d, 0)); + approval_tests.emplace_back(world2.composition(position_2d, 0, 0)); + approval_tests.emplace_back(world2.composition(position_2d, 0, 1)); + approval_tests.emplace_back(world2.composition(position_2d, 0, 2)); + approval_tests.emplace_back(world2.composition(position_2d, 0, 3)); + approval_tests.emplace_back(world2.composition(position_2d, 0, 4)); + approval_tests.emplace_back(world2.composition(position_2d, 0, 5)); + approval_tests.emplace_back(world2.composition(position_2d, 0, 6)); + + // 3d + position = {{6371000,0,0}}; + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.composition(position, 0, 0)); + approval_tests.emplace_back(world2.composition(position, 0, 1)); + approval_tests.emplace_back(world2.composition(position, 0, 2)); + approval_tests.emplace_back(world2.composition(position, 0, 3)); + approval_tests.emplace_back(world2.composition(position, 0, 4)); + approval_tests.emplace_back(world2.composition(position, 0, 5)); + approval_tests.emplace_back(world2.composition(position, 0, 6)); + + position = {{6371000, -5 * dtr,-5 * dtr}}; + position = coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.temperature(position, 240e3)); + approval_tests.emplace_back(world2.temperature(position, 260e3)); + approval_tests.emplace_back(world2.composition(position, 0, 0)); + approval_tests.emplace_back(world2.composition(position, 0, 1)); + approval_tests.emplace_back(world2.composition(position, 0, 2)); + approval_tests.emplace_back(world2.composition(position, 0, 3)); + approval_tests.emplace_back(world2.composition(position, 0, 4)); + approval_tests.emplace_back(world2.composition(position, 0, 5)); + approval_tests.emplace_back(world2.composition(position, 0, 6)); + + position = {{6371000, 5 * dtr,-5 * dtr}}; + position = coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.temperature(position, 240e3)); + approval_tests.emplace_back(world2.temperature(position, 260e3)); + approval_tests.emplace_back(world2.composition(position, 0, 0)); + approval_tests.emplace_back(world2.composition(position, 0, 1)); + approval_tests.emplace_back(world2.composition(position, 0, 2)); + approval_tests.emplace_back(world2.composition(position, 240e3, 2)); + approval_tests.emplace_back(world2.composition(position, 260e3, 2)); + approval_tests.emplace_back(world2.composition(position, 0, 3)); + approval_tests.emplace_back(world2.composition(position, 0, 4)); + approval_tests.emplace_back(world2.composition(position, 0, 5)); + approval_tests.emplace_back(world2.composition(position, 0, 6)); + + // check grains + { + const WorldBuilder::grains grains = world2.grains(position, 240e3, 0, 3); + approval_tests_grains.emplace_back(grains); + } + + position = {{6371000, 5 * dtr,5 * dtr}}; + position = coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.temperature(position, 240e3)); + approval_tests.emplace_back(world2.temperature(position, 260e3)); + approval_tests.emplace_back(world2.composition(position, 0, 0)); + approval_tests.emplace_back(world2.composition(position, 0, 1)); + approval_tests.emplace_back(world2.composition(position, 0, 2)); + approval_tests.emplace_back(world2.composition(position, 0, 3)); + approval_tests.emplace_back(world2.composition(position, 0, 4)); + approval_tests.emplace_back(world2.composition(position, 240e3, 4)); + approval_tests.emplace_back(world2.composition(position, 260e3, 4)); + approval_tests.emplace_back(world2.composition(position, 0, 5)); + approval_tests.emplace_back(world2.composition(position, 0, 6)); + + // check grains + { + const WorldBuilder::grains grains = world2.grains(position, 240e3, 0, 3); + approval_tests_grains.emplace_back(grains); + } + + position = {{6371000, -15 * dtr, -15 * dtr}}; + position = coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.temperature(position, 240e3)); + approval_tests.emplace_back(world2.temperature(position, 260e3)); + approval_tests.emplace_back(world2.composition(position, 0, 0)); + approval_tests.emplace_back(world2.composition(position, 0, 1)); + approval_tests.emplace_back(world2.composition(position, 0, 2)); + approval_tests.emplace_back(world2.composition(position, 0, 3)); + approval_tests.emplace_back(world2.composition(position, 0, 4)); + approval_tests.emplace_back(world2.composition(position, 0, 5)); + approval_tests.emplace_back(world2.composition(position, 0, 6)); + approval_tests.emplace_back(world2.composition(position, 240e3, 5)); + approval_tests.emplace_back(world2.composition(position, 240e3, 6)); + approval_tests.emplace_back(world2.composition(position, 260e3, 5)); + approval_tests.emplace_back(world2.composition(position, 260e3, 6)); + + // check grains layer 1 + { + const WorldBuilder::grains grains = world2.grains(position, 0, 0, 2); + approval_tests_grains.emplace_back(grains); + } + + // check grains layer 2 + { + const WorldBuilder::grains grains = world2.grains(position, 150e3, 0, 2); + approval_tests_grains.emplace_back(grains); + } + + position = {{6371000, 15 * dtr, -19 * dtr}}; + position = coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.temperature(position, 10)); + approval_tests.emplace_back(world2.temperature(position, 240e3)); + approval_tests.emplace_back(world2.temperature(position, 260e3)); + approval_tests.emplace_back(world2.composition(position, 0, 0)); + approval_tests.emplace_back(world2.composition(position, 0, 1)); + approval_tests.emplace_back(world2.composition(position, 0, 2)); + approval_tests.emplace_back(world2.composition(position, 0, 3)); + approval_tests.emplace_back(world2.composition(position, 0, 4)); + approval_tests.emplace_back(world2.composition(position, 0, 5)); + approval_tests.emplace_back(world2.composition(position, 0, 6)); + approval_tests.emplace_back(world2.composition(position, 240e3, 6)); + approval_tests.emplace_back(world2.composition(position, 260e3, 6)); + + // test symmetry + position = {{6371000, 16 * dtr, -19 * dtr}}; + position = coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.temperature(position, 10)); + approval_tests.emplace_back(world2.temperature(position, 240e3)); + approval_tests.emplace_back(world2.temperature(position, 260e3)); + + position = {{6371000, 14 * dtr, -19 * dtr}}; + position = coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.temperature(position, 10)); + approval_tests.emplace_back(world2.temperature(position, 240e3)); + approval_tests.emplace_back(world2.temperature(position, 260e3)); + + // test bend + position = {{6371000, 12.5 * dtr, -12.5 * dtr}}; + position = coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.temperature(position, 10)); + approval_tests.emplace_back(world2.temperature(position, 240e3)); + approval_tests.emplace_back(world2.temperature(position, 260e3)); + + std::vector approvals; + for (auto&& value : approval_tests) + { + std::stringstream s; + s << value; + approvals.emplace_back(s.str()); + } + for (auto&& value : approval_tests_grains) + { + std::stringstream s; + s << value; + approvals.emplace_back(s.str()); + } + ApprovalTests::Approvals::verifyAll("Test", approvals); +} + +TEST_CASE("WorldBuilder Features: Subducting Plate") +{ + std::vector approval_tests; + std::vector approval_tests_grains; + + // Cartesian + std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/subducting_plate_constant_angles_cartesian.wb"; + WorldBuilder::World world1(file_name); + + // Check continental plate directly (upper case should automatically turn into lower case). + { + 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(); + auto point = Point<3>(250e3,490e3,800e3,cartesian); + std::vector vector(1,0.); + auto nat_coord = Objects::NaturalCoordinate(point,*(world1.parameters.coordinate_system)); + CHECK_THROWS_WITH(subducting_plate->properties(point,nat_coord,100000, {{{5,0,0}}},10, {0},vector), + Contains("Internal error: Unimplemented property provided")); + } + // Check continental plate through the world + std::array position = {{0,0,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 240e3)); + approval_tests.emplace_back(world1.temperature(position, 260e3)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + + position = {{0,150e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 1)); + approval_tests.emplace_back(world1.temperature(position, 5)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 100)); + approval_tests.emplace_back(world1.temperature(position, 500)); + approval_tests.emplace_back(world1.temperature(position, 1000)); + approval_tests.emplace_back(world1.temperature(position, 5000)); + approval_tests.emplace_back(world1.temperature(position, 10e3)); + approval_tests.emplace_back(world1.temperature(position, 25e3)); + approval_tests.emplace_back(world1.temperature(position, 50e3)); + approval_tests.emplace_back(world1.temperature(position, 75e3)); + approval_tests.emplace_back(world1.temperature(position, 150e3)); + approval_tests.emplace_back(world1.temperature(position, 175e3)); + approval_tests.emplace_back(world1.temperature(position, 200e3)); + + + position = {{10e3,150e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 1)); + approval_tests.emplace_back(world1.temperature(position, 5)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 100)); + approval_tests.emplace_back(world1.temperature(position, 500)); + approval_tests.emplace_back(world1.temperature(position, 1000)); + approval_tests.emplace_back(world1.temperature(position, 5000)); + approval_tests.emplace_back(world1.temperature(position, 10e3)); + approval_tests.emplace_back(world1.temperature(position, 25e3)); + approval_tests.emplace_back(world1.temperature(position, 50e3)); + approval_tests.emplace_back(world1.temperature(position, 75e3)); + approval_tests.emplace_back(world1.temperature(position, 150e3)); + approval_tests.emplace_back(world1.temperature(position, 175e3)); + approval_tests.emplace_back(world1.temperature(position, 200e3)); + + position = {{0,160e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 1)); + approval_tests.emplace_back(world1.temperature(position, 5)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 100)); + approval_tests.emplace_back(world1.temperature(position, 500)); + approval_tests.emplace_back(world1.temperature(position, 1000)); + approval_tests.emplace_back(world1.temperature(position, 5000)); + approval_tests.emplace_back(world1.temperature(position, 10e3)); + approval_tests.emplace_back(world1.temperature(position, 25e3)); + approval_tests.emplace_back(world1.temperature(position, 50e3)); + approval_tests.emplace_back(world1.temperature(position, 75e3)); + approval_tests.emplace_back(world1.temperature(position, 150e3)); + approval_tests.emplace_back(world1.temperature(position, 175e3)); + approval_tests.emplace_back(world1.temperature(position, 200e3)); + + + position = {{750e3,175e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 1)); + approval_tests.emplace_back(world1.temperature(position, 5)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 100)); + approval_tests.emplace_back(world1.temperature(position, 500)); + approval_tests.emplace_back(world1.temperature(position, 1000)); + approval_tests.emplace_back(world1.temperature(position, 5000)); + approval_tests.emplace_back(world1.temperature(position, 10e3)); + approval_tests.emplace_back(world1.temperature(position, 25e3)); + approval_tests.emplace_back(world1.temperature(position, 50e3)); + approval_tests.emplace_back(world1.temperature(position, 75e3)); + approval_tests.emplace_back(world1.temperature(position, 150e3)); + approval_tests.emplace_back(world1.temperature(position, 175e3)); + approval_tests.emplace_back(world1.temperature(position, 200e3)); + + //position = {{250e3,450e3,800e3}}; + //approval_tests.emplace_back(world1.temperature(position, 0)); + //approval_tests.emplace_back(world1.temperature(position, 1)); // we are in the plate for sure (colder than anywhere in the mantle) + //approval_tests.emplace_back(world1.temperature(position, 5)); // we are in the plate for sure (colder than anywhere in the mantle) + //approval_tests.emplace_back(world1.temperature(position, 10)); // we are in the plate for sure (colder than anywhere in the mantle) + //approval_tests.emplace_back(world1.temperature(position, 100)); // we are in the plate for sure (colder than anywhere in the mantle) + //approval_tests.emplace_back(world1.temperature(position, 500)); // we are in the plate for sure (colder than anywhere in the mantle) + //approval_tests.emplace_back(world1.temperature(position, 1000)); // we are in the plate for sure (colder than anywhere in the mantle) + //approval_tests.emplace_back(world1.temperature(position, 5000)); // we are in the plate for sure (colder than anywhere in the mantle) + //approval_tests.emplace_back(world1.temperature(position, 10e3)); + //approval_tests.emplace_back(world1.temperature(position, 25e3)); + //approval_tests.emplace_back(world1.temperature(position, 50e3)); + //approval_tests.emplace_back(world1.temperature(position, 75e3)); + //approval_tests.emplace_back(world1.temperature(position, 150e3)); + + position = {{250e3,488.750e3,800e3}}; + position = {{250e3,500e3,800e3}}; + // results strongly dependent on the summation number of the McKenzie temperature. + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 1)); + approval_tests.emplace_back(world1.temperature(position, 5)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 100)); + approval_tests.emplace_back(world1.temperature(position, 500)); // we are in the plate for sure (colder than anywhere in the mantle) + approval_tests.emplace_back(world1.temperature(position, 1000)); // we are in the plate for sure (colder than anywhere in the mantle) + approval_tests.emplace_back(world1.temperature(position, 5000)); // we are in the plate for sure (colder than anywhere in the mantle) + approval_tests.emplace_back(world1.temperature(position, 10e3)); + approval_tests.emplace_back(world1.temperature(position, 25e3)); + approval_tests.emplace_back(world1.temperature(position, 50e3)); + approval_tests.emplace_back(world1.temperature(position, 75e3)); + approval_tests.emplace_back(world1.temperature(position, 150e3)); + //approval_tests.emplace_back(world1.temperature(position, std::sqrt(2) * 100e3 - 1)); + //approval_tests.emplace_back(world1.temperature(position, std::sqrt(2) * 100e3 + 1)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 10, 0)); + approval_tests.emplace_back(world1.composition(position, 10, 1)); + approval_tests.emplace_back(world1.composition(position, 10, 2)); + approval_tests.emplace_back(world1.composition(position, 10, 3)); + approval_tests.emplace_back(world1.composition(position, 10, 4)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 33e3 - 1, 0)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 33e3 + 1, 0)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 33e3 - 1, 1)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 33e3 + 1, 1)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 66e3 - 1, 1)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 66e3 + 1, 1)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 66e3 - 1, 2)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 66e3 + 1, 2)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 66e3 + 1, 3)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 99e3 - 1, 2)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 99e3 - 1, 3)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 99e3 + 1, 2)); + // this comes form the first subducting plate + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 99e3 + 1, 3)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 100e3 - 1, 3)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 100e3 + 1, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + // check grains layer 1 + { + WorldBuilder::grains grains = world1.grains(position, std::sqrt(2) * 33e3 - 5e3, 0, 2); + // these are random numbers, but they should stay the same. + // note that the values are different from for example the continental plate since + // this performs a interpolation between segments of the slab. + approval_tests_grains.emplace_back(grains); + + grains = world1.grains(position, std::sqrt(2) * 33e3 - 5e3, 1, 2); + approval_tests_grains.emplace_back(grains); + } + + // check grains layer 2 + { + const WorldBuilder::grains grains = world1.grains(position, std::sqrt(2) * 66e3 - 1, 0, 2); + approval_tests_grains.emplace_back(grains); + } + + position = {{250e3,550e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 45e3)); + approval_tests.emplace_back(world1.temperature(position, 50e3-1)); + approval_tests.emplace_back(world1.temperature(position, 50e3+1)); + approval_tests.emplace_back(world1.temperature(position, 55e3)); + approval_tests.emplace_back(world1.temperature(position, 100e3-1)); + approval_tests.emplace_back(world1.temperature(position, 100e3+1)); + approval_tests.emplace_back(world1.temperature(position, 101e3)); + approval_tests.emplace_back(world1.temperature(position, 110e3)); + approval_tests.emplace_back(world1.temperature(position, 150e3)); + approval_tests.emplace_back(world1.temperature(position, 155e3)); + approval_tests.emplace_back(world1.temperature(position, 175e3)); + approval_tests.emplace_back(world1.temperature(position, 200e3)); + approval_tests.emplace_back(world1.temperature(position, 250e3)); + approval_tests.emplace_back(world1.temperature(position, 300e3)); + + position = {{250e3,600e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 45e3)); + approval_tests.emplace_back(world1.temperature(position, 50e3-1)); + approval_tests.emplace_back(world1.temperature(position, 50e3+1)); + approval_tests.emplace_back(world1.temperature(position, 55e3)); + approval_tests.emplace_back(world1.temperature(position, 100e3-1)); + approval_tests.emplace_back(world1.temperature(position, 100e3+1)); + approval_tests.emplace_back(world1.temperature(position, 101e3)); + approval_tests.emplace_back(world1.temperature(position, 110e3)); + approval_tests.emplace_back(world1.temperature(position, 150e3)); + approval_tests.emplace_back(world1.temperature(position, 155e3)); + approval_tests.emplace_back(world1.temperature(position, 160e3)); + approval_tests.emplace_back(world1.temperature(position, 165e3)); + approval_tests.emplace_back(world1.temperature(position, 170e3)); + approval_tests.emplace_back(world1.temperature(position, 175e3)); + approval_tests.emplace_back(world1.temperature(position, 180e3)); + approval_tests.emplace_back(world1.temperature(position, 185e3)); + approval_tests.emplace_back(world1.temperature(position, 200e3)); + approval_tests.emplace_back(world1.temperature(position, 250e3)); + approval_tests.emplace_back(world1.temperature(position, 300e3)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 10, 0)); + approval_tests.emplace_back(world1.composition(position, 10, 1)); + approval_tests.emplace_back(world1.composition(position, 10, 2)); + approval_tests.emplace_back(world1.composition(position, 10, 3)); + approval_tests.emplace_back(world1.composition(position, 100e3-1, 0)); + approval_tests.emplace_back(world1.composition(position, 100e3-1, 1)); + approval_tests.emplace_back(world1.composition(position, 100e3-1, 2)); + approval_tests.emplace_back(world1.composition(position, 100e3-1, 3)); + approval_tests.emplace_back(world1.composition(position, 100e3-1, 4)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 0)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 1)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 2)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 3)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 4)); + approval_tests.emplace_back(world1.composition(position, 101e3, 0)); + approval_tests.emplace_back(world1.composition(position, 101e3+1, 1)); + approval_tests.emplace_back(world1.composition(position, 101e3+1, 2)); + approval_tests.emplace_back(world1.composition(position, 101e3+1, 3)); + approval_tests.emplace_back(world1.composition(position, 101e3+1, 4)); + approval_tests.emplace_back(world1.composition(position, 150e3, 0)); + approval_tests.emplace_back(world1.composition(position, 150e3, 1)); + approval_tests.emplace_back(world1.composition(position, 150e3, 2)); + approval_tests.emplace_back(world1.composition(position, 150e3, 3)); + approval_tests.emplace_back(world1.composition(position, 150e3, 4)); + approval_tests.emplace_back(world1.composition(position, 200e3, 0)); + approval_tests.emplace_back(world1.composition(position, 200e3, 1)); + approval_tests.emplace_back(world1.composition(position, 200e3, 2)); + approval_tests.emplace_back(world1.composition(position, 200e3, 3)); + approval_tests.emplace_back(world1.composition(position, 200e3, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + position = {{650e3,650e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 100e3)); + approval_tests.emplace_back(world1.temperature(position, 100e3+1)); + approval_tests.emplace_back(world1.temperature(position, 101e3)); + approval_tests.emplace_back(world1.temperature(position, 110e3)); + approval_tests.emplace_back(world1.temperature(position, 150e3)); + approval_tests.emplace_back(world1.temperature(position, 200e3)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 10, 0)); + approval_tests.emplace_back(world1.composition(position, 10, 1)); + approval_tests.emplace_back(world1.composition(position, 10, 2)); + approval_tests.emplace_back(world1.composition(position, 10, 3)); + approval_tests.emplace_back(world1.composition(position, 100e3, 0)); + approval_tests.emplace_back(world1.composition(position, 100e3, 1)); + approval_tests.emplace_back(world1.composition(position, 100e3, 2)); + approval_tests.emplace_back(world1.composition(position, 100e3, 3)); + approval_tests.emplace_back(world1.composition(position, 100e3, 4)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 0)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 1)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 2)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 3)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 4)); + approval_tests.emplace_back(world1.composition(position, 101e3, 0)); + approval_tests.emplace_back(world1.composition(position, 101e3+1, 1)); + approval_tests.emplace_back(world1.composition(position, 101e3+1, 2)); + approval_tests.emplace_back(world1.composition(position, 101e3+1, 3)); + approval_tests.emplace_back(world1.composition(position, 101e3+1, 4)); + approval_tests.emplace_back(world1.composition(position, 150e3, 0)); + approval_tests.emplace_back(world1.composition(position, 150e3, 1)); + approval_tests.emplace_back(world1.composition(position, 150e3, 2)); + approval_tests.emplace_back(world1.composition(position, 150e3, 3)); + approval_tests.emplace_back(world1.composition(position, 150e3, 4)); + approval_tests.emplace_back(world1.composition(position, 200e3, 0)); + approval_tests.emplace_back(world1.composition(position, 200e3, 1)); + approval_tests.emplace_back(world1.composition(position, 200e3, 2)); + approval_tests.emplace_back(world1.composition(position, 200e3, 3)); + approval_tests.emplace_back(world1.composition(position, 200e3, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + position = {{700e3,675e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 100e3)); + approval_tests.emplace_back(world1.temperature(position, 100e3+1)); + approval_tests.emplace_back(world1.temperature(position, 101e3)); + approval_tests.emplace_back(world1.temperature(position, 110e3)); + approval_tests.emplace_back(world1.temperature(position, 150e3)); + approval_tests.emplace_back(world1.temperature(position, 200e3)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 10, 0)); + approval_tests.emplace_back(world1.composition(position, 10, 1)); + approval_tests.emplace_back(world1.composition(position, 10, 2)); + approval_tests.emplace_back(world1.composition(position, 10, 3)); + approval_tests.emplace_back(world1.composition(position, 100e3, 0)); + approval_tests.emplace_back(world1.composition(position, 100e3, 1)); + approval_tests.emplace_back(world1.composition(position, 100e3, 2)); + approval_tests.emplace_back(world1.composition(position, 100e3, 3)); + approval_tests.emplace_back(world1.composition(position, 100e3, 4)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 0)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 1)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 2)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 3)); + approval_tests.emplace_back(world1.composition(position, 100e3+1, 4)); + approval_tests.emplace_back(world1.composition(position, 101e3, 0)); + approval_tests.emplace_back(world1.composition(position, 101e3+1, 1)); + approval_tests.emplace_back(world1.composition(position, 101e3+1, 2)); + approval_tests.emplace_back(world1.composition(position, 101e3+1, 3)); + approval_tests.emplace_back(world1.composition(position, 101e3+1, 4)); + approval_tests.emplace_back(world1.composition(position, 150e3, 0)); + approval_tests.emplace_back(world1.composition(position, 150e3, 1)); + approval_tests.emplace_back(world1.composition(position, 150e3, 2)); + approval_tests.emplace_back(world1.composition(position, 150e3, 3)); + approval_tests.emplace_back(world1.composition(position, 150e3, 4)); + approval_tests.emplace_back(world1.composition(position, 200e3, 0)); + approval_tests.emplace_back(world1.composition(position, 200e3, 1)); + approval_tests.emplace_back(world1.composition(position, 200e3, 2)); + approval_tests.emplace_back(world1.composition(position, 200e3, 3)); + approval_tests.emplace_back(world1.composition(position, 200e3, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + position = {{700e3,155e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 100e3)); + approval_tests.emplace_back(world1.temperature(position, 150e3)); + approval_tests.emplace_back(world1.temperature(position, 200e3)); + approval_tests.emplace_back(world1.temperature(position, 250e3)); + approval_tests.emplace_back(world1.temperature(position, 300e3)); + + // check grains + { + { + // layer 1 + const WorldBuilder::grains grains = world1.grains(position, 80e3, 0, 3); + approval_tests_grains.emplace_back(grains); + } + + { + // layer 2 + const WorldBuilder::grains grains = world1.grains(position, 100e3, 0, 3); + approval_tests_grains.emplace_back(grains); + } + + { + // layer 3 + const WorldBuilder::grains grains = world1.grains(position, 250e3, 0, 3); + approval_tests_grains.emplace_back(grains); + } + } + + + const std::string file_name2 = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/subducting_plate_different_angles_cartesian.wb"; + const WorldBuilder::World world2(file_name2); + + position = {{250e3,500e3,800e3}}; + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.composition(position, 0, 0)); + approval_tests.emplace_back(world2.temperature(position, 1)); + approval_tests.emplace_back(world2.composition(position, 1, 0)); + approval_tests.emplace_back(world2.temperature(position, 1e3)); + approval_tests.emplace_back(world2.composition(position, 1e3, 0)); + approval_tests.emplace_back(world2.temperature(position, 10e3)); + approval_tests.emplace_back(world2.composition(position, 10e3, 0)); + approval_tests.emplace_back(world2.temperature(position, 20e3)); + approval_tests.emplace_back(world2.composition(position, 20e3, 0)); + approval_tests.emplace_back(world2.temperature(position, 40e3)); + approval_tests.emplace_back(world2.composition(position, 40e3, 0)); + approval_tests.emplace_back(world2.temperature(position, 60e3)); + approval_tests.emplace_back(world2.composition(position, 60e3, 0)); + approval_tests.emplace_back(world2.temperature(position, 80e3)); + approval_tests.emplace_back(world2.composition(position, 80e3, 0)); + approval_tests.emplace_back(world2.temperature(position, 100e3)); + approval_tests.emplace_back(world2.composition(position, 100e3, 0)); + + + file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/subducting_plate_different_angles_cartesian_2.wb"; + const WorldBuilder::World world4(file_name); + + position = {{250e3,500e3,800e3}}; + approval_tests.emplace_back(world4.temperature(position, 0)); + approval_tests.emplace_back(world4.composition(position, 0, 0)); + approval_tests.emplace_back(world4.composition(position, 0, 1)); + approval_tests.emplace_back(world4.composition(position, 0, 2)); + approval_tests.emplace_back(world4.composition(position, 0, 3)); + approval_tests.emplace_back(world4.temperature(position, 1)); + approval_tests.emplace_back(world4.composition(position, 1, 0)); + approval_tests.emplace_back(world4.composition(position, 1, 1)); + approval_tests.emplace_back(world4.composition(position, 1, 2)); + approval_tests.emplace_back(world4.composition(position, 1, 3)); + approval_tests.emplace_back(world4.temperature(position, 1e3)); + approval_tests.emplace_back(world4.composition(position, 1e3, 0)); + approval_tests.emplace_back(world4.composition(position, 1e3, 1)); + approval_tests.emplace_back(world4.composition(position, 1e3, 2)); + approval_tests.emplace_back(world4.composition(position, 1e3, 3)); + approval_tests.emplace_back(world4.temperature(position, 10e3)); + approval_tests.emplace_back(world4.composition(position, 10e3, 0)); + approval_tests.emplace_back(world4.composition(position, 10e3, 1)); + approval_tests.emplace_back(world4.composition(position, 10e3, 2)); + approval_tests.emplace_back(world4.composition(position, 10e3, 3)); + approval_tests.emplace_back(world4.temperature(position, 20e3)); + approval_tests.emplace_back(world4.composition(position, 20e3, 0)); + approval_tests.emplace_back(world4.composition(position, 20e3, 1)); + approval_tests.emplace_back(world4.composition(position, 20e3, 2)); + approval_tests.emplace_back(world4.composition(position, 20e3, 3)); + approval_tests.emplace_back(world4.temperature(position, 30e3)); + approval_tests.emplace_back(world4.composition(position, 30e3, 0)); + approval_tests.emplace_back(world4.composition(position, 30e3, 1)); + approval_tests.emplace_back(world4.composition(position, 30e3, 2)); + approval_tests.emplace_back(world4.composition(position, 30e3, 3)); + approval_tests.emplace_back(world4.temperature(position, 35e3)); + approval_tests.emplace_back(world4.composition(position, 35e3, 0)); + approval_tests.emplace_back(world4.composition(position, 35e3, 1)); + approval_tests.emplace_back(world4.composition(position, 35e3, 2)); + approval_tests.emplace_back(world4.composition(position, 35e3, 3)); + approval_tests.emplace_back(world4.temperature(position, 40e3)); + approval_tests.emplace_back(world4.composition(position, 40e3, 0)); + approval_tests.emplace_back(world4.composition(position, 40e3, 1)); + approval_tests.emplace_back(world4.composition(position, 40e3, 2)); + approval_tests.emplace_back(world4.composition(position, 40e3, 3)); + approval_tests.emplace_back(world4.temperature(position, 45e3)); + approval_tests.emplace_back(world4.composition(position, 45e3, 0)); + approval_tests.emplace_back(world4.composition(position, 45e3, 1)); + approval_tests.emplace_back(world4.composition(position, 45e3, 2)); + approval_tests.emplace_back(world4.composition(position, 45e3, 3)); + approval_tests.emplace_back(world4.temperature(position, 50e3)); + approval_tests.emplace_back(world4.composition(position, 50e3, 0)); + approval_tests.emplace_back(world4.composition(position, 50e3, 1)); + approval_tests.emplace_back(world4.composition(position, 50e3, 2)); + approval_tests.emplace_back(world4.composition(position, 50e3, 3)); + approval_tests.emplace_back(world4.temperature(position, 60e3)); + approval_tests.emplace_back(world4.composition(position, 60e3, 0)); + approval_tests.emplace_back(world4.composition(position, 60e3, 1)); + approval_tests.emplace_back(world4.composition(position, 60e3, 2)); + approval_tests.emplace_back(world4.composition(position, 60e3, 3)); + approval_tests.emplace_back(world4.temperature(position, 80e3)); + approval_tests.emplace_back(world4.composition(position, 80e3, 0)); + approval_tests.emplace_back(world4.composition(position, 80e3, 1)); + approval_tests.emplace_back(world4.composition(position, 80e3, 2)); + approval_tests.emplace_back(world4.composition(position, 80e3, 3)); + approval_tests.emplace_back(world4.temperature(position, 100e3)); + approval_tests.emplace_back(world4.composition(position, 100e3, 0)); + approval_tests.emplace_back(world4.composition(position, 100e3, 1)); + approval_tests.emplace_back(world4.composition(position, 100e3, 2)); + approval_tests.emplace_back(world4.composition(position, 100e3, 3)); + + + std::vector approvals; + for (auto&& value : approval_tests) + { + std::stringstream s; + s << value; + approvals.emplace_back(s.str()); + } + for (auto&& value : approval_tests_grains) + { + std::stringstream s; + s << value; + approvals.emplace_back(s.str()); + } + ApprovalTests::Approvals::verifyAll("Test", approvals); +} + +TEST_CASE("WorldBuilder Features: Fault") +{ + std::vector approval_tests; + std::vector approval_tests_grains; + + // Cartesian + std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/fault_constant_angles_cartesian.wb"; + WorldBuilder::World world1(file_name); + + // Check continental plate directly (upper case should automatically turn into lower case). + { + std::unique_ptr fault = Features::Interface::create("Fault", &world1); + + world1.parameters.enter_subsection("features"); + world1.parameters.enter_subsection("2"); + fault->parse_entries(world1.parameters); + world1.parameters.leave_subsection(); + world1.parameters.leave_subsection(); + auto point = Point<3>(50e3,230e3,800e3,cartesian); + std::vector vector(1,0.); + auto nat_coord = Objects::NaturalCoordinate(point,*(world1.parameters.coordinate_system)); + CHECK_THROWS_WITH(fault->properties(point,nat_coord,1000, {{{5,0,0}}},10, {0},vector), + Contains("Internal error: Unimplemented property provided")); + } + + // Check fault plate through the world + std::array position = {{0,0,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 220e3)); + approval_tests.emplace_back(world1.temperature(position, 230e3)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + position = {{250e3,500e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, std::sqrt(2) * 50e3 - 1)); + approval_tests.emplace_back(world1.temperature(position, std::sqrt(2) * 50e3 + 1)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 10, 0)); + approval_tests.emplace_back(world1.composition(position, 10, 1)); + approval_tests.emplace_back(world1.composition(position, 10, 2)); + approval_tests.emplace_back(world1.composition(position, 10, 3)); + approval_tests.emplace_back(world1.composition(position, 10, 4)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 50e3 - 1, 3)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 50e3 - 1, 4)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 50e3 + 1, 3)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 50e3 + 1, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + // check grains + { + WorldBuilder::grains grains = world1.grains(position, 10, 0, 3); + approval_tests_grains.emplace_back(grains); + + grains = world1.grains(position, 10, 1, 3); + approval_tests_grains.emplace_back(grains); + } + + position = {{50e3,230e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 1)); + approval_tests.emplace_back(world1.temperature(position, 5)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 100)); + approval_tests.emplace_back(world1.temperature(position, 500)); + approval_tests.emplace_back(world1.temperature(position, 1000)); + approval_tests.emplace_back(world1.temperature(position, 5000)); + approval_tests.emplace_back(world1.temperature(position, std::sqrt(2) * 50e3/2)); + approval_tests.emplace_back(world1.temperature(position, std::sqrt(2) * 50e3 - 1)); + approval_tests.emplace_back(world1.temperature(position, std::sqrt(2) * 50e3 + 1)); + approval_tests.emplace_back(world1.temperature(position, 25e3)); + approval_tests.emplace_back(world1.temperature(position, 50e3)); + approval_tests.emplace_back(world1.temperature(position, 75e3)); + approval_tests.emplace_back(world1.temperature(position, 80e3)); + approval_tests.emplace_back(world1.temperature(position, 90e3)); + approval_tests.emplace_back(world1.temperature(position, 100e3)); + approval_tests.emplace_back(world1.temperature(position, 150e3)); + approval_tests.emplace_back(world1.temperature(position, 200e3)); + + position = {{250e3,250e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.temperature(position, 1)); + approval_tests.emplace_back(world1.temperature(position, 5)); + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.temperature(position, 100)); + approval_tests.emplace_back(world1.temperature(position, 500)); + approval_tests.emplace_back(world1.temperature(position, 1000)); + approval_tests.emplace_back(world1.temperature(position, 5000)); + approval_tests.emplace_back(world1.temperature(position, std::sqrt(2) * 50e3/2)); + approval_tests.emplace_back(world1.temperature(position, std::sqrt(2) * 50e3 - 1)); + approval_tests.emplace_back(world1.temperature(position, std::sqrt(2) * 50e3 + 1)); + approval_tests.emplace_back(world1.temperature(position, std::sqrt(2) * 51e3)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 1)); + approval_tests.emplace_back(world1.composition(position, 0, 2)); + approval_tests.emplace_back(world1.composition(position, 0, 3)); + approval_tests.emplace_back(world1.composition(position, 10, 0)); + approval_tests.emplace_back(world1.composition(position, 10, 1)); + approval_tests.emplace_back(world1.composition(position, 10, 2)); + approval_tests.emplace_back(world1.composition(position, 10, 3)); + + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 33e3 * 0.5 - 1, 0)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 33e3 * 0.5 - 1, 1)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 33e3 * 0.5 - 1, 2)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 33e3 * 0.5 + 1, 0)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 33e3 * 0.5 + 1, 1)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 33e3 * 0.5 + 1, 2)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 66e3 * 0.5 - 1, 1)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 66e3 * 0.5 + 1, 1)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 99e3 * 0.5 - 1, 2)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 99e3 * 0.5 + 1, 2)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 99e3 * 0.5 - 1, 3)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 99e3 * 0.5 + 1, 3)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 100e3 * 0.5 - 1, 3)); + approval_tests.emplace_back(world1.composition(position, std::sqrt(2) * 100e3 * 0.5 + 1, 3)); + approval_tests.emplace_back(world1.composition(position, 0, 4)); + approval_tests.emplace_back(world1.composition(position, 0, 5)); + approval_tests.emplace_back(world1.composition(position, 0, 6)); + + + // check grains + { + { + // layer 1 + WorldBuilder::grains grains = world1.grains(position, std::sqrt(2) * 33e3 * 0.5 - 5e3, 0, 3); + approval_tests_grains.emplace_back(grains); + + grains = world1.grains(position, std::sqrt(2) * 33e3 * 0.5 - 5e3, 1, 3); + approval_tests_grains.emplace_back(grains); + } + + { + // layer 2 + WorldBuilder::grains grains = world1.grains(position, std::sqrt(2) * 33e3 * 0.5 + 1, 0, 3); + approval_tests_grains.emplace_back(grains); + + grains = world1.grains(position, std::sqrt(2) * 33e3 * 0.5 + 1, 1, 3); + approval_tests_grains.emplace_back(grains); + } + + { + // layer 3 + const WorldBuilder::grains grains = world1.grains(position, std::sqrt(2) * 99e3 * 0.5 - 5e3, 0, 3); + approval_tests_grains.emplace_back(grains); + } + } + + + position = {{250e3,250e3,800e3}}; + approval_tests.emplace_back(world1.composition(position, 1, 0)); + approval_tests.emplace_back(world1.composition(position, 1, 1)); + approval_tests.emplace_back(world1.composition(position, 1, 2)); + position = {{250e3,250e3-std::sqrt(2) * 33e3 * 0.5 + 1, 800e3}}; + approval_tests.emplace_back(world1.composition(position, 1, 0)); + approval_tests.emplace_back(world1.composition(position, 1, 1)); + approval_tests.emplace_back(world1.composition(position, 1, 2)); + position = {{250e3,250e3-std::sqrt(2) * 66e3 * 0.5 + 1, 800e3}}; + approval_tests.emplace_back(world1.composition(position, 1, 0)); + approval_tests.emplace_back(world1.composition(position, 1, 1)); + approval_tests.emplace_back(world1.composition(position, 1, 2)); + position = {{250e3,250e3-std::sqrt(2) * 99e3 * 0.5 + 1, 800e3}}; + approval_tests.emplace_back(world1.composition(position, 1, 0)); + approval_tests.emplace_back(world1.composition(position, 1, 1)); + approval_tests.emplace_back(world1.composition(position, 1, 2)); + approval_tests.emplace_back(world1.composition(position, 1, 3)); + + const std::string file_name2 = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/fault_constant_angles_cartesian_force_temp.wb"; + const WorldBuilder::World world2(file_name2); + + // Check fault plate through the world + position = {{0,0,800e3}}; + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.temperature(position, 220e3)); + approval_tests.emplace_back(world2.temperature(position, 230e3)); + approval_tests.emplace_back(world2.composition(position, 0, 0)); + approval_tests.emplace_back(world2.composition(position, 0, 1)); + approval_tests.emplace_back(world2.composition(position, 0, 2)); + approval_tests.emplace_back(world2.composition(position, 0, 3)); + approval_tests.emplace_back(world2.composition(position, 0, 4)); + approval_tests.emplace_back(world2.composition(position, 0, 5)); + approval_tests.emplace_back(world2.composition(position, 0, 6)); + + position = {{250e3,500e3,800e3}}; + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.temperature(position, 10)); + approval_tests.emplace_back(world2.temperature(position, std::sqrt(2) * 50e3 - 1)); + approval_tests.emplace_back(world2.temperature(position, std::sqrt(2) * 50e3 + 1)); + approval_tests.emplace_back(world2.composition(position, 0, 0)); + approval_tests.emplace_back(world2.composition(position, 0, 1)); + approval_tests.emplace_back(world2.composition(position, 0, 2)); + approval_tests.emplace_back(world2.composition(position, 0, 3)); + approval_tests.emplace_back(world2.composition(position, 10, 0)); + approval_tests.emplace_back(world2.composition(position, 10, 1)); + approval_tests.emplace_back(world2.composition(position, 10, 2)); + approval_tests.emplace_back(world1.composition(position, 10, 3)); + approval_tests.emplace_back(world1.composition(position, 10, 4)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 50e3 - 1, 3)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 50e3 - 1, 4)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 50e3 + 1, 3)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 50e3 + 1, 4)); + approval_tests.emplace_back(world2.composition(position, 0, 4)); + approval_tests.emplace_back(world2.composition(position, 0, 5)); + approval_tests.emplace_back(world2.composition(position, 0, 6)); + + + position = {{250e3,250e3,800e3}}; + approval_tests.emplace_back(world2.temperature(position, 0)); + approval_tests.emplace_back(world2.temperature(position, 1)); + approval_tests.emplace_back(world2.temperature(position, 5)); + approval_tests.emplace_back(world2.temperature(position, 10)); + approval_tests.emplace_back(world2.temperature(position, 100)); + approval_tests.emplace_back(world2.temperature(position, 500)); + approval_tests.emplace_back(world2.temperature(position, 1000)); + approval_tests.emplace_back(world2.temperature(position, 5000)); + approval_tests.emplace_back(world2.temperature(position, std::sqrt(2) * 50e3/2)); + approval_tests.emplace_back(world2.temperature(position, std::sqrt(2) * 50e3 - 1)); + approval_tests.emplace_back(world2.temperature(position, std::sqrt(2) * 50e3 + 1)); + approval_tests.emplace_back(world2.composition(position, 0, 0)); + approval_tests.emplace_back(world2.composition(position, 0, 1)); + approval_tests.emplace_back(world2.composition(position, 0, 2)); + approval_tests.emplace_back(world2.composition(position, 0, 3)); + approval_tests.emplace_back(world2.composition(position, 10, 0)); + approval_tests.emplace_back(world2.composition(position, 10, 1)); + approval_tests.emplace_back(world2.composition(position, 10, 2)); + approval_tests.emplace_back(world2.composition(position, 10, 3)); + + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 33e3 * 0.5 - 1, 0)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 33e3 * 0.5 - 1, 1)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 33e3 * 0.5 - 1, 2)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 33e3 * 0.5 + 1, 0)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 33e3 * 0.5 + 1, 1)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 33e3 * 0.5 + 1, 2)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 66e3 * 0.5 - 1, 1)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 66e3 * 0.5 + 1, 1)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 99e3 * 0.5 - 1, 2)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 99e3 * 0.5 + 1, 2)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 99e3 * 0.5 - 1, 3)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 99e3 * 0.5 + 1, 3)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 100e3 * 0.5 - 1, 3)); + approval_tests.emplace_back(world2.composition(position, std::sqrt(2) * 100e3 * 0.5 + 1, 3)); + approval_tests.emplace_back(world2.composition(position, 0, 4)); + approval_tests.emplace_back(world2.composition(position, 0, 5)); + approval_tests.emplace_back(world2.composition(position, 0, 6)); + + position = {{250e3,250e3,800e3}}; + approval_tests.emplace_back(world2.composition(position, 1, 0)); + approval_tests.emplace_back(world2.composition(position, 1, 1)); + approval_tests.emplace_back(world2.composition(position, 1, 2)); + position = {{250e3,250e3-std::sqrt(2) * 33e3 * 0.5 + 1, 800e3}}; + approval_tests.emplace_back(world2.composition(position, 1, 0)); + approval_tests.emplace_back(world2.composition(position, 1, 1)); + approval_tests.emplace_back(world2.composition(position, 1, 2)); + position = {{250e3,250e3-std::sqrt(2) * 66e3 * 0.5 + 1, 800e3}}; + approval_tests.emplace_back(world2.composition(position, 1, 0)); + approval_tests.emplace_back(world2.composition(position, 1, 1)); + approval_tests.emplace_back(world2.composition(position, 1, 2)); + position = {{250e3,250e3-std::sqrt(2) * 99e3 * 0.5 + 1, 800e3}}; + approval_tests.emplace_back(world2.composition(position, 1, 0)); + approval_tests.emplace_back(world2.composition(position, 1, 1)); + approval_tests.emplace_back(world2.composition(position, 1, 2)); + approval_tests.emplace_back(world2.composition(position, 1, 3)); + + + // Cartesian + file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/fault_constant_angles_cartesian_2.wb"; + WorldBuilder::World world3(file_name); + + // Check fault directly (upper case should automatically turn into lower case). + const std::unique_ptr continental_plate = Features::Interface::create("Fault", &world3); + + // Check fault through the world + position = {{0,0,800e3}}; + approval_tests.emplace_back(world3.temperature(position, 0)); + approval_tests.emplace_back(world3.temperature(position, 240e3)); + approval_tests.emplace_back(world3.temperature(position, 260e3)); + approval_tests.emplace_back(world3.composition(position, 0, 0)); + approval_tests.emplace_back(world3.composition(position, 0, 1)); + approval_tests.emplace_back(world3.composition(position, 0, 2)); + approval_tests.emplace_back(world3.composition(position, 0, 3)); + approval_tests.emplace_back(world3.composition(position, 0, 4)); + approval_tests.emplace_back(world3.composition(position, 0, 5)); + approval_tests.emplace_back(world3.composition(position, 0, 6)); + + position = {{250e3,500e3,800e3}}; + //adibatic temperature + approval_tests.emplace_back(world3.temperature(position, 0)); + approval_tests.emplace_back(world3.temperature(position, 1)); + approval_tests.emplace_back(world3.temperature(position, 5000)); + approval_tests.emplace_back(world3.temperature(position, 10e3)); + approval_tests.emplace_back(world3.temperature(position, 25e3)); + approval_tests.emplace_back(world3.temperature(position, 50e3)); + approval_tests.emplace_back(world3.temperature(position, 75e3)); + approval_tests.emplace_back(world3.temperature(position, 150e3)); + //approval_tests.emplace_back(world3.temperature(position, std::sqrt(2) * 100e3 - 1)); + //approval_tests.emplace_back(world3.temperature(position, std::sqrt(2) * 100e3 + 1)); + approval_tests.emplace_back(world3.composition(position, 0, 0)); + approval_tests.emplace_back(world3.composition(position, 0, 1)); + approval_tests.emplace_back(world3.composition(position, 0, 2)); + approval_tests.emplace_back(world3.composition(position, 0, 3)); + approval_tests.emplace_back(world3.composition(position, 0, 4)); + approval_tests.emplace_back(world3.composition(position, 10, 0)); + approval_tests.emplace_back(world3.composition(position, 10, 1)); + approval_tests.emplace_back(world3.composition(position, 10, 2)); + approval_tests.emplace_back(world3.composition(position, 10, 3)); + approval_tests.emplace_back(world3.composition(position, 10, 4)); + //todo: recheck these results + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 16.5e3 - 1, 0)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 16.5e3 + 1, 0)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 16.5e3 - 1, 1)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 16.5e3 + 1, 1)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 33e3 - 1, 1)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 33e3 + 1, 1)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 33e3 - 1, 2)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 33e3 + 1, 2)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 33e3 + 1, 3)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 49.5e3 - 1, 2)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 49.5e3 - 1, 3)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 49.5e3 + 1, 2)); + // this comes form the first subducting plate + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 49.5e3 + 1, 3)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 50e3 - 1, 3)); + approval_tests.emplace_back(world3.composition(position, std::sqrt(2) * 50e3 + 1, 3)); + approval_tests.emplace_back(world3.composition(position, 0, 4)); + approval_tests.emplace_back(world3.composition(position, 0, 5)); + approval_tests.emplace_back(world3.composition(position, 0, 6)); + + { + const WorldBuilder::grains grains = world3.grains(position, std::sqrt(2) * 33e3 * 0.5 - 1, 0, 3); + approval_tests_grains.emplace_back(grains); + } + + position = {{250e3,600e3,800e3}}; + approval_tests.emplace_back(world3.temperature(position, 0)); + approval_tests.emplace_back(world3.temperature(position, 10)); + approval_tests.emplace_back(world3.temperature(position, 100e3-1)); + approval_tests.emplace_back(world3.temperature(position, 100e3+1)); + approval_tests.emplace_back(world3.temperature(position, 101e3)); + approval_tests.emplace_back(world3.temperature(position, 110e3)); + approval_tests.emplace_back(world3.temperature(position, 150e3)); + approval_tests.emplace_back(world3.temperature(position, 200e3)); + approval_tests.emplace_back(world3.composition(position, 0, 0)); + approval_tests.emplace_back(world3.composition(position, 0, 1)); + approval_tests.emplace_back(world3.composition(position, 0, 2)); + approval_tests.emplace_back(world3.composition(position, 0, 3)); + approval_tests.emplace_back(world3.composition(position, 10, 0)); + approval_tests.emplace_back(world3.composition(position, 10, 1)); + approval_tests.emplace_back(world3.composition(position, 10, 2)); + approval_tests.emplace_back(world3.composition(position, 10, 3)); + approval_tests.emplace_back(world3.composition(position, 100e3-1, 0)); + approval_tests.emplace_back(world3.composition(position, 100e3-1, 1)); + approval_tests.emplace_back(world3.composition(position, 100e3-1, 2)); + approval_tests.emplace_back(world3.composition(position, 100e3-1, 3)); + approval_tests.emplace_back(world3.composition(position, 100e3-1, 4)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 0)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 1)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 2)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 3)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 4)); + approval_tests.emplace_back(world3.composition(position, 101e3, 0)); + approval_tests.emplace_back(world3.composition(position, 101e3+1, 1)); + approval_tests.emplace_back(world3.composition(position, 101e3+1, 2)); + approval_tests.emplace_back(world3.composition(position, 101e3+1, 3)); + approval_tests.emplace_back(world3.composition(position, 101e3+1, 4)); + approval_tests.emplace_back(world3.composition(position, 150e3, 0)); + approval_tests.emplace_back(world3.composition(position, 150e3, 1)); + approval_tests.emplace_back(world3.composition(position, 150e3, 2)); + approval_tests.emplace_back(world3.composition(position, 150e3, 3)); + approval_tests.emplace_back(world3.composition(position, 150e3, 4)); + approval_tests.emplace_back(world3.composition(position, 200e3, 0)); + approval_tests.emplace_back(world3.composition(position, 200e3, 1)); + approval_tests.emplace_back(world3.composition(position, 200e3, 2)); + approval_tests.emplace_back(world3.composition(position, 200e3, 3)); + approval_tests.emplace_back(world3.composition(position, 200e3, 4)); + approval_tests.emplace_back(world3.composition(position, 0, 4)); + approval_tests.emplace_back(world3.composition(position, 0, 5)); + approval_tests.emplace_back(world3.composition(position, 0, 6)); + + { + const WorldBuilder::grains grains = world3.grains(position, 101e3+1, 0, 3); + approval_tests_grains.emplace_back(grains); + } + + position = {{650e3,650e3,800e3}}; + approval_tests.emplace_back(world3.temperature(position, 0)); + approval_tests.emplace_back(world3.temperature(position, 10)); + approval_tests.emplace_back(world3.temperature(position, 100e3)); + approval_tests.emplace_back(world3.temperature(position, 100e3+1)); + approval_tests.emplace_back(world3.temperature(position, 101e3)); + approval_tests.emplace_back(world3.temperature(position, 110e3)); + approval_tests.emplace_back(world3.temperature(position, 150e3)); + approval_tests.emplace_back(world3.temperature(position, 200e3)); + approval_tests.emplace_back(world3.composition(position, 0, 0)); + approval_tests.emplace_back(world3.composition(position, 0, 1)); + approval_tests.emplace_back(world3.composition(position, 0, 2)); + approval_tests.emplace_back(world3.composition(position, 0, 3)); + approval_tests.emplace_back(world3.composition(position, 10, 0)); + approval_tests.emplace_back(world3.composition(position, 10, 1)); + approval_tests.emplace_back(world3.composition(position, 10, 2)); + approval_tests.emplace_back(world3.composition(position, 10, 3)); + approval_tests.emplace_back(world3.composition(position, 100e3, 0)); + approval_tests.emplace_back(world3.composition(position, 100e3, 1)); + approval_tests.emplace_back(world3.composition(position, 100e3, 2)); + approval_tests.emplace_back(world3.composition(position, 100e3, 3)); + approval_tests.emplace_back(world3.composition(position, 100e3, 4)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 0)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 1)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 2)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 3)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 4)); + approval_tests.emplace_back(world3.composition(position, 101e3, 0)); + approval_tests.emplace_back(world3.composition(position, 101e3+1, 1)); + approval_tests.emplace_back(world3.composition(position, 101e3+1, 2)); + approval_tests.emplace_back(world3.composition(position, 101e3+1, 3)); + approval_tests.emplace_back(world3.composition(position, 101e3+1, 4)); + approval_tests.emplace_back(world3.composition(position, 150e3, 0)); + approval_tests.emplace_back(world3.composition(position, 150e3, 1)); + approval_tests.emplace_back(world3.composition(position, 150e3, 2)); + approval_tests.emplace_back(world3.composition(position, 150e3, 3)); + approval_tests.emplace_back(world3.composition(position, 150e3, 4)); + approval_tests.emplace_back(world3.composition(position, 200e3, 0)); + approval_tests.emplace_back(world3.composition(position, 200e3, 1)); + approval_tests.emplace_back(world3.composition(position, 200e3, 2)); + approval_tests.emplace_back(world3.composition(position, 200e3, 3)); + approval_tests.emplace_back(world3.composition(position, 200e3, 4)); + approval_tests.emplace_back(world3.composition(position, 0, 4)); + approval_tests.emplace_back(world3.composition(position, 0, 5)); + approval_tests.emplace_back(world3.composition(position, 0, 6)); + + { + const WorldBuilder::grains grains = world3.grains(position, 100e3+1, 0, 3); + approval_tests_grains.emplace_back(grains); + } + + position = {{700e3,675e3,800e3}}; + approval_tests.emplace_back(world3.temperature(position, 0)); + approval_tests.emplace_back(world3.temperature(position, 10)); + approval_tests.emplace_back(world3.temperature(position, 100e3)); + approval_tests.emplace_back(world3.temperature(position, 100e3+1)); + approval_tests.emplace_back(world3.temperature(position, 101e3)); + approval_tests.emplace_back(world3.temperature(position, 110e3)); + approval_tests.emplace_back(world3.temperature(position, 150e3)); + approval_tests.emplace_back(world3.temperature(position, 200e3)); + approval_tests.emplace_back(world3.composition(position, 0, 0)); + approval_tests.emplace_back(world3.composition(position, 0, 1)); + approval_tests.emplace_back(world3.composition(position, 0, 2)); + approval_tests.emplace_back(world3.composition(position, 0, 3)); + approval_tests.emplace_back(world3.composition(position, 10, 0)); + approval_tests.emplace_back(world3.composition(position, 10, 1)); + approval_tests.emplace_back(world3.composition(position, 10, 2)); + approval_tests.emplace_back(world3.composition(position, 10, 3)); + approval_tests.emplace_back(world3.composition(position, 100e3, 0)); + approval_tests.emplace_back(world3.composition(position, 100e3, 1)); + approval_tests.emplace_back(world3.composition(position, 100e3, 2)); + approval_tests.emplace_back(world3.composition(position, 100e3, 3)); + approval_tests.emplace_back(world3.composition(position, 100e3, 4)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 0)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 1)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 2)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 3)); + approval_tests.emplace_back(world3.composition(position, 100e3+1, 4)); + approval_tests.emplace_back(world3.composition(position, 101e3, 0)); + approval_tests.emplace_back(world3.composition(position, 101e3+1, 1)); + approval_tests.emplace_back(world3.composition(position, 101e3+1, 2)); + approval_tests.emplace_back(world3.composition(position, 101e3+1, 3)); + approval_tests.emplace_back(world3.composition(position, 101e3+1, 4)); + approval_tests.emplace_back(world3.composition(position, 150e3, 0)); + approval_tests.emplace_back(world3.composition(position, 150e3, 1)); + approval_tests.emplace_back(world3.composition(position, 150e3, 2)); + approval_tests.emplace_back(world3.composition(position, 150e3, 3)); + approval_tests.emplace_back(world3.composition(position, 150e3, 4)); + approval_tests.emplace_back(world3.composition(position, 200e3, 0)); + approval_tests.emplace_back(world3.composition(position, 200e3, 1)); + approval_tests.emplace_back(world3.composition(position, 200e3, 2)); + approval_tests.emplace_back(world3.composition(position, 200e3, 3)); + approval_tests.emplace_back(world3.composition(position, 200e3, 4)); + approval_tests.emplace_back(world3.composition(position, 0, 4)); + approval_tests.emplace_back(world3.composition(position, 0, 5)); + approval_tests.emplace_back(world3.composition(position, 0, 6)); + + position = {{750e3,35e3,800e3}}; + approval_tests.emplace_back(world3.temperature(position, 0)); + approval_tests.emplace_back(world3.temperature(position, 10)); + approval_tests.emplace_back(world3.temperature(position, 5e3)); + approval_tests.emplace_back(world3.temperature(position, 10e3)); + approval_tests.emplace_back(world3.temperature(position, 15e3)); + approval_tests.emplace_back(world3.temperature(position, 20e3)); + approval_tests.emplace_back(world3.temperature(position, 25e3)); + approval_tests.emplace_back(world3.temperature(position, 30e3)); + approval_tests.emplace_back(world3.temperature(position, 35e3)); + approval_tests.emplace_back(world3.temperature(position, 40e3)); + approval_tests.emplace_back(world3.temperature(position, 45e3)); + approval_tests.emplace_back(world3.temperature(position, 50e3)); + approval_tests.emplace_back(world3.temperature(position, 55e3)); + approval_tests.emplace_back(world3.temperature(position, 60e3)); + approval_tests.emplace_back(world3.temperature(position, 65e3)); + approval_tests.emplace_back(world3.temperature(position, 70e3)); + approval_tests.emplace_back(world3.temperature(position, 72.5e3)); + approval_tests.emplace_back(world3.temperature(position, 75e3)); + approval_tests.emplace_back(world3.temperature(position, 80e3)); + approval_tests.emplace_back(world3.temperature(position, 85e3)); + approval_tests.emplace_back(world3.temperature(position, 90e3)); + approval_tests.emplace_back(world3.temperature(position, 95e3)); + approval_tests.emplace_back(world3.temperature(position, 100e3)); + approval_tests.emplace_back(world3.temperature(position, 105e3)); + approval_tests.emplace_back(world3.temperature(position, 110e3)); + approval_tests.emplace_back(world3.temperature(position, 115e3)); + approval_tests.emplace_back(world3.temperature(position, 120e3)); + approval_tests.emplace_back(world3.temperature(position, 125e3)); + approval_tests.emplace_back(world3.temperature(position, 130e3)); + approval_tests.emplace_back(world3.temperature(position, 135e3)); + approval_tests.emplace_back(world3.temperature(position, 150e3)); + approval_tests.emplace_back(world3.temperature(position, 160e3)); + approval_tests.emplace_back(world3.temperature(position, 170e3)); + approval_tests.emplace_back(world3.temperature(position, 175e3)); + approval_tests.emplace_back(world3.temperature(position, 180e3)); + approval_tests.emplace_back(world3.temperature(position, 190e3)); + approval_tests.emplace_back(world3.temperature(position, 200e3)); + approval_tests.emplace_back(world3.temperature(position, 250e3)); + approval_tests.emplace_back(world3.temperature(position, 300e3)); + + // check grains layer 1 + { + const WorldBuilder::grains grains = world3.grains(position, 95e3, 0, 2); + // these are random numbers, but they should stay the same. + // note that the values are different from for example the continental plate since + // this performs a interpolation between segments of the slab. + approval_tests_grains.emplace_back(grains); + } + + // check grains layer 2 bottom (because of the randomness it will have different values.) + { + const WorldBuilder::grains grains = world3.grains(position, 150e3, 0, 2); + approval_tests_grains.emplace_back(grains); + + } + + // check grains layer 2 top + { + const WorldBuilder::grains grains = world3.grains(position, 35e3, 0, 2); + approval_tests_grains.emplace_back(grains); + //compare_vectors_approx(grains.sizes, {0.3512381923,0.6487618077}); + //approval_tests.emplace_back(grains.sizes[0] + grains.sizes[1]); + //// these are random numbers, but they should stay the same. +// + //std::array, 3> array_1 = {{{{-0.5760272563,-0.3302260164,0.7477589038}},{{-0.3927671635,-0.6904395086,-0.6074761232}},{{0.7168867103,-0.6436179481,0.26801004}}}}; + //std::array, 3> array_2 = {{{{0.7622618339,-0.3280663618,0.5579689586}},{{-0.2767873192,-0.9444558064,-0.1771779043}},{{0.5851031332,-0.01938277797,-0.8107272238}}}}; + //std::vector, 3> > vector_1 = {array_1,array_2}; + //compare_vectors_array3_array3_approx(grains.rotation_matrices, vector_1); + } + + + file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/fault_different_angles_cartesian.wb"; + const WorldBuilder::World world4(file_name); + + position = {{250e3,501e3,800e3}}; + approval_tests.emplace_back(world4.temperature(position, 0)); + approval_tests.emplace_back(world4.composition(position, 0, 0)); + approval_tests.emplace_back(world4.temperature(position, 1)); + approval_tests.emplace_back(world4.composition(position, 1, 0)); + approval_tests.emplace_back(world4.temperature(position, 1e3)); + approval_tests.emplace_back(world4.composition(position, 1e3, 0)); + approval_tests.emplace_back(world4.temperature(position, 10e3)); + approval_tests.emplace_back(world4.composition(position, 10e3, 0)); + approval_tests.emplace_back(world4.temperature(position, 20e3)); + approval_tests.emplace_back(world4.composition(position, 20e3, 0)); + approval_tests.emplace_back(world4.temperature(position, 30e3)); + approval_tests.emplace_back(world4.composition(position, 30e3, 0)); + approval_tests.emplace_back(world4.temperature(position, 35e3)); + approval_tests.emplace_back(world4.composition(position, 35e3, 0)); + approval_tests.emplace_back(world4.temperature(position, 40e3)); + approval_tests.emplace_back(world4.composition(position, 40e3, 0)); + approval_tests.emplace_back(world4.temperature(position, 45e3)); + approval_tests.emplace_back(world4.composition(position, 45e3, 0)); + approval_tests.emplace_back(world4.temperature(position, 50e3)); + approval_tests.emplace_back(world4.composition(position, 50e3, 0)); + approval_tests.emplace_back(world4.temperature(position, 60e3)); + approval_tests.emplace_back(world4.composition(position, 60e3, 0)); + approval_tests.emplace_back(world4.temperature(position, 80e3)); + approval_tests.emplace_back(world4.composition(position, 80e3, 0)); + approval_tests.emplace_back(world4.temperature(position, 100e3)); + approval_tests.emplace_back(world4.composition(position, 100e3, 0)); + + std::vector approvals; + for (auto&& value : approval_tests) + { + std::stringstream s; + s << value; + approvals.emplace_back(s.str()); + } + for (auto&& value : approval_tests_grains) + { + std::stringstream s; + s << value << " "; + approvals.emplace_back(s.str()); + } + ApprovalTests::Approvals::verifyAll("Test", approvals); +} + +TEST_CASE("WorldBuilder Features: coordinate interpolation") +{ + std::vector approval_tests; + + { + const std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/interpolation_monotone_spline_cartesian.wb"; + const WorldBuilder::World world1(file_name); + + std::array position = {{374e3,875e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + position = {{376e3,875e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + position = {{350e3,900e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + + position = {{375e3,874e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + position = {{375e3,876e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + + + position = {{374e3,625e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + position = {{376e3,625e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + position = {{350e3,600e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + + position = {{375e3,624e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + position = {{375e3,626e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 0)); + approval_tests.emplace_back(world1.composition(position, 0, 0)); + + + position = {{638e3,425e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.composition(position, 10, 0)); + position = {{637e3,425e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.composition(position, 10, 0)); + position = {{617.5e3,445e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 1e3)); + approval_tests.emplace_back(world1.composition(position, 1e3, 0)); + + position = {{625e3,200e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.composition(position, 10, 0)); + position = {{624e3,200e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 10)); + approval_tests.emplace_back(world1.composition(position, 10, 0)); + position = {{607e3,180e3,800e3}}; + approval_tests.emplace_back(world1.temperature(position, 3e3)); + approval_tests.emplace_back(world1.composition(position, 3e3, 0)); + } + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} +TEST_CASE("WorldBuilder Types: Double") +{ +#define TYPE Double + Types::TYPE const type(1); + CHECK(type.default_value == Approx(1.0)); + CHECK(type.get_type() == Types::type::TYPE); + + Types::TYPE const &type_copy(type); + CHECK(type_copy.default_value == Approx(1.0)); + CHECK(type_copy.get_type() == Types::type::TYPE); + + Types::TYPE const type_explicit(3); + CHECK(type_explicit.default_value == Approx(3.0)); + CHECK(type_explicit.get_type() == Types::type::TYPE); + + const std::unique_ptr type_clone = type_explicit.clone(); + Types::TYPE *type_clone_natural = dynamic_cast(type_clone.get()); + CHECK(type_clone_natural->default_value == Approx(3.0)); + CHECK(type_clone_natural->get_type() == Types::type::TYPE); +#undef TYPE +} + +/*TEST_CASE("WorldBuilder Types: UnsignedInt") +{ +#define TYPE UnsignedInt + Types::TYPE type(1,"test"); + CHECK(type.value == Approx(1.0)); + CHECK(type.default_value == Approx(1.0)); + CHECK(type.description == "test"); + CHECK(type.get_type() == Types::type::TYPE); + Types::TYPE type_copy(type); + CHECK(type_copy.value == Approx(1.0)); + CHECK(type_copy.default_value == Approx(1.0)); + CHECK(type_copy.description == "test"); + CHECK(type_copy.get_type() == Types::type::TYPE); + Types::TYPE type_explicit(2, 3, "test explicit"); + CHECK(type_explicit.value == Approx(2.0)); + CHECK(type_explicit.default_value == Approx(3.0)); + CHECK(type_explicit.description == "test explicit"); + CHECK(type_explicit.get_type() == Types::type::TYPE); + std::unique_ptr type_clone = type_explicit.clone(); + Types::TYPE *type_clone_natural = dynamic_cast(type_clone.get()); + CHECK(type_clone_natural->value == Approx(2.0)); + CHECK(type_clone_natural->default_value == Approx(3.0)); + CHECK(type_clone_natural->description == "test explicit"); + CHECK(type_clone_natural->get_type() == Types::type::TYPE); +#undef TYPE +}*/ + +TEST_CASE("WorldBuilder Types: String") +{ +#define TYPE String + Types::TYPE const type("1","test"); + CHECK(type.default_value == "1"); + CHECK(type.get_type() == Types::type::TYPE); + + Types::TYPE const &type_copy(type); + CHECK(type_copy.default_value == "1"); + CHECK(type_copy.get_type() == Types::type::TYPE); + + Types::TYPE const type_explicit("2", "3", "test explicit"); + CHECK(type_explicit.default_value == "3"); + CHECK(type_explicit.get_type() == Types::type::TYPE); + + const std::unique_ptr type_clone = type_explicit.clone(); + Types::TYPE *type_clone_natural = dynamic_cast(type_clone.get()); + CHECK(type_clone_natural->default_value == "3"); + CHECK(type_clone_natural->get_type() == Types::type::TYPE); +#undef TYPE +} + +TEST_CASE("WorldBuilder Types: Point 2d") +{ +#define TYPE Point<2> + Types::TYPE type(TYPE(1,2,cartesian),"test"); + CHECK(type.value[0] == Approx(TYPE(1,2,cartesian)[0])); + CHECK(type.value[1] == Approx(TYPE(1,2,cartesian)[1])); + CHECK(type.default_value[0] == Approx(TYPE(1,2,cartesian)[0])); + CHECK(type.default_value[1] == Approx(TYPE(1,2,cartesian)[1])); + CHECK(type.description == "test"); + CHECK(type.get_type() == Types::type::Point2D); + + Types::TYPE type_copy(type); + CHECK(type_copy.value[0] == Approx(TYPE(1,2,cartesian)[0])); + CHECK(type_copy.value[1] == Approx(TYPE(1,2,cartesian)[1])); + CHECK(type.default_value[0] == Approx(TYPE(1,2,cartesian)[0])); + CHECK(type.default_value[1] == Approx(TYPE(1,2,cartesian)[1])); + CHECK(type_copy.description == "test"); + CHECK(type_copy.get_type() == Types::type::Point2D); + + Types::TYPE type_explicit(TYPE(3,4,cartesian), TYPE(5,6,cartesian), "test explicit"); + CHECK(type_explicit.value[0] == Approx(TYPE(3,4,cartesian)[0])); + CHECK(type_explicit.value[1] == Approx(TYPE(3,4,cartesian)[1])); + CHECK(type_explicit.default_value[0] == Approx(TYPE(5,6,cartesian)[0])); + CHECK(type_explicit.default_value[1] == Approx(TYPE(5,6,cartesian)[1])); + CHECK(type_explicit.description == "test explicit"); + CHECK(type_explicit.get_type() == Types::type::Point2D); + + const std::unique_ptr type_clone = type_explicit.clone(); + Types::TYPE *type_clone_natural = dynamic_cast(type_clone.get()); + CHECK(type_clone_natural->value[0] == Approx(TYPE(3,4,cartesian)[0])); + CHECK(type_clone_natural->value[1] == Approx(TYPE(3,4,cartesian)[1])); + CHECK(type_clone_natural->default_value[0] == Approx(TYPE(5,6,cartesian)[0])); + CHECK(type_clone_natural->default_value[1] == Approx(TYPE(5,6,cartesian)[1])); + CHECK(type_clone_natural->description == "test explicit"); + CHECK(type_clone_natural->get_type() == Types::type::Point2D); + + + + // Test Point operators + + const TYPE point_array(std::array {{1,2}},cartesian); + const TYPE point_explicit(3,4,cartesian); + + Types::TYPE type_point_array(point_array, point_array, "test array"); + const Types::TYPE type_point_array_const(point_array, point_array, "test array"); + Types::TYPE const type_point_explicit(point_explicit, point_explicit, "test array"); + + CHECK(type_point_array.value.get_array() == std::array {{1,2}}); + CHECK(type_point_explicit.value.get_array() == std::array {{3,4}}); + + // Test multiply operator + TYPE point = 2 * type_point_array * 1.0; + + CHECK(point.get_array() == std::array {{2,4}}); + + // Test dot operator + CHECK(type_point_array * type_point_explicit == Approx(11.0)); + + // Test add operator + point = type_point_array + type_point_explicit; + + CHECK(point.get_array() == std::array {{4,6}}); + + // Test subtract operator + point = type_point_explicit - type_point_array; + + CHECK(point.get_array() == std::array {{2,2}}); + + // test the access operator + CHECK(type_point_array[0] == Approx(1.0)); + + type_point_array[0] = 2; + CHECK(type_point_array[0] == Approx(2.0)); + + // test the access operator + CHECK(type_point_array_const[0] == Approx(1.0)); + CHECK(type_point_array_const[1] == Approx(2.0)); + + // Test the point output stream. + std::ostringstream stream; + stream << point_array; + const std::string str = stream.str(); + CHECK(str == "1 2"); +#undef TYPE +} + +TEST_CASE("WorldBuilder Types: Point 3d") +{ +#define TYPE Point<3> + Types::TYPE type(TYPE(1,2,3,cartesian),"test"); + const double &value_0 = type.value[0]; + CHECK(value_0 == Approx(1.0)); + CHECK(type.value[1] == Approx(2.0)); + CHECK(type.value[2] == Approx(3.0)); + CHECK(type.default_value[0] == Approx(1.0)); + CHECK(type.default_value[1] == Approx(2.0)); + CHECK(type.default_value[2] == Approx(3.0)); + CHECK(type.description == "test"); + CHECK(type.get_type() == Types::type::Point3D); + + Types::TYPE type_copy(type); + CHECK(type_copy.value[0] == Approx(1.0)); + CHECK(type_copy.value[1] == Approx(2.0)); + CHECK(type_copy.value[2] == Approx(3.0)); + CHECK(type_copy.default_value[0] == Approx(1.0)); + CHECK(type_copy.default_value[1] == Approx(2.0)); + CHECK(type_copy.default_value[2] == Approx(3.0)); + CHECK(type_copy.description == "test"); + CHECK(type_copy.get_type() == Types::type::Point3D); + + Types::TYPE type_explicit(TYPE(4,5,6,cartesian), TYPE(7,8,9,cartesian), "test explicit"); + CHECK(type_explicit.value[0] == Approx(4.0)); + CHECK(type_explicit.value[1] == Approx(5.0)); + CHECK(type_explicit.value[2] == Approx(6.0)); + CHECK(type_explicit.default_value[0] == Approx(7.0)); + CHECK(type_explicit.default_value[1] == Approx(8.0)); + CHECK(type_explicit.default_value[2] == Approx(9.0)); + CHECK(type_explicit.description == "test explicit"); + CHECK(type_explicit.get_type() == Types::type::Point3D); + + const std::unique_ptr type_clone = type_explicit.clone(); + Types::TYPE *type_clone_natural = dynamic_cast(type_clone.get()); + CHECK(type_clone_natural->value[0] == Approx(4.0)); + CHECK(type_clone_natural->value[1] == Approx(5.0)); + CHECK(type_clone_natural->value[2] == Approx(6.0)); + CHECK(type_clone_natural->default_value[0] == Approx(7.0)); + CHECK(type_clone_natural->default_value[1] == Approx(8.0)); + CHECK(type_clone_natural->default_value[2] == Approx(9.0)); + CHECK(type_clone_natural->description == "test explicit"); + CHECK(type_clone_natural->get_type() == Types::type::Point3D); + + + // Test Point operators + + const TYPE point_array(std::array {{1,2,3}},cartesian); + const TYPE point_explicit(4,5,6,cartesian); + + Types::TYPE type_point_array(point_array, point_array, "test array"); + const Types::TYPE type_point_array_const(point_array, point_array, "test array"); + Types::TYPE const type_point_explicit(point_explicit, point_explicit, "test array"); + + CHECK(type_point_array.value.get_array() == std::array {{1,2,3}}); + CHECK(type_point_explicit.value.get_array() == std::array {{4,5,6}}); + + // Test multiply operator + TYPE point = 2 * type_point_array; + + CHECK(point.get_array() == std::array {{2,4,6}}); + + // Test multiply operator + point = type_point_array * 2; + + CHECK(point.get_array() == std::array {{2,4,6}}); + + // Test dot operator + CHECK(type_point_array * type_point_explicit == Approx(32.0)); + + // Test add operator + point = type_point_array + type_point_explicit; + + CHECK(point.get_array() == std::array {{5,7,9}}); + + // Test subtract operator + point = type_point_explicit - type_point_array; + + CHECK(point.get_array() == std::array {{3,3,3}}); + + // test the access operator + CHECK(type_point_array[0] == Approx(1.0)); + + type_point_array[0] = 2; + CHECK(type_point_array[0] == Approx(2.0)); + + // const test the access operator + CHECK(point_array[0] == Approx(1.0)); + + // test the const access operator + CHECK(type_point_array_const[0] == Approx(1.0)); + CHECK(type_point_array_const[1] == Approx(2.0)); + CHECK(type_point_array_const[2] == Approx(3.0)); + + // Test the point output stream. + std::ostringstream stream; + stream << point_array; + const std::string str = stream.str(); + CHECK(str == "1 2 3"); + +#undef TYPE +} +/* +TEST_CASE("WorldBuilder Types: Coordinate System") +{ +#define TYPE CoordinateSystem + Types::TYPE type("1","test"); + CHECK(type.value == nullptr); + CHECK(type.default_value == "1"); + CHECK(type.description == "test"); + CHECK(type.get_type() == Types::type::TYPE); + std::unique_ptr type_clone = type.clone(); + Types::TYPE *type_clone_natural = dynamic_cast(type_clone.get()); + CHECK(type_clone_natural->value == nullptr); + CHECK(type_clone_natural->default_value == "1"); + CHECK(type_clone_natural->description == "test"); + CHECK(type_clone_natural->get_type() == Types::type::TYPE); + // todo: test the set value function. +#undef TYPE +}*/ + +// not sure how to unit test this. +TEST_CASE("WorldBuilder Types: PluginSystem") +{ +#define TYPE PluginSystem + Types::TYPE type("test", Features::ContinentalPlate::declare_entries, std::vector {{"test required"}}, false); + CHECK(type.default_value == "test"); + CHECK(type.required_entries[0] == "test required"); + CHECK(type.allow_multiple == false); + CHECK(type.get_type() == Types::type::TYPE); + + Types::TYPE type_copy(type); + CHECK(type_copy.default_value == "test"); + CHECK(type_copy.required_entries[0] == "test required"); + CHECK(type_copy.allow_multiple == false); + CHECK(type_copy.get_type() == Types::type::TYPE); + + const std::unique_ptr type_clone = type_copy.clone(); + Types::TYPE *type_clone_natural = dynamic_cast(type_clone.get()); + CHECK(type_clone_natural->default_value == "test"); + CHECK(type_clone_natural->required_entries[0] == "test required"); + CHECK(type_clone_natural->allow_multiple == false); + CHECK(type_clone_natural->get_type() == Types::type::TYPE); + +#undef TYPE +} + + +// not sure how to unit test this. +TEST_CASE("WorldBuilder Types: Segment Object") +{ +#define TYPE Segment + const WorldBuilder::Point<2> thickness(1,2,invalid); + const WorldBuilder::Point<2> top_trucation(3,4,invalid); + const WorldBuilder::Point<2> angle(5,6,invalid); + Objects::TYPE + type (1.0, thickness, top_trucation, angle, + std::vector >(), + std::vector >(), + std::vector >()); + CHECK(type.value_length == Approx(1.0)); + CHECK(type.value_thickness[0] == Approx(1.0)); + CHECK(type.value_thickness[1] == Approx(2.0)); + CHECK(type.value_top_truncation[0] == Approx(3.0)); + CHECK(type.value_top_truncation[1] == Approx(4.0)); + CHECK(type.value_angle[0] == Approx(5.0)); + CHECK(type.value_angle[1] == Approx(6.0)); + + Objects::TYPE + type_copy(type); + const double &value_length = type_copy.value_length; + CHECK(value_length == Approx(1.0)); + CHECK(type_copy.value_thickness[0] == Approx(1.0)); + CHECK(type_copy.value_thickness[1] == Approx(2.0)); + CHECK(type_copy.value_top_truncation[0] == Approx(3.0)); + CHECK(type_copy.value_top_truncation[1] == Approx(4.0)); + CHECK(type_copy.value_angle[0] == Approx(5.0)); + CHECK(type_copy.value_angle[1] == Approx(6.0)); + +#undef TYPE +} + +TEST_CASE("WorldBuilder Types: Array") +{ +#define TYPE Array + Types::TYPE const type(Types::Double(0)); + CHECK(type.inner_type == Types::type::Double); + CHECK(type.inner_type_ptr.get() != nullptr); + CHECK(type.get_type() == Types::type::TYPE); + + Types::TYPE const &type_copy(type); + CHECK(type_copy.inner_type == Types::type::Double); + CHECK(type_copy.inner_type_ptr.get() != nullptr); + CHECK(type_copy.get_type() == Types::type::TYPE); + + /*Types::TYPE type_explicit(std::vector {1,2}, Types::type::Double, "array test explicit"); + CHECK(type_explicit.inner_type == Types::type::Double); + CHECK(type_explicit.inner_type_ptr.get() == nullptr); + CHECK(type_explicit.inner_type_index.size() == 2); + CHECK(type_explicit.description == "array test explicit"); + CHECK(type_explicit.get_type() == Types::type::TYPE);*/ + + //CHECK_THROWS_WITH(type.clone(),Contains("Error: Cloning Arrays is currently not possible.")); + /* + std::unique_ptr type_clone = type_explicit.clone() + Types::TYPE *type_clone_natural = dynamic_cast(type_clone.get()); + CHECK(type_clone_natural->inner_type == Types::type::Double); + CHECK(type_clone_natural->inner_type_ptr.get() == nullptr); + CHECK(type_clone_natural->inner_type_index.size() == 2); + CHECK(type_clone_natural->description == "array test explicit"); + CHECK(type_clone_natural->get_type() == Types::type::TYPE); + Types::TYPE type_copy2(*type_clone_natural); + CHECK(type_copy2.inner_type == Types::type::Double); + CHECK(type_copy2.inner_type_ptr.get() == nullptr); + CHECK(type_copy2.inner_type_index.size() == 2); + CHECK(type_copy2.description == "array test explicit"); + CHECK(type_copy2.get_type() == Types::type::TYPE);*/ + +#undef TYPE +} + +TEST_CASE("WorldBuilder Types: Object") +{ +#define TYPE Object + Types::TYPE type(std::vector {"test1","test2"},true); + CHECK(type.required.size() == 2); + CHECK(type.required[0] == "test1"); + CHECK(type.required[1] == "test2"); + CHECK(type.additional_properties == true); + CHECK(type.get_type() == Types::type::TYPE); + + Types::TYPE type_copy(type); + CHECK(type_copy.required.size() == 2); + CHECK(type_copy.required[0] == "test1"); + CHECK(type_copy.required[1] == "test2"); + CHECK(type_copy.additional_properties == true); + CHECK(type_copy.get_type() == Types::type::TYPE); + + const std::unique_ptr type_clone = type_copy.clone(); + Types::TYPE *type_clone_natural = dynamic_cast(type_clone.get()); + CHECK(type_clone_natural->required.size() == 2); + CHECK(type_clone_natural->required[0] == "test1"); + CHECK(type_clone_natural->required[1] == "test2"); + CHECK(type_clone_natural->additional_properties == true); + CHECK(type_clone_natural->get_type() == Types::type::TYPE); + + Types::TYPE type_copy2(*type_clone_natural); + CHECK(type_copy2.required.size() == 2); + CHECK(type_copy2.required[0] == "test1"); + CHECK(type_copy2.required[1] == "test2"); + CHECK(type_copy2.additional_properties == true); + CHECK(type_copy2.get_type() == Types::type::TYPE); + +#undef TYPE +} + + +TEST_CASE("WorldBuilder Types: Bool") +{ +#define TYPE Bool + Types::TYPE const type(true); + CHECK(type.default_value == true); + CHECK(type.get_type() == Types::type::TYPE); + + + Types::TYPE const &type_copy(type); + CHECK(type_copy.default_value == true); + CHECK(type_copy.get_type() == Types::type::TYPE); + + const std::unique_ptr type_clone = type_copy.clone(); + Types::TYPE *type_clone_natural = dynamic_cast(type_clone.get()); + CHECK(type_clone_natural->default_value == true); + CHECK(type_clone_natural->get_type() == Types::type::TYPE); + + Types::TYPE const type_copy2(*type_clone_natural); + CHECK(type_copy2.default_value == true); + CHECK(type_copy2.get_type() == Types::type::TYPE); + +#undef TYPE +} + +/* +TEST_CASE("WorldBuilder Types: print_tree") +{ + std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/simple_wb1.json"; + boost::property_tree::ptree tree; + std::ifstream json_input_stream(file_name.c_str()); + + boost::property_tree::json_parser::read_json (json_input_stream, tree); + std::stringstream output; + output << + "{\n" + " \"version\": \"0.1\",\n" + " \"coordinate system\": \n" + " {\n" + " \"model\": \"cartesian\"\n" + " },\n" + " \"cross section\": \n" + " {\n" + " \"\": \n" + " {\n" + " \"\": \"100e3\",\n" + " \"\": \"100e3\"\n" + " },\n" + " \"\": \n" + " {\n" + " \"\": \"400e3\",\n" + " \"\": \"500e3\"\n" + " }\n" + " },\n" + " \"maximum distance between coordinates\": \"5\",\n" + " \"features\": \n" + " {\n" + " \"\": \n" + " {\n" + " \"model\": \"continental plate\",\n" + " \"name\": \"Caribbean\",\n" + " \"max depth\": \"300e3\",\n" + " \"coordinates\": \n" + " {\n" + " \"\": \n" + " {\n" + " \"\": \"-1e3\",\n" + " \"\": \"500e3\"\n" + " },\n" + " \"\": \n" + " {\n" + " \"\": \"500e3\",\n" + " \"\": \"500e3\"\n" + " },\n" + " \"\": \n" + " {\n" + " \"\": \"500e3\",\n" + " \"\": \"1000e3\"\n" + " },\n" + " \"\": \n" + " {\n" + " \"\": \"-1e3\",\n" + " \"\": \"1000e3\"\n" + " }\n" + " },\n" + " \"temperature models\": \n" + " {\n" + " \"\": \n" + " {\n" + " \"model\": \"uniform\",\n" + " \"min depth\": \"0\",\n" + " \"max depth\": \"250e3\",\n" + " \"temperature\": \"150\"\n" + " }\n" + " }\n" + " },\n" + " \"\": \n" + " {\n" + " \"model\": \"continental plate\",\n" + " \"name\": \"Rest\",\n" + " \"max depth\": \"300e3\",\n" + " \"coordinates\": \n" + " {\n" + " \"\": \n" + " {\n" + " \"\": \"2000e3\",\n" + " \"\": \"2000e3\"\n" + " },\n" + " \"\": \n" + " {\n" + " \"\": \"1000e3\",\n" + " \"\": \"2000e3\"\n" + " },\n" + " \"\": \n" + " {\n" + " \"\": \"1000e3\",\n" + " \"\": \"1000e3\"\n" + " },\n" + " \"\": \n" + " {\n" + " \"\": \"2000e3\",\n" + " \"\": \"1000e3\"\n" + " }\n" + " },\n" + " \"temperature models\": \n" + " {\n" + " \"\": \n" + " {\n" + " \"model\": \"uniform\",\n" + " \"max depth\": \"250e3\",\n" + " \"temperature\": \"20\"\n" + " }\n" + " },\n" + " \"composition models\": \n" + " {\n" + " \"\": \n" + " {\n" + " \"model\": \"uniform\",\n" + " \"max depth\": \"250e3\",\n" + " \"compositions\": \n" + " {\n" + " \"\": \"2\"\n" + " }\n" + " }\n" + " }\n" + " },\n" + " \"\": \n" + " {\n" + " \"model\": \"continental plate\",\n" + " \"name\": \"Caribbean2\",\n" + " \"max depth\": \"300e3\",\n" + " \"coordinates\": \n" + " {\n" + " \"\": \n" + " {\n" + " \"\": \"-1e3\",\n" + " \"\": \"500e3\"\n" + " },\n" + " \"\": \n" + " {\n" + " \"\": \"500e3\",\n" + " \"\": \"500e3\"\n" + " },\n" + " \"\": \n" + " {\n" + " \"\": \"500e3\",\n" + " \"\": \"1000e3\"\n" + " },\n" + " \"\": \n" + " {\n" + " \"\": \"-1e3\",\n" + " \"\": \"1000e3\"\n" + " }\n" + " },\n" + " \"temperature models\": \n" + " {\n" + " \"\": \n" + " {\n" + " \"model\": \"uniform\",\n" + " \"min depth\": \"0\",\n" + " \"max depth\": \"250e3\",\n" + " \"temperature\": \"150\"\n" + " }\n" + " },\n" + " \"composition models\": \n" + " {\n" + " \"\": \n" + " {\n" + " \"model\": \"uniform\",\n" + " \"min depth\": \"0\",\n" + " \"max depth\": \"250e3\",\n" + " \"compositions\": \n" + " {\n" + " \"\": \"3\"\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }"; + approval_tests.emplace_back(Utilities::print_tree(tree, 0)); +}*/ + +TEST_CASE("WorldBuilder Parameters") +{ + std::vector approval_tests; + + // First test a world builder file with a cross section defined + std::string file = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/type_data.json"; + const std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/subducting_plate_different_angles_cartesian.wb"; + WorldBuilder::World world(file_name); + + world.parse_entries(world.parameters); + approval_tests.emplace_back(std::isinf(world.parameters.coordinate_system->max_model_depth())); + + Parameters prm(world); + prm.initialize(file); + + world.parameters.coordinate_system.swap(prm.coordinate_system); + + CHECK_THROWS_WITH(prm.get("non existent unsigned int"), + Contains("internal error: could not retrieve the default value at")); + + CHECK(prm.get("unsigned int") == 4); + + CHECK_THROWS_WITH(prm.get("non existent unsigned int"), + Contains("internal error: could not retrieve the default value at")); + + CHECK(prm.get("unsigned int") == 4); + + + CHECK_THROWS_WITH(prm.get("non existent double"), + Contains("internal error: could not retrieve the default value at")); + + CHECK(prm.get("double") == Approx(1.23456e2)); + + + CHECK_THROWS_WITH(prm.get("string"), + Contains("Could not convert values of")); + + CHECK_THROWS_WITH(prm.get("non existent string"), + Contains("internal error: could not retrieve the default value at")); + + CHECK(prm.get("string") == "mystring 0"); + prm.enter_subsection("properties"); + + { + WorldBuilder::World world_temp(file_name); + Parameters prm_temp(world_temp); + prm_temp.declare_entry("test",Types::OneOf(Types::OneOf(Types::Double(101),Types::Double(102)),Types::Double(103)),"doc"); + + CHECK(rapidjson::Pointer("/test/oneOf/0/oneOf/0/default value").Get(prm_temp.declarations)->GetDouble() == Approx(101.)); + CHECK(rapidjson::Pointer("/test/oneOf/0/oneOf/1/default value").Get(prm_temp.declarations)->GetDouble() == Approx(102.)); + CHECK(rapidjson::Pointer("/test/oneOf/1/default value").Get(prm_temp.declarations)->GetDouble() == Approx(103.)); + } + prm.declare_entry("one value at points one value string",Types::OneOf(Types::Double(101.),Types::Array(Types::ValueAtPoints(101., 2.))), + "Documentation"); + prm.declare_entry("array value at points one value string",Types::OneOf(Types::Double(101.),Types::Array(Types::ValueAtPoints(101., 2.))), + "Documentation"); + prm.declare_entry("value at points set ap val string",Types::OneOf(Types::Double(101.),Types::Array(Types::ValueAtPoints(101., 2.))), + "Documentation"); + prm.declare_entry("value at points set ap p1 string",Types::OneOf(Types::Double(101.),Types::Array(Types::ValueAtPoints(101., 2.))), + "Documentation"); + prm.declare_entry("value at points set ap p2 string",Types::OneOf(Types::Double(101.),Types::Array(Types::ValueAtPoints(101., 2.))), + "Documentation"); + prm.declare_entry("one value at points one value",Types::OneOf(Types::Double(101.),Types::Array(Types::ValueAtPoints(101., 2.))), + "Documentation"); + prm.declare_entry("array value at points one value",Types::OneOf(Types::Double(101.),Types::Array(Types::ValueAtPoints(101., 2.))), + "Documentation"); + prm.declare_entry("value at points",Types::OneOf(Types::Double(101.),Types::Array(Types::ValueAtPoints(101., 2.))), + "Documentation"); + prm.declare_entry("value at points default ap",Types::OneOf(Types::Double(101.),Types::Array(Types::ValueAtPoints(101., 2.))), + "Documentation"); + prm.declare_entry("value at array full",Types::OneOf(Types::Double(101.),Types::Array(Types::ValueAtPoints(101., std::numeric_limits::max()))), + "Documentation"); + prm.declare_entry("value at array",Types::OneOf(Types::Double(101.),Types::Array(Types::ValueAtPoints(101., std::numeric_limits::max()))), + "Documentation"); + prm.declare_entry("vector for vector or double", Types::OneOf(Types::Double(-1), Types::Array(Types::Array(Types::Double(-1), 1), 1)), + "Documentation"); + prm.leave_subsection(); + const std::vector > additional_points = {Point<2>(-10,-10,cartesian),Point<2>(-10,10,cartesian), + Point<2>(10,10,cartesian),Point<2>(10,-10,cartesian) + }; + CHECK_THROWS_WITH(prm.get("value at points non existent",additional_points), Contains("internal error: could not retrieve")); + std::pair,std::vector> v_at_p_one_value = prm.get("one value at points one value",additional_points); + + approval_tests.emplace_back(static_cast(v_at_p_one_value.first.size())); + approval_tests.emplace_back(static_cast(v_at_p_one_value.first[0])); + approval_tests.emplace_back(static_cast(v_at_p_one_value.second.size())); + + { + const Objects::Surface surface(v_at_p_one_value); + approval_tests.emplace_back(surface.local_value(Point<2>(0,0,CoordinateSystem::cartesian)).interpolated_value); + } + std::pair,std::vector> v_at_p_one_array_value = prm.get("array value at points one value",additional_points); + + approval_tests.emplace_back(static_cast(v_at_p_one_array_value.first.size())); + approval_tests.emplace_back(static_cast(v_at_p_one_array_value.first[0])); + approval_tests.emplace_back(static_cast(v_at_p_one_array_value.second.size())); + + std::pair,std::vector> v_at_p_full_default = prm.get("value at points",additional_points); + + approval_tests.emplace_back(static_cast(v_at_p_full_default.first.size())); + approval_tests.emplace_back(static_cast(v_at_p_full_default.first[0])); + approval_tests.emplace_back(static_cast(v_at_p_full_default.second.size())); + + std::pair,std::vector> v_at_p_dap = prm.get("value at points default ap",additional_points); + + approval_tests.emplace_back(static_cast(v_at_p_dap.first.size())); + approval_tests.emplace_back(v_at_p_dap.first[0]); + approval_tests.emplace_back(v_at_p_dap.first[1]); + approval_tests.emplace_back(v_at_p_dap.first[2]); + approval_tests.emplace_back(v_at_p_dap.first[3]); + approval_tests.emplace_back(v_at_p_dap.first[4]); + approval_tests.emplace_back(v_at_p_dap.first[5]); + approval_tests.emplace_back(v_at_p_dap.first[6]); + approval_tests.emplace_back(static_cast(v_at_p_dap.second.size())); + approval_tests.emplace_back(v_at_p_dap.second[0]); + approval_tests.emplace_back(v_at_p_dap.second[1]); + approval_tests.emplace_back(v_at_p_dap.second[2]); + approval_tests.emplace_back(v_at_p_dap.second[3]); + approval_tests.emplace_back(v_at_p_dap.second[4]); + approval_tests.emplace_back(v_at_p_dap.second[5]); + approval_tests.emplace_back(v_at_p_dap.second[6]); + approval_tests.emplace_back(v_at_p_dap.second[7]); + approval_tests.emplace_back(v_at_p_dap.second[8]); + approval_tests.emplace_back(v_at_p_dap.second[9]); + approval_tests.emplace_back(v_at_p_dap.second[10]); + approval_tests.emplace_back(v_at_p_dap.second[11]); + approval_tests.emplace_back(v_at_p_dap.second[12]); + approval_tests.emplace_back(v_at_p_dap.second[13]); + + { + const Objects::Surface surface(v_at_p_dap); + + approval_tests.emplace_back(surface.local_value(Point<2>(0,0,CoordinateSystem::cartesian)).interpolated_value); + approval_tests.emplace_back(surface.local_value(Point<2>(0.99,1.99,CoordinateSystem::cartesian)).interpolated_value); + approval_tests.emplace_back(surface.local_value(Point<2>(1.01,2.01,CoordinateSystem::cartesian)).interpolated_value); + approval_tests.emplace_back(surface.local_value(Point<2>(0.99,0.99,CoordinateSystem::cartesian)).interpolated_value); + approval_tests.emplace_back(surface.local_value(Point<2>(1.01,1.01,CoordinateSystem::cartesian)).interpolated_value); + approval_tests.emplace_back(surface.local_value(Point<2>(2.99,3.99,CoordinateSystem::cartesian)).interpolated_value); + approval_tests.emplace_back(surface.local_value(Point<2>(2.01,4.01,CoordinateSystem::cartesian)).interpolated_value); + approval_tests.emplace_back(surface.local_value(Point<2>(-0.5,7.48,CoordinateSystem::cartesian)).interpolated_value); + approval_tests.emplace_back(surface.local_value(Point<2>(-1,7.6,CoordinateSystem::cartesian)).interpolated_value); + approval_tests.emplace_back(surface.local_value(Point<2>(-2.4,8.2,CoordinateSystem::cartesian)).interpolated_value); + CHECK_THROWS_WITH(surface.local_value(Point<2>(11,11,CoordinateSystem::cartesian)), Contains("The requested point was not in any triangle.")); + } + + + CHECK_THROWS_WITH(prm.get("one value at points one value string",additional_points), + Contains("Could not convert values of /one value at points one value string into a double. The provided value was \"test1\".")); + CHECK_THROWS_WITH(prm.get("array value at points one value string",additional_points), + Contains("Could not convert values of /array value at points one value string/0/0 into a double. The provided value was \"test2\".")); + CHECK_THROWS_WITH(prm.get("value at points set ap val string",additional_points), + Contains("Could not convert values of /value at points set ap val string/2/0 into doubles. The provided value was \"test3\".")); + CHECK_THROWS_WITH(prm.get("value at points set ap p1 string",additional_points), + Contains("Could not convert values of /value at points set ap p1 string/3/1/0/0 into a Point<2> array, because it could not convert the 1st sub-elements into doubles. The provided value was \"test4\".")); + CHECK_THROWS_WITH(prm.get("value at points set ap p2 string",additional_points), + Contains("Could not convert values of /value at points set ap p2 string/3/1/0/1 into a Point<2> array, because it could not convert the 2nd sub-elements into doubles. The provided value was \"test5\".")); + + + CHECK_THROWS_WITH(prm.get_vector("non existent unsigned int vector"), + Contains("internal error: could not retrieve the minItems value at")); + + CHECK_THROWS_WITH(prm.get_vector("non existent bool vector"), + Contains("internal error: could not retrieve the minItems value at")); + + + typedef std::array array_3d; + CHECK_THROWS_WITH(prm.get_vector("vector of 3d arrays nan"), + Contains("Could not convert values of /vector of 3d arrays nan/0 into doubles.")); + + using array_3x3 = std::array, 3>; + CHECK_THROWS_WITH(prm.get_vector("vector of 3x3 arrays nan"), + Contains("Could not convert values of /vector of 3x3 arrays nan/0 into doubles.")); + + + using array_3x3 = std::array, 3>; + CHECK_THROWS_WITH(prm.get_vector("vector of 3x3 arrays not 3x3 1"), + Contains("Array 0 is supposed to be a 3x3 array, but the inner array dimensions of 0 is 2.")); + + + CHECK_THROWS_WITH(prm.get_vector("vector of 3x3 arrays not 3x3 2"), + Contains("Array 1 is supposed to be a 3x3 array, but the outer array dimensions is 2.")); + + + prm.enter_subsection("properties"); + { + prm.declare_entry("now existent unsigned int vector", + Types::Array(Types::UnsignedInt(1),2), + "This is an array of two points along where the cross section is taken"); + } + prm.leave_subsection(); + + std::vector v_int = prm.get_vector("now existent unsigned int vector"); + approval_tests.emplace_back(static_cast(v_int.size())); + approval_tests.emplace_back(static_cast(v_int[0])); + approval_tests.emplace_back(static_cast(v_int[1])); + + v_int = prm.get_vector("unsigned int array"); + approval_tests.emplace_back(static_cast(v_int.size())); + approval_tests.emplace_back(static_cast(v_int[0])); + approval_tests.emplace_back(static_cast(v_int[1])); + approval_tests.emplace_back(static_cast(v_int[2])); + + CHECK_THROWS_WITH(prm.get_vector("non existent unsigned int vector"), + Contains("internal error: could not retrieve the minItems value")); + + + + std::vector v_size_t = prm.get_vector("now existent unsigned int vector"); + approval_tests.emplace_back(static_cast(v_size_t.size())); + approval_tests.emplace_back(static_cast(v_size_t[0])); + approval_tests.emplace_back(static_cast(v_size_t[1])); + + v_size_t = prm.get_vector("unsigned int array"); + approval_tests.emplace_back(static_cast(v_size_t.size())); + approval_tests.emplace_back(static_cast(v_size_t[0])); + approval_tests.emplace_back(static_cast(v_size_t[1])); + approval_tests.emplace_back(static_cast(v_size_t[2])); + + + CHECK_THROWS_WITH(prm.get_vector("non existent unsigned int vector"), + Contains("internal error: could not retrieve the minItems value")); + + prm.enter_subsection("properties"); + { + prm.declare_entry("now existent bool vector", + Types::Array(Types::Bool(true),2), + "This is an array of two bools."); + } + prm.leave_subsection(); + + std::vector v_bool = prm.get_vector("now existent bool vector"); + approval_tests.emplace_back(static_cast(v_bool.size())); + approval_tests.emplace_back(static_cast(v_bool[0])); + approval_tests.emplace_back(static_cast(v_bool[1])); + + v_bool = prm.get_vector("bool array"); + approval_tests.emplace_back(static_cast(v_bool.size())); + approval_tests.emplace_back(static_cast(v_bool[0])); + approval_tests.emplace_back(static_cast(v_bool[1])); + approval_tests.emplace_back(static_cast(v_bool[2])); + approval_tests.emplace_back(static_cast(v_bool[3])); + approval_tests.emplace_back(static_cast(v_bool[4])); + approval_tests.emplace_back(static_cast(v_bool[1])); + + CHECK_THROWS_WITH(prm.get_vector("bool array nob"), + Contains("IsBool()")); + + + CHECK_THROWS_WITH(prm.get_vector("non existent double vector"), + Contains("internal error: could not retrieve the minItems value at")); + + prm.enter_subsection("properties"); + { + prm.declare_entry("now existent double vector", + Types::Array(Types::Double(2.4),2), + "This is an array of two points along where the cross section is taken"); + } + prm.leave_subsection(); + + std::vector v_double = prm.get_vector("now existent double vector"); + approval_tests.emplace_back(static_cast(v_double.size())); + approval_tests.emplace_back(v_double[0]); + approval_tests.emplace_back(v_double[1]); + + CHECK_THROWS_WITH(prm.get >("string array"), + Contains("Could not convert values of /string array into Point<2>, because it could not convert the sub-elements into doubles.")); + + v_double = prm.get_vector("double array"); + approval_tests.emplace_back(static_cast(v_double.size())); + approval_tests.emplace_back(v_double[0]); + approval_tests.emplace_back(v_double[1]); + approval_tests.emplace_back(v_double[2]); + + CHECK_THROWS_WITH(prm.get_vector >("point<2> array nan"), + Contains("Could not convert values of /point<2> array nan/0 into a Point<2> array, because it could not convert the sub-elements into doubles.")); + + std::vector,3> > v_3x3_array = prm.get_vector,3> >("vector of 3x3 arrays"); + approval_tests.emplace_back(static_cast(v_3x3_array.size())); + approval_tests.emplace_back(v_3x3_array[0][0][0]); + approval_tests.emplace_back(v_3x3_array[0][0][1]); + approval_tests.emplace_back(v_3x3_array[0][0][2]); + approval_tests.emplace_back(v_3x3_array[0][1][0]); + approval_tests.emplace_back(v_3x3_array[0][1][1]); + approval_tests.emplace_back(v_3x3_array[0][1][2]); + approval_tests.emplace_back(v_3x3_array[0][2][0]); + approval_tests.emplace_back(v_3x3_array[0][2][1]); + approval_tests.emplace_back(v_3x3_array[0][2][2]); + + approval_tests.emplace_back(v_3x3_array[1][0][0]); + approval_tests.emplace_back(v_3x3_array[1][0][1]); + approval_tests.emplace_back(v_3x3_array[1][0][2]); + approval_tests.emplace_back(v_3x3_array[1][1][0]); + approval_tests.emplace_back(v_3x3_array[1][1][1]); + approval_tests.emplace_back(v_3x3_array[1][1][2]); + approval_tests.emplace_back(v_3x3_array[1][2][0]); + approval_tests.emplace_back(v_3x3_array[1][2][1]); + approval_tests.emplace_back(v_3x3_array[1][2][2]); + + std::vector > > v_v_p2 = prm.get_vector>>("vector of vectors of points<2>"); + approval_tests.emplace_back(static_cast(v_v_p2.size())); + approval_tests.emplace_back(static_cast(v_v_p2[0].size())); + approval_tests.emplace_back(v_v_p2[0][0][0]); + approval_tests.emplace_back(v_v_p2[0][0][1]); + approval_tests.emplace_back(v_v_p2[0][1][0]); + approval_tests.emplace_back(v_v_p2[0][1][1]); + + approval_tests.emplace_back(static_cast(v_v_p2[1].size())); + approval_tests.emplace_back(v_v_p2[1][0][0]); + approval_tests.emplace_back(v_v_p2[1][0][1]); + approval_tests.emplace_back(v_v_p2[1][1][0]); + approval_tests.emplace_back(v_v_p2[1][1][1]); + approval_tests.emplace_back(v_v_p2[1][2][0]); + approval_tests.emplace_back(v_v_p2[1][2][1]); + + + CHECK_THROWS_WITH(prm.get_vector>>("vector of vectors of points<2> nan"), + Contains("Could not convert values of /vector of vectors of points<2> nan/1 into doubles")); + + + std::pair,std::vector> value_at_array = prm.get_value_at_array("value at array full"); + approval_tests.emplace_back(static_cast(value_at_array.first.size())); + approval_tests.emplace_back(value_at_array.first[0]); + approval_tests.emplace_back(value_at_array.first[1]); + + approval_tests.emplace_back(static_cast(value_at_array.second.size())); + approval_tests.emplace_back(value_at_array.second[0]); + approval_tests.emplace_back(value_at_array.second[1]); + approval_tests.emplace_back(value_at_array.second[2]); + approval_tests.emplace_back(value_at_array.second[3]); + approval_tests.emplace_back(value_at_array.second[4]); + + + std::pair,std::vector> double_value_at_array = prm.get_value_at_array("one value at points one value"); + approval_tests.emplace_back(static_cast(double_value_at_array.first.size())); + approval_tests.emplace_back(double_value_at_array.first[0]); + approval_tests.emplace_back(static_cast(double_value_at_array.second.size())); + approval_tests.emplace_back(double_value_at_array.second[0]); + + std::pair,std::vector> default_value_at_array = prm.get_value_at_array("value at array"); + approval_tests.emplace_back(static_cast(default_value_at_array.first.size())); + approval_tests.emplace_back(default_value_at_array.first[0]); + approval_tests.emplace_back(static_cast(default_value_at_array.second.size())); + approval_tests.emplace_back(default_value_at_array.second[0]); + + std::vector> vector_for_vector_or_double = prm.get_vector_or_double("vector for vector or double"); + approval_tests.emplace_back(static_cast(vector_for_vector_or_double.size())); + approval_tests.emplace_back(static_cast(vector_for_vector_or_double[0].size())); + approval_tests.emplace_back(static_cast(vector_for_vector_or_double[0][0])); + approval_tests.emplace_back(static_cast(vector_for_vector_or_double[0][1])); + approval_tests.emplace_back(static_cast(vector_for_vector_or_double[0][2])); + approval_tests.emplace_back(static_cast(vector_for_vector_or_double[0][3])); + + approval_tests.emplace_back(static_cast(vector_for_vector_or_double[1].size())); + approval_tests.emplace_back(static_cast(vector_for_vector_or_double[1][0])); + approval_tests.emplace_back(static_cast(vector_for_vector_or_double[1][1])); + + std::vector> double_for_vector_or_double = prm.get_vector_or_double("one value at points one value"); + approval_tests.emplace_back(static_cast(double_for_vector_or_double.size())); + approval_tests.emplace_back(static_cast(double_for_vector_or_double[0].size())); + approval_tests.emplace_back(static_cast(double_for_vector_or_double[0][0])); + /*CHECK_THROWS_WITH(prm.get_vector("non existent string vector"), + Contains("internal error: could not retrieve the default value at")); + + std::vector v_string = prm.get_vector("string array"); + approval_tests.emplace_back(v_string[0]); + approval_tests.emplace_back(v_string[1]);*/ + + //prm.load_entry("Coordinate system", false, Types::CoordinateSystem("cartesian","This determines the coordinate system")); + + // Test the UnsignedInt functions + /*CHECK_THROWS_WITH(prm.load_entry("non existent unsigned int", true, Types::UnsignedInt(1,"description")), + Contains("Entry undeclared: non existent unsigned int")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_unsigned_int("non existent unsigned int"), + Contains("Could not find entry 'non existent unsigned int' not found. Make sure it is loaded or set")); + #endif + CHECK(prm.load_entry("non existent unsigned int", false, Types::UnsignedInt(1,"description")) == false); + CHECK(prm.get_unsigned_int("non existent unsigned int") == Approx(1.0)); + + prm.set_entry("new unsigned int", Types::UnsignedInt(2,"description")); + CHECK(prm.get_unsigned_int("new unsigned int") == Approx(2.0)); + + prm.load_entry("unsigned int", true, Types::UnsignedInt(3,"description")); + CHECK(prm.get_unsigned_int("unsigned int") == Approx(4.0));*/ +// Todo: redo this with the new type system. + /* + // Test the Double functions + CHECK_THROWS_WITH(prm.load_entry("non existent double", true, Types::Double(1,"description")), + Contains("Entry undeclared: non existent")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_double("non existent double"), + Contains("Could not find entry 'non existent double' not found. Make sure it is loaded or set")); + #endif + CHECK(prm.load_entry("non existent double", false, Types::Double(1,"description")) == false); + CHECK(prm.get_double("non existent double") == Approx(1.0)); + + prm.set_entry("new double", Types::Double(2,"description")); + CHECK(prm.get_double("new double") == Approx(2.0)); + + prm.load_entry("double", true, Types::Double(3,"description")); + CHECK(prm.get_double("double") == 1.23456e2); + + + // Test the String functions + CHECK_THROWS_WITH(prm.load_entry("non existent string", true, Types::String("1","description")), + Contains("Entry undeclared: non existent string")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_string("non existent string"), + Contains("Could not find entry 'non existent string' not found. Make sure it is loaded or set")); + #endif + CHECK(prm.load_entry("non exitent string", false, Types::String("1","description")) == false); + CHECK(prm.get_string("non exitent string") == "1"); + + prm.set_entry("new string", Types::String("2","description")); + CHECK(prm.get_string("new string") == "2"); + + prm.load_entry("string", true, Types::String("3","description")); + CHECK(prm.get_string("string") == "mystring 0"); + + // Test the Point functions + CHECK_THROWS_WITH(prm.load_entry("non existent 2d Point", true, Types::Point<2>(Point<2>(1,2,cartesian),"description")), + Contains("Could not find .non existent 2d Point, while it is set as required.")); + CHECK_THROWS_WITH(prm.load_entry("non existent 3d Point", true, Types::Point<3>(Point<3>(1,2,3,cartesian),"description")), + Contains("Could not find .non existent 3d Point, while it is set as required.")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_point<2>("non existent 2d Point"), + Contains("Could not find entry 'non existent 2d Point' not found. Make sure it is loaded or set")); + CHECK_THROWS_WITH(prm.get_point<3>("non existent 3d Point"), + Contains("Could not find entry 'non existent 3d Point' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non existent 2d Point", false, Types::Point<2>(Point<2>(1,2,cartesian),"description")) == false); + CHECK(prm.load_entry("non existent 3d Point", false, Types::Point<3>(Point<3>(1,2,3,cartesian),"description")) == false); + + CHECK(prm.get_point<2>("non existent 2d Point").get_array() == std::array {1,2}); + CHECK(prm.get_point<3>("non existent 3d Point").get_array() == std::array {1,2,3}); + + prm.set_entry("new Point 2d", Types::Point<2>(Point<2>(3,4,cartesian),"description")); + prm.set_entry("new Point 3d", Types::Point<3>(Point<3>(5,6,7,cartesian),"description")); + + CHECK(prm.get_point<2>("new Point 2d").get_array() == std::array {3,4}); + CHECK(prm.get_point<3>("new Point 3d").get_array() == std::array {5,6,7}); + + + prm.load_entry("2d point", true, Types::Point<2>(Point<2>(1,2,cartesian),"description")); + prm.load_entry("3d point", true, Types::Point<3>(Point<3>(3,4,5,cartesian),"description")); + + CHECK(prm.get_point<2>("2d point").get_array() == std::array {10,11}); + CHECK(prm.get_point<3>("3d point").get_array() == std::array {12,13,14}); + + // Test the Array functions + CHECK_THROWS_WITH(prm.load_entry("non existent double array", true, Types::Array(Types::Double(1,"description"),"description")), + Contains("Could not find .non existent double array, while it is set as required.")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array("non existent double array"), + Contains("Could not find entry 'non existent double array' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non exitent double array", false, Types::Array(Types::Double(2,"description"),"description")) == false); + + #ifndef NDEBUG + CHECK(prm.get_array("non exitent double array").size() == 1); + CHECK(prm.get_array("non exitent double array")[0].value == Approx(2.0)); + CHECK(prm.get_array("non exitent double array")[0].description == "description"); + #endif + // This is not desired behavior, but it is not implemented yet. + + prm.set_entry("new double array", Types::Array(Types::Double(3,"description"),"description")); + std::vector set_typed_double = prm.get_array("new double array"); + approval_tests.emplace_back(set_typed_double.size()); + // This is not desired behavior, but it is not implemented yet. + + prm.load_entry("double array", true, Types::Array(Types::Double(4,"description"),"description")); + std::vector true_loaded_typed_double = prm.get_array("double array"); + approval_tests.emplace_back(true_loaded_typed_double.size()); + approval_tests.emplace_back(true_loaded_typed_double[0].value); + approval_tests.emplace_back(true_loaded_typed_double[1].value); + approval_tests.emplace_back(true_loaded_typed_double[2].value); + + + // Test the Array > functions + CHECK_THROWS_WITH(prm.load_entry("non existent point<2> array", true, Types::Array(Types::Point<2>(Point<2>(1,2,cartesian),"description"),"description")), + Contains("Could not find .non existent point<2> array, while it is set as required.")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array("non existent point<2> array"), + Contains("Could not find entry 'non existent point<2> array' not found. Make sure it is loaded or set")); + #endif + CHECK(prm.load_entry("non exitent double array", false, Types::Array(Types::Point<2>(Point<2>(3,4,cartesian),"description"),"description")) == false); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array >("non existent point<2> array"), + Contains("Could not find entry 'non existent point<2> array' not found. Make sure it is loaded or set.")); + // This is not desired behavior, but it is not implemented yet. + #endif + + prm.set_entry("new point<2> array", Types::Array(Types::Point<2>(Point<2>(5,6,cartesian),"description"),"description")); + std::vector > set_typed_point_2d = prm.get_array >("new point<2> array"); + approval_tests.emplace_back(set_typed_point_2d.size()); + // This is not desired behavior, but it is not implemented yet. + + prm.load_entry("point<2> array", true, Types::Array(Types::Point<2>(Point<2>(7,8,cartesian),"description"),"description")); + std::vector > true_loaded_typed_point_2d = prm.get_array >("point<2> array"); + approval_tests.emplace_back(true_loaded_typed_point_2d.size()); + CHECK(true_loaded_typed_point_2d[0].value.get_array() == std::array {10,11}); + CHECK(true_loaded_typed_point_2d[1].value.get_array() == std::array {12,13}); + CHECK(true_loaded_typed_point_2d[2].value.get_array() == std::array {14,15}); + + + // Test the Array > functions + CHECK_THROWS_WITH(prm.load_entry("non existent point<3> array", true, Types::Array(Types::Point<3>(Point<3>(1,2,3,cartesian),"description"),"description")), + Contains("Could not find .non existent point<3> array, while it is set as required.")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array("non existent point<3> array"), + Contains("Could not find entry 'non existent point<3> array' not found. Make sure it is loaded or set")); + #endif + CHECK(prm.load_entry("non exitent double array", false, Types::Array(Types::Point<3>(Point<3>(4,5,6,cartesian),"description"),"description")) == false); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array >("non existent point<3> array"), + Contains("Could not find entry 'non existent point<3> array' not found. Make sure it is loaded or set.")); + // This is not desired behavior, but it is not implemented yet. + #endif + + prm.set_entry("new point<3> array", Types::Array(Types::Point<3>(Point<3>(7,8,9,cartesian),"description"),"description")); + std::vector > set_typed_point_3d = prm.get_array >("new point<3> array"); + approval_tests.emplace_back(set_typed_point_3d.size()); + // This is not desired behavior, but it is not implemented yet. + + prm.load_entry("point<3> array", true, Types::Array(Types::Point<3>(Point<3>(10,11,12,cartesian),"description"),"description")); + std::vector > true_loaded_typed_point_3d = prm.get_array >("point<3> array"); + approval_tests.emplace_back(true_loaded_typed_point_3d.size()); + CHECK(true_loaded_typed_point_3d[0].value.get_array() == std::array {20,21,22}); + CHECK(true_loaded_typed_point_3d[1].value.get_array() == std::array {23,24,25}); + CHECK(true_loaded_typed_point_3d[2].value.get_array() == std::array {26,27,28}); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array("point<2> array"), + Contains("Could not get point<2> array, because it is not a 2d Point.")); + CHECK_THROWS_WITH(prm.get_array("point<3> array"), + Contains("Could not get point<3> array, because it is not a 3d Point.")); + + CHECK_THROWS_WITH(prm.get_array >("point<3> array"), + Contains("Could not get point<3> array, because it is not a 3d Point.")); + CHECK_THROWS_WITH(prm.get_array >("double array"), + Contains("Could not get double array, because it is not a Double.")); + + CHECK_THROWS_WITH(prm.get_array >("point<2> array"), + Contains("Could not get point<2> array, because it is not a 2d Point.")); + CHECK_THROWS_WITH(prm.get_array >("double array"), + Contains("Could not get double array, because it is not a Double.")); + #endif + + // Test the enter_subsection and leave_subsection functions + prm.enter_subsection("subsection 1"); + { + // Test the UnsignedInt functions + / *CHECK_THROWS_WITH(prm.load_entry("non existent unsigned int", true, Types::UnsignedInt(1,"description")), + Contains("Entry undeclared: subsection 1.non existent unsigned int")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_unsigned_int("non existent unsigned int"), + Contains("Could not find entry 'non existent unsigned int' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non existent unsigned int", false, Types::UnsignedInt(1,"description")) == false); + CHECK(prm.get_unsigned_int("non existent unsigned int") == Approx(1.0)); + + prm.set_entry("new unsigned int", Types::UnsignedInt(2,"description")); + CHECK(prm.get_unsigned_int("new unsigned int") == Approx(2.0)); + + prm.load_entry("unsigned int", true, Types::UnsignedInt(3,"description")); + CHECK(prm.get_unsigned_int("unsigned int") == Approx(5.0));* / + + + // Test the Double functions + CHECK_THROWS_WITH(prm.load_entry("non existent double", true, Types::Double(1,"description")), + Contains("Entry undeclared: subsection 1.non existent")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_double("non existent double"), + Contains("Could not find entry 'non existent double' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non existent double", false, Types::Double(2,"description")) == false); + CHECK(prm.get_double("non existent double") == Approx(2.0)); + + prm.set_entry("new double", Types::Double(3,"description")); + CHECK(prm.get_double("new double") == Approx(3.0)); + + prm.load_entry("double", true, Types::Double(4,"description")); + CHECK(prm.get_double("double") == 2.23456e2); + + + // Test the String functions + CHECK_THROWS_WITH(prm.load_entry("non existent string", true, Types::String("2","description")), + Contains("Entry undeclared: subsection 1.non existent string")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_string("non existent string"), + Contains("Could not find entry 'non existent string' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non exitent string", false, Types::String("3","description")) == false); + CHECK(prm.get_string("non exitent string") == "3"); + + prm.set_entry("new string", Types::String("4","description")); + CHECK(prm.get_string("new string") == "4"); + + prm.load_entry("string", true, Types::String("5","description")); + CHECK(prm.get_string("string") == "mystring 1"); + + // Test the Point functions + CHECK_THROWS_WITH(prm.load_entry("non existent 2d Point", true, Types::Point<2>(Point<2>(3,4,cartesian),"description")), + Contains("Could not find subsection 1.non existent 2d Point, while it is set as required.")); + CHECK_THROWS_WITH(prm.load_entry("non existent 3d Point", true, Types::Point<3>(Point<3>(4,5,6,cartesian),"description")), + Contains("Could not find subsection 1.non existent 3d Point, while it is set as required.")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_point<2>("non existent 2d Point"), + Contains("Could not find entry 'non existent 2d Point' not found. Make sure it is loaded or set")); + CHECK_THROWS_WITH(prm.get_point<3>("non existent 3d Point"), + Contains("Could not find entry 'non existent 3d Point' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non existent 2d Point", false, Types::Point<2>(Point<2>(3,4,cartesian),"description")) == false); + CHECK(prm.load_entry("non existent 3d Point", false, Types::Point<3>(Point<3>(4,5,6,cartesian),"description")) == false); + + CHECK(prm.get_point<2>("non existent 2d Point").get_array() == std::array {3,4}); + CHECK(prm.get_point<3>("non existent 3d Point").get_array() == std::array {4,5,6}); + + prm.set_entry("new Point 2d", Types::Point<2>(Point<2>(5,6,cartesian),"description")); + prm.set_entry("new Point 3d", Types::Point<3>(Point<3>(7,8,9,cartesian),"description")); + + CHECK(prm.get_point<2>("new Point 2d").get_array() == std::array {5,6}); + CHECK(prm.get_point<3>("new Point 3d").get_array() == std::array {7,8,9}); + + + prm.load_entry("2d point", true, Types::Point<2>(Point<2>(1,2,cartesian),"description")); + prm.load_entry("3d point", true, Types::Point<3>(Point<3>(3,4,5,cartesian),"description")); + + CHECK(prm.get_point<2>("2d point").get_array() == std::array {15,16}); + CHECK(prm.get_point<3>("3d point").get_array() == std::array {17,18,19}); + + + // Test the Array functions + CHECK_THROWS_WITH(prm.load_entry("non existent double array", true, Types::Array(Types::Double(1,"description"),"description")), + Contains("Could not find subsection 1.non existent double array, while it is set as required.")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array("non existent double array"), + Contains("Could not find entry 'non existent double array' not found. Make sure it is loaded or set")); + + CHECK(prm.load_entry("non exitent double array", false, Types::Array(Types::Double(2,"description"),"description")) == false); + CHECK(prm.get_array("non exitent double array").size() == 1); + CHECK(prm.get_array("non exitent double array")[0].value == Approx(2.0)); + CHECK(prm.get_array("non exitent double array")[0].description == "description"); + // This is not desired behavior, but it is not implemented yet. + #endif + + prm.set_entry("new double array", Types::Array(Types::Double(3,"description"),"description")); + std::vector set_typed_double = prm.get_array("new double array"); + approval_tests.emplace_back(set_typed_double.size()); + // This is not desired behavior, but it is not implemented yet. + + prm.load_entry("double array", true, Types::Array(Types::Double(4,"description"),"description")); + std::vector true_loaded_typed_double = prm.get_array("double array"); + approval_tests.emplace_back(true_loaded_typed_double.size()); + approval_tests.emplace_back(true_loaded_typed_double[0].value); + approval_tests.emplace_back(true_loaded_typed_double[1].value); + approval_tests.emplace_back(true_loaded_typed_double[2].value); + + // Test the Array > functions + CHECK_THROWS_WITH(prm.load_entry("non existent point<2> array", true, Types::Array(Types::Point<2>(Point<2>(1,2,cartesian),"description"),"description")), + Contains("Could not find subsection 1.non existent point<2> array, while it is set as required.")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array("non existent point<2> array"), + Contains("Could not find entry 'non existent point<2> array' not found. Make sure it is loaded or set")); + + CHECK(prm.load_entry("non exitent double array", false, Types::Array(Types::Point<2>(Point<2>(3,4,cartesian),"description"),"description")) == false); + CHECK_THROWS_WITH(prm.get_array >("non existent point<2> array"), + Contains("Could not find entry 'non existent point<2> array' not found. Make sure it is loaded or set.")); + // This is not desired behavior, but it is not implemented yet. + #endif + + prm.set_entry("new point<2> array", Types::Array(Types::Point<2>(Point<2>(5,6,cartesian),"description"),"description")); + std::vector > set_typed_point_2d = prm.get_array >("new point<2> array"); + approval_tests.emplace_back(set_typed_point_2d.size()); + // This is not desired behavior, but it is not implemented yet. + + prm.load_entry("point<2> array", true, Types::Array(Types::Point<2>(Point<2>(7,8,cartesian),"description"),"description")); + std::vector > true_loaded_typed_point_2d = prm.get_array >("point<2> array"); + approval_tests.emplace_back(true_loaded_typed_point_2d.size()); + CHECK(true_loaded_typed_point_2d[0].value.get_array() == std::array {20,21}); + CHECK(true_loaded_typed_point_2d[1].value.get_array() == std::array {22,23}); + CHECK(true_loaded_typed_point_2d[2].value.get_array() == std::array {24,25}); + + + // Test the Array > functions + CHECK_THROWS_WITH(prm.load_entry("non existent point<3> array", true, Types::Array(Types::Point<3>(Point<3>(1,2,3,cartesian),"description"),"description")), + Contains("Could not find subsection 1.non existent point<3> array, while it is set as required.")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array("non existent point<3> array"), + Contains("Could not find entry 'non existent point<3> array' not found. Make sure it is loaded or set")); + + CHECK(prm.load_entry("non exitent double array", false, Types::Array(Types::Point<3>(Point<3>(4,5,6,cartesian),"description"),"description")) == false); + CHECK_THROWS_WITH(prm.get_array >("non existent point<3> array"), + Contains("Could not find entry 'non existent point<3> array' not found. Make sure it is loaded or set.")); + // This is not desired behavior, but it is not implemented yet. + #endif + + prm.set_entry("new point<3> array", Types::Array(Types::Point<3>(Point<3>(7,8,9,cartesian),"description"),"description")); + std::vector > set_typed_point_3d = prm.get_array >("new point<3> array"); + approval_tests.emplace_back(set_typed_point_3d.size()); + // This is not desired behavior, but it is not implemented yet. + + prm.load_entry("point<3> array", true, Types::Array(Types::Point<3>(Point<3>(10,11,12,cartesian),"description"),"description")); + std::vector > true_loaded_typed_point_3d = prm.get_array >("point<3> array"); + approval_tests.emplace_back(true_loaded_typed_point_3d.size()); + CHECK(true_loaded_typed_point_3d[0].value.get_array() == std::array {30,31,32}); + CHECK(true_loaded_typed_point_3d[1].value.get_array() == std::array {33,34,35}); + CHECK(true_loaded_typed_point_3d[2].value.get_array() == std::array {36,37,38}); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array("point<2> array"), + Contains("Could not get subsection 1.point<2> array, because it is not a 2d Point.")); + CHECK_THROWS_WITH(prm.get_array("point<3> array"), + Contains("Could not get subsection 1.point<3> array, because it is not a 3d Point.")); + + CHECK_THROWS_WITH(prm.get_array >("point<3> array"), + Contains("Could not get subsection 1.point<3> array, because it is not a 3d Point.")); + CHECK_THROWS_WITH(prm.get_array >("double array"), + Contains("Could not get subsection 1.double array, because it is not a Double.")); + + CHECK_THROWS_WITH(prm.get_array >("point<2> array"), + Contains("Could not get subsection 1.point<2> array, because it is not a 2d Point.")); + CHECK_THROWS_WITH(prm.get_array >("double array"), + Contains("Could not get subsection 1.double array, because it is not a Double.")); + #endif + + prm.enter_subsection("subsection 2"); + { + // Test the UnsignedInt functions + / *CHECK_THROWS_WITH(prm.load_entry("non existent unsigned int", true, Types::UnsignedInt(1,"description")), + Contains("Entry undeclared: subsection 1.subsection 2.non existent unsigned int")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_unsigned_int("non existent unsigned int"), + Contains("Could not find entry 'non existent unsigned int' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non existent unsigned int", false, Types::UnsignedInt(1,"description")) == false); + CHECK(prm.get_unsigned_int("non existent unsigned int") == Approx(1.0)); + + prm.set_entry("new unsigned int", Types::UnsignedInt(2,"description")); + CHECK(prm.get_unsigned_int("new unsigned int") == Approx(2.0)); + + prm.load_entry("unsigned int", true, Types::UnsignedInt(3,"description")); + CHECK(prm.get_unsigned_int("unsigned int") == Approx(6.0));* / + + + // Test the Double functions + CHECK_THROWS_WITH(prm.load_entry("non existent double", true, Types::Double(3,"description")), + Contains("Entry undeclared: subsection 1.subsection 2.non existent")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_double("non existent double"), + Contains("Could not find entry 'non existent double' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non existent double", false, Types::Double(4,"description")) == false); + CHECK(prm.get_double("non existent double") == Approx(4.0)); + + prm.set_entry("new double", Types::Double(5,"description")); + CHECK(prm.get_double("new double") == Approx(5.0)); + + prm.load_entry("double", true, Types::Double(6,"description")); + CHECK(prm.get_double("double") == 3.23456e2); + + + // Test the String functions + CHECK_THROWS_WITH(prm.load_entry("non existent string", true, Types::String("3","description")), + Contains("Entry undeclared: subsection 1.subsection 2.non existent string")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_string("non existent string"), + Contains("Could not find entry 'non existent string' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non exitent string", false, Types::String("4","description")) == false); + CHECK(prm.get_string("non exitent string") == "4"); + + prm.set_entry("new string", Types::String("5","description")); + CHECK(prm.get_string("new string") == "5"); + + prm.load_entry("string", true, Types::String("6","description")); + CHECK(prm.get_string("string") == "mystring 2"); + + // Test the Point functions + + CHECK_THROWS_WITH(prm.load_entry("non existent 2d Point", true, Types::Point<2>(Point<2>(1,2,cartesian),"description")), + Contains("Could not find subsection 1.subsection 2.non existent 2d Point, while it is set as required.")); + CHECK_THROWS_WITH(prm.load_entry("non existent 3d Point", true, Types::Point<3>(Point<3>(1,2,3,cartesian),"description")), + Contains("Could not find subsection 1.subsection 2.non existent 3d Point, while it is set as required.")); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_point<2>("non existent 2d Point"), + Contains("Could not find entry 'non existent 2d Point' not found. Make sure it is loaded or set")); + CHECK_THROWS_WITH(prm.get_point<3>("non existent 3d Point"), + Contains("Could not find entry 'non existent 3d Point' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non existent 2d Point", false, Types::Point<2>(Point<2>(1,2,cartesian),"description")) == false); + CHECK(prm.load_entry("non existent 3d Point", false, Types::Point<3>(Point<3>(1,2,3,cartesian),"description")) == false); + + CHECK(prm.get_point<2>("non existent 2d Point").get_array() == std::array {1,2}); + CHECK(prm.get_point<3>("non existent 3d Point").get_array() == std::array {1,2,3}); + + prm.set_entry("new Point 2d", Types::Point<2>(Point<2>(3,4,cartesian),"description")); + prm.set_entry("new Point 3d", Types::Point<3>(Point<3>(5,6,7,cartesian),"description")); + + CHECK(prm.get_point<2>("new Point 2d").get_array() == std::array {3,4}); + CHECK(prm.get_point<3>("new Point 3d").get_array() == std::array {5,6,7}); + + + prm.load_entry("2d point", true, Types::Point<2>(Point<2>(1,2,cartesian),"description")); + prm.load_entry("3d point", true, Types::Point<3>(Point<3>(3,4,5,cartesian),"description")); + + CHECK(prm.get_point<2>("2d point").get_array() == std::array {20,21}); + CHECK(prm.get_point<3>("3d point").get_array() == std::array {22,23,24}); + + // Test the Array functions + + CHECK_THROWS_WITH(prm.load_entry("non existent double array", true, Types::Array(Types::Double(1,"description"),"description")), + Contains("Could not find subsection 1.subsection 2.non existent double array, while it is set as required.")); + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array("non existent double array"), + Contains("Could not find entry 'non existent double array' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non exitent double array", false, Types::Array(Types::Double(2,"description"),"description")) == false); + + CHECK(prm.get_array("non exitent double array").size() == 1); + CHECK(prm.get_array("non exitent double array")[0].value == Approx(2.0)); + CHECK(prm.get_array("non exitent double array")[0].description == "description"); + + prm.set_entry("new double array", Types::Array(Types::Double(3,"description"),"description")); + std::vector set_typed_double = prm.get_array("new double array"); + approval_tests.emplace_back(set_typed_double.size()); + // This is not desired behavior, but it is not implemented yet. + + prm.load_entry("double array", true, Types::Array(Types::Double(4,"description"),"description")); + std::vector true_loaded_typed_double = prm.get_array("double array"); + approval_tests.emplace_back(true_loaded_typed_double.size()); + approval_tests.emplace_back(true_loaded_typed_double[0].value); + approval_tests.emplace_back(true_loaded_typed_double[1].value); + approval_tests.emplace_back(true_loaded_typed_double[2].value); + + + // Test the Array > functions + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.load_entry("non existent point<2> array", true, Types::Array(Types::Point<2>(Point<2>(1,2,cartesian),"description"),"description")), + Contains("Could not find subsection 1.subsection 2.non existent point<2> array, while it is set as required.")); + + CHECK_THROWS_WITH(prm.get_array("non existent point<2> array"), + Contains("Could not find entry 'non existent point<2> array' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non exitent double array", false, Types::Array(Types::Point<2>(Point<2>(3,4,cartesian),"description"),"description")) == false); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array >("non existent point<2> array"), + Contains("Could not find entry 'non existent point<2> array' not found. Make sure it is loaded or set.")); + // This is not desired behavior, but it is not implemented yet. + #endif + + prm.set_entry("new point<2> array", Types::Array(Types::Point<2>(Point<2>(5,6,cartesian),"description"),"description")); + std::vector > set_typed_point_2d = prm.get_array >("new point<2> array"); + approval_tests.emplace_back(set_typed_point_2d.size()); + // This is not desired behavior, but it is not implemented yet. + + prm.load_entry("point<2> array", true, Types::Array(Types::Point<2>(Point<2>(7,8,cartesian),"description"),"description")); + std::vector > true_loaded_typed_point_2d = prm.get_array >("point<2> array"); + approval_tests.emplace_back(true_loaded_typed_point_2d.size()); + CHECK(true_loaded_typed_point_2d[0].value.get_array() == std::array {40,41}); + CHECK(true_loaded_typed_point_2d[1].value.get_array() == std::array {42,43}); + CHECK(true_loaded_typed_point_2d[2].value.get_array() == std::array {44,45}); + + + // Test the Array > functions + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.load_entry("non existent point<3> array", true, Types::Array(Types::Point<3>(Point<3>(1,2,3,cartesian),"description"),"description")), + Contains("Could not find subsection 1.subsection 2.non existent point<3> array, while it is set as required.")); + + CHECK_THROWS_WITH(prm.get_array("non existent point<3> array"), + Contains("Could not find entry 'non existent point<3> array' not found. Make sure it is loaded or set")); + #endif + + CHECK(prm.load_entry("non exitent double array", false, Types::Array(Types::Point<3>(Point<3>(4,5,6,cartesian),"description"),"description")) == false); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array >("non existent point<3> array"), + Contains("Could not find entry 'non existent point<3> array' not found. Make sure it is loaded or set.")); + // This is not desired behavior, but it is not implemented yet. + #endif + + prm.set_entry("new point<3> array", Types::Array(Types::Point<3>(Point<3>(7,8,9,cartesian),"description"),"description")); + std::vector > set_typed_point_3d = prm.get_array >("new point<3> array"); + approval_tests.emplace_back(set_typed_point_3d.size()); + // This is not desired behavior, but it is not implemented yet. + + prm.load_entry("point<3> array", true, Types::Array(Types::Point<3>(Point<3>(10,11,12,cartesian),"description"),"description")); + std::vector > true_loaded_typed_point_3d = prm.get_array >("point<3> array"); + approval_tests.emplace_back(true_loaded_typed_point_3d.size()); + CHECK(true_loaded_typed_point_3d[0].value.get_array() == std::array {40,41,42}); + CHECK(true_loaded_typed_point_3d[1].value.get_array() == std::array {43,44,45}); + CHECK(true_loaded_typed_point_3d[2].value.get_array() == std::array {46,47,48}); + + #ifndef NDEBUG + CHECK_THROWS_WITH(prm.get_array("point<2> array"), + Contains("Could not get subsection 1.subsection 2.point<2> array, because it is not a 2d Point.")); + CHECK_THROWS_WITH(prm.get_array("point<3> array"), + Contains("Could not get subsection 1.subsection 2.point<3> array, because it is not a 3d Point.")); + + CHECK_THROWS_WITH(prm.get_array >("point<3> array"), + Contains("Could not get subsection 1.subsection 2.point<3> array, because it is not a 3d Point.")); + CHECK_THROWS_WITH(prm.get_array >("double array"), + Contains("Could not get subsection 1.subsection 2.double array, because it is not a Double.")); + + CHECK_THROWS_WITH(prm.get_array >("point<2> array"), + Contains("Could not get subsection 1.subsection 2.point<2> array, because it is not a 2d Point.")); + CHECK_THROWS_WITH(prm.get_array >("double array"), + Contains("Could not get subsection 1.subsection 2.double array, because it is not a Double.")); + #endif + } + prm.leave_subsection(); + } + prm.leave_subsection(); + */ + + // Todo: add tests for list,feature and coordinate system. + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + + +TEST_CASE("Euler angle functions") +{ + const std::vector approval_tests; + + // note, this is only testing consistency (can it convert back and forth) and + // it only works for rotation matrices which are defined in the same way (z-x-z). + { + auto rot1 = Utilities::euler_angles_to_rotation_matrix(-85,340,56); + auto ea1 = Utilities::euler_angles_from_rotation_matrix(rot1); + auto rot2 = Utilities::euler_angles_to_rotation_matrix(ea1[0],ea1[1],ea1[2]); + compare_rotation_matrices_approx(rot2, rot1); + auto ea2 = Utilities::euler_angles_from_rotation_matrix(rot2); + compare_3d_arrays_approx(ea2,ea1); + auto rot3 = Utilities::euler_angles_to_rotation_matrix(ea2[0],ea2[1],ea2[2]); + compare_rotation_matrices_approx(rot3, rot2); + } + { + auto rot1 = Utilities::euler_angles_to_rotation_matrix(90,180,270); + auto ea1 = Utilities::euler_angles_from_rotation_matrix(rot1); + auto rot2 = Utilities::euler_angles_to_rotation_matrix(ea1[0],ea1[1],ea1[2]); + compare_rotation_matrices_approx(rot2, rot1); + auto ea2 = Utilities::euler_angles_from_rotation_matrix(rot2); + compare_3d_arrays_approx(ea2,ea1); + auto rot3 = Utilities::euler_angles_to_rotation_matrix(ea2[0],ea2[1],ea2[2]); + compare_rotation_matrices_approx(rot3, rot2); + } + + { + const std::array ea0 = {{20,30,40}}; + auto rot0 = Utilities::euler_angles_to_rotation_matrix(20,30,40); + auto ea1 = Utilities::euler_angles_from_rotation_matrix(rot0); + compare_3d_arrays_approx(ea1,ea0); + auto rot2 = Utilities::euler_angles_to_rotation_matrix(ea1[0],ea1[1],ea1[2]); + compare_rotation_matrices_approx(rot2, rot0); + auto ea2 = Utilities::euler_angles_from_rotation_matrix(rot2); + compare_3d_arrays_approx(ea2,ea1); + auto rot3 = Utilities::euler_angles_to_rotation_matrix(ea2[0],ea2[1],ea2[2]); + compare_rotation_matrices_approx(rot3, rot2); + } + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("GWB Bezier curve") +{ + + std::vector> approval_tests; + + std::vector > coordinates; + coordinates.emplace_back(0,10,cartesian); + coordinates.emplace_back(20,10,cartesian); + coordinates.emplace_back(30,20,cartesian); + + const Objects::BezierCurve bezier_curve(coordinates); + + approval_tests.emplace_back(bezier_curve(0,-0.1)); + approval_tests.emplace_back(bezier_curve(0,0.0)); + approval_tests.emplace_back(bezier_curve(0,0.1)); + approval_tests.emplace_back(bezier_curve(0,0.2)); + approval_tests.emplace_back(bezier_curve(0,0.3)); + approval_tests.emplace_back(bezier_curve(0,0.4)); + approval_tests.emplace_back(bezier_curve(0,0.5)); + approval_tests.emplace_back(bezier_curve(0,0.6)); + approval_tests.emplace_back(bezier_curve(0,0.7)); + approval_tests.emplace_back(bezier_curve(0,0.8)); + approval_tests.emplace_back(bezier_curve(0,0.9)); + approval_tests.emplace_back(bezier_curve(0,1.0)); + approval_tests.emplace_back(bezier_curve(0,1.1)); + + approval_tests.emplace_back(bezier_curve(1,-0.1)); + approval_tests.emplace_back(bezier_curve(1,0.0)); + approval_tests.emplace_back(bezier_curve(1,0.1)); + approval_tests.emplace_back(bezier_curve(1,0.2)); + approval_tests.emplace_back(bezier_curve(1,0.3)); + approval_tests.emplace_back(bezier_curve(1,0.4)); + approval_tests.emplace_back(bezier_curve(1,0.5)); + approval_tests.emplace_back(bezier_curve(1,0.6)); + approval_tests.emplace_back(bezier_curve(1,0.7)); + approval_tests.emplace_back(bezier_curve(1,0.8)); + approval_tests.emplace_back(bezier_curve(1,0.9)); + approval_tests.emplace_back(bezier_curve(1,1.0)); + approval_tests.emplace_back(bezier_curve(1,1.1)); + + + const Objects::BezierCurve bezier_curve_defined(coordinates, + { + 0.,Consts::PI,0. + }); + + approval_tests.emplace_back(bezier_curve_defined(0,-0.1)); + approval_tests.emplace_back(bezier_curve_defined(0,0.0)); + approval_tests.emplace_back(bezier_curve_defined(0,0.1)); + approval_tests.emplace_back(bezier_curve_defined(0,0.2)); + approval_tests.emplace_back(bezier_curve_defined(0,0.3)); + approval_tests.emplace_back(bezier_curve_defined(0,0.4)); + approval_tests.emplace_back(bezier_curve_defined(0,0.5)); + approval_tests.emplace_back(bezier_curve_defined(0,0.6)); + approval_tests.emplace_back(bezier_curve_defined(0,0.7)); + approval_tests.emplace_back(bezier_curve_defined(0,0.8)); + approval_tests.emplace_back(bezier_curve_defined(0,0.9)); + approval_tests.emplace_back(bezier_curve_defined(0,1.0)); + approval_tests.emplace_back(bezier_curve_defined(0,1.1)); + + approval_tests.emplace_back(bezier_curve_defined(1,-0.1)); + approval_tests.emplace_back(bezier_curve_defined(1,0.0)); + approval_tests.emplace_back(bezier_curve_defined(1,0.1)); + approval_tests.emplace_back(bezier_curve_defined(1,0.2)); + approval_tests.emplace_back(bezier_curve_defined(1,0.3)); + approval_tests.emplace_back(bezier_curve_defined(1,0.4)); + approval_tests.emplace_back(bezier_curve_defined(1,0.5)); + approval_tests.emplace_back(bezier_curve_defined(1,0.6)); + approval_tests.emplace_back(bezier_curve_defined(1,0.7)); + approval_tests.emplace_back(bezier_curve_defined(1,0.8)); + approval_tests.emplace_back(bezier_curve_defined(1,0.9)); + approval_tests.emplace_back(bezier_curve_defined(1,1.0)); + approval_tests.emplace_back(bezier_curve_defined(1,1.1)); + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + + +TEST_CASE("WorldBuilder Utilities function: distance_point_from_curved_planes cartesian part 1") +{ + std::vector approval_tests; + + const std::unique_ptr cartesian_system = CoordinateSystems::Interface::create("cartesian", nullptr);; + + //Todo:fix + //cartesian_system->declare_entries(); + + Point<3> position(10,0,0,cartesian); + + Objects::NaturalCoordinate natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + Point<2> reference_point(0,0,cartesian); + + std::vector > coordinates; + coordinates.emplace_back(0,10,cartesian); + coordinates.emplace_back(20,10,cartesian); + + std::vector > slab_segment_lengths(2); + slab_segment_lengths[0].push_back(std::sqrt(10*10+10*10)); + slab_segment_lengths[0].push_back(200); + slab_segment_lengths[1].push_back(std::sqrt(10*10+10*10)); + slab_segment_lengths[1].push_back(200); + + const double dtr = Consts::PI/180; + std::vector > > slab_segment_angles(2); + slab_segment_angles[0].emplace_back(45 * dtr,45 * dtr,cartesian); + slab_segment_angles[0].emplace_back(45 * dtr,45 * dtr,cartesian); + slab_segment_angles[1].emplace_back(45 * dtr,45 * dtr,cartesian); + slab_segment_angles[1].emplace_back(45 * dtr,45 * dtr,cartesian); + + const double starting_radius = 10; + + const std::vector x_list = {0.,20.}; + const std::vector y_list = {10.,10.}; + const std::vector > coordinate_list_local = coordinates; + + Objects::BezierCurve bezier_curve(coordinate_list_local); + + approval_tests.emplace_back(bezier_curve(0,-0.1)[0]); + approval_tests.emplace_back(bezier_curve(0,-0.1)[1]); + approval_tests.emplace_back(bezier_curve(0,0.0)[0]); + approval_tests.emplace_back(bezier_curve(0,0.0)[1]); + approval_tests.emplace_back(bezier_curve(0,0.1)[0]); + approval_tests.emplace_back(bezier_curve(0,0.1)[1]); + approval_tests.emplace_back(bezier_curve(0,0.2)[0]); + approval_tests.emplace_back(bezier_curve(0,0.2)[1]); + approval_tests.emplace_back(bezier_curve(0,0.3)[0]); + approval_tests.emplace_back(bezier_curve(0,0.3)[1]); + approval_tests.emplace_back(bezier_curve(0,0.4)[0]); + approval_tests.emplace_back(bezier_curve(0,0.4)[1]); + approval_tests.emplace_back(bezier_curve(0,0.5)[0]); + approval_tests.emplace_back(bezier_curve(0,0.5)[1]); + approval_tests.emplace_back(bezier_curve(0,0.6)[0]); + approval_tests.emplace_back(bezier_curve(0,0.6)[1]); + approval_tests.emplace_back(bezier_curve(0,0.7)[0]); + approval_tests.emplace_back(bezier_curve(0,0.7)[1]); + approval_tests.emplace_back(bezier_curve(0,0.8)[0]); + approval_tests.emplace_back(bezier_curve(0,0.8)[1]); + approval_tests.emplace_back(bezier_curve(0,0.9)[0]); + approval_tests.emplace_back(bezier_curve(0,0.9)[1]); + approval_tests.emplace_back(bezier_curve(0,1.0)[0]); + approval_tests.emplace_back(bezier_curve(0,1.0)[1]); + approval_tests.emplace_back(bezier_curve(0,1.1)[0]); + approval_tests.emplace_back(bezier_curve(0,1.1)[1]); + + + WorldBuilder::Utilities::PointDistanceFromCurvedPlanes distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[0]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[1]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[2]); + + + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-4); // practically zero + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-5); + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + approval_tests.insert( approval_tests.end(), std::begin(distance_from_planes.closest_trench_point.get_array()), + std::end(distance_from_planes.closest_trench_point.get_array())); + + + // center square test 2 + reference_point[1] = 20; + + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-14); // practically zero + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[0]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[1]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[2]); + + // center square test 3 + position[1] = 20; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[0]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[1]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[2]); + + // center square test 4 + reference_point[1] = 0; + + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-14); // practically zero + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[0]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[1]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[2]); + + // center square test 5 + position[1] = -10; + position[2] = -10; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers // practically zero + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers // practically zero + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[0]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[1]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[2]); + + // begin section square test 6 + position[0] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_section) < 1e-14); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.depth_reference_surface) > 1e-12 ? distance_from_planes.depth_reference_surface : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[0]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[1]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[2]); + + + // end section square test 7 + position[0] = 20; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-14); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers // practically zero + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers // practically zero + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[0]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[1]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[2]); + + // before begin section square test 8 + position[0] = -10; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-14); // practically zero + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + // The old method for slabs can not provide the corners when out of bounds and returns a nan. The new method can do this, + // and the old method is planned to be removed. + //CHECK(distance_from_planes.closest_trench_point.get_array() == std::array {{NaN::DSNAN,NaN::DSNAN,10.}}); + + + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-14); // practically zero + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + approval_tests.insert( approval_tests.end(), std::begin(distance_from_planes.closest_trench_point.get_array()), std::end(distance_from_planes.closest_trench_point.get_array())); + + + // beyond end section square test 9 + position[0] = 25; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-14); // practically zero + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + // The old method for slabs can not provide the corners when out of bounds and returns a nan. The new method can do this, + // and the old method is planned to be removed. + //CHECK(distance_from_planes.closest_trench_point.get_array() == std::array {{NaN::DSNAN,NaN::DSNAN,10.}}); + + + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-14); // practically zero + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[0]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[1]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[2]); + + + // beyond end section square test 10 + position[0] = 10; + position[1] = 0; + position[2] = 5; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[0]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[1]); + approval_tests.emplace_back(distance_from_planes.closest_trench_point.get_array()[2]); + + // beyond end section square test 10 (only positive version) + position[0] = 10; + position[1] = 0; + position[2] = 5; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + true, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + + // beyond end section square test 11 + position[0] = 10; + position[1] = 0; + position[2] = -5; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + + // beyond end section square test 11 (only positive version) + position[0] = 10; + position[1] = 0; + position[2] = -5; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + true, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // add coordinate + position[0] = 25; + position[1] = 0; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + coordinates.emplace_back(30,10,cartesian); + bezier_curve = Objects::BezierCurve(coordinates); + + slab_segment_lengths.resize(3); + slab_segment_lengths[2].push_back(std::sqrt(10*10+10*10)); + slab_segment_lengths[2].push_back(200); + + slab_segment_angles.resize(3); + slab_segment_angles[2].emplace_back(45 * dtr,45 * dtr,cartesian); + slab_segment_angles[2].emplace_back(45 * dtr,45 * dtr,cartesian); + + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-14); // practically zero + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-12); + + // different angle + slab_segment_angles[0][0][0] = 22.5 * dtr; + slab_segment_angles[0][0][1] = 22.5 * dtr; + slab_segment_angles[0][1][0] = 22.5 * dtr; + slab_segment_angles[0][1][1] = 22.5 * dtr; + slab_segment_angles[1][0][0] = 22.5 * dtr; + slab_segment_angles[1][0][1] = 22.5 * dtr; + slab_segment_angles[1][1][0] = 22.5 * dtr; + slab_segment_angles[1][1][1] = 22.5 * dtr; + + position[0] = 10; + position[1] = 0; + position[2] = 10-10*tan(22.5*dtr); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane)<1e-10); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // check interpolation 1 (in the middle of a segment with 22.5 degree and a segment with 45) + position[0] = 25; + position[1] = 0; + position[2] = 10-10*tan((22.5*1.5)*dtr); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // check interpolation 2 (at the end of the segment at 45 degree) + position[0] = 30; + position[1] = 0; + position[2] = 10-10*tan(45*dtr); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // check length interpolation with 90 degree angles for simplicity + // check length interpolation first segment center 1 + slab_segment_angles[0][0][0] = 90 * dtr; + slab_segment_angles[0][0][1] = 90 * dtr; + slab_segment_angles[0][1][0] = 90 * dtr; + slab_segment_angles[0][1][1] = 90 * dtr; + slab_segment_angles[1][0][0] = 90 * dtr; + slab_segment_angles[1][0][1] = 90 * dtr; + slab_segment_angles[1][1][0] = 90 * dtr; + slab_segment_angles[1][1][1] = 90 * dtr; + slab_segment_angles[2][0][0] = 90 * dtr; + slab_segment_angles[2][0][1] = 90 * dtr; + slab_segment_angles[2][1][0] = 90 * dtr; + slab_segment_angles[2][1][1] = 90 * dtr; + + slab_segment_lengths[0][0] = 100; + slab_segment_lengths[0][1] = 100; + slab_segment_lengths[1][0] = 100; + slab_segment_lengths[1][1] = 100; + slab_segment_lengths[2][0] = 50; + slab_segment_lengths[2][1] = 50; + + position[0] = 10; + position[1] = 10; + position[2] = 10-100; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers // practically zero + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // check length interpolation first segment center 2 + position[0] = 10; + position[1] = 10; + position[2] = 10-101; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers // practically zero + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // check length interpolation first segment center 3 + position[0] = 10; + position[1] = 10; + position[2] = 10-200; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + + + // check length interpolation first segment center 4 + position[0] = 10; + position[1] = 10; + position[2] = 10-201; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + + + // Now check the center of the second segment, each segment should have a length of 75. + // check length interpolation second segment center 1 + position[0] = 25; + position[1] = 10; + position[2] = 10-75; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-14); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers // practically zero + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // check length interpolation second segment center 2 + position[0] = 25; + position[1] = 10; + position[2] = 10-76; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-14); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers // practically zero + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // check length interpolation second segment center 3 + position[0] = 25; + position[1] = 10; + position[2] = 10-150; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-14); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + + + // check length interpolation second segment center 4 + position[0] = 25; + position[1] = 10; + position[2] = 10-151; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // Now check the end of the second segment, each segment should have a length of 50. + // check length interpolation second segment center 1 + position[0] = 30; + position[1] = 10; + position[2] = 10-50; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-14); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers // practically zero + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // check length interpolation second segment center 2 + position[0] = 30; + position[1] = 10; + position[2] = 10-51; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-14); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers // practically zero + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // check length interpolation second segment center 3 + position[0] = 30; + position[1] = 10; + position[2] = 10-100; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-14); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + + + // check length interpolation second segment center 4 + position[0] = 30; + position[1] = 10; + position[2] = 10-101; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("WorldBuilder Utilities function: distance_point_from_curved_planes cartesian part 2") +{ + std::vector approval_tests; + + const std::unique_ptr cartesian_system = CoordinateSystems::Interface::create("cartesian", nullptr);; + + //todo: fix + //cartesian_system->declare_entries(); + + Point<3> position(10,0,0,cartesian); + Objects::NaturalCoordinate natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + Point<2> reference_point(0,0,cartesian); + + std::vector > coordinates; + coordinates.emplace_back(0,10,cartesian); + coordinates.emplace_back(20,10,cartesian); + coordinates.emplace_back(30,10,cartesian); + + std::vector > slab_segment_lengths(3); + slab_segment_lengths[0].push_back(std::sqrt(10*10+10*10)); + slab_segment_lengths[0].push_back(200); + slab_segment_lengths[1].push_back(std::sqrt(10*10+10*10)); + slab_segment_lengths[1].push_back(200); + slab_segment_lengths[2].push_back(std::sqrt(10*10+10*10)); + slab_segment_lengths[2].push_back(200); + + const double dtr = Consts::PI/180; + std::vector > > slab_segment_angles(3); + slab_segment_angles[0].emplace_back(45 * dtr,45 * dtr,cartesian); + slab_segment_angles[0].emplace_back(45 * dtr,45 * dtr,cartesian); + slab_segment_angles[1].emplace_back(45 * dtr,45 * dtr,cartesian); + slab_segment_angles[1].emplace_back(45 * dtr,45 * dtr,cartesian); + slab_segment_angles[2].emplace_back(45 * dtr,45 * dtr,cartesian); + slab_segment_angles[2].emplace_back(45 * dtr,45 * dtr,cartesian); + + const double starting_radius = 10; + // Now test the curves into the depth + // curve test 1 + + slab_segment_angles[0][0][0] = 0.0 * dtr; + slab_segment_angles[0][0][1] = 45.0 * dtr; + slab_segment_angles[0][1][0] = 45.0 * dtr; + slab_segment_angles[0][1][1] = 90.0 * dtr; + slab_segment_angles[1][0][0] = 0.0 * dtr; + slab_segment_angles[1][0][1] = 45.0 * dtr; + slab_segment_angles[1][1][0] = 45.0 * dtr; + slab_segment_angles[1][1][1] = 90.0 * dtr; + slab_segment_angles[2][0][0] = 90 * dtr; + slab_segment_angles[2][0][1] = 90 * dtr; + slab_segment_angles[2][1][0] = 90 * dtr; + slab_segment_angles[2][1][1] = 90 * dtr; + + slab_segment_lengths[0][0] = 10 * 45 * dtr; + slab_segment_lengths[0][1] = 10 * 45 * dtr; + slab_segment_lengths[1][0] = 10 * 45 * dtr; + slab_segment_lengths[1][1] = 10 * 45 * dtr; + slab_segment_lengths[2][0] = 5; + slab_segment_lengths[2][1] = 5; + + + position[0] = 10; + position[1] = 0; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + + + const std::vector x_list = {0.,20., 30.}; + const std::vector y_list = {10.,10., 10.}; + const std::vector > coordinate_list_local = coordinates; + const Objects::BezierCurve bezier_curve(coordinates); + + WorldBuilder::Utilities::PointDistanceFromCurvedPlanes distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinate_list_local, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-10); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + + // curve test 2 + position[0] = 10; + position[1] = 5; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); // checked that it should be about 5 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + + // curve test 3 + position[0] = 10; + position[1] = -5; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); // checked that it should be about -5 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + + + // curve test 4 + position[0] = 10; + position[1] = 10 - 10 * sqrt(2)/2; + position[2] = 10 * sqrt(2)/2; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + + // curve test 5 + position[0] = 10; + position[1] = 10 - 10 * sqrt(2); + position[2] = 10 * sqrt(2); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); // checked that it should be about -10 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + + // curve test 6 + position[0] = 10; + position[1] = 10; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); // checked that it should be about 10 this with a drawing + // This is a special case where the point coincides with the center of the circle. + // Because all the points on the circle are equally close, we have chosen in the + // code to define this case as that this point belongs to the top of the top segment + // where the check point has angle 0. This means that the distanceAlongPlate is zero. + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + + + // curve test 7 + position[0] = 10; + position[1] = -5; + position[2] = -1; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + + // curve test 8 + slab_segment_lengths[0][0] = 5 * 45 * dtr; + slab_segment_lengths[0][1] = 5 * 45 * dtr; + slab_segment_lengths[1][0] = 5 * 45 * dtr; + slab_segment_lengths[1][1] = 5 * 45 * dtr; + + position[0] = 10; + position[1] = 5; + position[2] = 5; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + + // curve test 9 + position[0] = 10; + position[1] = 10 - 5 * sqrt(2)/2; + position[2] = 5 + 5 * sqrt(2)/2; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + + // curve test 10 + slab_segment_angles[0][0][0] = 0.0 * dtr; + slab_segment_angles[0][0][1] = 90.0 * dtr; + slab_segment_angles[0][1][0] = 90.0 * dtr; + slab_segment_angles[0][1][1] = 180.0 * dtr; + slab_segment_angles[1][0][0] = 0.0 * dtr; + slab_segment_angles[1][0][1] = 90.0 * dtr; + slab_segment_angles[1][1][0] = 90.0 * dtr; + slab_segment_angles[1][1][1] = 180.0 * dtr; + + slab_segment_lengths[0][0] = 10 * 90 * dtr; + slab_segment_lengths[0][1] = 10 * 90 * dtr; + slab_segment_lengths[1][0] = 10 * 90 * dtr; + slab_segment_lengths[1][1] = 10 * 90 * dtr; + + position[0] = 10; + position[1] = 0; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test 11 + position[0] = 10; + position[1] = 10 - 10 * sqrt(2)/2; + position[2] = 10 * sqrt(2)/2; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test 12 + position[0] = 10; + position[1] = 10 - 10 * sqrt(2)/2; + position[2] = -10 * sqrt(2)/2; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.depth_reference_surface); + + + // curve test 13 + position[0] = 10; + position[1] = 10; + position[2] = -10; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test 14 + slab_segment_angles[0][0][0] = 0.0 * dtr; + slab_segment_angles[0][0][1] = 180.0 * dtr; + slab_segment_angles[0][1][0] = 180.0 * dtr; + slab_segment_angles[0][1][1] = 270.0 * dtr; + slab_segment_angles[1][0][0] = 0.0 * dtr; + slab_segment_angles[1][0][1] = 180.0 * dtr; + slab_segment_angles[1][1][0] = 180.0 * dtr; + slab_segment_angles[1][1][1] = 270.0 * dtr; + + slab_segment_lengths[0][0] = 10 * 180 * dtr; + slab_segment_lengths[0][1] = 10 * 90 * dtr; + slab_segment_lengths[1][0] = 10 * 180 * dtr; + slab_segment_lengths[1][1] = 10 * 90 * dtr; + + position[0] = 10; + position[1] = 0; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test 15 + position[0] = 10; + position[1] = 10; + position[2] = -10; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test 16 + position[0] = 10; + position[1] = 10; + position[2] = -11; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); // checked that it should be about -1 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test 16 + position[0] = 10; + position[1] = 10; + position[2] = -9; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); // checked that it should be about -1 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test 17 + position[0] = 10; + position[1] = 20; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + + // curve test 18 + position[0] = 10; + position[1] = 21; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); // checked that it should be about 1 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test 19 + position[0] = 10; + position[1] = 19; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); // checked that it should be about 1 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + + // curve test 20 + slab_segment_angles[0][0][0] = 0.0 * dtr; + slab_segment_angles[0][0][1] = 270.0 * dtr; + slab_segment_angles[0][1][0] = 270.0 * dtr; + slab_segment_angles[0][1][1] = 315.0 * dtr; + slab_segment_angles[1][0][0] = 0.0 * dtr; + slab_segment_angles[1][0][1] = 270.0 * dtr; + slab_segment_angles[1][1][0] = 270.0 * dtr; + slab_segment_angles[1][1][1] = 315.0 * dtr; + + slab_segment_lengths[0][0] = 10 * 270 * dtr; + slab_segment_lengths[0][1] = 10 * 45 * dtr; + slab_segment_lengths[1][0] = 10 * 270 * dtr; + slab_segment_lengths[1][1] = 10 * 45 * dtr; + + position[0] = 10; + position[1] = 0; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test 21 + position[0] = 10; + position[1] = 10; + position[2] = -10; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test 21 + position[0] = 10; + position[1] = 20; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test 22 + position[0] = 10; + position[1] = 10 + 1e-14 + 10 * sqrt(2)/2; // somehow it doesn't get the exact value here, so adding an epsiolon of 1e-14. + position[2] = 10 * sqrt(2)/2; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test start 45 degree 1 + slab_segment_angles[0][0][0] = 45.0 * dtr; + slab_segment_angles[0][0][1] = 90.0 * dtr; + slab_segment_angles[0][1][0] = 90.0 * dtr; + slab_segment_angles[0][1][1] = 135.0 * dtr; + slab_segment_angles[1][0][0] = 45.0 * dtr; + slab_segment_angles[1][0][1] = 90.0 * dtr; + slab_segment_angles[1][1][0] = 90.0 * dtr; + slab_segment_angles[1][1][1] = 135.0 * dtr; + + slab_segment_lengths[0][0] = 10 * 45 * dtr; + slab_segment_lengths[0][1] = 10 * 45 * dtr; + slab_segment_lengths[1][0] = 10 * 45 * dtr; + slab_segment_lengths[1][1] = 10 * 45 * dtr; + slab_segment_lengths[2][0] = 5; + slab_segment_lengths[2][1] = 5; + + + position[0] = 10; + position[1] = 0; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); // checked that it should be about -7.3 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test change reference point 1 + reference_point[0] = 50; + reference_point[1] = 50; + + position[0] = 10; + position[1] = 0; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + // checked that distanceFromPlane should be infinity (it is on the other side of the circle this with a drawing + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test change reference point 2 + position[0] = 10; + position[1] = 10; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); // checked that it should be about 2.3 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test angle interpolation 1 + reference_point[0] = 0; + reference_point[1] = 0; + + slab_segment_angles[0][0][0] = 0.0 * dtr; + slab_segment_angles[0][0][1] = 180.0 * dtr; + slab_segment_angles[0][1][0] = 180.0 * dtr; + slab_segment_angles[0][1][1] = 270.0 * dtr; + slab_segment_angles[1][0][0] = 0.0 * dtr; + slab_segment_angles[1][0][1] = 90.0 * dtr; + slab_segment_angles[1][1][0] = 90.0 * dtr; + slab_segment_angles[1][1][1] = 135.0 * dtr; + + slab_segment_lengths[0][0] = 10 * 135 * dtr; + slab_segment_lengths[0][1] = 10 * 67.5 * dtr; + slab_segment_lengths[1][0] = 10 * 135 * dtr; + slab_segment_lengths[1][1] = 10 * 67.5 * dtr; + + + position[0] = 10; + position[1] = 0; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test reverse angle 1 + reference_point[0] = 0; + reference_point[1] = 0; + + slab_segment_angles[0][0][0] = 0.0 * dtr; + slab_segment_angles[0][0][1] = 90.0 * dtr; + slab_segment_angles[0][1][0] = 90.0 * dtr; + slab_segment_angles[0][1][1] = 0.0 * dtr; + slab_segment_angles[1][0][0] = 0.0 * dtr; + slab_segment_angles[1][0][1] = 90.0 * dtr; + slab_segment_angles[1][1][0] = 90.0 * dtr; + slab_segment_angles[1][1][1] = 0.0 * dtr; + + slab_segment_lengths[0][0] = 10 * 90 * dtr; + slab_segment_lengths[0][1] = 10 * 90 * dtr; + slab_segment_lengths[1][0] = 10 * 90 * dtr; + slab_segment_lengths[1][1] = 10 * 90 * dtr; + + position[0] = 10; + position[1] = 0; + position[2] = 0; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test reverse angle 2 + position[0] = 10; + position[1] = -10; + position[2] = -10; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test reverse angle 3 + position[0] = 10; + position[1] = 10 - (20 - 10 * sqrt(2)/2); + position[2] = -10 * sqrt(2)/2; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test reverse angle 4 + position[0] = 10; + + double angle = 180+0.1; + position[1] = 10 - (20 * std::cos(0 * Consts::PI/180) + 10 * std::cos((angle) * Consts::PI/180)); + position[2] = 0 * std::cos(0 * Consts::PI/180) + 10 * std::sin((angle) * Consts::PI/180); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) ); // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + + // curve test reverse angle 5 + position[0] = 10; + position[1] = 10 - (20 - 10 * std::cos(0.001 * Consts::PI/180)); + position[2] = - 10 * std::sin(0.001 * Consts::PI/180); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) > 1e-12 ? distance_from_planes.distance_from_plane : 0.); // to make sure the approval test have the same characters for very small numbers // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test reverse angle 6 + slab_segment_angles[0][0][0] = 0.0 * dtr; + slab_segment_angles[0][0][1] = 45.0 * dtr; + slab_segment_angles[0][1][0] = 45.0 * dtr; + slab_segment_angles[0][1][1] = 0.0 * dtr; + slab_segment_angles[1][0][0] = 0.0 * dtr; + slab_segment_angles[1][0][1] = 45.0 * dtr; + slab_segment_angles[1][1][0] = 45.0 * dtr; + slab_segment_angles[1][1][1] = 0.0 * dtr; + + slab_segment_lengths[0][0] = 10 * 45 * dtr; + slab_segment_lengths[0][1] = 10 * 45 * dtr; + slab_segment_lengths[1][0] = 10 * 45 * dtr; + slab_segment_lengths[1][1] = 10 * 45 * dtr; + + position[0] = 10; + position[1] = 10 - 10 * std::cos(45.000 * Consts::PI/180); + position[2] = 10 * std::sin(45.000 * Consts::PI/180); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-10); // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-10); + + // curve test reverse angle 6 + position[0] = 10; + angle = 45; + position[1] = 10 - (10 * std::cos((angle) * Consts::PI/180)); + position[2] = 10 * std::sin((angle) * Consts::PI/180); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-10); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-10); + + // curve test reverse angle 6 + position[0] = 10; + angle = 180+45; + position[1] = 10 - (20 * std::cos(45 * Consts::PI/180) + 10 * std::cos((angle) * Consts::PI/180)); + position[2] = 20 * std::cos(45 * Consts::PI/180) + 10 * std::sin((angle) * Consts::PI/180); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-10); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-10); + + + // curve test reverse angle 7 + position[0] = 10; + angle = 180+46; + position[1] = 10 - (20 * std::cos(45 * Consts::PI/180) + 10 * std::cos((angle) * Consts::PI/180)); + position[2] = 20 * std::cos(45 * Consts::PI/180) + 10 * std::sin((angle) * Consts::PI/180); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane)< 1e-10); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + + + // curve test reverse angle 8 + position[0] = 10; + angle = 180+46; + position[1] = 10 - (20 * std::cos(45 * Consts::PI/180) + 10 * std::cos((angle) * Consts::PI/180))+0.1; + position[2] = 20 * std::cos(45 * Consts::PI/180) + 10 * std::sin((angle) * Consts::PI/180); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(fabs(distance_from_planes.distance_from_plane)); // checked that it should be small positive this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test reverse angle 9 + position[0] = 10; + angle = 180+46; + position[1] = 10 - (20 * std::cos(45 * Consts::PI/180) + 10 * std::cos((angle) * Consts::PI/180))-0.1; + position[2] = 20 * std::cos(45 * Consts::PI/180) + 10 * std::sin((angle) * Consts::PI/180); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); // checked that it should be small negative this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // curve test reverse angle 10 + position[0] = 10; + angle = 180+90; + position[1] = 10 - (20 * std::cos(45 * Consts::PI/180) + 10 * std::cos((angle) * Consts::PI/180)); + position[2] = 20 * std::cos(45 * Consts::PI/180) + 10 * std::sin((angle) * Consts::PI/180); + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + + // global_x_list test 1 + // reminder, coordinates are {0,10},{20,10},{30,10} + position[0] = 10; + position[1] = 10; + position[2] = 10; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // global_x_list test 2 + position[0] = 10; + position[1] = 10; + position[2] = 10; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // global_x_list test 3 + position[0] = 15; + position[1] = 10; + position[2] = 10; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-14); // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) < 1e-14); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // global_x_list test 4 + position[0] = 20; + position[1] = 10; + position[2] = 10; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-14); // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) < 1e-14); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // global_x_list test 5 + position[0] = 25; + position[1] = 10; + position[2] = 10; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); // checked that it should be about 0 this with a drawing + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-12); + + + + // global_x_list test 6 + position[0] = 30; + position[1] = 10; + position[2] = 10; + natural_coordinate = Objects::NaturalCoordinate(position, + *cartesian_system); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + cartesian_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + + +TEST_CASE("WorldBuilder Utilities function: distance_point_from_curved_planes spherical") +{ + std::vector approval_tests; + + // Because most functionality is already tested by the cartesian version + // of this test case, the scope of this test case is only to test whether + // the code which is different for the spherical case is correct. + + // spherical test 1 + const std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/subducting_plate_different_angles_spherical.wb"; + WorldBuilder::World world(file_name); + + const double dtr = Consts::PI/180.0; + Point<3> position(10,0 * dtr,10 * dtr,spherical); + position = Point<3>(world.parameters.coordinate_system->natural_to_cartesian_coordinates(position.get_array()),cartesian); + + Objects::NaturalCoordinate natural_coordinate = Objects::NaturalCoordinate(position, + *(world.parameters.coordinate_system)); + const Point<2> reference_point(0,0,spherical); + + std::vector > coordinates; + coordinates.emplace_back(0 * dtr,10 * dtr,spherical); + coordinates.emplace_back(10 * dtr,10 * dtr,spherical); + + std::vector > slab_segment_lengths(2); + slab_segment_lengths[0].push_back(std::sqrt(10*10+10*10)); + slab_segment_lengths[0].push_back(200); + slab_segment_lengths[1].push_back(std::sqrt(10*10+10*10)); + slab_segment_lengths[1].push_back(200); + + //double dtr = Consts::PI/180; + std::vector > > slab_segment_angles(2); + slab_segment_angles[0].emplace_back(45 * dtr,45 * dtr,cartesian); + slab_segment_angles[0].emplace_back(45 * dtr,45 * dtr,cartesian); + slab_segment_angles[1].emplace_back(45 * dtr,45 * dtr,cartesian); + slab_segment_angles[1].emplace_back(45 * dtr,45 * dtr,cartesian); + + const double starting_radius = 10; + + const std::vector x_list = {0.,10 * dtr}; + const std::vector y_list = {10 * dtr,10 * dtr}; + const std::vector > coordinate_list_local = coordinates; + const Objects::BezierCurve bezier_curve(coordinates); + + WorldBuilder::Utilities::PointDistanceFromCurvedPlanes distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + world.parameters.coordinate_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_section) < 1e-14); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-14); + + + // spherical test 2 + position = Point<3>(10,10 * dtr,10 * dtr,spherical); + position = Point<3>(world.parameters.coordinate_system->natural_to_cartesian_coordinates(position.get_array()),cartesian); + + natural_coordinate = Objects::NaturalCoordinate(position, + *(world.parameters.coordinate_system)); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + world.parameters.coordinate_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-14); // practically zero + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) < 1e-14); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-14); + + + // spherical test 2 + coordinates[0][0] = -10 * dtr; + coordinates[0][1] = 45 * dtr; + coordinates[1][0] = 10 * dtr; + coordinates[1][1] = 45 * dtr; + position = Point<3>(10,0 * dtr,45 * dtr,spherical); + position = Point<3>(world.parameters.coordinate_system->natural_to_cartesian_coordinates(position.get_array()),cartesian); + + natural_coordinate = Objects::NaturalCoordinate(position, + *(world.parameters.coordinate_system)); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + world.parameters.coordinate_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_from_plane)); + approval_tests.emplace_back(std::isinf(distance_from_planes.distance_along_plane)); + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-14); + + +// spherical test 3 + position = Point<3>(5,0 * dtr,45 * dtr,spherical); + position = Point<3>(world.parameters.coordinate_system->natural_to_cartesian_coordinates(position.get_array()),cartesian); + natural_coordinate = Objects::NaturalCoordinate(position, + *(world.parameters.coordinate_system)); + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + world.parameters.coordinate_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + + /** + * I can't figure out why these are not working in the new structure, although I know it has to do with the different computation of the + * x-axis. In this new computation of the x-axis, the direction is no longer computed as perpendicual to the line P1-P2, but instead as + * the line from the closest point on the line to the check point. This is more accurate for the continuous case and seems to visually + * work well for the non-contiuous case, with only minor changes and of which some are clear improvements and for the rest it is not clear + * if is not clear whether it is an improvement or not. Since the new code seems to be an improvement, I don't have the original drawings + * at hand, don't have the time to redo them or spend much more time on these 18 checks, I will disable the failing parts of them for now. + */ + + /* + // spherical test 4 + position = Point<3>(10*sqrt(2)/2,0 * dtr,90 * dtr,spherical); + position = Point<3>(world.parameters.coordinate_system->natural_to_cartesian_coordinates(position.get_array()),cartesian); + + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + world.parameters.coordinate_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); // checked it with a geometric drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) < 1e-14); // checked it with a geometric drawing + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) < 1e-14); + + + // spherical test 5 + position = Point<3>(10*sqrt(2)/2,0 * dtr,0 * dtr,spherical); + position = Point<3>(world.parameters.coordinate_system->natural_to_cartesian_coordinates(position.get_array()),cartesian); + + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + world.parameters.coordinate_system, + false, + bezier_curve); + + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_from_plane) < 1e-14); // checked it with a geometric drawing + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers // checked it with a geometric drawing + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers + + // spherical curve test 1 + // This test has not been checked analytically or with a drawing, but + // since the non-curved version works, and the visuals look oke, this + // test is used to see if this changes. Todo: Construct analytical + // solutions to test against. + slab_segment_angles[0][0][0] = 0.0 * dtr; + slab_segment_angles[0][0][1] = 45.0 * dtr; + slab_segment_angles[0][1][0] = 45.0 * dtr; + slab_segment_angles[0][1][1] = 0.0 * dtr; + slab_segment_angles[1][0][0] = 0.0 * dtr; + slab_segment_angles[1][0][1] = 45.0 * dtr; + slab_segment_angles[1][1][0] = 45.0 * dtr; + slab_segment_angles[1][1][1] = 0.0 * dtr; + + position = Point<3>(10*sqrt(2)/2,0 * dtr,0 * dtr,spherical); + position = Point<3>(world.parameters.coordinate_system->natural_to_cartesian_coordinates(position.get_array()),cartesian); + + distance_from_planes = + Utilities::distance_point_from_curved_planes(position, + natural_coordinate, + reference_point, + coordinates, + slab_segment_lengths, + slab_segment_angles, + starting_radius, + world.parameters.coordinate_system, + false, + bezier_curve); + + approval_tests.emplace_back(distance_from_planes.distance_from_plane); // see comment at the top of the test + approval_tests.emplace_back(std::fabs(distance_from_planes.distance_along_plane) > 1e-12 ? distance_from_planes.distance_along_plane : 0.); // to make sure the approval test have the same characters for very small numbers // see comment at the top of the test + approval_tests.emplace_back(distance_from_planes.fraction_of_section); + approval_tests.emplace_back(static_cast(distance_from_planes.section)); + approval_tests.emplace_back(static_cast(distance_from_planes.segment)); + approval_tests.emplace_back(std::fabs(distance_from_planes.fraction_of_segment) > 1e-12 ? distance_from_planes.fraction_of_segment : 0.); // to make sure the approval test have the same characters for very small numbers*/ + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("WorldBuilder Utilities function: distance_point_from_curved_planes spherical depth methods") +{ + std::vector approval_tests; + + { + // starting point + const std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/spherical_depth_method_starting_point.wb"; + WorldBuilder::World world(file_name); + + const double dtr = Consts::PI/180.0; + world.parse_entries(world.parameters); + approval_tests.emplace_back(world.parameters.coordinate_system->max_model_depth()); + // slab goes down and up again + // origin + std::array position = {{6371000 - 0, 0 * dtr, 0 * dtr}}; + position = world.parameters.coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world.temperature(position, 0)); + approval_tests.emplace_back(world.temperature(position, 1)); + approval_tests.emplace_back(world.temperature(position, 200e3)); + approval_tests.emplace_back(world.temperature(position, 210e3)); + + // ~330 km + position = {{6371000 - 0, 0 * dtr, -3 * dtr}}; + position = world.parameters.coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world.temperature(position, 0)); + approval_tests.emplace_back(world.temperature(position, 50e3)); + approval_tests.emplace_back(world.temperature(position, 75e3)); + approval_tests.emplace_back(world.temperature(position, 250e3)); + approval_tests.emplace_back(world.temperature(position, 275e3)); + + + // ~1100 km + position = {{6371000 - 0, 0 * dtr, -10 * dtr}}; + position = world.parameters.coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world.temperature(position, 0)); + approval_tests.emplace_back(world.temperature(position, 95e3)); + approval_tests.emplace_back(world.temperature(position, 100e3)); + approval_tests.emplace_back(world.temperature(position, 300e3)); + approval_tests.emplace_back(world.temperature(position, 305e3)); + + + // ~2200 km + position = {{6371000 - 0, 0 * dtr, -20 * dtr}}; + position = world.parameters.coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world.temperature(position, 0)); + approval_tests.emplace_back(world.temperature(position, 1)); + approval_tests.emplace_back(world.temperature(position, 200e3)); + approval_tests.emplace_back(world.temperature(position, 205e3)); + approval_tests.emplace_back(world.temperature(position, 570e3)); + } + + { + // begin segment depth method + const std::string file_name = WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/spherical_depth_method_begin_segment.wb"; + WorldBuilder::World world(file_name); + + const double dtr = Consts::PI/180.0; + // origin + std::array position = {{6371000 - 0, 0 * dtr, 0 * dtr}}; + position = world.parameters.coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world.temperature(position, 0)); + approval_tests.emplace_back(world.temperature(position, 1)); + approval_tests.emplace_back(world.temperature(position, 200e3)); + approval_tests.emplace_back(world.temperature(position, 210e3)); + + // ~330 km + position = {{6371000 - 0, 0 * dtr, -3 * dtr}}; + position = world.parameters.coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world.temperature(position, 0)); + approval_tests.emplace_back(world.temperature(position, 50e3)); + approval_tests.emplace_back(world.temperature(position, 75e3)); + approval_tests.emplace_back(world.temperature(position, 250e3)); + approval_tests.emplace_back(world.temperature(position, 275e3)); + + + // ~1100 km + position = {{6371000 - 0, 0 * dtr, -10 * dtr}}; + position = world.parameters.coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world.temperature(position, 0)); + approval_tests.emplace_back(world.temperature(position, 150e3)); + approval_tests.emplace_back(world.temperature(position, 175e3)); + approval_tests.emplace_back(world.temperature(position, 380e3)); + approval_tests.emplace_back(world.temperature(position, 385e3)); + + + // ~1100 km + position = {{6371000 - 0, 0 * dtr, -20 * dtr}}; + position = world.parameters.coordinate_system->natural_to_cartesian_coordinates(position); + approval_tests.emplace_back(world.temperature(position, 0)); + approval_tests.emplace_back(world.temperature(position, 350e3)); + approval_tests.emplace_back(world.temperature(position, 355e3)); + approval_tests.emplace_back(world.temperature(position, 565e3)); + approval_tests.emplace_back(world.temperature(position, 570e3)); + } + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("WorldBuilder parameters: invalid 1") +{ + + CHECK_THROWS_WITH(WorldBuilder::World(WorldBuilder::Data::WORLD_BUILDER_SOURCE_DIR + "/tests/data/invalid_1.wb"), + Contains("Invalid keyword: additionalPropertiesInvalid schema: #/test")); + +} + +TEST_CASE("Fast sin functions") +{ + for (int i = -400; i < 400; i++) + { + const double angle = (WorldBuilder::Consts::PI/100.)*static_cast(i); + CHECK(fabs(FT::sin(angle)-std::sin(angle)) < 1.2e-5); + } + + for (int i = -400; i < 400; i++) + { + const double angle = (WorldBuilder::Consts::PI/100.)*static_cast(i); + CHECK(fabs(FT::cos(angle)-std::cos(angle)) < 1.2e-5); + } +} + +TEST_CASE("Fast vs slow distance function") +{ + std::vector approval_tests; + const Point<2> cartesian_1(1,2, cartesian); + const Point<2> cartesian_2(2,3, cartesian); + // Should be exactly the same. + approval_tests.emplace_back(sqrt(cartesian_1.cheap_relative_distance_cartesian(cartesian_2))); + + const Point<2> spherical_1(1,2, spherical); + const Point<2> spherical_2(2,3, spherical); + // will have an error associated with the faster sin functions. + CHECK(fabs(2.0 * asin(sqrt((spherical_1.cheap_relative_distance_spherical(spherical_2))))- spherical_1.distance(spherical_2)) < 3e-5); + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("Fast version of fmod") +{ + CHECK(FT::fmod(0,1) == Approx(std::fmod(0,1))); + CHECK(FT::fmod(0.2,1) == Approx(std::fmod(0.2,1))); + CHECK(FT::fmod(1,1) == Approx(std::fmod(1,1))); + CHECK(FT::fmod(5.3,2) == Approx(std::fmod(5.3,2))); + CHECK(FT::fmod(18.5,4.2) == Approx(std::fmod(18.5,4.2))); + CHECK(std::isnan(FT::fmod(1,0))); + //CHECK(std::isnan(std::fmod(1,0))); Return a signaling NAN (FE_INVALID is raised) +} + +TEST_CASE("WorldBuilder Utilities function: calculate_ridge_distance_and_spreading") +{ + std::vector approval_tests; + + const std::unique_ptr cartesian_system = CoordinateSystems::Interface::create("cartesian", nullptr);; + + // Ridge properties + const Point<2> p1a(std::array {{200e3, -1e3}},cartesian); + const Point<2> p1b(std::array {{200e3, 50e3}},cartesian); + const Point<2> p2a(std::array {{50e3, 50e3}},cartesian); + const Point<2> p2b(std::array {{50e3, 101e3}},cartesian); + const Point<2> p2c(std::array {{100e3, 151e3}},cartesian); + const std::vector> mid_ocean_ridges_segment_1 = {p1a, p1b}; + const std::vector> mid_ocean_ridges_segment_2 = {p2a, p2b, p2c}; + + std::vector>> mid_oceanic_ridges; + mid_oceanic_ridges.push_back(mid_ocean_ridges_segment_1); + mid_oceanic_ridges.push_back(mid_ocean_ridges_segment_2); + + const double mid_oceanic_spreading_velocitie_1a = 1.0; + const double mid_oceanic_spreading_velocitie_1b = 2.0; + const double mid_oceanic_spreading_velocitie_2a = 3.0; + const double mid_oceanic_spreading_velocitie_2b = 4.0; + const double mid_oceanic_spreading_velocitie_2c = 5.0; + + std::vector mid_oceanic_spreading_velocities_segment1 = {mid_oceanic_spreading_velocitie_1a, mid_oceanic_spreading_velocitie_1b}; + std::vector mid_oceanic_spreading_velocities_segment2 = {mid_oceanic_spreading_velocitie_2a, mid_oceanic_spreading_velocitie_2b, + mid_oceanic_spreading_velocitie_2c + }; + + std::vector> mid_oceanic_spreading_velocities; + mid_oceanic_spreading_velocities.push_back(mid_oceanic_spreading_velocities_segment1); + mid_oceanic_spreading_velocities.push_back(mid_oceanic_spreading_velocities_segment2); + + const std::vector> subducting_plate_velocities = {{0.0}}; + const std::vector &ridge_migration_times = {0.0}; + + // Query point 1 + Point<3> position_1(1e3,0,0,cartesian); + Objects::NaturalCoordinate position_in_natural_coordinates_1 = Objects::NaturalCoordinate(position_1, + *cartesian_system); + + const std::vector result1 = Utilities::calculate_ridge_distance_and_spreading(mid_oceanic_ridges, + mid_oceanic_spreading_velocities, + cartesian_system, + position_in_natural_coordinates_1, + subducting_plate_velocities, + ridge_migration_times); + approval_tests.emplace_back(result1[0]); // spreading velocity at ridge + approval_tests.emplace_back(result1[1]); // ridge distance + approval_tests.emplace_back(result1[2]); // subducting velocity at trench + approval_tests.emplace_back(result1[3]); // ridge migration time + + // Query point 2: locates outside of the ridge, current solution is to take the end point as the reference point + Point<3> position_2(1e3,-2e3,0,cartesian); + Objects::NaturalCoordinate position_in_natural_coordinates_2 = Objects::NaturalCoordinate(position_2, + *cartesian_system); + + const std::vector result2 = Utilities::calculate_ridge_distance_and_spreading(mid_oceanic_ridges, + mid_oceanic_spreading_velocities, + cartesian_system, + position_in_natural_coordinates_2, + subducting_plate_velocities, + ridge_migration_times); + approval_tests.emplace_back(result2[0]); // spreading velocity at ridge + approval_tests.emplace_back(result2[1]); // ridge distance + approval_tests.emplace_back(result2[2]); // subducting velocity at trench + approval_tests.emplace_back(result2[3]); // ridge migration time + + // Query point 3: the nearest point on the ridge is in the middle of p2b and p2c + // thus it should have intermediate velocity values + Point<3> position_3(50e3,151e3,0,cartesian); + Objects::NaturalCoordinate position_in_natural_coordinates_3 = Objects::NaturalCoordinate(position_3, + *cartesian_system); + + const std::vector result3 = Utilities::calculate_ridge_distance_and_spreading(mid_oceanic_ridges, + mid_oceanic_spreading_velocities, + cartesian_system, + position_in_natural_coordinates_3, + subducting_plate_velocities, + ridge_migration_times); + approval_tests.emplace_back(result3[0]); // spreading velocity at ridge + approval_tests.emplace_back(result3[1]); // ridge distance + approval_tests.emplace_back(result3[2]); // subducting velocity at trench + approval_tests.emplace_back(result3[3]); // ridge migration time + + // Query point 4: the nearest point on the ridge is in the middle of p2a and p2b + // thus it should have intermediate velocity values + Point<3> position_4(100e3,76e3,0,cartesian); + Objects::NaturalCoordinate position_in_natural_coordinates_4 = Objects::NaturalCoordinate(position_4, + *cartesian_system); + + const std::vector result4 = Utilities::calculate_ridge_distance_and_spreading(mid_oceanic_ridges, + mid_oceanic_spreading_velocities, + cartesian_system, + position_in_natural_coordinates_4, + subducting_plate_velocities, + ridge_migration_times); + approval_tests.emplace_back(result4[0]); // spreading velocity at ridge + approval_tests.emplace_back(result4[1]); // ridge distance + approval_tests.emplace_back(result4[2]); // subducting velocity at trench + approval_tests.emplace_back(result4[3]); // ridge migration time + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + +TEST_CASE("WorldBuilder Utilities function: calculate_ridge_distance_and_spreading spherical") +{ + std::vector approval_tests; + + const std::unique_ptr spherical_system = CoordinateSystems::Interface::create("spherical", nullptr);; + + // Ridge properties + const Point<2> p1a(std::array {{0.3491, -0.6981}},spherical); + const Point<2> p1b(std::array {{0.3491, 0.0}},spherical); + const Point<2> p2a(std::array {{0.1745, 0.0}},spherical); + const Point<2> p2b(std::array {{0.1745, 0.5236}},spherical); + const Point<2> p2c(std::array {{0.3491, 0.6981}},spherical); + const std::vector> mid_ocean_ridges_segment_1 = {p1a, p1b}; + const std::vector> mid_ocean_ridges_segment_2 = {p2a, p2b, p2c}; + + std::vector>> mid_oceanic_ridges; + mid_oceanic_ridges.push_back(mid_ocean_ridges_segment_1); + mid_oceanic_ridges.push_back(mid_ocean_ridges_segment_2); + + const double mid_oceanic_spreading_velocitie_1a = 1.0; + const double mid_oceanic_spreading_velocitie_1b = 2.0; + const double mid_oceanic_spreading_velocitie_2a = 3.0; + const double mid_oceanic_spreading_velocitie_2b = 4.0; + const double mid_oceanic_spreading_velocitie_2c = 5.0; + + std::vector mid_oceanic_spreading_velocities_segment1 = {mid_oceanic_spreading_velocitie_1a, mid_oceanic_spreading_velocitie_1b}; + std::vector mid_oceanic_spreading_velocities_segment2 = {mid_oceanic_spreading_velocitie_2a, mid_oceanic_spreading_velocitie_2b, + mid_oceanic_spreading_velocitie_2c + }; + + std::vector> mid_oceanic_spreading_velocities; + mid_oceanic_spreading_velocities.push_back(mid_oceanic_spreading_velocities_segment1); + mid_oceanic_spreading_velocities.push_back(mid_oceanic_spreading_velocities_segment2); + + const std::vector> subducting_plate_velocities = {{0.0}}; + const std::vector &ridge_migration_times = {0.0}; + + // Query point 1, the nearest point on the ridge is in the middle of p1a and p1b + Point<3> position_1(6371e3, 0.1745, -0.3491, spherical); + Objects::NaturalCoordinate position_in_natural_coordinates_1 = Objects::NaturalCoordinate(Utilities::spherical_to_cartesian_coordinates(position_1.get_array()), + *spherical_system); + + const std::vector result1 = Utilities::calculate_ridge_distance_and_spreading(mid_oceanic_ridges, + mid_oceanic_spreading_velocities, + spherical_system, + position_in_natural_coordinates_1, + subducting_plate_velocities, + ridge_migration_times); + approval_tests.emplace_back(result1[0]); // spreading velocity at ridge + approval_tests.emplace_back(result1[1]); // ridge distance + approval_tests.emplace_back(result1[2]); // subducting velocity at trench + approval_tests.emplace_back(result1[3]); // ridge migration time + + // Query point 2, the nearest point on the ridge is in the middle of p2b and p2c + Point<3> position_2(6371e3, 0.3491, 0.5236, spherical); + Objects::NaturalCoordinate position_in_natural_coordinates_2 = Objects::NaturalCoordinate(Utilities::spherical_to_cartesian_coordinates(position_2.get_array()), + *spherical_system); + + const std::vector result2 = Utilities::calculate_ridge_distance_and_spreading(mid_oceanic_ridges, + mid_oceanic_spreading_velocities, + spherical_system, + position_in_natural_coordinates_2, + subducting_plate_velocities, + ridge_migration_times); + approval_tests.emplace_back(result2[0]); // spreading velocity at ridge + approval_tests.emplace_back(result2[1]); // ridge distance + approval_tests.emplace_back(result2[2]); // subducting velocity at trench + approval_tests.emplace_back(result2[3]); // ridge migration time + + // Query point 3, the nearest point on the ridge is p2b, the purpose is to test a negative value of longitude + Point<3> position_3(6371e3, -0.1745, 0.5236, spherical); + Objects::NaturalCoordinate position_in_natural_coordinates_3 = Objects::NaturalCoordinate(Utilities::spherical_to_cartesian_coordinates(position_3.get_array()), + *spherical_system); + + const std::vector result3 = Utilities::calculate_ridge_distance_and_spreading(mid_oceanic_ridges, + mid_oceanic_spreading_velocities, + spherical_system, + position_in_natural_coordinates_3, + subducting_plate_velocities, + ridge_migration_times); + approval_tests.emplace_back(result3[0]); // spreading velocity at ridge + approval_tests.emplace_back(result3[1]); // ridge distance + approval_tests.emplace_back(result3[2]); // subducting velocity at trench + approval_tests.emplace_back(result3[3]); // ridge migration time + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); +} + + +TEST_CASE("WorldBuilder Utilities function: calculate_effective_trench_and_plate_ages") +{ + std::vector approval_tests; + + // test 1: trivial case, spreading velocity = subducting velocity and no ridge migration + const std::vector ridge_parameters_1 = {4.75299e-10, 1.04512e+06, 4.75299e-10, 0.0}; // m/s, m, m/s, s + const double distance_along_plane_1 = 1000e3; + std::vector result1 = Utilities::calculate_effective_trench_and_plate_ages(ridge_parameters_1, distance_along_plane_1); + + approval_tests.emplace_back(result1[0]); // age at trench + approval_tests.emplace_back(result1[1]); // effective plate age + + // test 2: 2 * spreading velocity = subducting velocity and no ridge migration, trench retreating + std::vector ridge_parameters_2 = {4.75299e-10, 1.04512e+06, 9.50598e-10, 0.0}; // m/s, m, m/s, s + const double distance_along_plane_2 = 1000e3; + std::vector result2 = Utilities::calculate_effective_trench_and_plate_ages(ridge_parameters_2, distance_along_plane_2); + + approval_tests.emplace_back(result2[0]); // age at trench + approval_tests.emplace_back(result2[1]); // effective plate age + + ApprovalTests::Approvals::verifyAll("TITLE", approval_tests); + + // test 3: negative subducting velocity triggers error + std::vector ridge_parameters_3 = {4.75299e-10, 1.04512e+06, -9.50598e-10, 0.0}; // m/s, m, m/s, s + const double distance_along_plane_3 = 1000e3; + CHECK_THROWS_WITH(Utilities::calculate_effective_trench_and_plate_ages(ridge_parameters_3, distance_along_plane_3), + Contains("The subducting velocity is less than 0.")); + + // test 4: subducting velocity is too small, causing negative trench age at subducting initiation + std::vector ridge_parameters_4 = {4.75299e-10, 1.04512e+06, 9.50598e-11, 0.0}; // m/s, m, m/s, s + const double distance_along_plane_4 = 1000e3; + CHECK_THROWS_WITH(Utilities::calculate_effective_trench_and_plate_ages(ridge_parameters_4, distance_along_plane_4), + Contains("The age of trench at subducting initiation is less than 0. ")); +} diff --git a/cookbooks/2d_annulus_visualization/2d_annulus_example.prm.bak b/cookbooks/2d_annulus_visualization/2d_annulus_example.prm.bak new file mode 100644 index 00000000000..08d1554f2b4 --- /dev/null +++ b/cookbooks/2d_annulus_visualization/2d_annulus_example.prm.bak @@ -0,0 +1,89 @@ +# This setup is a copy of +# cookbook/onset-of-convection/onset-of-convection.prm +# with the difference that the geometry is a 2D cylindrical +# annulus and the initial and boundary temperatures +# are reduced to generate a lower Rayleigh number system. + +set Dimension = 2 +set Use years in output instead of seconds = true +set Output directory = output +set Pressure normalization = surface +set Surface pressure = 0 +set Use conduction timestep = true + +subsection Termination criteria + set Termination criteria = end step + set End step = 100 +end + +subsection Formulation + set Formulation = Boussinesq approximation +end + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Outer radius = 6371000 + set Inner radius = 3481000 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Coordinate system = spherical + set Variable names = r,phi + set Function expression = 1600 + 10*sin(10*phi) + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 2000 + set Outer temperature = 0 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = bottom, top +end + +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 10.0 + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 4000 + set Reference specific heat = 1250 + set Reference temperature = 0 + set Thermal conductivity = 4.0 + set Thermal expansion coefficient = 3e-5 + set Viscosity = 1e23 + end +end + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = velocity statistics, visualization + + subsection Visualization + set Time steps between graphical output = 5 + end +end diff --git a/cookbooks/allken_et_al_2012_rift_interaction/allken.prm b/cookbooks/allken_et_al_2012_rift_interaction/allken.prm index a42b73d30c3..fbe89f631e1 100644 --- a/cookbooks/allken_et_al_2012_rift_interaction/allken.prm +++ b/cookbooks/allken_et_al_2012_rift_interaction/allken.prm @@ -5,7 +5,7 @@ set Dimension = 3 set Start time = 0 set End time = 5e6 set Use years in output instead of seconds = true -set Nonlinear solver scheme = iterated Stokes +set Nonlinear solver scheme = single Advection, iterated Stokes set Nonlinear solver tolerance = 1e-4 set Max nonlinear iterations = 25 set Output directory = output-allken_etal_2012 diff --git a/cookbooks/allken_et_al_2012_rift_interaction/allken.prm.bak b/cookbooks/allken_et_al_2012_rift_interaction/allken.prm.bak new file mode 100644 index 00000000000..a42b73d30c3 --- /dev/null +++ b/cookbooks/allken_et_al_2012_rift_interaction/allken.prm.bak @@ -0,0 +1,155 @@ +# Input file to replicate Allken et al, G3, 2012. + +# Global parameters +set Dimension = 3 +set Start time = 0 +set End time = 5e6 +set Use years in output instead of seconds = true +set Nonlinear solver scheme = iterated Stokes +set Nonlinear solver tolerance = 1e-4 +set Max nonlinear iterations = 25 +set Output directory = output-allken_etal_2012 +set Pressure normalization = no +set CFL number = .5 + +# Solver settings +subsection Solver parameters + subsection Stokes solver parameters + set Number of cheap Stokes solver steps = 0 + set Stokes solver type = block AMG + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 7 + set Y repetitions = 7 + set Z repetitions = 1 + set X extent = 210e3 + set Y extent = 210e3 + set Z extent = 30e3 + end +end + +# Mesh refinement specifications. +subsection Mesh refinement + set Initial adaptive refinement = 2 + set Initial global refinement = 2 + set Time steps between mesh refinement = 1 + set Refinement fraction = 0.5 + set Strategy = strain rate + set Coarsening fraction = 0 +end + +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + set Additional tangential mesh velocity boundary indicators = left,right + + subsection Free surface + set Surface velocity projection = normal + end +end + +# Velocity boundary conditions +# The imposed velocity produces a background strain-rate of approx. 1.51e-15. +subsection Boundary velocity model + set Tangential velocity boundary indicators = front,back,bottom + set Prescribed velocity boundary indicators = left x: function, right x:function + + subsection Function + set Variable names = x,y,z + set Function constants = cm=0.01, year=1, vel=0.5 + set Function expression = if (x<20e3 , -vel*cm/year, vel*cm/year); 0; 0 + end +end + +# Number and name of compositional fields +subsection Compositional fields + set Number of fields = 3 + set Names of fields = noninitial_plastic_strain, plastic_strain , lower_crust +end + +# Spatial domain of different compositional fields +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y,z + set Function constants = xL=85e3 , xR=135e3 + set Function expression = 0; \ + if( (y<=50e3 && abs(x-xL)<=4e3 && z>=15e3 && z<=19e3) || \ + (y>=160e3 && abs(x-xR)<=4e3 && z>=15e3 && z<=19e3),1.25,0); \ + if(z<=15e3, 1, 0); + end +end + +# Temperature boundary conditions +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top, left, right + set List of model names = initial temperature +end + +# Temperature initial conditions (isothermal) +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 293 + end +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +# Material model +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + set Densities = 2800 + set Reference strain rate = 1.51e-15 + set Maximum viscosity = 1.e24 + set Minimum viscosity = 1.e19 + set Viscous flow law = diffusion + set Grain size exponents for diffusion creep = 0. + set Prefactors for diffusion creep = 5e-26,1e-50,1e-50,5e-21 + set Activation energies for diffusion creep = 0. + set Activation volumes for diffusion creep = 0. + set Viscosity averaging scheme = maximum composition + set Angles of internal friction = 15. + set Cohesions = 20.e6 + + # The parameters below weaken the friction and cohesion by a + # a factor of 4 between plastic strain values of 0.25 and 1.25. + set Strain weakening mechanism = plastic weakening with plastic strain only + set Start plasticity strain weakening intervals = 0.25 + set End plasticity strain weakening intervals = 1.25 + set Cohesion strain weakening factors = 0.25 + set Friction strain weakening factors = 0.25 + set Use plastic damper = true + set Plastic damper viscosity = 5e19 + end +end + +# Post processing +subsection Postprocess + set List of postprocessors = basic statistics, composition statistics, velocity statistics, visualization, topography + + subsection Visualization + set List of output variables = material properties, strain rate, named additional outputs + set Time between graphical output = 10e3 + set Interpolate output = true + + subsection Material properties + set List of material properties = density, viscosity + end + end +end diff --git a/cookbooks/anisotropic_viscosity/AV_Rayleigh_Taylor.prm.bak b/cookbooks/anisotropic_viscosity/AV_Rayleigh_Taylor.prm.bak new file mode 100644 index 00000000000..8d4fc00b635 --- /dev/null +++ b/cookbooks/anisotropic_viscosity/AV_Rayleigh_Taylor.prm.bak @@ -0,0 +1,100 @@ +# This cookbook uses the implementation of anisotropic viscosity terms in the Stokes +# equation. Here, it is applied to the Rayleigh-Taylor instability problem, following +# Lev and Hager (2008) and Perry-Houts and Karlstrom (2019) and the van Keken cookbook. +# + +set Additional shared libraries = ./libanisotropic_viscosity.so +set Dimension = 2 +set CFL number = 0.5 +set Start time = 0 +set End time = 30 +set Adiabatic surface temperature = 0 +set Surface pressure = 0 +set Use years in output instead of seconds = false +set Output directory = output-AV-Rayleigh-Taylor-noAV + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 # width of the box, present in the functions of the compositional fields + set Y extent = 1 + end +end + +# temperature field doesn't matter. set it to zero +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +# 3 compositional fields, 1 for the material, 2 for the anisotropic viscosity (AV) normals +subsection Compositional fields + set Number of fields = 3 + set Names of fields = gamma, ni, nj +end + +subsection Material model + set Model name = AV material + + # density is hard-coded into the AV_material.cc plugin + # everything else is set to 0 + + subsection AV + set Normal viscosity = 1 + set Shear viscosity = 1 + end +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = pi=3.1415926; + set Function expression = 0.5*(1+tanh((z-0.85-0.02*cos(2*pi*x/2))/0.02)); \ + (0.5*(1+tanh((z-0.85-0.02*cos(2*pi*x/2))/0.02))) > 0.8 ? sin(45*pi/180) : 0.0; \ + (0.5*(1+tanh((z-0.85-0.02*cos(2*pi*x/2))/0.02))) > 0.8 ? cos(45*pi/180) : 0.0; + end +end + +subsection Mesh refinement + set Initial global refinement = 6 + set Initial adaptive refinement = 2 + set Strategy = composition + set Time steps between mesh refinement = 1 + set Coarsening fraction = 0.05 + set Refinement fraction = 0.1 +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right + set Zero velocity boundary indicators = bottom, top +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, composition statistics, material statistics + + subsection Visualization + # add "named additional outputs" to the list to save the stress-strain director (AV tensor) + set List of output variables = compositional vector, density, viscosity, gravity, shear stress, stress, strain rate, strain rate tensor, named additional outputs + set Output format = vtu + set Time between graphical output = 0.5 + + subsection Compositional fields as vectors + set Names of fields = ni,nj + set Names of vectors = n + end + end +end diff --git a/cookbooks/anisotropic_viscosity/av_material.cc.bak b/cookbooks/anisotropic_viscosity/av_material.cc.bak new file mode 100644 index 00000000000..e475d22e459 --- /dev/null +++ b/cookbooks/anisotropic_viscosity/av_material.cc.bak @@ -0,0 +1,831 @@ +/* + Copyright (C) 2015 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * Additional output fields for anisotropic viscosities to be added to + * the MaterialModel::MaterialModelOutputs structure and filled in the + * MaterialModel::Interface::evaluate() function. + */ + template + class AnisotropicViscosity : public NamedAdditionalMaterialOutputs + { + public: + AnisotropicViscosity(const unsigned int n_points); + + std::vector get_nth_output(const unsigned int idx) const override; + + /** + * Stress-strain "director" tensors at the given positions. This + * variable is used to implement anisotropic viscosity. + * + * @note The strain rate term in equation (1) of the manual will be + * multiplied by this tensor *and* the viscosity scalar ($\eta$), as + * described in the manual section titled "Constitutive laws". This + * variable is assigned the rank-four identity tensor by default. + * This leaves the isotropic constitutive law unchanged if the material + * model does not explicitly assign a value. + */ + std::vector> stress_strain_directors; + }; + + namespace + { + + + + template + std::vector make_AnisotropicViscosity_additional_outputs_names() + { + std::vector names; + + for (unsigned int i = 0; i < Tensor<4,dim>::n_independent_components ; ++i) + { + TableIndices<4> indices(Tensor<4,dim>::unrolled_to_component_indices(i)); + names.push_back("anisotropic_viscosity"+std::to_string(indices[0])+std::to_string(indices[1])+std::to_string(indices[2])+std::to_string(indices[3])); + } + return names; + } + } + + + + template + AnisotropicViscosity::AnisotropicViscosity (const unsigned int n_points) + : + NamedAdditionalMaterialOutputs(make_AnisotropicViscosity_additional_outputs_names()), + stress_strain_directors(n_points, dealii::identity_tensor ()) + {} + + + + template + std::vector + AnisotropicViscosity::get_nth_output(const unsigned int idx) const + { + std::vector output(stress_strain_directors.size()); + for (unsigned int i = 0; i < stress_strain_directors.size() ; ++i) + { + output[i]= stress_strain_directors[i][Tensor<4,dim>::unrolled_to_component_indices(idx)]; + } + return output; + } + } +} + +namespace aspect +{ + namespace Assemblers + { + /** + * A class containing the functions to assemble the Stokes preconditioner. + */ + template + class StokesPreconditionerAnisotropicViscosity : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch, + internal::Assembly::CopyData::CopyDataBase &data) const override; + + /** + * Create AnisotropicViscosities. + */ + void create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const override; + }; + + /** + * This class assembles the terms for the matrix and right-hand-side of the incompressible + * Stokes equation for the current cell. + */ + template + class StokesIncompressibleTermsAnisotropicViscosity : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch, + internal::Assembly::CopyData::CopyDataBase &data) const override; + + /** + * Create AdditionalMaterialOutputsStokesRHS if we need to do so. + */ + void create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const override; + }; + + + + template + void + StokesPreconditionerAnisotropicViscosity:: + execute (internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const + { + internal::Assembly::Scratch::StokesPreconditioner &scratch = dynamic_cast&> (scratch_base); + internal::Assembly::CopyData::StokesPreconditioner &data = dynamic_cast&> (data_base); + + const MaterialModel::AnisotropicViscosity *anisotropic_viscosity = + scratch.material_model_outputs.template get_additional_output>(); + + const Introspection &introspection = this->introspection(); + const FiniteElement &fe = this->get_fe(); + const unsigned int stokes_dofs_per_cell = data.local_dof_indices.size(); + const unsigned int n_q_points = scratch.finite_element_values.n_quadrature_points; + const double pressure_scaling = this->get_pressure_scaling(); + + // First loop over all dofs and find those that are in the Stokes system + // save the component (pressure and dim velocities) each belongs to. + for (unsigned int i = 0, i_stokes = 0; i_stokes < stokes_dofs_per_cell; /*increment at end of loop*/) + { + if (introspection.is_stokes_component(fe.system_to_component_index(i).first)) + { + scratch.dof_component_indices[i_stokes] = fe.system_to_component_index(i).first; + ++i_stokes; + } + ++i; + } + + // Loop over all quadrature points and assemble their contributions to + // the preconditioner matrix + for (unsigned int q = 0; q < n_q_points; ++q) + { + for (unsigned int i = 0, i_stokes = 0; i_stokes < stokes_dofs_per_cell; /*increment at end of loop*/) + { + if (introspection.is_stokes_component(fe.system_to_component_index(i).first)) + { + scratch.grads_phi_u[i_stokes] = + scratch.finite_element_values[introspection.extractors + .velocities].symmetric_gradient(i, q); + scratch.phi_p[i_stokes] = scratch.finite_element_values[introspection + .extractors.pressure].value(i, q); + ++i_stokes; + } + ++i; + } + + const double eta = scratch.material_model_outputs.viscosities[q]; + const double one_over_eta = 1. / eta; + const SymmetricTensor<4, dim> &stress_strain_director = anisotropic_viscosity->stress_strain_directors[q]; + const double JxW = scratch.finite_element_values.JxW(q); + + for (unsigned int i = 0; i < stokes_dofs_per_cell; ++i) + for (unsigned int j = 0; j < stokes_dofs_per_cell; ++j) + if (scratch.dof_component_indices[i] == + scratch.dof_component_indices[j]) + data.local_matrix(i, j) += (2.0 * eta * (scratch.grads_phi_u[i] + * stress_strain_director + * scratch.grads_phi_u[j]) + + one_over_eta * pressure_scaling + * pressure_scaling + * (scratch.phi_p[i] + * scratch.phi_p[j])) + * JxW; + } + } + + + + template + void + StokesPreconditionerAnisotropicViscosity:: + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const + { + const unsigned int n_points = outputs.viscosities.size(); + + if (outputs.template get_additional_output>() == nullptr) + { + outputs.additional_outputs.push_back( + std::make_unique> (n_points)); + } + } + + + + template + void + StokesIncompressibleTermsAnisotropicViscosity:: + execute (internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const + { + internal::Assembly::Scratch::StokesSystem &scratch = dynamic_cast&> (scratch_base); + internal::Assembly::CopyData::StokesSystem &data = dynamic_cast&> (data_base); + + const MaterialModel::AnisotropicViscosity *anisotropic_viscosity = + scratch.material_model_outputs.template get_additional_output>(); + + const Introspection &introspection = this->introspection(); + const FiniteElement &fe = this->get_fe(); + const unsigned int stokes_dofs_per_cell = data.local_dof_indices.size(); + const unsigned int n_q_points = scratch.finite_element_values.n_quadrature_points; + const double pressure_scaling = this->get_pressure_scaling(); + + const MaterialModel::AdditionalMaterialOutputsStokesRHS + *force = scratch.material_model_outputs.template get_additional_output>(); + + for (unsigned int q=0; q()); + + const SymmetricTensor<4, dim> &stress_strain_director = anisotropic_viscosity->stress_strain_directors[q]; + + const Tensor<1,dim> + gravity = this->get_gravity_model().gravity_vector (scratch.finite_element_values.quadrature_point(q)); + + const double density = scratch.material_model_outputs.densities[q]; + const double JxW = scratch.finite_element_values.JxW(q); + + for (unsigned int i=0; irhs_u[q] * scratch.phi_u[i] + + pressure_scaling * force->rhs_p[q] * scratch.phi_p[i]) + * JxW; + + if (scratch.rebuild_stokes_matrix) + for (unsigned int j=0; j + void + StokesIncompressibleTermsAnisotropicViscosity:: + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const + { + const unsigned int n_points = outputs.viscosities.size(); + + if (outputs.template get_additional_output>() == nullptr) + { + outputs.additional_outputs.push_back( + std::make_unique> (n_points)); + } + + if (this->get_parameters().enable_additional_stokes_rhs + && outputs.template get_additional_output>() == nullptr) + { + outputs.additional_outputs.push_back( + std::make_unique> (n_points)); + } + Assert(!this->get_parameters().enable_additional_stokes_rhs + || + outputs.template get_additional_output>()->rhs_u.size() + == n_points, ExcInternalError()); + } + } + + namespace HeatingModel + { + template + class ShearHeatingAnisotropicViscosity : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Compute the heating model outputs for this class. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + /** + * Allow the heating model to attach additional material model outputs. + */ + void + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &material_model_outputs) const override; + }; + + + + template + void + ShearHeatingAnisotropicViscosity:: + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + Assert(heating_model_outputs.heating_source_terms.size() == material_model_inputs.position.size(), + ExcMessage ("Heating outputs need to have the same number of entries as the material model inputs.")); + + Assert(heating_model_outputs.heating_source_terms.size() == material_model_inputs.strain_rate.size(), + ExcMessage ("The shear heating plugin needs the strain rate!")); + + // Some material models provide dislocation viscosities and boundary area work fractions + // as additional material outputs. If they are attached, use them. + const ShearHeatingOutputs *shear_heating_out = + material_model_outputs.template get_additional_output>(); + + const MaterialModel::AnisotropicViscosity *anisotropic_viscosity = + material_model_outputs.template get_additional_output>(); + + for (unsigned int q=0; q &directed_strain_rate = ((anisotropic_viscosity != nullptr) + ? + anisotropic_viscosity->stress_strain_directors[q] + * material_model_inputs.strain_rate[q] + : + material_model_inputs.strain_rate[q]); + + const SymmetricTensor<2,dim> stress = + 2 * material_model_outputs.viscosities[q] * + (this->get_material_model().is_compressible() + ? + directed_strain_rate - 1./3. * trace(directed_strain_rate) * unit_symmetric_tensor() + : + directed_strain_rate); + + const SymmetricTensor<2,dim> deviatoric_strain_rate = + (this->get_material_model().is_compressible() + ? + material_model_inputs.strain_rate[q] + - 1./3. * trace(material_model_inputs.strain_rate[q]) * unit_symmetric_tensor() + : + material_model_inputs.strain_rate[q]); + + heating_model_outputs.heating_source_terms[q] = stress * deviatoric_strain_rate; + + // If shear heating work fractions are provided, reduce the + // overall heating by this amount (which is assumed to be converted into other forms of energy) + if (shear_heating_out != nullptr) + heating_model_outputs.heating_source_terms[q] *= shear_heating_out->shear_heating_work_fractions[q]; + + heating_model_outputs.lhs_latent_heat_terms[q] = 0.0; + } + } + + + + template + void + ShearHeatingAnisotropicViscosity:: + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &material_model_outputs) const + { + const unsigned int n_points = material_model_outputs.viscosities.size(); + + if (material_model_outputs.template get_additional_output>() == nullptr) + { + material_model_outputs.additional_outputs.push_back( + std::make_unique> (n_points)); + } + + this->get_material_model().create_additional_named_outputs(material_model_outputs); + } + } + + namespace MaterialModel + { + // The AV material model calculates an anisotropic viscosity tensor from director vectors and the normal and shear + // viscosities (defined in the .prm file). In contrast to the `Anisotropic` material model, the principal directions of the + // tensor are not read from an input file, but instead are computed at every quadrature point. This material model is used in T independent models. + // All the parameters are defined below. + template + class AV : public MaterialModel::Simple + { + public: + void initialize() override; + + void evaluate (const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + static void declare_parameters (ParameterHandler &prm); + + void parse_parameters (ParameterHandler &prm) override; + + bool is_compressible () const override; + + double reference_density () const; + + void create_additional_named_outputs(MaterialModel::MaterialModelOutputs &out) const override; + + private: + double eta_N, viscosity_ratio; //normal viscosity and ratio between the shear and the normal viscosities + static int delta (const unsigned int i, const unsigned int j); //kronecker delta function + void set_assemblers(const SimulatorAccess &, + Assemblers::Manager &assemblers) const; + }; + } +} + +namespace aspect +{ + +//Next session is a more evolved implementation of anisotropic viscosity in the material model based on Jonathan Perry-Houts'paper + namespace MaterialModel + { + template + void + AV::set_assemblers(const SimulatorAccess &, + Assemblers::Manager &assemblers) const + { + for (unsigned int i=0; i>(*(assemblers.stokes_preconditioner[i]))) + assemblers.stokes_preconditioner[i] = std::make_unique> (); + } + + for (unsigned int i=0; i>(*(assemblers.stokes_system[i]))) + assemblers.stokes_system[i] = std::make_unique> (); + } + } + + + + template + void + AV:: + initialize() + { + this->get_signals().set_assemblers.connect (std::bind(&AV::set_assemblers, + std::cref(*this), + std::placeholders::_1, + std::placeholders::_2)); + AssertThrow((dim==2), + ExcMessage("For now the anisotropic viscosity assemblers work only in 2D")); + + } + + + + template + void + AV::evaluate (const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + MaterialModel::AnisotropicViscosity *anisotropic_viscosity = + out.template get_additional_output>(); + + AssertThrow((this->introspection().compositional_name_exists("gamma")), + ExcMessage("AV material model only works if there is a compositional field called gamma.")); + AssertThrow(this->introspection().compositional_name_exists("ni"), + ExcMessage("AV material model only works if there is a compositional field called ni.")); + AssertThrow(this->introspection().compositional_name_exists("nj"), + ExcMessage("AV material model only works if there is a compositional field called nj.")); + if (dim == 3) + AssertThrow(this->introspection().compositional_name_exists("nk"), + ExcMessage("AV material model only works if there is a compositional field called nk.")); + + const unsigned int c_idx_gamma = this->introspection().compositional_index_for_name("gamma"); + + std::vector c_idx_n; + c_idx_n.push_back (this->introspection().compositional_index_for_name("ni")); + c_idx_n.push_back (this->introspection().compositional_index_for_name("nj")); + if (dim == 3) + c_idx_n.push_back (this->introspection().compositional_index_for_name("nk")); + + // Get the grad_u tensor, at the center of this cell, if possible. + + std::vector> velocity_gradients (in.n_evaluation_points()); + if (in.current_cell.state() == IteratorState::valid) + { + std::vector> quadrature_positions(in.n_evaluation_points()); + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + quadrature_positions[i] = this->get_mapping().transform_real_to_unit_cell(in.current_cell, in.position[i]); + + // FEValues requires a quadrature and we provide the default quadrature + // as we only need to evaluate the gradients of the solution. + FEValues fe_values (this->get_mapping(), + this->get_fe(), + Quadrature(quadrature_positions), + update_gradients); + fe_values.reinit (in.current_cell); + fe_values[this->introspection().extractors.velocities] + .get_function_gradients(this->get_solution(), velocity_gradients); + } + + for (unsigned int q=0; q 0.8 ? 1 : 0); + out.viscosities[q] = eta_N; + out.thermal_expansion_coefficients[q] = 0; + out.specific_heat[q] = 0; + out.thermal_conductivities[q] = 0; + out.compressibilities[q] = 0.0; + out.entropy_derivative_pressure[q] = 0.0; + out.entropy_derivative_temperature[q] = 0.0; + for (unsigned int c=0; c n; + for (unsigned int i=0; isimulator_is_past_initialization()) + { + Tensor<1,dim> n_dot; + if (n.norm() > 0.5 && in.composition[q][c_idx_gamma] > 0.8) + { + // Symmetric and anti-symmetric parts of grad_u + const SymmetricTensor<2,dim> D = symmetrize(velocity_gradients[q]); + Tensor<2,dim> W; + for (unsigned int i=0; iget_timestep() == 0) + { + n_dot = (n/n.norm())-n; + } + else + { + Tensor<1,dim> n_new = n + (n_dot * this->get_timestep()); + Assert (n_new.norm() != 0, ExcInternalError()); + n_new /= n_new.norm(); + n_dot = (n_new-n)/ this->get_timestep(); + } + } + else + { + n_dot = 0; + } + // update n[i] = in.composition[q][c_idx_n[i]] with adding to it n_dot*dt + for (unsigned int i=0; iget_timestep() == 0) + out.reaction_terms[q][c_idx_n[i]] = n_dot[i]; + else + out.reaction_terms[q][c_idx_n[i]] = n_dot[i] * this->get_timestep(); + + if (n.norm() > 0.5) + { + n /= n.norm(); + SymmetricTensor<4,dim> Lambda; + for (unsigned int i=0; istress_strain_directors[q] =dealii::identity_tensor () + - (1. - viscosity_ratio) * Lambda; + SymmetricTensor<2,3> ViscoTensor; + ViscoTensor[0][0]=anisotropic_viscosity->stress_strain_directors[q][0][0][0][0]; + ViscoTensor[0][1]=anisotropic_viscosity->stress_strain_directors[q][0][0][1][1]; + ViscoTensor[0][2]=anisotropic_viscosity->stress_strain_directors[q][0][0][0][1] * std::sqrt(2); + ViscoTensor[1][0]=anisotropic_viscosity->stress_strain_directors[q][1][1][0][0]; + ViscoTensor[1][1]=anisotropic_viscosity->stress_strain_directors[q][1][1][1][1]; + ViscoTensor[1][2]=anisotropic_viscosity->stress_strain_directors[q][1][1][0][1] * std::sqrt(2); + ViscoTensor[2][0]=anisotropic_viscosity->stress_strain_directors[q][0][1][0][0] * std::sqrt(2); + ViscoTensor[2][1]=anisotropic_viscosity->stress_strain_directors[q][0][1][1][1] * std::sqrt(2); + ViscoTensor[2][2]=anisotropic_viscosity->stress_strain_directors[q][0][1][0][1] * 2; + + const std::array Viscoeigenvalues = eigenvalues(ViscoTensor); + for (unsigned int i=0; i<3; ++i) + { + AssertThrow((Viscoeigenvalues[i]>0), + ExcMessage("Eigenvalue "+ std::to_string(i) + " of the viscosity tensor is negative at " + + std::to_string(Viscoeigenvalues[i]) + ". This is not allowed.")); + } + } + } + } + } + } + + + + template + int + AV::delta (const unsigned int i, + const unsigned int j) + { + return (i == j ? 1 : 0); + } + + + + template + bool + AV::is_compressible () const + { + return false; + } + + + + template + double + AV::reference_density () const + { + return 1.0; + } + + + + template + void + AV::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("AV"); + { + eta_N = prm.get_double("Normal viscosity"); + viscosity_ratio = prm.get_double("Shear viscosity")/eta_N; + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + AV::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("AV"); + { + prm.declare_entry ("Normal viscosity", "1e-3", + Patterns::Double(), + "Magnitude of normal viscosity."); + prm.declare_entry ("Shear viscosity", "1e-4", + Patterns::Double(), + "Magnitude of shear viscosity."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + AV::create_additional_named_outputs(MaterialModel::MaterialModelOutputs &out) const + { + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + } + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace Assemblers + { +#define INSTANTIATE(dim) \ + template class StokesPreconditioner; \ + template class StokesIncompressibleTerms; \ + template class StokesBoundaryTraction; + + ASPECT_INSTANTIATE(INSTANTIATE) + } + + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(ShearHeatingAnisotropicViscosity, + "anisotropic shear heating", + "Implementation of a standard model for shear heating. " + "Adds the term: " + "$ 2 \\eta \\left( \\varepsilon - \\frac{1}{3} \\text{tr} " + "\\varepsilon \\mathbf 1 \\right) : \\left( \\varepsilon - \\frac{1}{3} " + "\\text{tr} \\varepsilon \\mathbf 1 \\right)$ to the " + "right-hand side of the temperature equation.") + } + + + + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(AV, + "AV material", + "Transverse isotropic material model.") + } +} diff --git a/cookbooks/bunge_et_al_mantle_convection/bunge_et_al.prm.bak b/cookbooks/bunge_et_al_mantle_convection/bunge_et_al.prm.bak new file mode 100644 index 00000000000..e4a7249a52b --- /dev/null +++ b/cookbooks/bunge_et_al_mantle_convection/bunge_et_al.prm.bak @@ -0,0 +1,104 @@ +# Setup for convection in a 2d shell. +# Parameters from Bunge et al, Nature, 1996. + +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 5e9 +set Output directory = output_bunge_et_al +set CFL number = 1 + +subsection Material model + set Model name = depth dependent + + subsection Depth dependent model + set Base model = simple + set Depth dependence method = File + set Data directory = $ASPECT_SOURCE_DIR/cookbooks/bunge_et_al_mantle_convection/ + set Viscosity depth file = visc_depth_a.txt + set Reference viscosity = 1e22 + end + + subsection Simple model + set Reference density = 4500 + set Thermal expansion coefficient = 2.5e-5 + set Viscosity = 1e22 + set Reference specific heat = 1000 + set Thermal conductivity = 4 + end +end + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3480000 + set Outer radius = 6370000 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = inner + set Tangential velocity boundary indicators = top +end + +subsection Heating model + set List of model names = constant heating + + subsection Constant heating + set Radiogenic heating rate = 1e-12 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 3450 + set Outer temperature = 1060 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Coordinate system = spherical + set Variable names = r,phi + set Function constants = A=100, B=75, C=50, D=25, pi=3.1415926536, Ri=3480e3, Ro=6370e3, Ti=3450, To=1060 + set Function expression = (r-Ri)/(Ro-Ri)*(To-Ti)+Ti + A*sin(7*phi) + B*sin(13*phi) + C*cos(0.123*phi+pi/3) + D*cos(0.456*phi+pi/6) + end +end + +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 10 + end + + #set Model name = ascii data +end + +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 0 + set Strategy = temperature + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics, depth average + + subsection Visualization + set List of output variables = viscosity, strain rate, density, specific heat, thermal expansivity, gravity, heating + set Output format = vtu + set Time between graphical output = 1e6 + set Number of grouped files = 0 + end + + subsection Depth average + set Time between graphical output = 1e7 + set Number of zones = 100 + end +end diff --git a/cookbooks/burnman/burnman.prm.bak b/cookbooks/burnman/burnman.prm.bak new file mode 100644 index 00000000000..c67bf3be8e9 --- /dev/null +++ b/cookbooks/burnman/burnman.prm.bak @@ -0,0 +1,143 @@ +# A cookbook for using adiabatic conditions and a gravity +# profile generated by a mineral physics toolkit and read in +# through an ascii data file. In this example, material properties +# are based on a Birch-Murnaghan equation of state. + +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 2.63e8 +set Output directory = output-burnman + +subsection Material model + set Model name = ascii reference profile + set Material averaging = harmonic average + + subsection Ascii reference profile + set Thermal viscosity exponent = 10.0 + set Viscosity prefactors = 1.0, 0.1, 1.0, 10.0 + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/data/adiabatic-conditions/ascii-data/ + set Data file name = example_isentrope.txt + end + end +end + +# The geometry is a spherical shell with the inner and +# outer radius of the Earth's mantle. +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Outer radius = 6336000 + end +end + +subsection Adiabatic conditions model + set Model name = ascii data + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/data/adiabatic-conditions/ascii-data/ + set Data file name = example_isentrope.txt + end +end + +# The gravity model reads an ascii data file that contains a gravity +# profile consistent with the material properties computed using the +# Birch-Murnaghan equation of state. It automatically uses the same file +# specified in the adiabatic conditions model. +subsection Gravity model + set Model name = ascii data + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/data/adiabatic-conditions/ascii-data/ + set Data file name = example_isentrope.txt + end +end + +# The model uses the anelastic liquid approximation. +subsection Formulation + set Formulation = anelastic liquid approximation +end + +# The present-day plate velocities are imposed on the upper model +# boundary. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = top:gplates + set Tangential velocity boundary indicators = bottom + + subsection GPlates model + set Data directory = $ASPECT_SOURCE_DIR/data/boundary-velocity/gplates/ + set Velocity file name = current_day.gpml + set Data file time step = 1e6 + set Point one = 1.5708,4.87 + set Point two = 1.5708,5.24 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 3500 + set Outer temperature = 273 + end +end + +# The initial temperature is an adiabatic profile, which is +# taken from the adabatic conditions model. In this case, this is +# is the ascii data model that loads a file containing profiles +# corresponding to the Birch-Murnaghan equation of state. +# In addition to the adiabatic profile, there are thermal boundary +# layers at the sirface and the core-mantle boundary. +subsection Initial temperature model + set Model name = adiabatic + + subsection Adiabatic + set Age top boundary layer = 5e7 + end +end + +subsection Mesh refinement + set Refinement fraction = 0.4 + set Coarsening fraction = 0.05 + set Initial adaptive refinement = 1 + set Initial global refinement = 5 + set Strategy = temperature + set Time steps between mesh refinement = 5 +end + +subsection Heating model + set List of model names = adiabatic heating, shear heating + + subsection Adiabatic heating + set Use simplified adiabatic heating = true + end +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics, depth average + + subsection Visualization + set Output format = vtu + set Time between graphical output = 0 + set Number of grouped files = 0 + set List of output variables = material properties, gravity, adiabat, nonadiabatic temperature, nonadiabatic pressure + end + + subsection Depth average + set Time between graphical output = 1e6 + end +end + +subsection Checkpointing + set Time between checkpoint = 1800 +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-6 + end +end diff --git a/cookbooks/burnman/doc/adiabatic_conditions.part.prm.bak b/cookbooks/burnman/doc/adiabatic_conditions.part.prm.bak new file mode 100644 index 00000000000..4cadabb890d --- /dev/null +++ b/cookbooks/burnman/doc/adiabatic_conditions.part.prm.bak @@ -0,0 +1,8 @@ +subsection Adiabatic conditions model + set Model name = ascii data + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/data/adiabatic-conditions/ascii-data/ + set Data file name = isentrope_properties.txt + end +end diff --git a/cookbooks/burnman/doc/formulation.part.prm.bak b/cookbooks/burnman/doc/formulation.part.prm.bak new file mode 100644 index 00000000000..ed9e31a69cd --- /dev/null +++ b/cookbooks/burnman/doc/formulation.part.prm.bak @@ -0,0 +1,3 @@ +subsection Formulation + set Formulation = anelastic liquid approximation +end diff --git a/cookbooks/burnman/doc/formulation_ica.part.prm.bak b/cookbooks/burnman/doc/formulation_ica.part.prm.bak new file mode 100644 index 00000000000..fb0585cd286 --- /dev/null +++ b/cookbooks/burnman/doc/formulation_ica.part.prm.bak @@ -0,0 +1,3 @@ +subsection Formulation + set Formulation = isentropic compression +end diff --git a/cookbooks/burnman/doc/gravity_model.part.prm.bak b/cookbooks/burnman/doc/gravity_model.part.prm.bak new file mode 100644 index 00000000000..ac7bc06486c --- /dev/null +++ b/cookbooks/burnman/doc/gravity_model.part.prm.bak @@ -0,0 +1,3 @@ +subsection Gravity model + set Model name = ascii data +end diff --git a/cookbooks/burnman/doc/material_model.part.prm.bak b/cookbooks/burnman/doc/material_model.part.prm.bak new file mode 100644 index 00000000000..e741a44f895 --- /dev/null +++ b/cookbooks/burnman/doc/material_model.part.prm.bak @@ -0,0 +1,14 @@ +subsection Material model + set Model name = ascii reference profile + set Material averaging = harmonic average + + subsection Ascii data model + set Data file name = isentrope_properties.txt + set Data directory = $ASPECT_SOURCE_DIR/data/adiabatic-conditions/ascii-data/ + end + + subsection Ascii reference profile + set Thermal viscosity exponent = 10.0 + set Viscosity prefactors = 1.0, 0.1, 1.0, 10.0 + end +end diff --git a/cookbooks/burnman/doc/tala.part.prm.bak b/cookbooks/burnman/doc/tala.part.prm.bak new file mode 100644 index 00000000000..6b71b0fb510 --- /dev/null +++ b/cookbooks/burnman/doc/tala.part.prm.bak @@ -0,0 +1,5 @@ +subsection Material model + subsection Ascii reference profile + set Use TALA = true + end +end diff --git a/cookbooks/christensen_yuen_phase_function/christensen_yuen_phase_function.prm.bak b/cookbooks/christensen_yuen_phase_function/christensen_yuen_phase_function.prm.bak new file mode 100644 index 00000000000..cd508be93fd --- /dev/null +++ b/cookbooks/christensen_yuen_phase_function/christensen_yuen_phase_function.prm.bak @@ -0,0 +1,172 @@ +# This is a setup for convection in a 2D box with a phase transition +# in the center, and corresponds to the setup of the Boussinesq cases +# in Christensen & Yuen 1985. + +set Dimension = 2 +set End time = 2e8 +set Output directory = christensen_yuen + +# We use a nonlinear solver to make sure any nonlinearity that may be +# associated with the phase transition is resolved, and we use a large +# value for the Maximum nonlinear iterations to make it obvious if the +# nonlinear solver does not converge. Usually, the nonlinear solver +# should converge within 1-5 iterations. +set Nonlinear solver scheme = iterated Advection and Stokes +set Max nonlinear iterations = 500 +set Maximum time step = 1e5 +set Adiabatic surface temperature = 500 + +subsection Solver parameters + subsection Stokes solver parameters + set Stokes solver type = block GMG + end +end + +# This model assumes the Boussinesq approximation, so it is +# incompressible and has a constant reference density. +subsection Formulation + set Formulation = Boussinesq approximation +end + +# For the Boussinesq approximation, all heating terms are switched off. +subsection Heating model + set List of model names = +end + +# The model domain is a quadratic box. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1350000 + set Y extent = 1350000 + end +end + +# Set the reference profile. +# The temperature on the reference profile is 500 K, halfway between the +# top temperature of 0 K and the bottom temperature of 1000 K. +subsection Adiabatic conditions model + set Model name = function + + subsection Function + set Function constants = density=1000 + set Function expression = 500; density*10*depth; density + set Variable names = depth + end +end + +# This temperature initial condition resembles the one on Christensen & Yuen, 1985. +# It has conductive boundary layers at the top and bottom, and sinusoidal +# temperature perturbations. +subsection Initial temperature model + set Model name = function + + subsection Function + set Function constants = delta=0.1, A=10, h=1350000, pi=3.1416 + set Variable names = x,z + set Function expression = 500 + 500*(erfc(z/(h*delta)) - erfc((1-z/h)/delta)) + A*cos(pi*x/h)*sin(pi*z/h) + A*cos(2*pi*x/h)*sin(pi*z/h) + A*cos(pi*x/h)*sin(2*pi*z/h) + A*cos(2*pi*x/h)*sin(2*pi*z/h) + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = box + + subsection Box + set Top temperature = 0 + set Bottom temperature = 1000 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = top, bottom, left, right +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +# This material model uses phase functions. +# The model in Christensen & Yuen is nondimensional, but we want to keep +# Earth-like parameters. To achieve this, we set all material +# properties to multiples of 10, and then control the three important +# model parameters by setting: +# +# k = 2.460375e7 / Ra, to control the Rayleigh number, +# deltarho = 2 alpha rho DeltaT = 200 kg/m3, to achieve Rb = 2Ra, as in Christensen & Yuen, +# gamma = P * Ra/Rb * rho g h / DeltaT = P/2 * 1.35e7 Pa/K, to set the phase buoyancy parameter. +# +# (for a more detailed explanation, see the corresponding cookbook description in the manual). + +subsection Material model + set Model name = latent heat + set Material averaging = harmonic average only viscosity + + subsection Latent heat + # All parameters in the equation of state are constant, and the mode is incompressible. + set Reference temperature = 500 + set Reference density = 1000 + set Reference specific heat = 1000 + set Thermal expansion coefficient = 1e-4 + set Compressibility = 0 + set Thermal conductivity = 246.03750 # k = 2.460375e7/Ra, corresponds to Ra = 1e5 + + # There is one phase transition in the center of the box (at a depth of 675 km), + # with a width of 67.5 km (5% of the box height). + # It occurs at that depth if the temperature corresponds to the reference temperature (500 K); + # for different temperatures the depth changes according to the Clapeyron slope (-2.7 MPa/K). + # At the phase transition, the density increases from its reference value of 1000 kg/m^3 to + # 1200 kg/m^3. + set Define transition by depth instead of pressure = true + set Phase transition depths = 675000 + set Phase transition widths = 67500 + set Phase transition temperatures = 500 + set Phase transition Clapeyron slopes = -2700000 # gamma = P * Ra/Rb, corresponds to P = -0.4 + set Phase transition density jumps = 200 # deltarho = 2 alpha rho DeltaT (Rb = 2Ra) + set Corresponding phase for density jump = 0 + + # The viscosity is constant + set Viscosity = 1e20 + set Minimum viscosity = 1e20 + set Maximum viscosity = 1e20 + set Viscosity prefactors = 1,1 + set Thermal viscosity exponent = 0.0 + end +end + +subsection Mesh refinement + set Initial global refinement = 6 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +# Stop the model run when a steady state heat flux is reached. +# Some of the models do not reach steady state and will continue +# until the end time is reached. +subsection Termination criteria + set Termination criteria = end time, steady state heat flux + + subsection Steady state heat flux + set Maximum relative deviation = 0.005 + set Time in steady state = 1e7 + set Boundary indicators = top + end +end + +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, heating statistics, visualization + + subsection Visualization + set Time between graphical output = 1e5 + set List of output variables = material properties, adiabat, strain rate + + subsection Material properties + set List of material properties = viscosity, density + end + end +end diff --git a/cookbooks/christensen_yuen_phase_function/doc/material.part.prm.bak b/cookbooks/christensen_yuen_phase_function/doc/material.part.prm.bak new file mode 100644 index 00000000000..4c442a8a694 --- /dev/null +++ b/cookbooks/christensen_yuen_phase_function/doc/material.part.prm.bak @@ -0,0 +1,35 @@ +subsection Material model + set Model name = latent heat + set Material averaging = harmonic average only viscosity + + subsection Latent heat + # All parameters in the equation of state are constant, and the mode is incompressible. + set Reference temperature = 500 + set Reference density = 1000 + set Reference specific heat = 1000 + set Thermal expansion coefficient = 1e-4 + set Compressibility = 0 + set Thermal conductivity = 246.03750 # k = 2.460375e7/Ra, corresponds to Ra = 1e5 + + # There is one phase transition in the center of the box (at a depth of 675 km), + # with a width of 67.5 km (5% of the box height). + # It occurs at that depth if the temperature corresponds to the reference temperature (500 K); + # for different temperatures the depth changes according to the Clapeyron slope (-2.7 MPa/K). + # At the phase transition, the density increases from its reference value of 1000 kg/m^3 to + # 1200 kg/m^3. + set Define transition by depth instead of pressure = true + set Phase transition depths = 675000 + set Phase transition widths = 67500 + set Phase transition temperatures = 500 + set Phase transition Clapeyron slopes = -2700000 # gamma = P * Ra/Rb, corresponds to P = -0.4 + set Phase transition density jumps = 200 # deltarho = 2 alpha rho DeltaT (Rb = 2Ra) + set Corresponding phase for density jump = 0 + + # The viscosity is constant + set Viscosity = 1e20 + set Minimum viscosity = 1e20 + set Maximum viscosity = 1e20 + set Viscosity prefactors = 1,1 + set Thermal viscosity exponent = 0.0 + end +end diff --git a/cookbooks/composition-reaction/composition-reaction.prm.bak b/cookbooks/composition-reaction/composition-reaction.prm.bak new file mode 100644 index 00000000000..fe59917c746 --- /dev/null +++ b/cookbooks/composition-reaction/composition-reaction.prm.bak @@ -0,0 +1,113 @@ +# A description of convection in a rectangular box where we prescribe +# temporally variable boundary conditions for the velocity along the top +# boundary. See the manual for more information. + + +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 20 +set Use years in output instead of seconds = false +set Output directory = output-composition-reaction + +############### Parameters describing the model +# Let us here choose again a box domain of size 2x1 +# where we fix the temperature at the bottom and top, +# allow free slip along the bottom, left and right, +# and prescribe the velocity along the top using the +# `function' description. + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 1 + end +end + +subsection Compositional fields + set Number of fields = 2 +end + +# We then set the temperature to one at the bottom and zero +# at the top: +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Top temperature = 0 + end +end + +# The velocity along the top boundary models a spreading +# center that is moving left and right: +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom + set Prescribed velocity boundary indicators = top: function + + subsection Function + set Variable names = x,z,t + set Function constants = pi=3.1415926 + set Function expression = if(x>1+sin(0.5*pi*t), 1, -1); 0 + end +end + +# We then choose a vertical gravity model and describe the +# initial temperature with a vertical gradient. The default +# strength for gravity is one. The material model is the +# same as before. +subsection Gravity model + set Model name = vertical +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = (1-z) + end +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = if(z<0.5,1,0);0 + end +end + +subsection Material model + set Model name = composition reaction + + subsection Composition reaction model + set Thermal conductivity = 1e-6 + set Thermal expansion coefficient = 1e-4 + set Viscosity = 1 + set Density differential for compositional field 1 = -5 + set Density differential for compositional field 2 = 5 + set Reaction depth = 0.2 + end +end + +# The final part of this input file describes how many times the +# mesh is refined and what to do with the solution once computed +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, temperature statistics, heat flux statistics + + subsection Visualization + set Time between graphical output = 0.1 + set List of output variables = density + end +end diff --git a/cookbooks/composition-reaction/doc/initial.part.prm.bak b/cookbooks/composition-reaction/doc/initial.part.prm.bak new file mode 100644 index 00000000000..39d359f8f51 --- /dev/null +++ b/cookbooks/composition-reaction/doc/initial.part.prm.bak @@ -0,0 +1,8 @@ +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = if(z<0.5, 1, 0); 0 + end +end diff --git a/cookbooks/composition-reaction/doc/material.part.prm.bak b/cookbooks/composition-reaction/doc/material.part.prm.bak new file mode 100644 index 00000000000..8f48516b3ae --- /dev/null +++ b/cookbooks/composition-reaction/doc/material.part.prm.bak @@ -0,0 +1,12 @@ +subsection Material model + set Model name = composition reaction + + subsection Composition reaction model + set Thermal conductivity = 1e-6 + set Thermal expansion coefficient = 0.01 + set Viscosity = 1 + set Density differential for compositional field 1 = -5 + set Density differential for compositional field 2 = 5 + set Reaction depth = 0.2 + end +end diff --git a/cookbooks/composition_active/composition_active.prm.bak b/cookbooks/composition_active/composition_active.prm.bak new file mode 100644 index 00000000000..96c752b0a3d --- /dev/null +++ b/cookbooks/composition_active/composition_active.prm.bak @@ -0,0 +1,106 @@ +######################################################### +# This is a variation of the composition-passive.prm file. +# Here, we choose a higher Rayleigh number and make the +# density depend on the compositional variable as well. +# +# See the manual for more information about this setup. + + +set Dimension = 2 +set Start time = 0 +set End time = 20 +set Use years in output instead of seconds = false +set Output directory = output-composition-active + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 1 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Top temperature = 0 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom + set Prescribed velocity boundary indicators = top: function + + subsection Function + set Variable names = x,z,t + set Function constants = pi=3.1415926 + set Function expression = if(x>1+sin(0.5*pi*t), 1, -1); 0 + end +end + +subsection Gravity model + set Model name = vertical +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = (1-z) + end +end + +# Compared to the passive material model, we here make +# the density composition dependent by letting it depend +# linearly on the value of the first compositional field. +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal conductivity = 1e-6 + set Thermal expansion coefficient = 0.01 + set Viscosity = 1 + set Reference density = 1 + set Reference temperature = 0 + set Density differential for compositional field 1 = 100 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, temperature statistics, composition statistics + + subsection Visualization + set List of output variables = density + set Time between graphical output = 0.1 + end +end + +# This is the new part: We declare that there will +# be two compositional fields that will be +# advected along. Their initial conditions are given by +# a function that is one for the lowermost 0.2 height +# units of the domain and zero otherwise in the first case, +# and one in the top most 0.2 height units in the latter. +subsection Compositional fields + set Number of fields = 2 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if(y<0.2, 1, 0) ; if(y>0.8, 1, 0) + end +end diff --git a/cookbooks/composition_active/doc/active.part.prm.bak b/cookbooks/composition_active/doc/active.part.prm.bak new file mode 100644 index 00000000000..0a354dd39b6 --- /dev/null +++ b/cookbooks/composition_active/doc/active.part.prm.bak @@ -0,0 +1,12 @@ +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal conductivity = 1e-6 + set Thermal expansion coefficient = 0.01 + set Viscosity = 1 + set Reference density = 1 + set Reference temperature = 0 + set Density differential for compositional field 1 = 0.1 + end +end diff --git a/cookbooks/composition_active/doc/postprocess.part.prm.bak b/cookbooks/composition_active/doc/postprocess.part.prm.bak new file mode 100644 index 00000000000..94337847f3c --- /dev/null +++ b/cookbooks/composition_active/doc/postprocess.part.prm.bak @@ -0,0 +1,8 @@ +subsection Postprocess + set List of postprocessors = visualization, temperature statistics, composition statistics + + subsection Visualization + set List of output variables = density + set Time between graphical output = 0.1 + end +end diff --git a/cookbooks/composition_active_particles/composition_active_particles.prm.bak b/cookbooks/composition_active_particles/composition_active_particles.prm.bak new file mode 100644 index 00000000000..dc6b3fa1111 --- /dev/null +++ b/cookbooks/composition_active_particles/composition_active_particles.prm.bak @@ -0,0 +1,127 @@ +######################################################### +# This is a variation of the composition-active.prm file. +# Here, we track compositional fields and their associated +# density differences with a particle, rather than field, +# based methods. +# +# See the manual for more information about this setup. + + +set Dimension = 2 +set Start time = 0 +set End time = 20 +set Use years in output instead of seconds = false +set Output directory = output-composition-active-particles + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 1 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Top temperature = 0 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom + set Prescribed velocity boundary indicators = top: function + + subsection Function + set Variable names = x,z,t + set Function constants = pi=3.1415926 + set Function expression = if(x>1+sin(0.5*pi*t), 1, -1); 0 + end +end + +subsection Gravity model + set Model name = vertical +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = (1-z) + end +end + +# Compared to the passive material model, we here make +# the density composition dependent by letting it depend +# linearly on the value of the first compositional field. +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal conductivity = 1e-6 + set Thermal expansion coefficient = 0.01 + set Viscosity = 1 + set Reference density = 1 + set Reference temperature = 0 + set Density differential for compositional field 1 = 100 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, temperature statistics, composition statistics,particles + + subsection Visualization + set List of output variables = density + set Time between graphical output = 0.1 + end + + subsection Particles + set Time between data output = 0 + set Data output format = vtu + end +end + +# Here, we track compositional fields via active particle particles. +# The initial composition assigned to the particles is 'mapped' +# to the particles at each time step. This property is accessed in +# the material model through a compositional field (standard method) +# whose values are interpolated from the particles. +subsection Compositional fields + set Number of fields = 2 + set Names of fields = lower, upper + set Compositional field methods = particles, particles + set Mapped particle properties = lower:initial lower, upper:initial upper +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if(y<0.2, 1, 0) ; if(y>0.8, 1, 0) + end +end + +subsection Particles + set List of particle properties = velocity, initial composition + set Interpolation scheme = cell average + set Update ghost particles = true + set Particle generator name = random uniform + + subsection Generator + subsection Probability density function + set Number of particles = 100000 + end + end +end diff --git a/cookbooks/composition_active_particles/doc/composition.part.prm.bak b/cookbooks/composition_active_particles/doc/composition.part.prm.bak new file mode 100644 index 00000000000..9248b34bd3c --- /dev/null +++ b/cookbooks/composition_active_particles/doc/composition.part.prm.bak @@ -0,0 +1,6 @@ +subsection Compositional fields + set Number of fields = 2 + set Names of fields = lower, upper + set Compositional field methods = particles, particles + set Mapped particle properties = lower:initial lower, upper:initial upper +end diff --git a/cookbooks/composition_active_particles/doc/particles.part.prm.bak b/cookbooks/composition_active_particles/doc/particles.part.prm.bak new file mode 100644 index 00000000000..d43080c8b9e --- /dev/null +++ b/cookbooks/composition_active_particles/doc/particles.part.prm.bak @@ -0,0 +1,18 @@ +subsection Postprocess + subsection Particles + set Time between data output = 0 + set Data output format = vtu + end +end + +subsection Particles + set List of particle properties = velocity, initial composition + set Interpolation scheme = cell average + set Particle generator name = random uniform + + subsection Generator + subsection Probability density function + set Number of particles = 100000 + end + end +end diff --git a/cookbooks/composition_passive/composition_passive.prm.bak b/cookbooks/composition_passive/composition_passive.prm.bak new file mode 100644 index 00000000000..1d2cb078e8f --- /dev/null +++ b/cookbooks/composition_passive/composition_passive.prm.bak @@ -0,0 +1,99 @@ +######################################################### +# This is a variation of the platelike-boundary.prm file. +# All settings are exactly the same with the exception +# of the ones that pertain to compositional fields. +# +# See the manual for more information about this setup. + + +set Dimension = 2 +set Start time = 0 +set End time = 20 +set Use years in output instead of seconds = false +set Output directory = output-composition-passive + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 1 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Top temperature = 0 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom + set Prescribed velocity boundary indicators = top: function + + subsection Function + set Variable names = x,z,t + set Function constants = pi=3.1415926 + set Function expression = if(x>1+sin(0.5*pi*t), 1, -1); 0 + end +end + +subsection Gravity model + set Model name = vertical +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = (1-z) + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal conductivity = 1e-6 + set Thermal expansion coefficient = 1e-4 + set Viscosity = 1 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, temperature statistics, composition statistics + + subsection Visualization + set Time between graphical output = 0.1 + end +end + +# This is the new part: We declare that there will +# be two compositional fields that will be +# advected along. Their initial conditions are given by +# a function that is one for the lowermost 0.2 height +# units of the domain and zero otherwise in the first case, +# and one in the top most 0.2 height units in the latter. +subsection Compositional fields + set Number of fields = 2 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if(y<0.2, 1, 0) ; if(y>0.8, 1, 0) + end +end diff --git a/cookbooks/composition_passive/doc/passive.part.prm.bak b/cookbooks/composition_passive/doc/passive.part.prm.bak new file mode 100644 index 00000000000..cddd8c7c649 --- /dev/null +++ b/cookbooks/composition_passive/doc/passive.part.prm.bak @@ -0,0 +1,18 @@ +# This is the new part: We declare that there will +# be two compositional fields that will be +# advected along. Their initial conditions are given by +# a function that is one for the lowermost 0.2 height +# units of the domain and zero otherwise in the first case, +# and one in the top most 0.2 height units in the latter. +subsection Compositional fields + set Number of fields = 2 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if(y<0.2, 1, 0) ; if(y>0.8, 1, 0) + end +end diff --git a/cookbooks/composition_passive/doc/postprocess.part.prm.bak b/cookbooks/composition_passive/doc/postprocess.part.prm.bak new file mode 100644 index 00000000000..f9bbf737b98 --- /dev/null +++ b/cookbooks/composition_passive/doc/postprocess.part.prm.bak @@ -0,0 +1,3 @@ +subsection Postprocess + set List of postprocessors = visualization, temperature statistics, composition statistics +end diff --git a/cookbooks/composition_passive_particles/composition_passive_particles.prm.bak b/cookbooks/composition_passive_particles/composition_passive_particles.prm.bak new file mode 100644 index 00000000000..e7bcbabe929 --- /dev/null +++ b/cookbooks/composition_passive_particles/composition_passive_particles.prm.bak @@ -0,0 +1,114 @@ +######################################################### +# This is a variation of the composition-passive.prm +# parameter file, with the exception that we also +# advect along a set of particles and that we do not longer +# compute temperature statistics and composition statistics +# as part of postprocessing +# +# See the manual for more information about this setup. + + +set Dimension = 2 +set Start time = 0 +set End time = 7.2 +set Use years in output instead of seconds = false +set Output directory = output-composition-passive-particles + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 1 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Top temperature = 0 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom + set Prescribed velocity boundary indicators = top: function + + subsection Function + set Variable names = x,z,t + set Function constants = pi=3.1415926 + set Function expression = if(x>1+sin(0.5*pi*t), 1, -1); 0 + end +end + +subsection Gravity model + set Model name = vertical +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = (1-z) + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal conductivity = 1e-6 + set Thermal expansion coefficient = 1e-4 + set Viscosity = 1 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, particles + + subsection Visualization + set Time between graphical output = 0.1 + end + + subsection Particles + set Time between data output = 0.1 + set Data output format = vtu + end +end + +# This is the new part: We declare that there will +# be two compositional fields that will be +# advected along. Their initial conditions are given by +# a function that is one for the lowermost 0.2 height +# units of the domain and zero otherwise in the first case, +# and one in the top most 0.2 height units in the latter. +subsection Compositional fields + set Number of fields = 2 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if(y<0.2, 1, 0) ; if(y>0.8, 1, 0) + end +end + +subsection Particles + subsection Generator + subsection Probability density function + set Number of particles = 1000 + end + end +end diff --git a/cookbooks/composition_passive_particles/composition_passive_particles_properties.prm.bak b/cookbooks/composition_passive_particles/composition_passive_particles_properties.prm.bak new file mode 100644 index 00000000000..d5f29bcf12d --- /dev/null +++ b/cookbooks/composition_passive_particles/composition_passive_particles_properties.prm.bak @@ -0,0 +1,121 @@ +######################################################### +# This is a variation of the composition-passive.prm +# parameter file, with the exception that we also +# advect along a set of particles and that we do not longer +# compute temperature statistics and composition statistics +# as part of postprocessing +# +# See the manual for more information about this setup. + + +set Dimension = 2 +set Start time = 0 +set End time = 20 +set Use years in output instead of seconds = false +set Output directory = output-composition-passive-particles-properties + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 1 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Top temperature = 0 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom + set Prescribed velocity boundary indicators = top: function + + subsection Function + set Variable names = x,z,t + set Function constants = pi=3.1415926 + set Function expression = if(x>1+sin(0.5*pi*t), 1, -1); 0 + end +end + +subsection Gravity model + set Model name = vertical +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = (1-z) + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal conductivity = 1e-6 + set Thermal expansion coefficient = 1e-4 + set Viscosity = 1 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, particles + + subsection Visualization + set Time between graphical output = 0.1 + end + + subsection Particles + set Time between data output = 0.1 + set Data output format = vtu + end +end + +# This is the new part: We declare that there will +# be two compositional fields that will be +# advected along. Their initial conditions are given by +# a function that is one for the lowermost 0.2 height +# units of the domain and zero otherwise in the first case, +# and one in the top most 0.2 height units in the latter. +subsection Compositional fields + set Number of fields = 2 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if(y<0.2, 1, 0) ; if(y>0.8, 1, 0) + end +end + +subsection Particles + set List of particle properties = function, initial composition, initial position, pT path + + subsection Function + set Variable names = x,y + set Function expression = if(y<0.2, 1, 0) + end + + subsection Generator + subsection Probability density function + set Number of particles = 50000 + end + end +end diff --git a/cookbooks/composition_passive_particles/doc/particle-properties.part.prm.bak b/cookbooks/composition_passive_particles/doc/particle-properties.part.prm.bak new file mode 100644 index 00000000000..51f951526e7 --- /dev/null +++ b/cookbooks/composition_passive_particles/doc/particle-properties.part.prm.bak @@ -0,0 +1,17 @@ +subsection Postprocess +end + +subsection Particles + set List of particle properties = function, initial composition, initial position, pT path + + subsection Function + set Variable names = x,y + set Function expression = if(y<0.2, 1, 0) + end + + subsection Generator + subsection Probability density function + set Number of particles = 50000 + end + end +end diff --git a/cookbooks/composition_passive_particles/doc/particles.part.prm.bak b/cookbooks/composition_passive_particles/doc/particles.part.prm.bak new file mode 100644 index 00000000000..6036ea43824 --- /dev/null +++ b/cookbooks/composition_passive_particles/doc/particles.part.prm.bak @@ -0,0 +1,20 @@ +subsection Postprocess + set List of postprocessors = visualization, particles + + subsection Visualization + set Time between graphical output = 0.1 + end + + subsection Particles + set Time between data output = 0.1 + set Data output format = vtu + end +end + +subsection Particles + subsection Generator + subsection Probability density function + set Number of particles = 1000 + end + end +end diff --git a/cookbooks/continental_extension/continental_extension.prm.bak b/cookbooks/continental_extension/continental_extension.prm.bak new file mode 100644 index 00000000000..a0dcd80a382 --- /dev/null +++ b/cookbooks/continental_extension/continental_extension.prm.bak @@ -0,0 +1,314 @@ +#### Continental Extension Cookbook +# This cookbook is based off numerous published studies, five of which are listed below. +# For additional information, see these publications and references therein. +# 1. Brune, S., Heine, C., Perez-Gussinye, M., and Sobolev, S.V. (2014), Nat. Comm., v.5, n.4014, +# Rift migration explains continental margin asymmetry and crustal hyperextension +# 2. Huismans, R., and Beaumont, C. (2011), Nature, v.473, p.71-75. +# Depth-dependent extension, two-stage breakup and cratonic underplating at rifted margins +# 3. Naliboff, J., and Buiter, S.H. (2015), Earth Planet. Sci. Lett., v.421, p.58-67, +# "Rift Reactivation and migration during multiphase extension" +# 4. Naliboff, J., Glerum, A., Sascha, S., Peron-Pinvidic, G., and Wrona, T. (2020), Geophys. +# Res. Lett., 47, e2019GL086611, "Development of 3‐D rift heterogeneity through fault +# network evolution" +# 5. Sandiford, D., Brune, S., Glerum, A., Naliboff, J., and Whittaker, J.M. (2021), Geophys. +# Geochem. Geosys., 22, e2021GC009681, "Kinematics of footwall exhumation at oceanic +# detachment faults: Solid-block rotation and apparent unbending" + +#### Global parameters +set Dimension = 2 +set Start time = 0 +set End time = 5e6 +set Use years in output instead of seconds = true +set Nonlinear solver scheme = single Advection, iterated defect correction Stokes +set Nonlinear solver tolerance = 1e-4 +set Max nonlinear iterations = 100 +set CFL number = 0.5 +set Maximum time step = 20e3 +set Output directory = output-continental_extension +set Pressure normalization = no + +#### Parameters describing the model + +# Governing equations +subsection Formulation + set Formulation = Boussinesq approximation +end + +# Model geometry (200x100 km, 20 km spacing) +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 10 + set Y repetitions = 5 + set X extent = 200e3 + set Y extent = 100e3 + end +end + +# Globally refine the mesh to 2.5 km spacing, and then +# adaptively refine the mesh to 1.25 km spacing above y=50 km +# and between x=40 and x=160 km. These values ensure areas +# undergoing brittle deformation are in the high-resolution +# region. +subsection Mesh refinement + set Initial adaptive refinement = 1 + set Initial global refinement = 3 + set Time steps between mesh refinement = 0 + set Strategy = minimum refinement function + + subsection Minimum refinement function + set Coordinate system = cartesian + set Variable names = x,y + set Function expression = if ( y>=50e3 && x>=40.e3 && x<=160.e3, 4, 3) + end +end + +# Use the Eisenstat Walker method to automatically determine the +# linear solver tolerance during the defect Picard iterations. +# Adjusting the Maximum linear solver tolerance will affect how long +# it takes to reach a solution, but not the actual value of the +# solution. +subsection Solver parameters + subsection Stokes solver parameters + set Number of cheap Stokes solver steps = 0 + end + + subsection Newton solver parameters + set Maximum linear Stokes solver tolerance = 1e-2 + set Use Eisenstat Walker method for Picard iterations = true + end +end + +# Advecting the free surface using a normal, rather than vertical, +# projection. To reduce mesh instabilities and associated solver +# issues when deformation becomes large, diffusion is applied to +# the free surface at each time step. +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface, top: diffusion + + subsection Free surface + set Surface velocity projection = normal + end + + subsection Diffusion + # Diffusivity term. Increasing this value will result + # in a smoother free surface and lower topography + # amplitudes. + set Hillslope transport coefficient = 1.e-8 + end +end + +# Velocity on boundaries characterized by functions +# The outward velocity (x-direction) on the left and right walls is 0.25 cm/year +# The vertical velocity at the base is 0.25 cm/year (balances outflow on sides) +# Velocity components parallel to the base (x-velocity) and side walls (y-velocity) +# are unconstrained (i.e. 'free'). +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left x: function, right x:function, bottom y:function + + subsection Function + set Variable names = x,y + set Function constants = v=0.0025, w=200.e3, d=100.e3 + set Function expression = if (x < w/2 , -v, v) ; v*2*d/w + end +end + +# Number and names of compositional fields +# The five compositional fields represent: +# 1. The plastic strain that accumulates over time, with the initial plastic strain removed +# 2. The plastic strain that accumulated over time, including the initial plastic strain values +# 3. The upper crust +# 4. The lower crust +# 5. The mantle lithosphere +subsection Compositional fields + set Number of fields = 5 + set Names of fields = noninitial_plastic_strain, plastic_strain, crust_upper, crust_lower, mantle_lithosphere +end + +# Initial values of different compositional fields +# The upper crust (20 km thick), lower crust (20 km thick) +# and mantle (60 km thick) are continuous horizontal layers +# of constant thickness. The non initial plastic strain is set +# to 0 and the initial plastic strain is randomized between +# 0.5 and 1.5. +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = 0; \ + if(x>50.e3 && x<150.e3 && y>50.e3, 0.5 + rand_seed(1), 0); \ + if(y>=80.e3, 1, 0); \ + if(y<80.e3 && y>=60.e3, 1, 0); \ + if(y<60.e3, 1, 0); + end +end + +# Composition: fixed on bottom (inflow boundary), free on sides and top +subsection Boundary composition model + set Fixed composition boundary indicators = bottom + set List of model names = initial composition +end + +# Temperature boundary conditions +# Top and bottom (fixed) temperatures are consistent with the initial temperature field +# Note that while temperatures are specified for the model sides, these values are +# not used as the sides are not specified "Fixed temperature boundaries". Rather, +# these boundaries are insulating (zero net heat flux). +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1613 + set Top temperature = 273 + end +end + +# Initial temperature field +# Typical continental geotherm based on equations 4-6 from: +# D.S. Chapman (1986), "Thermal gradients in the continental crust", +# Geological Society of London Special Publications, v.24, p.63-70. +# The initial constraints are: +# Surface Temperature - upper crust (ts1) = 273 K +# Surface Heat Flow - upper crust (qs1) = 0.055 mW/m^2 +# Heat Production - upper crust (A1) = 1.00e-6 W/m^3; +# Heat Production - lower crust (A2) = 0.25e-6 W/m^3; +# Heat Production - mantle (A3) = 0.00e-6 W/m^3; +# Thermal Conductivity - all layers = 2.5 (W/(m K)); +# To satisfy these constraints, the following values are required: +# Surface Temperature - lower crust (ts2) = 633 K +# - mantle (ts3) = 893 K +# Surface Heat Flow - lower crust (qs2) = 0.035 W/m^2; +# - mantle (qs3) = 0.030 W/m^2; +# Note: The continental geotherm initial temperature model +# plugin can be used to compute an identical geotherm +# for the lithosphere. An example of how to use this +# plugin is illustrated in the test for this cookbook +# (tests/continental_extension.prm). +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = h=100e3, ts1=273, ts2=633, ts3=893, \ + A1=1.e-6, A2=0.25e-6, A3=0.0, \ + k1=2.5, k2=2.5, k3=2.5, \ + qs1=0.055, qs2=0.035, qs3=0.030 + set Function expression = if( (h-y)<=20.e3, \ + ts1 + (qs1/k1)*(h-y) - (A1*(h-y)*(h-y))/(2.0*k1), \ + if( (h-y)>20.e3 && (h-y)<=40.e3, \ + ts2 + (qs2/k2)*(h-y-20.e3) - (A2*(h-y-20.e3)*(h-y-20.e3))/(2.0*k2), \ + ts3 + (qs3/k3)*(h-y-40.e3) - (A3*(h-y-40.e3)*(h-y-40.e3))/(2.0*k3) ) ); + end +end + +# Constant internal heat production values (W/m^3) for background material +# and compositional fields. +subsection Heating model + set List of model names = compositional heating + + subsection Compositional heating + set Use compositional field for heat production averaging = 1, 0, 0, 1, 1, 1 + set Compositional heating values = 0.0, 0.0, 0.0, 1.0e-6, 0.25e-6, 0. + end +end + +# Material model +# Rheology: Non-linear viscous flow and Drucker Prager Plasticity +# Values for most rheological parameters are specified for a background material and +# each compositional field. Values for viscous deformation are based on dislocation +# creep flow-laws, with distinct values for the upper crust (wet quartzite), lower +# crust (wet anorthite) and mantle (dry olivine). Table 1 of Naliboff and Buiter (2015), +# Earth Planet. Sci. Lett., v.421, p. 58-67 contains values for each of these flow laws. +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + # Reference temperature and viscosity + set Reference temperature = 273 + + # The minimum strain-rate helps limit large viscosities values that arise + # as the strain-rate approaches zero. + # The reference strain-rate is used on the first non-linear iteration + # of the first time step when the velocity has not been determined yet. + set Minimum strain rate = 1.e-20 + set Reference strain rate = 1.e-16 + + # Limit the viscosity with minimum and maximum values + set Minimum viscosity = 1e18 + set Maximum viscosity = 1e26 + + # Thermal diffusivity is adjusted to match thermal conductivities + # assumed in assigning the initial geotherm + set Define thermal conductivities = true + set Thermal conductivities = 2.5 + set Heat capacities = 750. + + # Density values of 1 are assigned to "strain" fields, which are not taken into + # account when computing material properties. + set Densities = 3300, 1.0, 1.0, 2700, 2900, 3300 + set Thermal expansivities = 2e-5 + + # Harmonic viscosity averaging + set Viscosity averaging scheme = harmonic + + # Choose to have the viscosity (pre-yield) follow a dislocation + # diffusion or composite flow law. Here, dislocation is selected + # so no need to specify diffusion creep parameters below, which are + # only used if "diffusion" or "composite" option is selected. + set Viscous flow law = dislocation + + # Dislocation creep parameters for + # 1. Background material/mantle (dry olivine) + # Hirth & Kohlstedt (2004), Geophys. Monogr. Am. Geophys. Soc., v.138, p.83-105. + # "Rheology of the upper mantle and the mantle wedge:a view from the experimentalists" + # 2. Upper crust (wet quartzite) + # Rutter & Brodie (2004), J. Struct. Geol., v.26, p.2011-2023. + # "Experimental grain size-sensitive flow of hot-pressed Brazilian quartz aggregates" + # 3. Lower crust and weak seed (wet anorthite) + # Rybacki et al. (2006), J. Geophys. Res., v.111(B3). + # "Influence of water fugacity and activation volume on the flow properties of fine-grained + # anorthite aggregates" + # Note that the viscous pre-factors below are scaled to plane strain from unixial strain experiments. + # For ease of identification, fields tracking strain are assigned prefactors of 1e-50 + set Prefactors for dislocation creep = 6.52e-16, 1.00e-50, 1.00e-50, 8.57e-28, 7.13e-18, 6.52e-16 + set Stress exponents for dislocation creep = 3.5, 1.0, 1.0, 4.0, 3.0, 3.5 + set Activation energies for dislocation creep = 530.e3, 0.0, 0.0, 223.e3, 345.e3, 530.e3 + set Activation volumes for dislocation creep = 18.e-6, 0.0, 0.0, 0.0, 0.0, 18.e-6 + + # Plasticity parameters + set Angles of internal friction = 30 + set Cohesions = 20.e6 + + # The parameters below weaken the friction and cohesion by a + # a factor of 4 between plastic strain values of 0.5 and 1.5. + set Strain weakening mechanism = plastic weakening with plastic strain only + set Start plasticity strain weakening intervals = 0.5 + set End plasticity strain weakening intervals = 1.5 + set Cohesion strain weakening factors = 0.25 + set Friction strain weakening factors = 0.25 + end +end + +# Gravity model +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +# Post processing +subsection Postprocess + set List of postprocessors = basic statistics, composition statistics, heat flux densities, heat flux statistics, mass flux statistics, matrix statistics, pressure statistics, temperature statistics, topography, velocity statistics, visualization + + subsection Visualization + set List of output variables = density, heat flux map, named additional outputs, strain rate, viscosity + set Output format = vtu + set Time between graphical output = 100.e3 + set Interpolate output = true + end +end diff --git a/cookbooks/continental_extension/doc/continental_extension_boundary_conditions.prm.bak b/cookbooks/continental_extension/doc/continental_extension_boundary_conditions.prm.bak new file mode 100644 index 00000000000..60422171c39 --- /dev/null +++ b/cookbooks/continental_extension/doc/continental_extension_boundary_conditions.prm.bak @@ -0,0 +1,36 @@ +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left x: function, right x:function, bottom y:function + + subsection Function + set Variable names = x,y + set Function constants = v=0.0025, w=200.e3, d=100.e3 + set Function expression = if (x < w/2 , -v, v) ; v*2*d/w + end +end + +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface, top: diffusion + + subsection Free surface + set Surface velocity projection = normal + end + + subsection Diffusion + set Hillslope transport coefficient = 1.e-8 + end +end + +subsection Boundary composition model + set Fixed composition boundary indicators = bottom + set List of model names = initial composition +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1613 + set Top temperature = 273 + end +end diff --git a/cookbooks/continental_extension/doc/continental_extension_composition.prm.bak b/cookbooks/continental_extension/doc/continental_extension_composition.prm.bak new file mode 100644 index 00000000000..6a119dd1b49 --- /dev/null +++ b/cookbooks/continental_extension/doc/continental_extension_composition.prm.bak @@ -0,0 +1,16 @@ +subsection Compositional fields + set Number of fields = 4 + set Names of fields = upper, lower, mantle, seed +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if(y>=80.e3, 1, 0); \ + if(y<80.e3 && y>=70.e3, 1, 0); \ + if(y<70.e3 && y>-100.e3,1, 0); \ + if(y<68.e3 && y>60.e3 && x>=198.e3 && x<=202.e3 , 1, 0); + end +end diff --git a/cookbooks/continental_extension/doc/continental_extension_geometry_mesh.prm.bak b/cookbooks/continental_extension/doc/continental_extension_geometry_mesh.prm.bak new file mode 100644 index 00000000000..acd0ab7ee12 --- /dev/null +++ b/cookbooks/continental_extension/doc/continental_extension_geometry_mesh.prm.bak @@ -0,0 +1,23 @@ +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 10 + set Y repetitions = 5 + set X extent = 200e3 + set Y extent = 100e3 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 1 + set Initial global refinement = 3 + set Time steps between mesh refinement = 0 + set Strategy = minimum refinement function + + subsection Minimum refinement function + set Coordinate system = cartesian + set Variable names = x,y + set Function expression = if ( y>=50e3 && x>=40.e3 && x<=160.e3, 4, 3) + end +end diff --git a/cookbooks/continental_extension/doc/continental_extension_material_model.prm.bak b/cookbooks/continental_extension/doc/continental_extension_material_model.prm.bak new file mode 100644 index 00000000000..769682e2608 --- /dev/null +++ b/cookbooks/continental_extension/doc/continental_extension_material_model.prm.bak @@ -0,0 +1,6 @@ +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + end +end diff --git a/cookbooks/convection-box-particles/convection-box-particles.prm.bak b/cookbooks/convection-box-particles/convection-box-particles.prm.bak new file mode 100644 index 00000000000..b4a8978e456 --- /dev/null +++ b/cookbooks/convection-box-particles/convection-box-particles.prm.bak @@ -0,0 +1,170 @@ +# A modification of the convection box cookbook using physical units +# and particle output. See the manual for more information. + +# At the top, we define the number of space dimensions we would like to +# work in: +set Dimension = 2 + +# There are several global variables that have to do with what +# time system we want to work in and what the end time is. We +# also designate an output directory. +set Use years in output instead of seconds = true +set End time = 3e10 +set Output directory = output-tutorial + +# Then there are variables that describe how the pressure should +# be normalized. Here, we choose a zero average pressure +# at the surface of the domain (for the current geometry, the +# surface is defined as the top boundary). +set Pressure normalization = surface +set Surface pressure = 0 + +# Then come a number of sections that deal with the setup +# of the problem to solve. The first one deals with the +# geometry of the domain within which we want to solve. +# The sections that follow all have the same basic setup +# where we select the name of a particular model (here, +# the box geometry) and then, in a further subsection, +# set the parameters that are specific to this particular +# model. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 4.2e6 + set Y extent = 3e6 + end +end + +# The next section deals with the initial conditions for the +# temperature. Note that there are no initial conditions for the +# velocity variable since the velocity is assumed to always +# be in a static equilibrium with the temperature field. +# There are a number of models with the 'function' model +# a generic one that allows us to enter the actual initial +# conditions in the form of a formula that can contain +# constants. We choose a linear temperature profile that +# matches the boundary conditions defined below plus +# a small perturbation. The variables in this equation are +# described below, and it is important to note that in many +# cases the values correspond to other model parameters +# defined elsewhere. As such, if these model parameters are +# changed, the values below will also need to be adjusted. +# L - Model length/width +# D - Model depth/height +# T_top - Temperature at the top boundary +# T_bottom - Temperature at the bottom boundary +# p, k - values related to the small temperature perturbation + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = p=-0.01, L=4.2e6, D=3e6, pi=3.1415926536, k=1, T_top=273, T_bottom=3600 + set Function expression = T_top + (T_bottom-T_top)*(1-(y/D) - p*cos(k*pi*x/L)*sin(pi*y/D)) + end +end + +# Then follows a section that describes the boundary conditions +# for the temperature. The model we choose is called 'box' and +# allows to set a constant temperature on each of the four sides +# of the box geometry. In our case, we choose something that is +# heated from below and cooled from above, whereas all other +# parts of the boundary are insulated (i.e., no heat flux through +# these boundaries; this is also often used to specify symmetry +# boundaries). +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 3300 + set Top temperature = 300 + end +end + +# The next parameters then describe on which parts of the +# boundary we prescribe a zero or nonzero velocity and +# on which parts the flow is allowed to be tangential. +# Here, all four sides of the box allow tangential +# unrestricted flow but with a zero normal component: +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +# The following two sections describe first the +# direction (vertical) and magnitude of gravity and the +# material model (i.e., density, viscosity, etc). +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Viscosity = 3e24 + set Reference density = 3000 + set Thermal conductivity = 4.86 + set Thermal expansion coefficient = 2e-5 + set Reference specific heat = 1000 + set Reference temperature = 0 + end +end + +# We also have to specify that we want to use the Boussinesq +# approximation (assuming the density in the temperature +# equation to be constant, and incompressibility). +subsection Formulation + set Formulation = Boussinesq approximation +end + +# The following section deals with the discretization of +# this problem, namely the kind of mesh we want to compute +# on. We here use a globally refined mesh without +# adaptive mesh refinement. +subsection Mesh refinement + set Initial global refinement = 3 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +# The final part is to specify what ASPECT should do with the +# solution once computed at the end of every time step. The +# process of evaluating the solution is called `postprocessing' +# and we choose to compute velocity and temperature statistics, +# statistics about the heat flux through the boundaries of the +# domain, and to generate graphical output files for later +# visualization. These output files are created every time +# a time step crosses time points separated by 1e7 years. +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, visualization, particles, basic statistics + + subsection Visualization + set Time between graphical output = 1e7 + set Output format = vtu + set List of output variables = material properties + end + + subsection Particles + set Time between data output = 1e7 + set Data output format = vtu + end +end + +subsection Solver parameters + set Temperature solver tolerance = 1e-10 +end + +subsection Particles + subsection Generator + subsection Probability density function + set Number of particles = 1000 + end + end +end diff --git a/cookbooks/convection-box/convection-box.prm.bak b/cookbooks/convection-box/convection-box.prm.bak new file mode 100644 index 00000000000..dd2995dda29 --- /dev/null +++ b/cookbooks/convection-box/convection-box.prm.bak @@ -0,0 +1,160 @@ +# A description of convection in a 2d box. See the manual for more information. + + +# At the top, we define the number of space dimensions we would like to +# work in: +set Dimension = 2 + +# There are several global variables that have to do with what +# time system we want to work in and what the end time is. We +# also designate an output directory. +set Use years in output instead of seconds = false +set End time = 0.5 +set Output directory = output-convection-box + +# Then there are variables that describe how the pressure should +# be normalized. Here, we choose a zero average pressure +# at the surface of the domain (for the current geometry, the +# surface is defined as the top boundary). +set Pressure normalization = surface +set Surface pressure = 0 + +# Then come a number of sections that deal with the setup +# of the problem to solve. The first one deals with the +# geometry of the domain within which we want to solve. +# The sections that follow all have the same basic setup +# where we select the name of a particular model (here, +# the box geometry) and then, in a further subsection, +# set the parameters that are specific to this particular +# model. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +# The next section deals with the initial conditions for the +# temperature. Note that there are no initial conditions for the +# velocity variable since the velocity is assumed to always +# be in a static equilibrium with the temperature field. +# There are a number of models with the 'function' model +# a generic one that allows us to enter the actual initial +# conditions in the form of a formula that can contain +# constants. We choose a linear temperature profile that +# matches the boundary conditions defined below plus +# a small perturbation. The variables in this equation are +# described below, and it is important to note that in many +# cases the values correspond to other model parameters +# defined elsewhere. As such, if these model parameters are +# changed, the values below will also need to be adjusted. +# L - Model length/width +# p, k - values related to the small temperature perturbation + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = p=0.01, L=1, pi=3.1415926536, k=1 + set Function expression = (1.0-z) - p*cos(k*pi*x/L)*sin(pi*z) + end +end + +# Then follows a section that describes the boundary conditions +# for the temperature. The model we choose is called 'box' and +# allows to set a constant temperature on each of the four sides +# of the box geometry. In our case, we choose something that is +# heated from below and cooled from above, whereas all other +# parts of the boundary are insulated (i.e., no heat flux through +# these boundaries; this is also often used to specify symmetry +# boundaries). +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +# The next parameters then describe on which parts of the +# boundary we prescribe a zero or nonzero velocity and +# on which parts the flow is allowed to be tangential. +# Here, all four sides of the box allow tangential +# unrestricted flow but with a zero normal component: +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +# The following two sections describe first the +# direction (vertical) and magnitude of gravity and the +# material model (i.e., density, viscosity, etc). We have +# discussed the settings used here in the introduction to +# this cookbook in the manual already. +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1e4 # = Ra + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 1 + set Reference specific heat = 1 + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1 + set Viscosity = 1 + end +end + +# We also have to specify that we want to use the Boussinesq +# approximation (assuming the density in the temperature +# equation to be constant, and incompressibility). +subsection Formulation + set Formulation = Boussinesq approximation +end + +# The settings above all pertain to the description of the +# continuous partial differential equations we want to solve. +# The following section deals with the discretization of +# this problem, namely the kind of mesh we want to compute +# on. We here use a globally refined mesh without +# adaptive mesh refinement. +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +# The final part is to specify what ASPECT should do with the +# solution once computed at the end of every time step. The +# process of evaluating the solution is called `postprocessing' +# and we choose to compute velocity and temperature statistics, +# statistics about the heat flux through the boundaries of the +# domain, and to generate graphical output files for later +# visualization. These output files are created every time +# a time step crosses time points separated by 0.01. Given +# our start time (zero) and final time (0.5) this means that +# we will obtain 50 output files. +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, visualization + + subsection Visualization + set Time between graphical output = 0.01 + end +end + +subsection Solver parameters + set Temperature solver tolerance = 1e-10 +end diff --git a/cookbooks/convection-box/doc/disc.part.prm.bak b/cookbooks/convection-box/doc/disc.part.prm.bak new file mode 100644 index 00000000000..472d365dfc9 --- /dev/null +++ b/cookbooks/convection-box/doc/disc.part.prm.bak @@ -0,0 +1,4 @@ +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 3 +end diff --git a/cookbooks/convection-box/doc/gravity.part.prm.bak b/cookbooks/convection-box/doc/gravity.part.prm.bak new file mode 100644 index 00000000000..c4830f97d58 --- /dev/null +++ b/cookbooks/convection-box/doc/gravity.part.prm.bak @@ -0,0 +1,5 @@ +subsection Gravity model + subsection Vertical + set Magnitude = 1e6 # = Ra + end +end diff --git a/cookbooks/convection-box/doc/refine.part.prm.bak b/cookbooks/convection-box/doc/refine.part.prm.bak new file mode 100644 index 00000000000..3dbcf41380f --- /dev/null +++ b/cookbooks/convection-box/doc/refine.part.prm.bak @@ -0,0 +1,5 @@ +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end diff --git a/cookbooks/convection-box/doc/refine2.part.prm.bak b/cookbooks/convection-box/doc/refine2.part.prm.bak new file mode 100644 index 00000000000..cd704f93193 --- /dev/null +++ b/cookbooks/convection-box/doc/refine2.part.prm.bak @@ -0,0 +1,8 @@ +subsection Mesh refinement + set Initial global refinement = 3 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 + set Additional refinement times = 0.2, 0.3, 0.4 + set Refinement fraction = 1.0 + set Coarsening fraction = 0.0 +end diff --git a/cookbooks/convection-box/tutorial-onset-of-convection/model_input/convection-box.prm.bak b/cookbooks/convection-box/tutorial-onset-of-convection/model_input/convection-box.prm.bak new file mode 100644 index 00000000000..dd2995dda29 --- /dev/null +++ b/cookbooks/convection-box/tutorial-onset-of-convection/model_input/convection-box.prm.bak @@ -0,0 +1,160 @@ +# A description of convection in a 2d box. See the manual for more information. + + +# At the top, we define the number of space dimensions we would like to +# work in: +set Dimension = 2 + +# There are several global variables that have to do with what +# time system we want to work in and what the end time is. We +# also designate an output directory. +set Use years in output instead of seconds = false +set End time = 0.5 +set Output directory = output-convection-box + +# Then there are variables that describe how the pressure should +# be normalized. Here, we choose a zero average pressure +# at the surface of the domain (for the current geometry, the +# surface is defined as the top boundary). +set Pressure normalization = surface +set Surface pressure = 0 + +# Then come a number of sections that deal with the setup +# of the problem to solve. The first one deals with the +# geometry of the domain within which we want to solve. +# The sections that follow all have the same basic setup +# where we select the name of a particular model (here, +# the box geometry) and then, in a further subsection, +# set the parameters that are specific to this particular +# model. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +# The next section deals with the initial conditions for the +# temperature. Note that there are no initial conditions for the +# velocity variable since the velocity is assumed to always +# be in a static equilibrium with the temperature field. +# There are a number of models with the 'function' model +# a generic one that allows us to enter the actual initial +# conditions in the form of a formula that can contain +# constants. We choose a linear temperature profile that +# matches the boundary conditions defined below plus +# a small perturbation. The variables in this equation are +# described below, and it is important to note that in many +# cases the values correspond to other model parameters +# defined elsewhere. As such, if these model parameters are +# changed, the values below will also need to be adjusted. +# L - Model length/width +# p, k - values related to the small temperature perturbation + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = p=0.01, L=1, pi=3.1415926536, k=1 + set Function expression = (1.0-z) - p*cos(k*pi*x/L)*sin(pi*z) + end +end + +# Then follows a section that describes the boundary conditions +# for the temperature. The model we choose is called 'box' and +# allows to set a constant temperature on each of the four sides +# of the box geometry. In our case, we choose something that is +# heated from below and cooled from above, whereas all other +# parts of the boundary are insulated (i.e., no heat flux through +# these boundaries; this is also often used to specify symmetry +# boundaries). +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +# The next parameters then describe on which parts of the +# boundary we prescribe a zero or nonzero velocity and +# on which parts the flow is allowed to be tangential. +# Here, all four sides of the box allow tangential +# unrestricted flow but with a zero normal component: +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +# The following two sections describe first the +# direction (vertical) and magnitude of gravity and the +# material model (i.e., density, viscosity, etc). We have +# discussed the settings used here in the introduction to +# this cookbook in the manual already. +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1e4 # = Ra + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 1 + set Reference specific heat = 1 + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1 + set Viscosity = 1 + end +end + +# We also have to specify that we want to use the Boussinesq +# approximation (assuming the density in the temperature +# equation to be constant, and incompressibility). +subsection Formulation + set Formulation = Boussinesq approximation +end + +# The settings above all pertain to the description of the +# continuous partial differential equations we want to solve. +# The following section deals with the discretization of +# this problem, namely the kind of mesh we want to compute +# on. We here use a globally refined mesh without +# adaptive mesh refinement. +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +# The final part is to specify what ASPECT should do with the +# solution once computed at the end of every time step. The +# process of evaluating the solution is called `postprocessing' +# and we choose to compute velocity and temperature statistics, +# statistics about the heat flux through the boundaries of the +# domain, and to generate graphical output files for later +# visualization. These output files are created every time +# a time step crosses time points separated by 0.01. Given +# our start time (zero) and final time (0.5) this means that +# we will obtain 50 output files. +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, visualization + + subsection Visualization + set Time between graphical output = 0.01 + end +end + +subsection Solver parameters + set Temperature solver tolerance = 1e-10 +end diff --git a/cookbooks/convection-box/tutorial-onset-of-convection/model_input/convection-box2.prm.bak b/cookbooks/convection-box/tutorial-onset-of-convection/model_input/convection-box2.prm.bak new file mode 100644 index 00000000000..4cff06a310a --- /dev/null +++ b/cookbooks/convection-box/tutorial-onset-of-convection/model_input/convection-box2.prm.bak @@ -0,0 +1,161 @@ +# A description of convection in a 2d box. See the manual for more information. + + +# At the top, we define the number of space dimensions we would like to +# work in: +set Dimension = 2 + +# There are several global variables that have to do with what +# time system we want to work in and what the end time is. We +# also designate an output directory. +set Use years in output instead of seconds = false +set End time = 0.1 +set Output directory = output-convection-box2 + +# Then there are variables that describe how the pressure should +# be normalized. Here, we choose a zero average pressure +# at the surface of the domain (for the current geometry, the +# surface is defined as the top boundary). +set Pressure normalization = surface +set Surface pressure = 0 + +# Then come a number of sections that deal with the setup +# of the problem to solve. The first one deals with the +# geometry of the domain within which we want to solve. +# The sections that follow all have the same basic setup +# where we select the name of a particular model (here, +# the box geometry) and then, in a further subsection, +# set the parameters that are specific to this particular +# model. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +# The next section deals with the initial conditions for the +# temperature. Note that there are no initial conditions for the +# velocity variable since the velocity is assumed to always +# be in a static equilibrium with the temperature field. +# There are a number of models with the 'function' model +# a generic one that allows us to enter the actual initial +# conditions in the form of a formula that can contain +# constants. We choose a linear temperature profile that +# matches the boundary conditions defined below plus +# a small perturbation. The variables in this equation are +# described below, and it is important to note that in many +# cases the values correspond to other model parameters +# defined elsewhere. As such, if these model parameters are +# changed, the values below will also need to be adjusted. +# L - Model length/width +# p, k - values related to the small temperature perturbation + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = p=0.01, L=1, pi=3.1415926536, k=1 + set Function expression = (1.0-z) - p*cos(k*pi*x/L)*sin(pi*z) + end +end + +# Then follows a section that describes the boundary conditions +# for the temperature. The model we choose is called 'box' and +# allows to set a constant temperature on each of the four sides +# of the box geometry. In our case, we choose something that is +# heated from below and cooled from above, whereas all other +# parts of the boundary are insulated (i.e., no heat flux through +# these boundaries; this is also often used to specify symmetry +# boundaries). +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +# The next parameters then describe on which parts of the +# boundary we prescribe a zero or nonzero velocity and +# on which parts the flow is allowed to be tangential. +# Here, all four sides of the box allow tangential +# unrestricted flow but with a zero normal component: +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +# The following two sections describe first the +# direction (vertical) and magnitude of gravity and the +# material model (i.e., density, viscosity, etc). We have +# discussed the settings used here in the introduction to +# this cookbook in the manual already. +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1e4 # = Ra + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 1 + set Reference specific heat = 1 + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1 + set Viscosity = 1 + end +end + +# We also have to specify that we want to use the Boussinesq +# approximation (assuming the density in the temperature +# equation to be constant, and incompressibility). +subsection Formulation + set Formulation = Boussinesq approximation +end + +# The settings above all pertain to the description of the +# continuous partial differential equations we want to solve. +# The following section deals with the discretization of +# this problem, namely the kind of mesh we want to compute +# on. We here use a globally refined mesh without +# adaptive mesh refinement. +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +# The final part is to specify what ASPECT should do with the +# solution once computed at the end of every time step. The +# process of evaluating the solution is called `postprocessing' +# and we choose to compute velocity and temperature statistics, +# statistics about the heat flux through the boundaries of the +# domain, and to generate graphical output files for later +# visualization. These output files are created every time +# a time step crosses time points separated by 0.01. Given +# our start time (zero) and final time (0.5) this means that +# we will obtain 50 output files. +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, visualization, heat flux map + + subsection Visualization + set Time between graphical output = 0.00 + set Output format = hdf5 + end +end + +subsection Solver parameters + set Temperature solver tolerance = 1e-10 +end diff --git a/cookbooks/convection-box/tutorial-onset-of-convection/model_input/tutorial.prm b/cookbooks/convection-box/tutorial-onset-of-convection/model_input/tutorial.prm index 5c8302c747c..18e7f499a7b 100644 --- a/cookbooks/convection-box/tutorial-onset-of-convection/model_input/tutorial.prm +++ b/cookbooks/convection-box/tutorial-onset-of-convection/model_input/tutorial.prm @@ -82,21 +82,6 @@ end # whereas all other parts of the boundary are insulated (i.e., # no heat flux through these boundaries; this is also often used # to specify symmetry boundaries). -# subsection Model settings OLD DEPRECATED -# set Fixed temperature boundary indicators = 2,3 OLD MOVED - -# The next parameters then describe on which parts of the -# boundary we prescribe a zero or nonzero velocity and -# on which parts the flow is allowed to be tangential. -# Here, all four sides of the box allow tangential -# unrestricted flow but with a zero normal component: -# set Zero velocity boundary indicators = OLD MOVED -# set Prescribed velocity boundary indicators = OLD MOVED -# set Tangential velocity boundary indicators = 0,1,2,3 OLD MOVED - -subsection Boundary velocity model - set Tangential velocity boundary indicators = left, right, bottom, top -end # The final part of this section describes whether we # want to include adiabatic heating (from a small @@ -118,7 +103,11 @@ end # at the left and right does not matter.) subsection Boundary temperature model set Fixed temperature boundary indicators = 2,3 - set Model name = box + set List of model names = box + + # subsection Model settings OLD DEPRECATED + # set Fixed temperature boundary indicators = 2,3 OLD MOVED + subsection Box set Bottom temperature = 3600 @@ -126,6 +115,20 @@ subsection Boundary temperature model end end +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top + + # The next parameters then describe on which parts of the + # boundary we prescribe a zero or nonzero velocity and + # on which parts the flow is allowed to be tangential. + # Here, all four sides of the box allow tangential + # unrestricted flow but with a zero normal component: + # set Zero velocity boundary indicators = OLD MOVED + # set Prescribed velocity boundary indicators = OLD MOVED + # set Tangential velocity boundary indicators = 0,1,2,3 OLD MOVED + +end + # The final part is to specify what ASPECT should do with the # solution once computed at the end of every time step. The # process of evaluating the solution is called `postprocessing' diff --git a/cookbooks/convection-box/tutorial-onset-of-convection/model_input/tutorial.prm.bak b/cookbooks/convection-box/tutorial-onset-of-convection/model_input/tutorial.prm.bak new file mode 100644 index 00000000000..5c8302c747c --- /dev/null +++ b/cookbooks/convection-box/tutorial-onset-of-convection/model_input/tutorial.prm.bak @@ -0,0 +1,157 @@ +# At the top, we define the number of space dimensions we would like to +# work in: +set Dimension = 2 + +# There are several global variables that have to do with what +# time system we want to work in and what the end time is. We +# also designate an output directory. +set Use years in output instead of seconds = true +set End time = 1.00e10 +set Output directory = output-tutorial + +# Then come a number of sections that deal with the setup +# of the problem to solve. The first one deals with the +# geometry of the domain within which we want to solve. +# The sections that follow all have the same basic setup +# where we select the name of a particular model (here, +# the box geometry) and then, in a further subsection, +# set the parameters that are specific to this particular +# model. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 4.2e6 + set Y extent = 3e6 + end +end + +# The following section deals with the discretization of +# this problem, namely the kind of mesh we want to compute +# on. We here use a globally refined mesh without +# adaptive mesh refinement. +subsection Mesh refinement + set Initial global refinement = 3 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +# The following two sections describe first the +# direction (vertical) and magnitude of gravity and the +# material model (i.e., density, viscosity, etc). +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Viscosity = 5.099e23 + end +end + +# The next section deals with the initial conditions for the +# temperature (there are no initial conditions for the +# velocity variable since the velocity is assumed to always +# be in a static equilibrium with the temperature field). +# There are a number of models with the 'function' model +# a generic one that allows us to enter the actual initial +# conditions in the form of a formula that can contain +# constants. We choose a linear temperature profile that +# matches the boundary conditions defined below plus +# a small perturbation: +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = p=-0.01, L=4.2e6, D=3e6, pi=3.1415926536, k=1, T_top=273, T_bottom=3600 + set Function expression = T_top + (T_bottom-T_top)*(1-(y/D) - p*cos(k*pi*x/L)*sin(pi*y/D)) + end +end + +# We then also have to prescribe several other parts of the model +# such as which boundaries actually carry a prescribed boundary +# temperature (as described in the documentation of the `box' +# geometry, boundaries 2 and 3 are the bottom and top boundaries) +# whereas all other parts of the boundary are insulated (i.e., +# no heat flux through these boundaries; this is also often used +# to specify symmetry boundaries). +# subsection Model settings OLD DEPRECATED +# set Fixed temperature boundary indicators = 2,3 OLD MOVED + +# The next parameters then describe on which parts of the +# boundary we prescribe a zero or nonzero velocity and +# on which parts the flow is allowed to be tangential. +# Here, all four sides of the box allow tangential +# unrestricted flow but with a zero normal component: +# set Zero velocity boundary indicators = OLD MOVED +# set Prescribed velocity boundary indicators = OLD MOVED +# set Tangential velocity boundary indicators = 0,1,2,3 OLD MOVED + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +# The final part of this section describes whether we +# want to include adiabatic heating (from a small +# compressibility of the medium) or from shear friction, +# as well as the rate of internal heating. We do not +# want to use any of these options here: +# set Include adiabatic heating = false OLD is false +# set Include shear heating = false OLD is false +# end + + + +# Then follows a section that describes the boundary conditions +# for the temperature. The model we choose is called 'box' and +# allows to set a constant temperature on each of the four sides +# of the box geometry. In our case, we choose something that is +# heated from below and cooled from above. (As will be seen +# in the next section, the actual temperature prescribed here +# at the left and right does not matter.) +subsection Boundary temperature model + set Fixed temperature boundary indicators = 2,3 + set Model name = box + + subsection Box + set Bottom temperature = 3600 + set Top temperature = 273 + end +end + +# The final part is to specify what ASPECT should do with the +# solution once computed at the end of every time step. The +# process of evaluating the solution is called `postprocessing' +# and we choose to compute velocity and temperature statistics, +# statistics about the heat flux through the boundaries of the +# domain, and to generate graphical output files for later +# visualization. These output files are created every time +# a time step crosses time points separated by 1e7 years. +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics , visualization, particles, basic statistics + + subsection Visualization + set Time between graphical output = 1e7 + set Output format = vtu + end + + subsection Particles + set Time between data output = 1e7 + set Data output format = vtu + end +end + +subsection Particles + subsection Generator + subsection Probability density function + set Number of particles = 1000 + end + end +end diff --git a/cookbooks/convection_box_3d/convection_box_3d.prm.bak b/cookbooks/convection_box_3d/convection_box_3d.prm.bak new file mode 100644 index 00000000000..88e81d1c124 --- /dev/null +++ b/cookbooks/convection_box_3d/convection_box_3d.prm.bak @@ -0,0 +1,152 @@ +# A description of convection in a 3d box. See the manual for more information. + +# At the top, we define the number of space dimensions we would like to +# work in: +set Dimension = 3 + +# There are several global variables that have to do with what +# time system we want to work in and what the end time is. We +# also designate an output directory. +set Use years in output instead of seconds = false +set End time = 1.0 +set Output directory = output-convection_box_3d + +# Then there are variables that describe how the pressure should +# be normalized. Here, we choose a zero average pressure +# at the surface of the domain (for the current geometry, the +# surface is defined as the top boundary). +set Pressure normalization = surface +set Surface pressure = 0 + +# Then come a number of sections that deal with the setup +# of the problem to solve. The first one deals with the +# geometry of the domain within which we want to solve. +# The sections that follow all have the same basic setup +# where we select the name of a particular model (here, +# the box geometry) and then, in a further subsection, +# set the parameters that are specific to this particular +# model. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + set Z extent = 1 + end +end + +# The next section deals with the initial conditions for the +# temperature (there are no initial conditions for the +# velocity variable since the velocity is assumed to always +# be in a static equilibrium with the temperature field). +# There are a number of models with the 'function' model +# a generic one that allows us to enter the actual initial +# conditions in the form of a formula that can contain +# constants. We choose a linear temperature profile that +# matches the boundary conditions defined below plus +# a small perturbation: +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y,z + set Function constants = p=0.01, L=1, pi=3.1415926536, k=1 + set Function expression = (1.0-z) - p*cos(k*pi*x/L)*sin(pi*z)*y^3 + end +end + +# Then follows a section that describes the boundary conditions for the +# temperature. The model we choose is called 'box' and allows to set a constant +# temperature on each of the four sides of the box geometry. In our case, we +# choose something that is heated from below and cooled from above. +# All other parts of the boundary are insulated (i.e., no heat flux through +# these boundaries; this is also often used to specify symmetry boundaries). +subsection Boundary temperature model + set List of model names = box + set Fixed temperature boundary indicators = bottom, top + + subsection Box + set Bottom temperature = 1 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +# The next parameters then describe on which parts of the +# boundary we prescribe a zero or nonzero velocity and +# on which parts the flow is allowed to be tangential. +# Here, all six sides of the box allow tangential +# unrestricted flow but with a zero normal component: +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, front, back, bottom, top +end + +# The following two sections describe first the +# direction (vertical) and magnitude of gravity and the +# material model (i.e., density, viscosity, etc). We have +# discussed the settings used here in the introduction to +# this cookbook in the manual already. +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1e16 # = Ra / Thermal expansion coefficient + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 1 + set Reference specific heat = 1 + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1e-10 + set Viscosity = 1 + end +end + +# The settings above all pertain to the description of the +# continuous partial differential equations we want to solve. +# The following section deals with the discretization of +# this problem, namely the kind of mesh we want to compute +# on. We here use a globally refined mesh without +# adaptive mesh refinement. +subsection Mesh refinement + set Initial global refinement = 3 + set Initial adaptive refinement = 3 + set Time steps between mesh refinement = 15 + set Additional refinement times = 0.003 +end + +# The final part is to specify what ASPECT should do with the +# solution once computed at the end of every time step. The +# process of evaluating the solution is called `postprocessing' +# and we choose to compute velocity and temperature statistics, +# statistics about the heat flux through the boundaries of the +# domain, and to generate graphical output files for later +# visualization. These output files are created every time +# a time step crosses time points separated by 0.01. Given +# our start time (zero) and final time (0.5) this means that +# we will obtain 50 output files. +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, visualization + + subsection Visualization + set Time between graphical output = 0.0001 + end +end + +subsection Checkpointing + # The number of timesteps between performing checkpoints. If 0 and time + # between checkpoint is not specified, checkpointing will not be performed. + # Units: None. + set Steps between checkpoint = 50 +end + +subsection Solver parameters + set Temperature solver tolerance = 1e-10 +end diff --git a/cookbooks/convection_box_3d/doc/amr.part.prm.bak b/cookbooks/convection_box_3d/doc/amr.part.prm.bak new file mode 100644 index 00000000000..b68e96eda57 --- /dev/null +++ b/cookbooks/convection_box_3d/doc/amr.part.prm.bak @@ -0,0 +1,6 @@ +subsection Mesh refinement + set Initial global refinement = 3 + set Initial adaptive refinement = 3 + set Time steps between mesh refinement = 15 + set Additional refinement times = 0.003 +end diff --git a/cookbooks/convection_box_3d/doc/checkpoint.part.prm.bak b/cookbooks/convection_box_3d/doc/checkpoint.part.prm.bak new file mode 100644 index 00000000000..595a2feeb79 --- /dev/null +++ b/cookbooks/convection_box_3d/doc/checkpoint.part.prm.bak @@ -0,0 +1,3 @@ +subsection Checkpointing + set Steps between checkpoint = 50 +end diff --git a/cookbooks/convection_box_3d/doc/gravity.part.prm.bak b/cookbooks/convection_box_3d/doc/gravity.part.prm.bak new file mode 100644 index 00000000000..4b07cb3808e --- /dev/null +++ b/cookbooks/convection_box_3d/doc/gravity.part.prm.bak @@ -0,0 +1,7 @@ +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1e16 # = Ra / Thermal expansion coefficient + end +end diff --git a/cookbooks/convection_box_3d/doc/initial.part.prm.bak b/cookbooks/convection_box_3d/doc/initial.part.prm.bak new file mode 100644 index 00000000000..15b76c9dae8 --- /dev/null +++ b/cookbooks/convection_box_3d/doc/initial.part.prm.bak @@ -0,0 +1,9 @@ +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y,z + set Function constants = p=0.01, L=1, pi=3.1415926536, k=1 + set Function expression = (1.0-z) - p*cos(k*pi*x/L)*sin(pi*z)*y^3 + end +end diff --git a/cookbooks/convection_box_3d/doc/postprocess.part.prm.bak b/cookbooks/convection_box_3d/doc/postprocess.part.prm.bak new file mode 100644 index 00000000000..2f592ff8cfe --- /dev/null +++ b/cookbooks/convection_box_3d/doc/postprocess.part.prm.bak @@ -0,0 +1,8 @@ +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, \ + heat flux statistics, visualization + + subsection Visualization + set Time between graphical output = 0.0001 + end +end diff --git a/cookbooks/convection_box_3d/doc/start.part.prm.bak b/cookbooks/convection_box_3d/doc/start.part.prm.bak new file mode 100644 index 00000000000..eb4a52a204c --- /dev/null +++ b/cookbooks/convection_box_3d/doc/start.part.prm.bak @@ -0,0 +1,25 @@ +set Dimension = 3 + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + set Z extent = 1 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Top temperature = 0 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, front, back, bottom, top +end diff --git a/cookbooks/crustal_deformation/crustal_model_2D.prm.bak b/cookbooks/crustal_deformation/crustal_model_2D.prm.bak new file mode 100644 index 00000000000..3756ca1b7d0 --- /dev/null +++ b/cookbooks/crustal_deformation/crustal_model_2D.prm.bak @@ -0,0 +1,134 @@ +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 1e6 +set Use years in output instead of seconds = true +set Nonlinear solver scheme = single Advection, iterated Stokes + +# This model is very sensitive to the nonlinear solver tolerance, +# results still change slightly down to a tolerance of 1e-8, but +# require much more resources than reasonable for a cookbook. +set Nonlinear solver tolerance = 2e-6 +set Max nonlinear iterations = 100 +set CFL number = 0.5 +set Output directory = output-crustal_model_2D +set Timing output frequency = 1 +set Pressure normalization = no + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 5 + set X extent = 80e3 + set Y extent = 16e3 + end +end + +# Advecting the free surface vertically rather than +# in the surface normal direction can result in a +# more stable mesh when the deformation is large +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + + subsection Free surface + set Surface velocity projection = vertical + end +end + +subsection Material model + # set Model name = viscoplastic + # subsection Viscoplastic model + # set Reference density = 2800 + # end + + set Model name = drucker prager + + subsection Drucker Prager + set Reference density = 2800 + + subsection Viscosity + set Minimum viscosity = 1e19 + set Maximum viscosity = 1e25 + set Reference strain rate = 1e-20 + set Angle of internal friction = 30 + set Cohesion = 20e6 + end + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left: function, right:function, bottom:function + + subsection Function + set Variable names = x,y + set Function constants = cm=0.01, year=1 + set Function expression = if (x<40e3 , 1*cm/year, -1*cm/year) ; 0 + end +end + +############### Parameters describing the temperature field +# As above, there is no need to set anything for the +# temperature boundary conditions. + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the discretization +# The following parameters describe how often we want to refine +# the mesh globally and adaptively, what fraction of cells should +# be refined in each adaptive refinement step, and what refinement +# indicator to use when refining the mesh adaptively. + +subsection Mesh refinement + set Initial adaptive refinement = 1 + set Initial global refinement = 3 + set Refinement fraction = 0.95 + set Strategy = strain rate + set Coarsening fraction = 0.05 + set Time steps between mesh refinement = 1 + set Run postprocessors on initial refinement = true +end + +############### Parameters describing what to do with the solution +# The final section allows us to choose which postprocessors to +# run at the end of each time step. We select to generate graphical +# output that will consist of the primary variables (velocity, pressure, +# temperature and the compositional fields) as well as the density and +# viscosity. We also select to compute some statistics about the +# velocity field. + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, basic statistics + + subsection Visualization + set List of output variables = density, viscosity, strain rate, error indicator, heating, partition + set Time between graphical output = 0 + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Stokes solver type = block AMG + set Linear solver tolerance = 1e-9 + set Number of cheap Stokes solver steps = 0 + set Maximum number of expensive Stokes solver steps = 5000 + set GMRES solver restart length = 200 + end +end diff --git a/cookbooks/crustal_deformation/crustal_model_3D.prm.bak b/cookbooks/crustal_deformation/crustal_model_3D.prm.bak new file mode 100644 index 00000000000..81cebdc1e59 --- /dev/null +++ b/cookbooks/crustal_deformation/crustal_model_3D.prm.bak @@ -0,0 +1,128 @@ +############### Global parameters + +set Dimension = 3 +set Start time = 0 +set End time = 1e6 +set Use years in output instead of seconds = true +set CFL number = .5 +set Output directory = output-crustal_model_3D +set Nonlinear solver scheme = single Advection, iterated Stokes +set Nonlinear solver tolerance = 1e-8 +set Max nonlinear iterations = 100 +set Pressure normalization = no +set Timing output frequency = 1 + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 128e3 + set Y extent = 96e3 + set Z extent = 16e3 + set X repetitions = 8 + set Y repetitions = 3 + end +end + +# Advecting the free surface vertically rather than +# in the surface normal direction can result in a +# more stable mesh when the deformation is large +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + + subsection Free surface + set Surface velocity projection = vertical + end +end + +subsection Material model + set Model name = drucker prager + + subsection Drucker Prager + set Reference density = 2800 + + subsection Viscosity + set Minimum viscosity = 1e19 + set Maximum viscosity = 1e25 + set Reference strain rate = 1e-20 + set Angle of internal friction = 30 + set Cohesion = 20e6 + end + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +# The velocity along the top boundary models a spreading +# center that is moving left and right: +subsection Boundary velocity model + set Tangential velocity boundary indicators = front,back + set Prescribed velocity boundary indicators = left: function, right:function, bottom:function + + subsection Function + set Variable names = x,y,z + set Function constants = cm=0.01, year=1 + set Function expression = if (x<56e3 && y<=48e3 | x<72e3 && y>48e3, -1*cm/year, 1*cm/year) ; 0 ; 0 + end +end + +############### Parameters describing the temperature field +# As above, there is no need to set anything for the +# temperature boundary conditions. + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the discretization +# The following parameters describe how often we want to refine +# the mesh globally and adaptively, what fraction of cells should +# be refined in each adaptive refinement step, and what refinement +# indicator to use when refining the mesh adaptively. + +subsection Mesh refinement + set Initial adaptive refinement = 2 + set Initial global refinement = 2 + set Refinement fraction = 0.9 + set Strategy = strain rate + set Coarsening fraction = 0.05 + set Minimum refinement level = 2 + set Time steps between mesh refinement = 1 + set Run postprocessors on initial refinement = true +end + +############### Parameters describing what to do with the solution +# The final section allows us to choose which postprocessors to +# run at the end of each time step. We select to generate graphical +# output that will consist of the primary variables (velocity, pressure, +# temperature and the compositional fields) as well as the density and +# viscosity. We also select to compute some statistics about the +# velocity field. + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, topography, pressure statistics + + subsection Visualization + set List of output variables = density, viscosity, strain rate, error indicator, partition + set Time between graphical output = 0 + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-9 + set Number of cheap Stokes solver steps = 0 + end +end diff --git a/cookbooks/crustal_deformation/doc/crustal_model_2D_part1.prm.bak b/cookbooks/crustal_deformation/doc/crustal_model_2D_part1.prm.bak new file mode 100644 index 00000000000..9720b54bbd6 --- /dev/null +++ b/cookbooks/crustal_deformation/doc/crustal_model_2D_part1.prm.bak @@ -0,0 +1,15 @@ +subsection Material model + set Model name = drucker prager + + subsection Drucker Prager + set Reference density = 2800 + + subsection Viscosity + set Minimum viscosity = 1e19 + set Maximum viscosity = 1e25 + set Reference strain rate = 1e-20 + set Angle internal friction = 30 + set Cohesion = 20e6 + end + end +end diff --git a/cookbooks/crustal_deformation/doc/crustal_model_2D_part2.prm.bak b/cookbooks/crustal_deformation/doc/crustal_model_2D_part2.prm.bak new file mode 100644 index 00000000000..b0bea70f396 --- /dev/null +++ b/cookbooks/crustal_deformation/doc/crustal_model_2D_part2.prm.bak @@ -0,0 +1,7 @@ +subsection Boundary velocity model + subsection Function + set Variable names = x,y + set Function constants = cm=0.01, year=1 + set Function expression = if (x<40e3 , 1*cm/year, -1*cm/year) ; 0 + end +end diff --git a/cookbooks/crustal_deformation/doc/crustal_model_2D_part3.prm.bak b/cookbooks/crustal_deformation/doc/crustal_model_2D_part3.prm.bak new file mode 100644 index 00000000000..9e58f845656 --- /dev/null +++ b/cookbooks/crustal_deformation/doc/crustal_model_2D_part3.prm.bak @@ -0,0 +1,3 @@ +subsection Free surface + set Surface velocity projection = vertical +end diff --git a/cookbooks/crustal_deformation/doc/crustal_model_2D_part4.prm.bak b/cookbooks/crustal_deformation/doc/crustal_model_2D_part4.prm.bak new file mode 100644 index 00000000000..3f5ec4647db --- /dev/null +++ b/cookbooks/crustal_deformation/doc/crustal_model_2D_part4.prm.bak @@ -0,0 +1,9 @@ +subsection Mesh refinement + set Initial adaptive refinement = 1 + set Initial global refinement = 3 + set Refinement fraction = 0.95 + set Strategy = strain rate + set Coarsening fraction = 0.05 + set Time steps between mesh refinement = 1 + set Run postprocessors on initial refinement = true +end diff --git a/cookbooks/crustal_deformation/doc/crustal_model_3D_part1.prm.bak b/cookbooks/crustal_deformation/doc/crustal_model_3D_part1.prm.bak new file mode 100644 index 00000000000..8d19f6bc84a --- /dev/null +++ b/cookbooks/crustal_deformation/doc/crustal_model_3D_part1.prm.bak @@ -0,0 +1,7 @@ +subsection Boundary velocity model + subsection Function + set Variable names = x,y,z + set Function constants = cm=0.01, year=1 + set Function expression = if (x<56e3 && y<=48e3 | x<72e3 && y>48e3,-1*cm/year,1*cm/year);0;0 + end +end diff --git a/cookbooks/fastscape_eroding_box/fastscape_eroding_box.prm.bak b/cookbooks/fastscape_eroding_box/fastscape_eroding_box.prm.bak new file mode 100644 index 00000000000..eeadbbaae4b --- /dev/null +++ b/cookbooks/fastscape_eroding_box/fastscape_eroding_box.prm.bak @@ -0,0 +1,177 @@ +# This cookbook is used as a test to ensure that FastScape is properly working with ASPECT. +# It consists of a 2.5 km high central mountain block that is eroded through the use of +# hillslope diffusion and the Stream Power Law. Within ASPECT, the model is based off +# convection-box-3d. However, it is set up in a way that nothing happens in the geodynamic model. + +# At the top, we define the number of space dimensions we would like to +# work in: +set Dimension = 3 +set Use years in output instead of seconds = true +set End time = 2.5e5 +set Maximum time step = 50000 +set Output directory = eroding_box +set Pressure normalization = no +set Surface pressure = 0 + +# A box that has an initial 60x60 km mountain block that is 2.5 km above the initial model surface. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 125e3 + set Y extent = 100e3 + set Z extent = 25e3 + set X repetitions = 5 + set Y repetitions = 4 + end + + subsection Initial topography model + set Model name = function + + subsection Function + set Function expression = if(y>20e3 && y<80e3 && x>32.5e3 && x<92.5e3, 2500, 0) + end + end +end + +# We do not consider temperature in this setup +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = initial temperature +end + +# X Set all boundaries except the top to freeslip. +subsection Boundary velocity model + set Tangential velocity boundary indicators = bottom, front, back, left, right +end + +# Here we setup the top boundary with fastscape. +subsection Mesh deformation + set Mesh deformation boundary indicators = top : fastscape + set Additional tangential mesh velocity boundary indicators = left, right, front, back + + subsection Fastscape + # As the highest resolution at the surface is 4 in the mesh refinement function, we set this the same. + set Maximum surface refinement level = 4 + + # Because we only have the same level across the entire surface we set this to zero. + # If we had multiple resolutions, e.g. 3 different cell sizes at the surface, + # this would be set to 2 (number of cell sizes at surface - 1). + set Surface refinement difference = 0 + + # We set FastScape as 1 level more resolved than ASPECT's initial global surface resolution. + set Additional fastscape refinement = 1 + + # Number of FastScape timesteps we want per ASPECT timestep. + set Number of fastscape timesteps per aspect timestep = 5 + + # Set the maximum allowable FastScape time step length. If the (ASPECT time step length)/(Number of FastScape steps per ASPECT step) + # is greater than this value, then the number of FastScape steps per ASPECT step is automatically doubled. + # This is continued until the FastScape timestep length is less than this value. + # + # The units of this parameter are either years or seconds, dependent on the global parameter that + # determines whether an input file uses one or the other. + set Maximum timestep length = 10000 + + # Seed number for initial topography noise + set Fastscape seed = 1000 + + # Because no boundaries are periodic, no flux is prescribed, and no advection occurs in FastScape, + # we do not need ghost nodes. + set Use ghost nodes = false + set Vertical exaggeration = 1 + + # Fix all boundaries in FastScape. + subsection Boundary conditions + set Front = 1 + set Right = 1 + set Back = 1 + set Left = 1 + end + + # We use both the Stream Power Law (SPL) and hillslope diffusion. The bedrock deposition + # variable allows deposition of sediment; however, because + # the sediment variables are not set, they are equal to + # bedrock values. + subsection Erosional parameters + set Drainage area exponent = 0.4 + set Bedrock diffusivity = 1e-2 + set Bedrock river incision rate = 1e-4 + set Slope exponent = 1 + set Bedrock deposition coefficient = 1 + + # A negative value indicates varied flow. 10 is steepest descent, and 1 is uniform distribution. + set Multi-direction slope exponent = -1 + end + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0 + end +end + +# Dimensionless +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 1 + set Reference specific heat = 1 + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1 + set Viscosity = 1 + end +end + +# We also have to specify that we want to use the Boussinesq +# approximation (assuming the density in the temperature +# equation to be constant, and incompressibility). +subsection Formulation + set Formulation = Boussinesq approximation +end + +# We set a maximum surface refinement level of 4 using the max/minimum refinement level. +# This will make it so that the ASPECT surface refinement is the same as what we set +# for our maximum surface refinement level for FastScape. +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 1 + set Time steps between mesh refinement = 0 + set Strategy = minimum refinement function, maximum refinement function + + subsection Maximum refinement function + set Coordinate system = cartesian + set Variable names = x,y,z + set Function expression = if(z>=21000, 4, 2) + end + + subsection Minimum refinement function + set Coordinate system = cartesian + set Variable names = x,y,z + set Function expression = if(z>=21000, 4, 2) + end +end + +subsection Postprocess + set List of postprocessors = visualization + + subsection Visualization + set Time between graphical output = 0 + set List of output variables = strain rate + set Interpolate output = true + set Write higher order output = true + end +end diff --git a/cookbooks/finite_strain/doc/finite_strain.part.prm.bak b/cookbooks/finite_strain/doc/finite_strain.part.prm.bak new file mode 100644 index 00000000000..85b15281c49 --- /dev/null +++ b/cookbooks/finite_strain/doc/finite_strain.part.prm.bak @@ -0,0 +1,14 @@ +set Additional shared libraries = ./libfinite_strain.so + +subsection Material model + set Model name = finite strain + + subsection Simple model + set Thermal conductivity = 4.7 + set Reference density = 3400 + set Thermal expansion coefficient = 2e-5 + set Viscosity = 5e21 + set Thermal viscosity exponent = 7 + set Reference temperature = 1600 + end +end diff --git a/cookbooks/finite_strain/finite_strain.cc.bak b/cookbooks/finite_strain/finite_strain.cc.bak new file mode 100644 index 00000000000..88ba08af862 --- /dev/null +++ b/cookbooks/finite_strain/finite_strain.cc.bak @@ -0,0 +1,128 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + template + class FiniteStrain : public MaterialModel::Simple + { + public: + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + void parse_parameters(ParameterHandler &prm) override; + }; + + } +} + +namespace aspect +{ + namespace MaterialModel + { + + template + void + FiniteStrain:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + // First, we use the material descriptions of the 'simple' material model to fill all of the material + // model outputs. Below, we will then overwrite selected properties (the reaction terms), which are + // needed to track the finite strain. + Simple::evaluate(in, out); + + // We need the velocity gradient for the finite strain (they are not included in material model inputs), + // so we get them from the finite element. + if (in.current_cell.state() == IteratorState::valid && this->get_timestep_number() > 0) + { + const QGauss quadrature_formula (this->introspection().polynomial_degree.velocities+1); + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_gradients); + + std::vector> velocity_gradients (quadrature_formula.size(), Tensor<2,dim>()); + + fe_values.reinit (in.current_cell); + fe_values[this->introspection().extractors.velocities].get_function_gradients (this->get_solution(), + velocity_gradients); + + // Assign the strain components to the compositional fields reaction terms. + // If there are too many fields, we simply fill only the first fields with the + // existing strain rate tensor components. + for (unsigned int q=0; q < in.n_evaluation_points(); ++q) + { + // Convert the compositional fields into the tensor quantity they represent. + const Tensor<2,dim> strain(make_array_view(&in.composition[q][0], + &in.composition[q][0] + Tensor<2,dim>::n_independent_components)); + + // Compute the strain accumulated in this timestep. + const Tensor<2,dim> strain_increment = this->get_timestep() * (velocity_gradients[q] * strain); + + // Output the strain increment component-wise to its respective compositional field's reaction terms. + strain_increment.unroll(&out.reaction_terms[q][0], + &out.reaction_terms[q][0] + Tensor<2,dim>::n_independent_components); + } + } + } + + + template + void + FiniteStrain:: + parse_parameters (ParameterHandler &prm) + { + Simple::parse_parameters (prm); + + AssertThrow(this->n_compositional_fields() >= (Tensor<2,dim>::n_independent_components), + ExcMessage("There must be at least as many compositional fields as independent components in the full " + "strain rate tensor.")); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(FiniteStrain, + "finite strain", + "A simple material model that is like the " + "'Simple' model, but tracks the finite strain as compositional " + "fields. More precisely, the model assumes that the first 4 (in 2D) " + "or 9 (in 3D) compositional fields contain the components " + "of the deformation gradient tensor, $\\mathbf F$, which can " + "be polar-decomposed into the left stretching tensor " + "$\\mathbf L$ (the finite strain we are interested in), and the " + "rotation tensor $\\mathbf Q$. See the corresponding cookbook in " + "the manual for more detailed information.") + } +} diff --git a/cookbooks/finite_strain/finite_strain.prm.bak b/cookbooks/finite_strain/finite_strain.prm.bak new file mode 100644 index 00000000000..1347f0827c5 --- /dev/null +++ b/cookbooks/finite_strain/finite_strain.prm.bak @@ -0,0 +1,119 @@ +# Listing of Parameters +# --------------------- +# Model for global mantle convection with tracking of the finite strain tensor. + +set Additional shared libraries = ./libfinite_strain_cookbook.so +set Adiabatic surface temperature = 1600 +set Maximum time step = 1e6 +set Dimension = 2 +set End time = 6e8 +set Pressure normalization = surface +set Surface pressure = 0 +set Use years in output instead of seconds = true +set Output directory = output-finite_strain + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = initial temperature + + subsection Initial temperature + set Minimal temperature = 293 + set Maximal temperature = 2780 + end +end + +subsection Compositional fields + set Number of fields = 4 + set Names of fields = strain_xx, strain_xy, strain_yx, strain_yy +end + +subsection Boundary composition model + set List of model names = initial composition +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Function expression = 1.0;0.0;0.0;1.0 + set Variable names = x,y + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 8700000 + set Y extent = 2900000 + set X repetitions = 3 + set X periodic = true + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +subsection Initial temperature model + set Model name = adiabatic + + subsection Adiabatic + set Age bottom boundary layer = 5e8 + set Age top boundary layer = 3e8 + set Amplitude = 0 + set Position = center + set Radius = 350000 + + subsection Function + set Function expression = 0;0;0;0 + end + end +end + +subsection Material model + set Model name = finite strain + set Material averaging = none + + subsection Simple model + set Thermal conductivity = 4.7 + set Reference density = 3400 + set Thermal expansion coefficient = 2e-5 + set Viscosity = 5e21 + set Thermal viscosity exponent = 7 + set Reference temperature = 1600 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 6 + set Time steps between mesh refinement = 0 +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = top,bottom +end + +subsection Nullspace removal + set Remove nullspace = net x translation +end + +subsection Postprocess + set List of postprocessors = visualization,composition statistics,velocity statistics, temperature statistics + + subsection Visualization + set List of output variables = nonadiabatic temperature, strain rate + set Output format = vtu + set Time between graphical output = 0 + set Interpolate output = true + end +end + +subsection Checkpointing + set Time between checkpoint = 1800 +end diff --git a/cookbooks/free_surface/doc/free_surface.part.prm.bak b/cookbooks/free_surface/doc/free_surface.part.prm.bak new file mode 100644 index 00000000000..a4d60719ccb --- /dev/null +++ b/cookbooks/free_surface/doc/free_surface.part.prm.bak @@ -0,0 +1,41 @@ +set Maximum first time step = 1e3 +set Maximum relative increase in time step = 30 +set Pressure normalization = no + +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + + subsection Free surface + set Free surface stabilization theta = 0.5 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = left, right, bottom, top + set List of model names = constant + + subsection Constant + set Boundary indicator to temperature mappings = left:0, right:0, bottom:0, top:0 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = sqrt((x-250.e3)^2 + (y-100.e3)^2) < 25.e3 ? 200.0 : 0.0 + end +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, topography + + subsection Visualization + set Time between graphical output = 1.e6 + end +end diff --git a/cookbooks/free_surface/free_surface.prm.bak b/cookbooks/free_surface/free_surface.prm.bak new file mode 100644 index 00000000000..ada080f9918 --- /dev/null +++ b/cookbooks/free_surface/free_surface.prm.bak @@ -0,0 +1,141 @@ +# This is a very simple cookbook which demonstrates the use of a free surface +# for computing surface topography. The model is a 2D box, with a rising blob +# beneath a free surface that generates an initially increasing and then +# decaying surface topography while its heat diffuses. We output the maximum +# and minimum topography at every time step to document the evolution of +# topography. + +set Dimension = 2 +set End time = 2e7 +set Use years in output instead of seconds = true +set Output directory = output-free_surface + +# Free surface calculations are typically more difficult to stabilize, and tend +# to mesh oscillations, in particular for the initial time steps. Thus, we limit +# the initial time steps to a smaller size (1000 years, and we allow each time +# step to only grow by 30% compared to the last one to avoid jumps in time step +# length). We could also reduce the CFL number to decrease all time steps, but +# that would slow down the whole model instead of just the first time steps. +set Maximum first time step = 1e3 +set Maximum relative increase in time step = 30 +set CFL number = 1.0 + +# Pressure normalization must be set to ``no'' for free surface models, as its +# equations are based on the assumption that the pressure is zero at the free +# surface. +set Pressure normalization = no + +# We can use any of the normal geometry models for free surface modeling, we +# just need to specify further down which surface is to be the free one. We +# here use a box model with vertical downwards gravity. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 500.e3 + set Y extent = 200.e3 + set X repetitions = 5 + set Y repetitions = 2 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +# Here is the major new section for this parameter file, specifying the +# parameters for running free surface calculations. +subsection Mesh deformation + # We specify a comma delimited list of all boundaries for which the mesh will + # deform (the top boundary), and the method by which their deformation is + # determined (in this case a free surface). + set Mesh deformation boundary indicators = top: free surface + + # We can specify the free surface stabilization parameter + # theta, between zero and one with 0.5 being the default. + # If the parameter is zero, there is no stabilization + # and you are likely to see a sloshing instability develop. If + # it is one, the surface should be the most stable, though you + # may find that the rates that it moves are fairly damped. + # See the paper describing the free surface for more details on + # this parameter. + subsection Free surface + set Free surface stabilization theta = 0.5 + end +end + +# Here we specify that the model has free slip velocity boundary conditions for +# the sides and bottom. We do not specify a boundary condition for the top, +# which is equivalent to a zero stress boundary condition. This means while the +# section above describes how the mesh deforms, this section still describes +# how the velocity should behave at these boundaries, and only the combination +# of prescribing the mesh to move with the velocity and allowing the velocity +# to move through the boundary generates the effect we commonly call "free +# surface". +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom +end + +# We prescribe a zero boundary temperature, as we are just modeling a single +# rising blob +subsection Boundary temperature model + set Fixed temperature boundary indicators = left, right, bottom, top + set List of model names = constant + + subsection Constant + set Boundary indicator to temperature mappings = left:0, right:0, bottom:0, top:0 + end +end + +# Our temperature initial conditions are simply a blob of hot +# rock in the center of the domain. +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = sqrt((x-250.e3)^2 + (y-100.e3)^2) < 25.e3 ? 200.0 : 0.0 + end +end + +# A fairly standard simple material model, except we use an +# artificially low thermal conductivity to keep our anomaly +# from diffusing too fast. +subsection Material model + set Model name = simpler + + subsection Simpler model + set Reference density = 3300 + set Reference specific heat = 1250 + set Reference temperature = 0.0 + set Thermal conductivity = 1.0 + set Thermal expansion coefficient = 4e-5 + set Viscosity = 1.e20 + end +end + +# For simplicity we disable adaptive mesh refinement, +# although it would significantly speed up this model +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Refinement fraction = 0.3 + set Coarsening fraction = 0.05 + set Strategy = temperature + set Time steps between mesh refinement = 0 +end + +# We also include the topography postprocessor, which just calculates +# the maximum and minimum topography on your free surface at +# every time step. +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, topography + + subsection Visualization + set Time between graphical output = 1.e6 + end +end diff --git a/cookbooks/free_surface_with_crust/doc/free_surface_with_crust.part1.prm.bak b/cookbooks/free_surface_with_crust/doc/free_surface_with_crust.part1.prm.bak new file mode 100644 index 00000000000..9b69c3b729a --- /dev/null +++ b/cookbooks/free_surface_with_crust/doc/free_surface_with_crust.part1.prm.bak @@ -0,0 +1,4 @@ +# This model loads an additional shared library, which provides another +# material model that is not part of the main ASPECT code, but instead +# lies in in a subdirectory of this cookbook folder. +set Additional shared libraries = ./plugin/libsimpler_with_crust.so diff --git a/cookbooks/free_surface_with_crust/doc/free_surface_with_crust.part2.prm.bak b/cookbooks/free_surface_with_crust/doc/free_surface_with_crust.part2.prm.bak new file mode 100644 index 00000000000..1a2d0b1f977 --- /dev/null +++ b/cookbooks/free_surface_with_crust/doc/free_surface_with_crust.part2.prm.bak @@ -0,0 +1,19 @@ +# Because we load the additional shared library at the top, we here have the +# option to choose the new material model that is described inside that library +# called 'simpler with crust'. This model has additional input options for the +# two layers with different viscosities and the depth of the transition between +# the two layers. +subsection Material model + set Model name = simpler with crust + + subsection Simpler with crust model + set Reference density = 3300 + set Reference specific heat = 1250 + set Reference temperature = 0.0 + set Thermal conductivity = 1.0 + set Thermal expansion coefficient = 4e-5 + set Lower viscosity = 1.e20 + set Upper viscosity = 1.e23 + set Jump height = 170.e3 + end +end diff --git a/cookbooks/free_surface_with_crust/free_surface_with_crust.prm.bak b/cookbooks/free_surface_with_crust/free_surface_with_crust.prm.bak new file mode 100644 index 00000000000..1f17a9c109d --- /dev/null +++ b/cookbooks/free_surface_with_crust/free_surface_with_crust.prm.bak @@ -0,0 +1,112 @@ +# This cookbook is an extension of the free_surface cookbook. Please see the +# other cookbook for details about the free surface. This cookbook illustrates +# how to use an external plugin to modify the material model, and what +# influence a viscous crust has on the magnitude of surface topography. + +# This model loads an additional shared library, which provides another +# material model that is not part of the main ASPECT code, but instead +# lies in in a subdirectory of this cookbook folder. +set Additional shared libraries = ./plugin/libsimpler_with_crust.so +set Dimension = 2 +set End time = 2e7 +set Use years in output instead of seconds = true +set Output directory = output-free_surface_with_crust +set Maximum first time step = 1e3 +set Maximum relative increase in time step = 30 +set CFL number = 1.0 +set Pressure normalization = no + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 500.e3 + set Y extent = 200.e3 + set X repetitions = 5 + set Y repetitions = 2 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +subsection Mesh deformation + set Mesh deformation boundary indicators = top: free surface + + subsection Free surface + set Free surface stabilization theta = 0.5 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = left, right, bottom, top + set List of model names = constant + + subsection Constant + set Boundary indicator to temperature mappings = left:0, right:0, bottom:0, top:0 + end +end + +# As in the free_surface cookbook our temperature initial conditions are simply +# a blob of hot rock in the center of the domain. +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = sqrt((x-250.e3)^2 + (y-100.e3)^2) < 25.e3 ? 200.0 : 0.0 + end +end + +# Because we load the additional shared library at the top, we here have the +# option to choose the new material model that is described inside that library +# called 'simpler with crust'. This model has additional input options for the +# two layers with different viscosities and the depth of the transition between +# the two layers. +subsection Material model + set Model name = simpler with crust + + subsection Simpler with crust model + set Reference density = 3300 + set Reference specific heat = 1250 + set Reference temperature = 0.0 + set Thermal conductivity = 1.0 + set Thermal expansion coefficient = 4e-5 + set Lower viscosity = 1.e20 + set Upper viscosity = 1.e23 + set Jump height = 170.e3 + end +end + +# For simplicity we disable adaptive mesh refinement, +# although it would significantly speed up this model +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Refinement fraction = 0.3 + set Coarsening fraction = 0.05 + set Strategy = temperature + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, topography + + subsection Visualization + set List of output variables = material properties + set Time between graphical output = 1.e6 + + subsection Material properties + set List of material properties = density, viscosity + end + end +end diff --git a/cookbooks/free_surface_with_crust/plugin/simpler_with_crust.cc.bak b/cookbooks/free_surface_with_crust/plugin/simpler_with_crust.cc.bak new file mode 100644 index 00000000000..db2922e301d --- /dev/null +++ b/cookbooks/free_surface_with_crust/plugin/simpler_with_crust.cc.bak @@ -0,0 +1,220 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model similar to the "simpler" material model, but where the + * viscosity has two different values dependent on whether we are above or + * below a line at a certain z-value, i.e., representing a crustal layer. + * + * @ingroup MaterialModels + */ + template + class SimplerWithCrust : public Interface + { + public: + /** + * Return whether the model is compressible or not. This model is + * incompressible. + */ + bool is_compressible () const override; + + /** + * Function to compute the material properties in @p out given the + * inputs in @p in. + */ + void evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + private: + double reference_density; + double reference_temperature; + double eta_L; + double eta_U; + double jump_height; + double thermal_expansion_coefficient; + double reference_specific_heat; + double thermal_conductivity; + }; + + + + template + bool + SimplerWithCrust:: + is_compressible () const + { + return false; + } + + + + template + void + SimplerWithCrust:: + evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out ) const + { + for (unsigned int i=0; ijump_height) + out.viscosities[i] = eta_U; + else + out.viscosities[i] = eta_L; + + out.densities[i] = reference_density * (1.0 - thermal_expansion_coefficient * (in.temperature[i] - reference_temperature)); + out.thermal_expansion_coefficients[i] = thermal_expansion_coefficient; + out.specific_heat[i] = reference_specific_heat; + out.thermal_conductivities[i] = thermal_conductivity; + out.compressibilities[i] = 0.0; + out.entropy_derivative_pressure[i] = 0.0; + out.entropy_derivative_temperature[i] = 0.0; + for (unsigned int c=0; c + void + SimplerWithCrust::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Simpler with crust model"); + { + prm.declare_entry ("Reference density", "3300.", + Patterns::Double (0.), + "Reference density $\\rho_0$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. The reference temperature is used " + "in the density formula. Units: \\si{\\kelvin}."); + prm.declare_entry ("Lower viscosity", "1e20", + Patterns::Double (0.), + "The value of the viscosity $\\eta_L$ in the lower layer. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Upper viscosity", "1e23", + Patterns::Double (0.), + "The value of the viscosity $\\eta_U$ in the upper layer. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Jump height", "100000.", + Patterns::Double (0.), + "The height at which the viscosity changes. Units: \\si{\\meter}."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Reference specific heat", "1250.", + Patterns::Double (0.), + "The value of the specific heat capacity $c_p$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Thermal expansion coefficient", "2e-5", + Patterns::Double (0.), + "The value of the thermal expansion coefficient $\\alpha$. " + "Units: \\si{\\per\\kelvin}."); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + SimplerWithCrust::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Simpler with crust model"); + { + reference_density = prm.get_double ("Reference density"); + reference_temperature = prm.get_double ("Reference temperature"); + eta_L = prm.get_double ("Lower viscosity"); + eta_U = prm.get_double ("Upper viscosity"); + jump_height = prm.get_double ("Jump height"); + thermal_conductivity = prm.get_double ("Thermal conductivity"); + reference_specific_heat = prm.get_double ("Reference specific heat"); + thermal_expansion_coefficient = prm.get_double ("Thermal expansion coefficient"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::none; + this->model_dependence.density = NonlinearDependence::none; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(SimplerWithCrust, + "simpler with crust", + "A material model that is like the ``simpler'' model but " + "has a jump in the viscosity at a specified depth.") + } +} diff --git a/cookbooks/future/mantle_setup_restart.prm.bak b/cookbooks/future/mantle_setup_restart.prm.bak new file mode 100644 index 00000000000..1117b749463 --- /dev/null +++ b/cookbooks/future/mantle_setup_restart.prm.bak @@ -0,0 +1,30 @@ +include ./mantle_setup_start.prm + +set Dimension = 2 +set End time = 3e8 +set Resume computation = true +set Nonlinear solver tolerance = 1e-4 + +subsection Melt settings + set Include melt transport = true + set Melt scaling factor threshold = 1e-8 +end + +subsection Solver parameters + subsection Operator splitting parameters + set Reaction time step = 2e2 + set Reaction time steps per advection step = 20 + end +end + +subsection Material model + subsection Melt boukare + set Melting time scale for operator splitting = 1e3 + end +end + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 2 + set Time steps between mesh refinement = 3 +end diff --git a/cookbooks/future/mantle_setup_start.prm b/cookbooks/future/mantle_setup_start.prm index 4b733a7e240..98a79045800 100644 --- a/cookbooks/future/mantle_setup_start.prm +++ b/cookbooks/future/mantle_setup_start.prm @@ -7,7 +7,7 @@ set Dimension = 2 set Use years in output instead of seconds = true set End time = 1.5e8 # run until 1.5e8, then restart with Melt scaling factor threshold = 1e-8 set Output directory = output_ULVZ_2 -set Nonlinear solver scheme = iterated IMPES +set Nonlinear solver scheme = iterated Advection and Stokes set Max nonlinear iterations = 20 #set Resume computation = true @@ -101,7 +101,7 @@ end subsection Boundary composition model set Allow fixed composition on outflow boundaries = false set Fixed composition boundary indicators = top - set Model name = initial composition + set List of model names = initial composition end subsection Heating model diff --git a/cookbooks/future/mantle_setup_start.prm.bak b/cookbooks/future/mantle_setup_start.prm.bak new file mode 100644 index 00000000000..4b733a7e240 --- /dev/null +++ b/cookbooks/future/mantle_setup_start.prm.bak @@ -0,0 +1,192 @@ +# Model for melt transport within the lowermost mantle. +# This input file runs a model without melt transport to +# steady state, and the file mantle_setup_restart.prm +# restarts it with melt migration enabled. + +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 1.5e8 # run until 1.5e8, then restart with Melt scaling factor threshold = 1e-8 +set Output directory = output_ULVZ_2 +set Nonlinear solver scheme = iterated IMPES +set Max nonlinear iterations = 20 + +#set Resume computation = true +set Pressure normalization = surface + +# The top of the model is 200 km above the CMB, so we have to choose the surface pressure +# accordingly. With this value, the CMB pressure should be 136 GPa. +set Surface pressure = 1.25e11 +set Adiabatic surface temperature = 2510 +set Use conduction timestep = true +set Use operator splitting = true +set Maximum time step = 1e6 + +subsection Compositional fields + set Number of fields = 3 + set Names of fields = porosity, molar_Fe_in_solid, molar_Fe_in_melt +end + +# The melt scaling factor threshold controls the porosity above which melt is transported +# in a given cell of the model. Since the value of 1e20 is never reached anywhere in the +# model, setting the parameter to this value disables melt transport. For the restart, this +# value is decreased to enable melt transport. +subsection Melt settings + set Include melt transport = true + set Melt scaling factor threshold = 1e20 +end + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-7 + set GMRES solver restart length = 200 + end + + subsection Operator splitting parameters + set Reaction time step = 4e3 #2e2 for the restart + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 600000 + set Y extent = 200000 + set X periodic = false + set X repetitions = 3 + end +end + +subsection Initial temperature model + set List of model names = adiabatic, function + + subsection Adiabatic + set Age bottom boundary layer = 5e7 + + subsection Function + set Function expression = 0; 0.07; 0.07 + end + end + + subsection Function + set Function constants = amplitude=500, width=50000, b=100000, x0=300000 #25000 + set Function expression = 10 * exp(-((x-x0)*(x-x0)/(2*5000*5000)+y*y/(2*5000*5000))) + end +end + +subsection Initial composition model + set List of model names = function, porosity + + subsection Function + set Function expression = 0; 0.07; 0.07 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = + set Prescribed velocity boundary indicators = + set Tangential velocity boundary indicators = bottom, left, right +end + +subsection Boundary temperature model + set Allow fixed temperature on outflow boundaries = false + set Fixed temperature boundary indicators = bottom, top + set List of model names = initial temperature + + subsection Initial temperature + set Maximal temperature = 4000 + end +end + +subsection Boundary composition model + set Allow fixed composition on outflow boundaries = false + set Fixed composition boundary indicators = top + set Model name = initial composition +end + +subsection Heating model + set List of model names = adiabatic heating, shear heating, latent heat melt + + subsection Latent heat melt + set Melting entropy change = 0 + set Retrieve entropy change from material model = true + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +subsection Material model + set Model name = melt boukare + + subsection Melt boukare + set Thermal conductivity = 8.5 + set Reference shear viscosity = 1e23 + set Reference bulk viscosity = 1e23 + set Reference volumes = 2.534e-05, 2.445e-05, 1.206e-05, 1.125e-05, 1.9e-5, 1.218e-05, 1.218e-05 + set Thermal viscosity exponent = 10 + set Thermal bulk viscosity exponent = 10 + set Exponential melt weakening factor = 20 + set Include melting and freezing = true + set Melting time scale for operator splitting = 1e5 + set Fe mantle melting temperature = 2774.5 + set Mg mantle melting temperature = 4171.2 + set Reference permeability = 5e-12 + end +end + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 2 + set Time steps between mesh refinement = 3 + set Strategy = composition threshold, minimum refinement function + + subsection Minimum refinement function + set Coordinate system = cartesian + set Function expression = (x>285000 && x<315000) ? 7 : 4 + end + + subsection Composition threshold + set Compositional field thresholds = 2e-4, 1, 1 + end +end + +subsection Boundary fluid pressure model + subsection Density + set Density formulation = fluid density + end +end + +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, visualization, composition statistics + + subsection Visualization + set Time between graphical output = 1e6 + set List of output variables = material properties, nonadiabatic temperature, melt fraction, melt material properties, named additional outputs + set Output format = vtu + set Interpolate output = false + + subsection Material properties + set List of material properties = density,thermal expansivity,specific heat,viscosity,compressibility + end + + subsection Melt material properties + set List of properties = compaction viscosity, permeability, fluid density + end + end +end + +subsection Checkpointing + # The wall time between performing checkpoints. If 0, will use the + # checkpoint step frequency instead. Units: Seconds. + set Time between checkpoint = 900 +end + +subsection Termination criteria + set Checkpoint on termination = true +end diff --git a/cookbooks/future/net_rotation.prm.bak b/cookbooks/future/net_rotation.prm.bak new file mode 100644 index 00000000000..ed9b661979d --- /dev/null +++ b/cookbooks/future/net_rotation.prm.bak @@ -0,0 +1,78 @@ +# A 2d shell with free slip top and bottom boundary to demonstrate +# net rotation removal + +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 1.5e9 +set Output directory = output-netrot + +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal expansion coefficient = 4e-5 + set Viscosity = 1e20 + end +end + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Outer radius = 6336000 + set Opening angle = 360 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = bottom, top +end + +subsection Nullspace removal + # net rotation|net translation|angular momentum|translational momentum + set Remove nullspace = net rotation +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 4273 + set Outer temperature = 973 + end +end + +subsection Initial temperature model + set Model name = spherical hexagonal perturbation +end + +subsection Gravity model + set Model name = ascii data +end + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 0 + set Strategy = temperature + set Time steps between mesh refinement = 5 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics, depth average + + subsection Visualization + set Output format = vtu + set Time between graphical output = 1 + set Number of grouped files = 0 + end + + subsection Depth average + set Time between graphical output = 1e6 + end +end + +subsection Heating model + set List of model names = shear heating +end diff --git a/cookbooks/future/periodic_box.prm.bak b/cookbooks/future/periodic_box.prm.bak new file mode 100644 index 00000000000..b675d2d538e --- /dev/null +++ b/cookbooks/future/periodic_box.prm.bak @@ -0,0 +1,106 @@ +# This is a simple 2d setup that is periodic in x direction, which +# requires removing the nullspace (here we use "net x translation") + +set Dimension = 2 +set CFL number = 1.0 +set End time = 1e9 +set Output directory = output-periodic_box +set Resume computation = false +set Start time = 0 +set Adiabatic surface temperature = 0 +set Surface pressure = 0 +set Pressure normalization = no +set Use years in output instead of seconds = true +set Nonlinear solver scheme = single Advection, single Stokes + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Top temperature = 0.0 + set Bottom temperature = 1000.0 + end +end + +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Temperature polynomial degree = 2 + set Use locally conservative discretization = false + + subsection Stabilization parameters + set alpha = 2 + set beta = 0.078 + set cR = 0.5 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X periodic = true + set X extent = 1.e6 + set Y extent = 5.e5 + set Z extent = 5.e5 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if((sqrt((x-1.e5)^2+(y-4.0e5)^2)<5.0e4) | (sqrt((x-3.e5)^2+(y-2.e5)^2)<1.0e5) , 800.0, 0) + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3300 + set Reference specific heat = 1250 + set Reference temperature = 0.0 + set Thermal conductivity = 4.7 + set Thermal expansion coefficient = 4e-5 + set Viscosity = 1.e20 + end +end + +subsection Mesh refinement + set Additional refinement times = + set Initial adaptive refinement = 2 + set Initial global refinement = 6 + set Refinement fraction = 0.3 + set Coarsening fraction = 0.03 + set Strategy = thermal energy density + set Time steps between mesh refinement = 10 +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = bottom, top +end + +subsection Nullspace removal + set Remove nullspace = net x translation +end + +subsection Postprocess + set List of postprocessors = visualization + + subsection Visualization + set List of output variables = + set Number of grouped files = 1 + set Output format = vtu + set Time between graphical output = 1.e3 + end +end diff --git a/cookbooks/future/radiogenic_heating.prm.bak b/cookbooks/future/radiogenic_heating.prm.bak new file mode 100644 index 00000000000..1d04f7d6a78 --- /dev/null +++ b/cookbooks/future/radiogenic_heating.prm.bak @@ -0,0 +1,104 @@ +############### Global parameters +# We use a 2d setup. Since it takes some time for +# the model to reach a steady state we set the +# end time to approximately 2 million years. + +set Dimension = 2 +set Start time = 0 +set End time = 2e6 +set Use years in output instead of seconds = false +set Output directory = output-radiogenic_heating + +subsection Heating model + set List of model names = constant heating + + subsection Constant heating + set Radiogenic heating rate = 1 + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1000000 + set Y extent = 1000000 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +############### Boundary conditions +# We only fix the temperature at the upper boundary, the other boundaries +# are isolating. +subsection Boundary temperature model + set Fixed temperature boundary indicators = top + set List of model names = box + + subsection Box + set Top temperature = 1000 + end +end + +# To guarantuee a steady downward flow, we fix the velocity +# at the top and bottom, and set it to free slip on the sides. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = bottom:function, top:function + set Tangential velocity boundary indicators = left, right + + subsection Function + set Function expression = 0;-1 + set Variable names = x,y + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1000.0 + set Variable names = x,y + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3400 + set Reference specific heat = 1000 + set Reference temperature = 1000 + set Thermal conductivity = 0.0 + set Thermal expansion coefficient = 0.0 + set Thermal viscosity exponent = 0.0 + set Viscosity = 1e21 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 6 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization + + subsection Visualization + set Number of grouped files = 0 + set Output format = vtu + + # We are only interested in the last timestep (when the system hast reached + # a steady state). For following the development of the system or checking + # if the solution already reached steady state, this parameter can be set + # to a smaller value. + set Time between graphical output = 1e4 + set List of output variables = density + end +end diff --git a/cookbooks/future/radiogenic_heating_function.prm.bak b/cookbooks/future/radiogenic_heating_function.prm.bak new file mode 100644 index 00000000000..57b8d692dac --- /dev/null +++ b/cookbooks/future/radiogenic_heating_function.prm.bak @@ -0,0 +1,108 @@ +############### Global parameters +# We use a 2d setup. Since it takes some time for +# the model to reach a steady state we set the +# end time to approximately 2 million years. + +set Dimension = 2 +set Start time = 0 +set End time = 3e6 +set Use years in output instead of seconds = false +set Output directory = output-radiogenic_heating_function + +# As we only want to look at the effects of radiogenic heating, this one +# is the only active heating plugin. +subsection Heating model + set List of model names = function + + subsection Function + set Variable names = x,y,t + set Function constants = length=1000000 + set Function expression = if(t<2e6,x / length, 0.0) + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1000000 + set Y extent = 1000000 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +############### Boundary conditions +# We only fix the temperature at the upper boundary, the other boundaries +# are isolating. +subsection Boundary temperature model + set Fixed temperature boundary indicators = top + set List of model names = box + + subsection Box + set Top temperature = 1000 + end +end + +# To guarantuee a steady downward flow, we fix the velocity +# at the top and bottom, and set it to free slip on the sides. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = bottom:function, top:function + set Tangential velocity boundary indicators = left, right + + subsection Function + set Function expression = 0;-1 + set Variable names = x,y + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1000.0 + set Variable names = x,y + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3400 + set Reference specific heat = 1000 + set Reference temperature = 1000 + set Thermal conductivity = 0.0 + set Thermal expansion coefficient = 0.0 + set Thermal viscosity exponent = 0.0 + set Viscosity = 1e21 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 6 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization + + subsection Visualization + set Number of grouped files = 0 + set Output format = vtu + + # We are only interested in the last timestep (when the system hast reached + # a steady state). For following the development of the system or checking + # if the solution already reached steady state, this parameter can be set + # to a smaller value. + set Time between graphical output = 1e4 + set List of output variables = density + end +end diff --git a/cookbooks/future/sphere.prm.bak b/cookbooks/future/sphere.prm.bak new file mode 100644 index 00000000000..c12f5efbbe0 --- /dev/null +++ b/cookbooks/future/sphere.prm.bak @@ -0,0 +1,74 @@ +# A simple setup for convection in a sphere +# manual for more information. +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 5.0e8 +set Output directory = output-sphere + +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal expansion coefficient = 4e-5 + set Viscosity = 1e20 + end +end + +subsection Geometry model + set Model name = sphere + + subsection Sphere + set Radius = 1250000 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = top +end + +subsection Nullspace removal + set Remove nullspace = net rotation +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top + set List of model names = constant + + subsection Constant + set Boundary indicator to temperature mappings = top: 0.0 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = if( sqrt( (x-5.e5)^2 + (y-5.e5)^2) < 1.e5, 0, 100) + end +end + +subsection Gravity model + set Model name = radial linear + + subsection Radial linear + set Magnitude at bottom = 0.0 + set Magnitude at surface = 4.5 + end +end + +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 2 + set Strategy = temperature + set Time steps between mesh refinement = 15 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics + + subsection Visualization + set Output format = vtu + set Time between graphical output = 1e6 + set Number of grouped files = 0 + end +end diff --git a/cookbooks/geomio/doc/geomIO.prm.bak b/cookbooks/geomio/doc/geomIO.prm.bak new file mode 100644 index 00000000000..3ac91a8771b --- /dev/null +++ b/cookbooks/geomio/doc/geomIO.prm.bak @@ -0,0 +1,40 @@ +subsection Geometry model + set Model name = box + + # The extents of the box is the same as the width + # and height of the drawing in px + # (an A4 page = 7350x10500 px). + subsection Box + set X extent = 7350 + set Y extent = 10500 + end +end + +# We need one compositional field that will be assigned +# the values read in from the ascii data plugin. +subsection Compositional fields + set Number of fields = 1 +end + +# We use the ascii data plugin to read in the file created with geomIO. +subsection Initial composition model + set Model name = ascii data + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/data/initial-composition/ascii-data/test/ + set Data file name = jelly.txt + end +end + +# We refine the mesh where compositional gradients are +# high, i.e. at the boundary between the different phases +# assigned to the compositional field through the initial +# condition. +subsection Mesh refinement + set Refinement fraction = 0.99 + set Coarsening fraction = 0 + set Initial global refinement = 5 + set Initial adaptive refinement = 4 + set Time steps between mesh refinement = 0 + set Strategy = composition +end diff --git a/cookbooks/geomio/geomIO.prm.bak b/cookbooks/geomio/geomIO.prm.bak new file mode 100644 index 00000000000..96034af10f6 --- /dev/null +++ b/cookbooks/geomio/geomIO.prm.bak @@ -0,0 +1,96 @@ +# A model using the ascii data plugin to read in a file +# generated by geomIO. +# See the manual for more information. + +set Output directory = output-geomIO +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 0 +set Adiabatic surface temperature = 1613.0 + +subsection Geometry model + set Model name = box + + # The extents of the box in m is the same as the width + # and height of the drawing in px + # (an A4 page = 7350x10500 px). + subsection Box + set X extent = 7350 + set Y extent = 10500 + end +end + +subsection Initial temperature model + set Model name = adiabatic + + subsection Adiabatic + set Amplitude = 300 + set Radius = 250000 + end +end + +# We need one compositional field that will be assigned +# the values read in from the ascii data plugin. +subsection Compositional fields + set Number of fields = 1 +end + +# We use the ascii data plugin to read in the file created with geomIO. +subsection Initial composition model + set Model name = ascii data + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/data/initial-composition/ascii-data/test/ + set Data file name = jelly.txt + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = box +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = bottom:function,left:function,right:function,top:function + + subsection Function + set Function expression = 1;0 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Viscosity = 1e21 + end +end + +# We refine the mesh where compositional gradients are +# high, i.e. at the boundary between the different phases +# assigned to the compositional field through the initial +# condition. +subsection Mesh refinement + set Refinement fraction = 0.99 + set Coarsening fraction = 0 + set Initial global refinement = 5 + set Initial adaptive refinement = 4 + set Time steps between mesh refinement = 0 + set Strategy = composition +end + +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, heat flux statistics, visualization + + subsection Visualization + set Time between graphical output = 0.01 + end +end diff --git a/cookbooks/global_melt/doc/global_melt.prm.bak b/cookbooks/global_melt/doc/global_melt.prm.bak new file mode 100644 index 00000000000..5c82d601395 --- /dev/null +++ b/cookbooks/global_melt/doc/global_melt.prm.bak @@ -0,0 +1,248 @@ +# Cookbook for a global-scale 2D box mantle convection model +# with melt migration. +# In this file we will go through all of the steps that are +# required for adding melting and melt transport to a mantle +# convection simulation. + +# For models with melt migration, there is a nonlinear coupling between +# the Stokes system, the temperature, and the advection equation for the +# porosity (several material properties, such as the viscosities and the +# permeability depend nonlinearly on the porosity; and changes in temperature +# determine how much material is melting or freezing). +# Because of that, we use a nonlinear solver scheme ('iterated Advection and Stokes') +# that iterates between all of these equations, and we have to set its +# solver tolerance and the maximum number of iterations separately from +# the linear solver parameters. +set Nonlinear solver scheme = iterated Advection and Stokes +set Max nonlinear iterations = 20 +set Nonlinear solver tolerance = 1e-5 + +# In addition, melting and freezing normally happens on a much faster +# time scale than the flow of melt, so we want to decouple the advection +# of melt (and temperature) and the melting process itself. To do that, +# we use the operator splitting scheme, and define that for every +# advection time step, we want to do at least 10 reaction time steps. +# If these time steps would be larger than 10,000 years, we will do +# more reaction time steps (so that reaction time step size never exceeds +# 10,000 years). Here, we also specify the Stokes linear solver tolerance +# and maximum number of cheap Stokes solver steps to improve the nonlinear +# convergence behavior. +set Use operator splitting = true + +subsection Solver parameters + subsection Operator splitting parameters + set Reaction time step = 1e4 + set Reaction time steps per advection step = 10 + end + + subsection Stokes solver parameters + set Linear solver tolerance = 1e-8 + set Number of cheap Stokes solver steps = 100 + end +end + +subsection Melt settings + # In addition, we now also specify in the model settings that we want to + # run a model with melt transport. + set Include melt transport = true +end + +##################### Settings for melt transport ######################## + +# In models with melt transport, we always need a compositional field with +# the name 'porosity'. Only the field with that name will be advected with +# the melt velocity, all other compositional fields will continue to work +# as before. Material models will typically query for the field with the +# name porosity to compute all melt material properties. +# In addition, the 'melt global' material model also requires a field with the +# name 'peridotite'. This field is used to track how much material has been +# molten at each point of the model, so it tracks the information how the +# composition of the rock changes due to partial melting events (sometimes +# also called depletion). This is important, because usually less melt is +# generated for a given temperature and pressure if the rock has undergone +# melting before. Typically, material properties like the density are also +# different for more or less depleted material. +subsection Compositional fields + set Number of fields = 2 + set Names of fields = porosity, peridotite +end + +##################### Initial conditions ######################## + +# Now that our model uses compositional fields, we also need initial +# conditions for the composition. +# We use the function plugin to set both fields to zero at the beginning +# of the model run. +subsection Initial composition model + set Model name = function + + subsection Function + set Function expression = 0; 0 + set Variable names = x,y + end +end + +##################### Boundary conditions ######################## + +# We again choose the initial composition as boundary condition +# for all compositional fields. +subsection Boundary composition model + set List of model names = initial composition +end + +# Models with melt transport also need an additional boundary condition: +# the gradient of the fluid pressure at the model boundaries. This boundary +# condition indirectly also prescribes boundary conditions for the melt velocity, +# as the melt velocity is related to the fluid pressure gradient via Darcy's law. +# If we choose the fluid pressure gradient = solid density * gravity, melt will +# flow in and out of the model (even if the solid can not flow out) according to +# the dynamic fluid pressure in the model. Conversely, if we choose the +# fluid pressure gradient = fluid density * gravity, melt will flow in or out +# with the same velocity as the solid (so for a closed boundary, no melt will +# flow in or out). This is what we choose as our boundary condition here. +subsection Boundary fluid pressure model + set Plugin name = density + + subsection Density + set Density formulation = fluid density + end +end + +##################### Material properties ######################## + +# In addition to the material properties for the solid rock, +# we also have to specify properties for the melt. +subsection Material model + set Model name = melt global + + subsection Melt global + # First we describe the parameters for the solid, in the same way + # we did in the model without melt transport + set Thermal conductivity = 4.7 + set Reference solid density = 3400 + set Thermal expansion coefficient = 2e-5 + set Reference shear viscosity = 5e21 + set Thermal viscosity exponent = 7 + set Reference temperature = 1600 + set Solid compressibility = 4.2e-12 + + # The melt usually has a different (lower) density than the solid. + set Reference melt density = 3000 + + # The permeability describes how well the pores of a porous material + # are connected (and hence how fast melt can flow through the rock). + # It is computed as the product of the reference value given here + # and the porosity cubed. This means that the lower the porosity is + # the more difficult it is for the melt to flow. + set Reference permeability = 1e-8 + + # The bulk viscosity describes the resistance of the rock to dilation + # and compaction. Melt can only flow into a region that had no melt + # before if the matrix of the solid rock expands, so this parameter + # also limits how fast melt can flow upwards. + # The bulk viscosity is computed as the reference value given here times + # a term that scales with one over the porosity. This means that for zero + # porosity, the rock can not dilate/compact any more, which is the same + # behavior that we have for solid mantle convection. + set Reference bulk viscosity = 1e19 + + # In dependence of how much melt is present, we also weaken the shear + # viscosity: The more melt is present, the weaker the rock gets. + # This scaling is exponential, following the relation + # viscosity ~ exp(-alpha * phi), + # where alpha is the parameter given here, and phi is the porosity. + set Exponential melt weakening factor = 10 + + # In the same way the shear viscosity is reduced with increasing temperature, + # we also prescribe the temperature-dependence of the bulk viscosity. + set Thermal bulk viscosity exponent = 7 + + # Analogous to the compressibility of the solid rock, we also define a + # comressibility for the melt (which is generally higher than for the solid). + # As we do not want our compressibility to depend on depth, we set the + # pressure derivative to zero. + set Melt compressibility = 1.25e-11 + set Melt bulk modulus derivative = 0.0 + + # Finally, we prescribe the viscosity of the melt, which is used in Darcy's + # law. The lower this viscosity, the faster melt can flow. + set Reference melt viscosity = 1 + + # change the density contrast of depleted material (in kg/m^3) + set Depletion density change = -200.0 + + # How much melt has been generated and subsequently extracted from a particular + # volume of rock (how 'depleted' that volume of rock is) usually changes the + # solidus. The more the material has been molten already, the less melt will be + # generated afterwards for the same pressure and temperature conditions. We + # model this using a simplified, linear relationship, saying that to melt 100% + # of the rock the temperature has to be 200 K higher than to melt it initially. + set Depletion solidus change = 200 + + # We also have to determine how fast melting and freezing should happen. + # Here, we choose a time scale of 10,000 years, which is a relatively long time + # (or in other words, slow melting rate), but because this is a global model + # and the time steps are big, it should be sufficient. + set Melting time scale for operator splitting = 1e4 + end +end + +##################### Mesh refinement ######################### + +# For the model with melt migration, we use adaptive refinement. +# We make use of two different refinement criteria: we set a minimum of 5 global +# refinements everywhere in the model (which is the same resolution as for the +# model without melt), and we refine in regions where melt is present, to be +# precise, everywhere where the porosity is bigger than 1e-6. +# We adapt the mesh every 5 time steps. +subsection Mesh refinement + set Coarsening fraction = 0.05 + set Refinement fraction = 0.8 + set Initial adaptive refinement = 2 + set Initial global refinement = 5 + set Strategy = composition threshold, minimum refinement function, boundary + set Time steps between mesh refinement = 5 + + # minimum of 5 global refinements + subsection Minimum refinement function + set Function expression = 5 + end + + # refine where the porosity is bigger than 1e-6 + subsection Composition threshold + set Compositional field thresholds = 1e-6,1.0 + end + + # refine at top and bottom boundary + subsection Boundary + set Boundary refinement indicators = top, bottom + end +end + +##################### Postprocessing ######################## + +# In addition to the visualization output, we select a number +# of postprocessors that allow us to compute some statistics +# about the output (to see how much the model without and the +# model with melt migration differ), and in particular we use +# the "depth average" postprocessor that will allow us to plot +# depth-averaged model quantities over time. +subsection Postprocess + set List of postprocessors = visualization, composition statistics, velocity statistics, temperature statistics, depth average + + # For the model with melt migration, also add a visualization + # postprocessor that computes the material properties relevant + # to migration (permeability, viscosity of the melt, etc.). + + subsection Visualization + set List of output variables = material properties, nonadiabatic temperature, strain rate, melt material properties + + subsection Material properties + set List of material properties = density, viscosity, thermal expansivity + end + + subsection Melt material properties + set List of properties = fluid density, permeability, fluid viscosity, compaction viscosity + end + end +end diff --git a/cookbooks/global_melt/doc/global_no_melt.prm.bak b/cookbooks/global_melt/doc/global_no_melt.prm.bak new file mode 100644 index 00000000000..c6c5eaad18b --- /dev/null +++ b/cookbooks/global_melt/doc/global_no_melt.prm.bak @@ -0,0 +1,211 @@ +# Model setup for mantle convection in a 2D box without melting. +# This file is used as a starting point for a cookbook that +# explains how to add melting and melt transport to a mantle +# convection simulation. + +set Dimension = 2 +set Adiabatic surface temperature = 1600 +set Maximum time step = 1e6 +set Output directory = output-global_no_melt +set Use years in output instead of seconds = true + +# The end time of the simulation. Because we want to see how upwellings +# and downwellings evolve over time, and if differences develop between +# the model with and without melt migration, we set the end time to 200 Ma. +set End time = 2e8 + +# We choose a stricter than default linear Stokes solver tolerance, +# to be consistent with the global_melt cookbook. +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-8 + set Number of cheap Stokes solver steps = 100 + end +end + +# We prescribe free-slip boundary conditions on all +# sides. +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, top, bottom +end + +# We also choose relatively large values for the stabilization parameters: +# The model resolution is very coarse (in order for this model to run in a +# short time), so we want to make sure that no temperature over- and +# undershoots will develop. In a model with melting this would be +# particularly problematic, as large amounts of melt could be generated +# by temperature spikes, and we want to be consistent between the model +# with and without melt transport. +subsection Discretization + subsection Stabilization parameters + set beta = 0.5 + set cR = 1 + end +end + +##################### Initial conditions ######################## + +# We choose an adiabatic temperature profile as initial condition, +# with conductive temperature profiles in the top and bottom boundary +# layers, which were computed using a half space cooling model. +# The cold top boundary layer corresponds to an age of 70 Ma, +# and the hot top boundary layer corresponds to an age of 700 Ma. +# A small temperature perturbation is added at the bottom of the +# domain. To make the model asymmetric, we place it in a distance of +# x = 2900 km from the left boundary. +# Temperatures from both initial temperature models we specify are +# added (by default). +subsection Initial temperature model + set List of model names = adiabatic, function + + subsection Adiabatic + set Age bottom boundary layer = 7e8 + set Age top boundary layer = 7e7 + + subsection Function + set Function expression = 0;0 + end + end + + subsection Function + set Function constants = r=350000, amplitude=50 + set Function expression = if((x-2900000)*(x-2900000)+y*y310000,0.05,0.05*y/310000); 0 + end +end + +# We prescribe a boundary traction in vertical direction at the bottom and +# and right boundaries, setting it to the lithostatic pressure to allow +# for free in- and outflow of material. +subsection Boundary traction model + set Prescribed traction boundary indicators = right y:initial lithostatic pressure, bottom y:initial lithostatic pressure + + subsection Initial lithostatic pressure + set Number of integration points = 1000 + set Representative point = 2000000,0 + end +end + +# The initial temperature follows an adiabatic profile with a cold +# boundary layer added at the surface. Since we model a plate moving away +# from a ridge with 5 cm/yr, we pick an according age for this boundary +# layer (increasing from the ridge on the left towards the right as the +# plate gets older. +# We additionally add a small temperature perturbation near the ridge +# to reduce the viscosity below the ridge axis where strong deformation +# occurs due to our boundary conditions (material has to flow upwards +# beneath the ridge axis and horizontally towards the right at the +# surface). +subsection Initial temperature model + set List of model names = adiabatic, function + + subsection Adiabatic + set Age bottom boundary layer = 0.0 + set Top boundary layer age model = function + + subsection Age function + set Function expression = 0.01 + x / 0.05 + end + end + + subsection Function + set Function constants = DeltaT = 300, b = 0, width = 10000, c=410000 + set Function expression = DeltaT * exp(-((x-b)*(x-b)+(y-c)*(y-c))/(2*width*width)) + set Variable names = x,y + end +end + +# The temperature at the boundary is taken from the initial conditions. +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom, right + set List of model names = initial temperature + + subsection Initial temperature + set Minimal temperature = 293 + set Maximal temperature = 1623 + end +end + +# Our only compositional field is the grain size, and we use particles +# to track it. In order for the grain size to not just be tracked, but +# to evolve over time depending on the temperature and deformation in +# the model, we select ``grain_size'' as the mapped particle property +# for the grain_size compositional field. +subsection Compositional fields + set Number of fields = 1 + set Names of fields = grain_size + set Compositional field methods = particles + set Mapped particle properties = grain_size:grain_size +end + +# We set the initial grain size to 5 mm, with a reduction at the ridge +# axis, again to allow for easy deformation there. +subsection Initial composition model + set Model name = function + + subsection Function + set Function constants = DeltaC = -29e-4, b = 0, width = 30000, c=397000 + set Function expression = 5e-3 + DeltaC * exp(-((x-b)*(x-b)+(y-c)*(y-c))/(2*width*width)) + set Variable names = x,y + end +end + +# The composition at the boundary is taken from the initial conditions. +subsection Boundary composition model + set Fixed composition boundary indicators = bottom, right + set List of model names = initial composition +end + +# We use the grain size material model, which implements the equations +# for grain size evolution. +subsection Material model + # Because we use the GMG solver, we need to average the viscosity. + set Material averaging = project to Q1 only viscosity + set Model name = grain size + + subsection Grain size model + # We use typical upper-mantle material properties. + set Reference density = 3300 + set Reference specific heat = 1200 + set Thermal expansion coefficient = 3.3e-5 + + # Diffusion creep has a prefactor, a temperature dependence defined by the + # activation energy, a pressure dependence defined by the activation volume + # and a grain size dependence. We take the activation energy from Hirth & + # Kohlstedt, 2003, and pick the prefactor and activation volume so that we + # get a reasonable upper mantle viscosity profile and a balance between + # diffusion and dislocation creep. + set Diffusion creep prefactor = 5e-15 + set Diffusion activation energy = 3.75e5 + set Diffusion activation volume = 4e-6 + set Diffusion creep grain size exponent = 3 + + # Dislocation creep has a prefactor, a temperature dependence defined by the + # activation energy, a pressure dependence defined by the activation volume + # and a strain-rate dependence defined by the exponent. We take the activation + # energy and volume from Hirth & Kohlstedt, 2003, and pick the prefactor so + # that we get a reasonable upper mantle viscosity and a balance between + # diffusion and dislocation creep. + set Dislocation creep prefactor = 1e-15 + set Dislocation activation energy = 5.3e5 + set Dislocation activation volume = 1.4e-5 + set Dislocation creep exponent = 3.5 + set Dislocation viscosity iteration number = 10000 + + # Grain size is reduced when work is being done by dislocation creep. + # Here, 10% of this work goes into reducing the grain size rather than + # into shear heating. + # Grain size increases with a rate controlled by the grain growth + # constant and a temperature-depndence defined by the activation + # energy. By setting the activation volume to zero, we disable the + # pressure-dependence of grain growth. + # The parameter values are taken from Dannberg et al., 2017, G-cubed, + # with the parameters being based on Faul and Jackson, 2007. + set Work fraction for boundary area change = 0.1 + set Grain growth rate constant = 1.92e-10 + set Grain growth activation energy = 4e5 + set Grain growth activation volume = 0 + + # Viscosity is cut off at a minimum value of 10^16 Pa s + # and a maximum value of 10^23 Pa s. + set Maximum viscosity = 1e23 + set Minimum viscosity = 1e16 + set Maximum temperature dependence of viscosity = 1e8 + end +end + +# The gravity points downward and is set to 10. +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +# We need a high resolution in locations where strong gradients +# in grain size/viscosity occur, which is within the cold plate. +# We therefore refine the mesh for low nonadiabatic temperatures. +subsection Mesh refinement + set Time steps between mesh refinement = 5 + set Initial global refinement = 5 + set Initial adaptive refinement = 1 + set Strategy = nonadiabatic temperature threshold + set Skip solvers on initial refinement = true + set Minimum refinement level = 5 + + subsection Nonadiabatic temperature threshold + set Temperature anomaly type = negative only + set Threshold = 25 + end +end + +# The model includes shear (dissipation) heating and adiabatic heating. +subsection Heating model + set List of model names = shear heating, adiabatic heating +end + +# We use a discontinuous discretization to interpolate from the particles +# to the mesh because the bilinear least squares interpolator can lead to +# jumps of the composition at cell boundaries. +subsection Discretization + set Use discontinuous composition discretization = true +end + +# Below, we describe the variables we want to include in the graphical output. +subsection Postprocess + set List of postprocessors = visualization, composition statistics, velocity statistics, mass flux statistics, particles + + subsection Visualization + set List of output variables = material properties, nonadiabatic temperature, nonadiabatic pressure, strain rate, melt fraction, named additional outputs + set Point-wise stress and strain = true + set Number of grouped files = 0 + set Interpolate output = false + set Output format = vtu + set Time between graphical output = 1e6 + + subsection Material properties + set List of material properties = density, viscosity, thermal expansivity + end + end + + subsection Particles + set Time between data output = 1e6 + end +end + +# Every 10 minutes (600 seconds) we write a restart file that could be used to +# restart a simulation. +subsection Checkpointing + set Time between checkpoint = 600 +end + +subsection Termination criteria + set Checkpoint on termination = true +end + +# We use particles to advect the grain size. +subsection Particles + set Interpolation scheme = bilinear least squares + set List of particle properties = grain size + set Load balancing strategy = remove and add particles + set Minimum particles per cell = 40 + set Maximum particles per cell = 640 + set Integration scheme = rk2 + set Update ghost particles = true + + subsection Interpolator + subsection Bilinear least squares + set Use linear least squares limiter = true + end + end + + subsection Generator + subsection Probability density function + set Number of particles = 500000 + end + end +end diff --git a/cookbooks/heat_flow/heat-flow-plume.prm.bak b/cookbooks/heat_flow/heat-flow-plume.prm.bak new file mode 100644 index 00000000000..3da16ffb5ea --- /dev/null +++ b/cookbooks/heat_flow/heat-flow-plume.prm.bak @@ -0,0 +1,154 @@ +# A model of a plume arriving at the base of a plate. + +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 1e7 +set Use years in output instead of seconds = true +set Output directory = output-heat-flow-plume +set Adiabatic surface temperature = 1600 +set Maximum time step = 1e6 + +############### Parameters describing the model +# Let us choose a box domain (400 km wide and 200 km in depth) +# where we fix the temperature at the bottom and top, +# allow free slip along the bottom, left and right, +# and prescribe the velocity along the top using the +# `function' description. + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 400000 + set Y extent = 200000 + set X repetitions = 2 + end +end + +# In order to allow plume material to flow in with the +# temperature selected in the initial temperature section, +# we apply the initial temperature as the boundary temperature. +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = initial temperature + + subsection Initial temperature + set Maximal temperature = 1600 + set Minimal temperature = 293 + end +end + +# In this model we want material to be able to (1) flow in freely +# through the base, (2) flow freely in the horizontal direction +# through the left and right walls where the vertical velocity is 0, +# and (3) have a velocity of zero at the top boundary. This is +# achieved through a combination of velocity and pressure boundary +# conditions, where only the vertical (y) component of the velocity +# is set to 0 on the left and right walls, while the x and y velocity +# are both set to zero on the top boundary. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left y: function, right y:function, top:function + + subsection Function + set Variable names = x,z + set Function expression = 0;0 + end +end + +# We allow inflow and outflow at the model base by setting the traction +# boundary condition to the initial lithostatic pressure. On the left +# and right boundaries, the x component of the boundary traction is +# also set to the initial lithostatic pressure, which enables horizontal +# inflow and outflow. +subsection Boundary traction model + set Prescribed traction boundary indicators = bottom:initial lithostatic pressure,right x:initial lithostatic pressure, left x:initial lithostatic pressure + + subsection Initial lithostatic pressure + set Representative point = 0,0 + set Number of integration points = 1000 + end +end + +# We then choose a vertical gravity model. +subsection Gravity model + set Model name = vertical +end + +# The initial temperature is set to the value of the +# Adiabatic surface temperature, in this case 1600 K, +# but with a cold boundary layer at the surface and a +# hot thermal anomaly at the base of the model +# representing a plume. The age of the cold top +# boundary layer determines its thickness. +subsection Initial temperature model + set List of model names = adiabatic, function + + subsection Adiabatic + # This is the age of the top boundary layer in years. + set Age top boundary layer = 1 + end + + # The constant DeltaT determines the amplitude of the temperature anomaly, + # which is a 2d Gaussian located at the center of the bottom boundary. + subsection Function + set Variable names = x,z + set Function constants = DeltaT=0 + set Function expression = DeltaT * exp(-((z*z)+(x-200000)*(x-200000))/(5e8)) + end +end + +# This model uses the composition reaction material model, +# where most material properties are constant, except for the +# viscosity and the density, which depend on temperature as +# expressed by the Thermal viscosity exponent and the +# Thermal expansion coefficient. At the Reference temperature, +# the viscosity equals the value set with the Viscosity +# parameter. +subsection Material model + set Model name = composition reaction + + subsection Composition reaction model + set Thermal conductivity = 4.7 + set Thermal expansion coefficient = 1e-4 + set Viscosity = 2e19 + set Thermal viscosity exponent = 10.0 + set Reference temperature = 1600 + end +end + +# This part of this input file describes how many times the +# mesh is refined and what to do with the solution once computed. +# Here, the mesh is designed to be finer at the surface than at +# the bottom of the model to better capture the conductive cooling +# of the plates. It initially undergoes two global refinements and +# four adaptive refinements in the first time step, but is not +# refined further (i.e., it remains static) throughout the model +# run. The adaptive refinements use the minimum refinement function +# to increase the resolution towards the model surface in a +# piece-wise fashion at depths of 7 and 30 kilometers. +subsection Mesh refinement + set Initial adaptive refinement = 4 + set Initial global refinement = 2 + set Time steps between mesh refinement = 0 + set Strategy = minimum refinement function + + subsection Minimum refinement function + set Variable names = depth, z + set Function expression = if(depth<7000,6,if(depth<30000,5,4)) + end +end + +subsection Postprocess + set List of postprocessors = visualization, temperature statistics, heat flux densities + + subsection Visualization + set Time between graphical output = 1e5 + set List of output variables = material properties, heat flux map, vertical heat flux + + subsection Material properties + set List of material properties = density, thermal expansivity, specific heat, viscosity, thermal conductivity + end + end +end diff --git a/cookbooks/heat_flow/heat-flow-terms.prm.bak b/cookbooks/heat_flow/heat-flow-terms.prm.bak new file mode 100644 index 00000000000..68173b55a29 --- /dev/null +++ b/cookbooks/heat_flow/heat-flow-terms.prm.bak @@ -0,0 +1,40 @@ +include $ASPECT_SOURCE_DIR/cookbooks/heat_flow/heat-flow.prm + + +# This is a copy of the heat-flow cookbook, modified to include +# radiogenic heat production and shear heating, and to output +# the different heating terms in a visualization postprocessor. + +set Output directory = output-heat-flow-terms + +subsection Material model + set Model name = composition reaction + + subsection Composition reaction model + set Thermal conductivity = 4.7 + set Thermal expansion coefficient = 1e-4 + + # Changig the viscosity changes the shear heating. + set Viscosity = 3e21 + end +end + +# This is a new section specifying the heating terms +subsection Heating model + set List of model names = function, shear heating + + # Radiogenic heat production. Changing the variable + # Hcrust in the equation below changes the heat + # production rate in the crust. + subsection Function + set Variable names = x,y,t + set Function expression = if(y>93000, Hcrust, Hmantle) + set Function constants = Hcrust=2e-8, Hmantle=7.38e-12 + end +end + +subsection Postprocess + subsection Visualization + set List of output variables = density, heat flux map, vertical heat flux, heating, viscosity + end +end diff --git a/cookbooks/heat_flow/heat-flow.prm.bak b/cookbooks/heat_flow/heat-flow.prm.bak new file mode 100644 index 00000000000..1f7cb70d9cc --- /dev/null +++ b/cookbooks/heat_flow/heat-flow.prm.bak @@ -0,0 +1,143 @@ +# A model of spreading at a mid-ocean ridge. + +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 5e6 +set Use years in output instead of seconds = true +set Output directory = output-heat-flow + +############### Parameters describing the model +# Let us choose a box domain (400 km wide and 100 km in depth) +# where we fix the temperature at the bottom and top, +# allow inflow from the bottom and outflow on the left and right, +# and prescribe the velocity along the top using the +# `function' description. + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 400000 + set Y extent = 100000 + set X repetitions = 4 + set Box origin X coordinate = -200000 + end +end + +# We fix the temperature at the top, representing the Earth's +# surface, and at the bottom, where material flows in and we +# need to prescribe what temperature this material should +# have (in this case, 1600 K). +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1600 + set Top temperature = 293 + end +end + +# The velocity along the top boundary models a spreading +# center of a mid-ocean ridge. The horizontal component of +# the velocity is presribed on both side boundaries to +# cause flow away from the spreading center, while the +# vertical component of the velocity is allowed to evolve +# freely based on the pressure in the model. The bottom +# boundary is left open so that material can flow in. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left x:function, right x:function, top: function + + subsection Function + set Variable names = x,z + + # We can choose a (half-)spreading rate by changing the value of v (in cm/year) + # This value should be somewhere between 1 and 10 (cm/yr). + set Function constants = v=5, cm_per_year=0.01 + set Function expression = if(x>0, v * cm_per_year, -v * cm_per_year); 0 + end +end + +subsection Boundary traction model + set Prescribed traction boundary indicators = left y:initial lithostatic pressure, right y:initial lithostatic pressure + + subsection Initial lithostatic pressure + set Representative point = 0,0 + set Number of integration points = 1000 + end +end + +# We then choose a vertical gravity model and describe the +# initial temperature as a constant (being equivalent to a +# plate age of 0). +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +# The initial temperature is set to a constant value that +# corresponds to the temperature of the sublithospheric +# mantle throughout the model, but subsequently cools +# over time. +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = 1600 + end +end + +# This model uses the composition reaction material model, +# where most material properties are constant. Here, only +# the density depends on temperature as expressed by the +# Thermal expansion coefficient. +subsection Material model + set Model name = composition reaction + + subsection Composition reaction model + set Thermal conductivity = 4.7 + set Thermal expansion coefficient = 1e-4 + set Viscosity = 1e23 + end +end + +# This part of this input file describes how many times the +# mesh is refined and what to do with the solution once computed. +# Here, the mesh is designed to be finer at the surface than at +# the bottom of the model to better capture the conductive cooling +# of the plates. It initially undergoes two global refinements and +# four adaptive refinements in the first time step, but is not +# refined further (i.e., it remains static) throughout the model +# run. The adaptive refinements use the minimum refinement function +# to increase the resolution towards the model surface in a +# piece-wise fashion at depths of 7, 30, and 45 kilometers. +subsection Mesh refinement + set Initial adaptive refinement = 4 + set Initial global refinement = 2 + set Time steps between mesh refinement = 0 + set Strategy = minimum refinement function + + subsection Minimum refinement function + set Variable names = depth, w + set Function expression = if(depth<7000,6,if(depth<30000,5,if(depth<45000,4,3))) + end +end + +subsection Postprocess + set List of postprocessors = visualization, temperature statistics, heat flux statistics + + subsection Visualization + set Time between graphical output = 1e5 + set List of output variables = material properties, heat flux map, vertical heat flux + + subsection Material properties + set List of material properties = density, specific heat, thermal conductivity + end + end +end diff --git a/cookbooks/inclusions/ellipse_pure_shear.prm.bak b/cookbooks/inclusions/ellipse_pure_shear.prm.bak new file mode 100644 index 00000000000..2944de60745 --- /dev/null +++ b/cookbooks/inclusions/ellipse_pure_shear.prm.bak @@ -0,0 +1,13 @@ +include ellipse_ref.prm + +set Output directory = output-ellipse-pure-shear + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left x: function, right x:function, bottom y:function, top y: function + + subsection Function + set Variable names = x,y + set Function constants = v=0.5 + set Function expression = if (x<0.5,v,-v) ; if (y<0.5,-v,v) + end +end diff --git a/cookbooks/inclusions/ellipse_pure_shear_nonlinear.prm.bak b/cookbooks/inclusions/ellipse_pure_shear_nonlinear.prm.bak new file mode 100644 index 00000000000..0f8d409324b --- /dev/null +++ b/cookbooks/inclusions/ellipse_pure_shear_nonlinear.prm.bak @@ -0,0 +1,129 @@ +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = false +set Pressure normalization = volume +set Nonlinear solver scheme = iterated Advection and Stokes +set Output directory = output-ellipse-pure-shear-NL + +subsection Solver parameters + subsection Stokes solver parameters + set Number of cheap Stokes solver steps = 0 + end +end + +subsection Discretization + set Use locally conservative discretization = true +end + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0 + end +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1 + end +end + +############### Parameters describing the compositional field + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y,z + set Function constants = a=0.2, b=0.1, phi=0.52359877559 + set Function expression = if( ( (x-.5)*cos(phi)+(y-.5)*sin(phi))^2/a^2 + \ + ( (x-.5)*sin(phi)-(y-.5)*cos(phi))^2/b^2 < 1, 1, 0) + end +end + +############### Parameters describing the discretization + +subsection Mesh refinement + set Initial adaptive refinement = 3 + set Initial global refinement = 7 + set Refinement fraction = 0.75 + set Strategy = velocity, composition +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics + + subsection Visualization + set List of output variables = density, viscosity, strain rate + end +end + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left x: function, right x:function, bottom y:function, top y: function + + subsection Function + set Variable names = x,y + set Function constants = v=0.5 + set Function expression = if (x<0.5,v,-v) ; if (y<0.5,-v,v) + end +end + +################################################3 + +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + # Reference temperature and viscosity + set Reference temperature = 273 + + # The minimum strain-rate helps limit large viscosities values that arise + # as the strain-rate approaches zero. + # The reference strain-rate is used on the first non-linear iteration + # of the first time step when the velocity has not been determined yet. + set Minimum strain rate = 1.e-2 + set Reference strain rate = 1. + + # Limit the viscosity with minimum and maximum values + set Minimum viscosity = 1e-3 + set Maximum viscosity = 1e3 + set Densities = 1 + set Thermal expansivities = 0 + set Viscosity averaging scheme = harmonic + set Viscous flow law = dislocation + + #matrix inclusion + set Prefactors for dislocation creep = 0.5, 500 + set Stress exponents for dislocation creep = 1, 1 + set Activation energies for dislocation creep = 0, 0 + set Activation volumes for dislocation creep = 0, 0 + + # Plasticity parameters + set Cohesions = 1e50 + end +end diff --git a/cookbooks/inclusions/ellipse_ref.prm.bak b/cookbooks/inclusions/ellipse_ref.prm.bak new file mode 100644 index 00000000000..d59e09701d8 --- /dev/null +++ b/cookbooks/inclusions/ellipse_ref.prm.bak @@ -0,0 +1,94 @@ +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = false +set Pressure normalization = volume + +subsection Solver parameters + subsection Stokes solver parameters + set Number of cheap Stokes solver steps = 0 + end +end + +subsection Discretization + set Use locally conservative discretization = true +end + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Material model + set Model name = simple + set Material averaging = harmonic average + + subsection Simple model + set Reference density = 1 + set Viscosity = 1 + set Density differential for compositional field 1 = 1 + set Composition viscosity prefactor = 0.001 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0 + end +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the compositional field + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y,z + set Function constants = a=0.2, b=0.1, phi=0.52359877559 + set Function expression = if( ( (x-.5)*cos(phi)+(y-.5)*sin(phi))^2/a^2 + \ + ( (x-.5)*sin(phi)-(y-.5)*cos(phi))^2/b^2 < 1, 1, 0) + end +end + +############### Parameters describing the discretization + +subsection Mesh refinement + set Initial adaptive refinement = 3 + set Initial global refinement = 7 + set Refinement fraction = 0.75 + set Strategy = velocity, composition +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics + + subsection Visualization + set List of output variables = density, viscosity, strain rate + end +end diff --git a/cookbooks/inclusions/ellipse_simple_shear.prm.bak b/cookbooks/inclusions/ellipse_simple_shear.prm.bak new file mode 100644 index 00000000000..14d8f083175 --- /dev/null +++ b/cookbooks/inclusions/ellipse_simple_shear.prm.bak @@ -0,0 +1,13 @@ +include ellipse_ref.prm + +set Output directory = output-ellipse-simple-shear + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left y: function, right y:function, bottom: function, top: function + + subsection Function + set Variable names = x,y + set Function constants = v=0.5 + set Function expression = if (y<0.5,-v,+v) ; 0 + end +end diff --git a/cookbooks/inclusions/rectangle_pure_shear.prm.bak b/cookbooks/inclusions/rectangle_pure_shear.prm.bak new file mode 100644 index 00000000000..7e5d4ab1e2f --- /dev/null +++ b/cookbooks/inclusions/rectangle_pure_shear.prm.bak @@ -0,0 +1,13 @@ +include rectangle_ref.prm + +set Output directory = output-rectangle-pure-shear + +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left x: function, right x:function, bottom y:function, top y: function + + subsection Function + set Variable names = x,y + set Function constants = v=0.5 + set Function expression = if (x<0.5,v,-v) ; if (y<0.5,-v,v) + end +end diff --git a/cookbooks/inclusions/rectangle_ref.prm.bak b/cookbooks/inclusions/rectangle_ref.prm.bak new file mode 100644 index 00000000000..d287d3db6f5 --- /dev/null +++ b/cookbooks/inclusions/rectangle_ref.prm.bak @@ -0,0 +1,94 @@ +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = false +set Pressure normalization = volume + +subsection Solver parameters + subsection Stokes solver parameters + set Number of cheap Stokes solver steps = 0 + end +end + +subsection Discretization + set Use locally conservative discretization = true +end + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end + +subsection Material model + set Model name = simple + set Material averaging = harmonic average + + subsection Simple model + set Reference density = 1 + set Viscosity = 1 + set Density differential for compositional field 1 = 1 + set Composition viscosity prefactor = 1000 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0 + end +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the compositional field + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y,z + set Function constants = a=0.2, b=0.1, phi=1.0471975512 + set Function expression = if( abs( (x-.5)*cos(phi)+(y-.5)*sin(phi))infinity, the boundary is a free slip boundary, and for + # P-->0, the boundary is an open boundary (with zero normal stress). + subsection Inner core + subsection Phase change resistance function + set Variable names = x,y,z + set Function expression = 1e-2 # <-- P + end + end +end diff --git a/cookbooks/inner_core_convection/doc/inner_core_traction.part.2.prm.bak b/cookbooks/inner_core_convection/doc/inner_core_traction.part.2.prm.bak new file mode 100644 index 00000000000..2bde3180a1e --- /dev/null +++ b/cookbooks/inner_core_convection/doc/inner_core_traction.part.2.prm.bak @@ -0,0 +1,13 @@ +# The gravity has its maximum value at the boundary of inner and +# outer core, and decreases approximately linearly to zero towards +# the center of the core. +# The Rayleigh number used in the model is given by the magnitude +# of the gravity at the inner core/outer core boundary. +subsection Gravity model + set Model name = radial linear + + subsection Radial linear + set Magnitude at bottom = 0.0 + set Magnitude at surface = 2 # <-- Ra + end +end diff --git a/cookbooks/inner_core_convection/doc/inner_core_traction.part.3.prm.bak b/cookbooks/inner_core_convection/doc/inner_core_traction.part.3.prm.bak new file mode 100644 index 00000000000..79342416a60 --- /dev/null +++ b/cookbooks/inner_core_convection/doc/inner_core_traction.part.3.prm.bak @@ -0,0 +1,11 @@ +subsection Mesh refinement + set Initial global refinement = 4 #this may be more expensive, and should be run on a cluster. + set Initial adaptive refinement = 1 + set Strategy = minimum refinement function + set Time steps between mesh refinement = 0 + + subsection Minimum refinement function + set Variable names = depth, phi, theta + set Function expression = if(depth>0.1,if(depth>0.2,2,5),6) + end +end diff --git a/cookbooks/inner_core_convection/inner_core_assembly.cc.bak b/cookbooks/inner_core_convection/inner_core_assembly.cc.bak new file mode 100644 index 00000000000..8cd7a42d249 --- /dev/null +++ b/cookbooks/inner_core_convection/inner_core_assembly.cc.bak @@ -0,0 +1,140 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include + +#include +#include + + +#include "inner_core_convection.cc" + +namespace aspect +{ + /** + * A new assembler class that implements boundary conditions for the + * normal stress and the normal velocity that take into account the + * rate of phase change (melting/freezing) at the inner-outer core + * boundary. The model is based on Deguen, Alboussiere, and Cardin + * (2013), Thermal convection in Earth's inner core with phase change + * at its boundary. GJI, 194, 1310-133. + * + * The mechanical boundary conditions for the inner core are + * tangential stress-free and continuity of the normal stress at the + * inner-outer core boundary. For the non-dimensional equations, that + * means that we can define a 'phase change number' $\mathcal{P}$ so + * that the normal stress at the boundary is $-\mathcal{P} u_r$ with + * the radial velocity $u_r$. This number characterizes the resistance + * to phase change at the boundary, with $\mathcal{P}\rightarrow\infty$ + * corresponding to infinitely slow melting/freezing (free slip + * boundary), and $\mathcal{P}\rightarrow0$ corresponding to + * instantaneous melting/freezing (zero normal stress, open boundary). + * + * In the weak form, this results in boundary conditions of the form + * of a surface integral: + * $$\int_S \mathcal{P} (\mathbf u \cdot \mathbf n) (\mathbf v \cdot \mathbf n) dS,$$, + * with the normal vector $\mathbf n$. + * + * The function value of $\mathcal{P}$ is taken from the inner core + * material model. + */ + template + class PhaseBoundaryAssembler : + public aspect::Assemblers::Interface, + public SimulatorAccess + { + + public: + + void + execute (internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override + { + internal::Assembly::Scratch::StokesSystem &scratch = dynamic_cast&> (scratch_base); + internal::Assembly::CopyData::StokesSystem &data = dynamic_cast&> (data_base); + + const Introspection &introspection = this->introspection(); + const FiniteElement &fe = this->get_fe(); + const unsigned int stokes_dofs_per_cell = data.local_dof_indices.size(); + const unsigned int n_q_points = scratch.face_finite_element_values.n_quadrature_points; + + //assemble force terms for the matrix for all boundary faces + if (scratch.cell->face(scratch.face_number)->at_boundary()) + { + scratch.face_finite_element_values.reinit (scratch.cell, scratch.face_number); + + for (unsigned int q=0; q> + (this->get_material_model()).resistance_to_phase_change + .value(scratch.material_model_inputs.position[q]); + + for (unsigned int i = 0, i_stokes = 0; i_stokes < stokes_dofs_per_cell; /*increment at end of loop*/) + { + if (introspection.is_stokes_component(fe.system_to_component_index(i).first)) + { + scratch.phi_u[i_stokes] = scratch.face_finite_element_values[introspection + .extractors.velocities].value(i, q); + ++i_stokes; + } + ++i; + } + + const Tensor<1,dim> normal_vector = scratch.face_finite_element_values.normal_vector(q); + const double JxW = scratch.face_finite_element_values.JxW(q); + + // boundary term: P*u*n*v*n*JxW(q) + for (unsigned int i=0; i + void set_assemblers_phase_boundary(const SimulatorAccess &simulator_access, + Assemblers::Manager &assemblers) + { + AssertThrow (Plugins::plugin_type_matches> + (simulator_access.get_material_model()), + ExcMessage ("The phase boundary assembler can only be used with the " + "material model 'inner core material'!")); + + assemblers.stokes_system_on_boundary_face.push_back (std::make_unique>()); + } +} + +template +void signal_connector (aspect::SimulatorSignals &signals) +{ + signals.set_assemblers.connect (&aspect::set_assemblers_phase_boundary); +} + +ASPECT_REGISTER_SIGNALS_CONNECTOR(signal_connector<2>, + signal_connector<3>) diff --git a/cookbooks/inner_core_convection/inner_core_convection.cc.bak b/cookbooks/inner_core_convection/inner_core_convection.cc.bak new file mode 100644 index 00000000000..69aded1aab9 --- /dev/null +++ b/cookbooks/inner_core_convection/inner_core_convection.cc.bak @@ -0,0 +1,488 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + template + class InnerCore : public MaterialModel::Simple + { + public: + /** + * Constructor. + */ + InnerCore (); + + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * A function that is called at the beginning of each time step to + * indicate what the model time is for which the boundary values will + * next be evaluated. For the current class, the function passes to + * the parsed function what the current time is. + */ + void + update () override; + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * A function object representing resistance to phase change at the + * inner core boundary as a function the position (and, optionally, + * the model time). + */ + Functions::ParsedFunction resistance_to_phase_change; + + private: + /** + * Parameters related to the phase transition. + */ + double transition_radius; + double transition_width; + double transition_temperature; + double transition_clapeyron_slope; + double transition_density_change; + bool compute_quadratic_pressure_profile; + + /** + * A function object representing the hydrostatic pressure in the + * inner core as a function of radius. This is needed to compute + * the depth of phase transitions. + * Note that we can not simply use the adiabatic pressure here, + * as the equations are solved for the dynamic pressure, and the + * adiabatic conditions are used as initial guess for the solution. + */ + Functions::ParsedFunction<1> hydrostatic_pressure_profile; + + /** + * Percentage of material that has already undergone the phase + * transition to the higher-pressure material. + */ + double + phase_function (const Point &position, + const double temperature) const; + + /** + * Hydrostatic pressure profile. + */ + double + hydrostatic_pressure (const double radius) const; + }; + + } +} + +namespace aspect +{ + namespace MaterialModel + { + template + InnerCore::InnerCore () + : + resistance_to_phase_change (1), + hydrostatic_pressure_profile (1) + {} + + template + double + InnerCore:: + phase_function (const Point &position, + const double temperature) const + { + // We need to convert the depth to pressure, + // keeping in mind that for this model, the pressure is only the dynamic pressure, + // so we have to get the hydrostatic pressure explicitly as an input. + const double radius = this->get_geometry_model().maximal_depth() - this->get_geometry_model().depth(position); + Assert(radius >= 0, + ExcMessage("There is a point in the model where the depth is larger " + "than the maximal depth of this geometry.")); + + const double pressure_deviation = hydrostatic_pressure(radius) - hydrostatic_pressure(transition_radius); + + double depth_deviation = transition_radius - radius; + if (std::fabs(pressure_deviation) > 100.0 * std::numeric_limits::epsilon() + * (std::fabs(hydrostatic_pressure(radius)) + std::fabs(hydrostatic_pressure(transition_radius)))/2) + depth_deviation *= (1.0 - transition_clapeyron_slope * (temperature - transition_temperature) / pressure_deviation); + + double phase_func; + // use delta function for width = 0 + if (transition_width == 0) + phase_func = (depth_deviation > 0) ? 1 : 0; + else + phase_func = 0.5 * (1.0 + std::tanh(depth_deviation / transition_width)); + return phase_func; + } + + + template + double + InnerCore:: + hydrostatic_pressure (const double radius) const + { + if (compute_quadratic_pressure_profile) + { + // Compute a quadratic hydrostatic pressure profile, based on a linear gravity model. + AssertThrow (Plugins::plugin_type_matches>(this->get_gravity_model()), + ExcMessage ("Automatic computation of the hydrostatic pressure profile is " + "only implemented for the 'radial linear' gravity model.")); + + const double max_radius = this->get_geometry_model().maximal_depth(); + const Point surface_point = this->get_geometry_model().representative_point(0); + const double gravity_magnitude = this->get_gravity_model().gravity_vector(surface_point).norm(); + + // The gravity is zero in the center of the Earth, and we assume the density to be constant and equal to 1. + // We fix the surface pressure to 0 (and we are only interested in pressure differences anyway). + return gravity_magnitude * 0.5 * (1.0 - std::pow(radius/max_radius,2)); + } + else + return hydrostatic_pressure_profile.value(Point<1>(radius)); + } + + + template + void + InnerCore:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + // First, we use the material descriptions of the 'simple' material model to fill all of the material + // model outputs. Below, we will then overwrite selected properties (the specific heat) to make the + // product of density and specific heat a constant. + Simple::evaluate(in, out); + + // We want the right-hand side of the momentum equation to be (- Ra T gravity) and + // density * cp to be 1 + for (unsigned int q=0; q < in.n_evaluation_points(); ++q) + { + out.densities[q] = - out.thermal_expansion_coefficients[q] * in.temperature[q] + + phase_function (in.position[q], in.temperature[q]) * transition_density_change; + if (std::abs(out.densities[q]) > 0.0) + out.specific_heat[q] /= out.densities[q]; + } + } + + + template + void + InnerCore::update() + { + // we get time passed as seconds (always) but may want + // to reinterpret it in years + if (this->convert_output_to_years()) + resistance_to_phase_change.set_time (this->get_time() / year_in_seconds); + else + resistance_to_phase_change.set_time (this->get_time()); + + if (this->convert_output_to_years()) + hydrostatic_pressure_profile.set_time (this->get_time() / year_in_seconds); + else + hydrostatic_pressure_profile.set_time (this->get_time()); + } + + + template + void + InnerCore::declare_parameters (ParameterHandler &prm) + { + Simple::declare_parameters (prm); + + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Inner core"); + { + prm.enter_subsection("Phase change resistance function"); + { + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + + prm.enter_subsection("Hydrostatic pressure function"); + { + Functions::ParsedFunction<1>::declare_parameters (prm, 1); + } + prm.leave_subsection(); + + prm.declare_entry ("Phase transition radius", "0.0", + Patterns::Double (0), + "The distance from the center of the Earth where the phase " + "transition occurs. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Phase transition width", "0.0", + Patterns::Double (0), + "The width of the phase transition. The argument of the phase function " + "is scaled with this value, leading to a jump between phases " + "for a value of zero and a gradual transition for larger values. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Phase transition temperature", "0.0", + Patterns::Double (0), + "The temperature at which the phase transition occurs in the depth " + "given by the 'Phase transition depth' parameter. Higher or lower " + "temperatures lead to phase transition occurring in shallower or greater " + "depths, depending on the Clapeyron slope given in 'Phase transition " + "Clapeyron slope'. " + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Phase transition Clapeyron slope", "0.0", + Patterns::Double (), + "The Clapeyron slope of the phase transition. A positive " + "Clapeyron slope indicates that the phase transition will occur in " + "a greater depth if the temperature is higher than the one given in " + "Phase transition temperatures (and in a smaller depth if the " + "temperature is smaller than the one given in Phase transition temperatures). " + "For negative Clapeyron slopes, the effect is in the opposite direction. " + "Units: Pa/K."); + prm.declare_entry ("Phase transition density change", "0.0", + Patterns::Double (), + "The density change that occurs across the phase transition. " + "A positive value means that the density increases with depth. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Compute quadratic pressure profile from gravity", "true", + Patterns::Bool (), + "Whether to automatically compute the hydrostatic pressure profile " + "(that is used to compute the location of phase transitions) from " + "the magnitude of the gravity, assuming a linear gravity profile " + "and a constant density (if true), or to use the function that is " + "given in 'Hydrostatic pressure function' (if false)."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + InnerCore::parse_parameters (ParameterHandler &prm) + { + Simple::parse_parameters (prm); + + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Inner core"); + { + prm.enter_subsection("Phase change resistance function"); + try + { + resistance_to_phase_change.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Phase boundary model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + prm.leave_subsection(); + + prm.enter_subsection("Hydrostatic pressure function"); + try + { + hydrostatic_pressure_profile.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Hydrostatic pressure model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + prm.leave_subsection(); + + transition_radius = prm.get_double ("Phase transition radius"); + transition_width = prm.get_double ("Phase transition width"); + transition_temperature = prm.get_double ("Phase transition temperature"); + transition_clapeyron_slope = prm.get_double ("Phase transition Clapeyron slope"); + transition_density_change = prm.get_double ("Phase transition density change"); + compute_quadratic_pressure_profile = prm.get_bool ("Compute quadratic pressure profile from gravity"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + + + +namespace aspect +{ + namespace HeatingModel + { + using namespace dealii; + + /** + * A class that implements a constant radiogenic heating rate. + * + * @ingroup HeatingModels + */ + template + class ConstantCoreHeating : public Interface + { + public: + /** + * Return the heating terms. For the current class, this + * function obviously simply returns a constant value. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + private: + double radiogenic_heating_rate; + }; + } +} + +namespace aspect +{ + namespace HeatingModel + { + template + void + ConstantCoreHeating:: + evaluate (const MaterialModel::MaterialModelInputs &/*material_model_inputs*/, + const MaterialModel::MaterialModelOutputs &/*material_model_outputs*/, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + for (unsigned int q=0; q + void + ConstantCoreHeating::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Constant core heating"); + { + prm.declare_entry ("Radiogenic heating rate", "0e0", + Patterns::Double (0), + "The specific rate of heating due to radioactive decay (or other bulk sources " + "you may want to describe). This parameter corresponds to the variable " + "$H$ in the temperature equation stated in the manual, and the heating " + "term is $\\rho H$. Units: W/kg."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + ConstantCoreHeating::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Constant core heating"); + { + radiogenic_heating_rate = prm.get_double ("Radiogenic heating rate"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(InnerCore, + "inner core material", + "A simple material model that is like the " + "'Simple' model, but has a constant $\rho c_p$, " + "and implements a function that characterizes the " + "resistance to melting/freezing at the inner core " + "boundary.") + } + + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(ConstantCoreHeating, + "constant core heating", + "Implementation of a model in which the heating " + "rate is constant.") + } +} diff --git a/cookbooks/inner_core_convection/inner_core_traction.prm b/cookbooks/inner_core_convection/inner_core_traction.prm index 215f28bc066..01137135c4c 100644 --- a/cookbooks/inner_core_convection/inner_core_traction.prm +++ b/cookbooks/inner_core_convection/inner_core_traction.prm @@ -131,6 +131,6 @@ end subsection Solver parameters subsection Stokes solver parameters - set Stokes solver type = block AMG + set Stokes solver type = block AMG end end diff --git a/cookbooks/inner_core_convection/inner_core_traction.prm.bak b/cookbooks/inner_core_convection/inner_core_traction.prm.bak new file mode 100644 index 00000000000..215f28bc066 --- /dev/null +++ b/cookbooks/inner_core_convection/inner_core_traction.prm.bak @@ -0,0 +1,136 @@ +# A simple setup for convection the inner core. See the +# manual, Section Cookbooks/Geophysical setups/Inner core convection +# for more information. Changing the Rayleigh number Ra +# and the resistance to phase change P will change the mode +# of inner core convection between translation, plume convection +# or no convection. +# +# Setup and equations are given in: Deguen, Alboussiere, +# and Cardin (2013), Thermal convection in Earth’s inner core +# with phase change at its boundary. GJI, 194, 1310-133. + +set Additional shared libraries = ./libinner_core_convection.so +set Dimension = 3 +set Use years in output instead of seconds = false +set End time = 1.5e9 +set Output directory = output-inner_core_traction + +# The equations are non-dimensionalized, and all of the +# material properties are constant and set to one, except +# for the density, which scales with temperature. +subsection Material model + set Model name = inner core material + + subsection Simple model + set Reference density = 0 + set Reference specific heat = 1 + set Reference temperature = 0 + set Thermal conductivity = 1 + set Thermal expansion coefficient = 1 + set Viscosity = 1 + end + + # The 'inner core material' model also contains a function that + # represents the resistance to melting/freezing at the inner core + # boundary. + # This phase boundary model combines a prescribed a normal + # velocity and normal stress. The relation between the two scales + # with the phase change number P, which is given in the 'Function + # expression'. + # For P-->infinity, the boundary is a free slip boundary, and for + # P-->0, the boundary is an open boundary (with zero normal stress). + + # For time dependence, the variable names have to have dim+1 entries, + # and the last variable will be the time + subsection Inner core + subsection Phase change resistance function + set Variable names = x,y,z + set Function expression = 1e-2 # <-- P + end + end +end + +# The inner core is a sphere, and the non-dimensional radius +# is 1. +subsection Geometry model + set Model name = sphere + + subsection Sphere + set Radius = 1 + end +end + +# We use a new boundary condition at the surface, which takes +# into account the effect of melting/freezing of material at +# the boundary of inner and outer core, and which is implemented +# in the shared library. +subsection Boundary traction model + set Prescribed traction boundary indicators = surface: zero traction +end + +# We use a constant radiogenic heating rate. +subsection Heating model + set List of model names = constant core heating + + subsection Constant core heating + set Radiogenic heating rate = 6 + end +end + +# The (potential) temperature is set to zero at the outer boundary. +subsection Boundary temperature model + set Fixed temperature boundary indicators = surface + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 0.1 + set Outer temperature = 0 + end +end + +subsection Initial temperature model + set Model name = spherical hexagonal perturbation +end + +# The gravity has its maximum value at the boundary of inner and +# outer core, and decreases approximately linearly to zero towards +# the center of the core. +# The Rayleigh number used in the model is given by the magnitude +# of the gravity at the inner core/outer core boundary. +subsection Gravity model + set Model name = radial linear + + subsection Radial linear + set Magnitude at bottom = 0.0 + set Magnitude at surface = 2 # <-- Ra + end +end + +subsection Mesh refinement + set Initial global refinement = 3 + set Initial adaptive refinement = 0 + set Strategy = minimum refinement function + set Time steps between mesh refinement = 0 + + subsection Minimum refinement function + set Variable names = depth, phi, theta + set Function expression = if(depth>0.1,if(depth>0.2,2,5),6) + end +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics + + subsection Visualization + set Output format = vtu + set Time between graphical output = 0 + set Number of grouped files = 0 + set List of output variables = strain rate, gravity, density, specific heat, heating + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Stokes solver type = block AMG + end +end diff --git a/cookbooks/kinematically_driven_subduction_2d/composition_trms_statistics.cc.bak b/cookbooks/kinematically_driven_subduction_2d/composition_trms_statistics.cc.bak new file mode 100644 index 00000000000..c77565c10c5 --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/composition_trms_statistics.cc.bak @@ -0,0 +1,227 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + +#include "composition_trms_statistics.h" +#include +#include + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + CompositionTrmsStatistics::execute (TableHandler &statistics) + { + // create a quadrature formula based on the temperature element alone. + const Quadrature &quadrature_formula = this->introspection().quadratures.temperature; + const unsigned int n_q_points = quadrature_formula.size(); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_quadrature_points | + update_JxW_values); + + std::vector temperature_values(n_q_points); + std::vector compositional_values(n_q_points); + + std::vector local_temperature_square_integral (this->n_compositional_fields()); + std::vector local_area_integral (this->n_compositional_fields()); + double local_total_temperature_square_integral = 0.; + double local_total_area_integral = 0.; + const double kelvin_to_celsius = 273.15; + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit(cell); + + fe_values[this->introspection().extractors.temperature].get_function_values(this->get_solution(), + temperature_values); + + // Loop over the quadrature points to get the temperature and area + // integral for the whole domain. + for (unsigned int q = 0; q < n_q_points; ++q) + { + local_total_temperature_square_integral += (((temperature_values[q]-kelvin_to_celsius) * + (temperature_values[q]-kelvin_to_celsius)) * fe_values.JxW(q)); + local_total_area_integral += fe_values.JxW(q); + } + + // For each field, loop over the quadrature points to get the temperature + // and area per field. + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + { + fe_values[this->introspection().extractors.compositional_fields[c]].get_function_values(this->get_solution(), + compositional_values); + + for (unsigned int q = 0; q < n_q_points; ++q) + { + if (compositional_values[q] >= 0.5) + { + local_temperature_square_integral[c] += (((temperature_values[q]-kelvin_to_celsius) * + (temperature_values[q]-kelvin_to_celsius)) * fe_values.JxW(q)); + local_area_integral[c] += fe_values.JxW(q); + } + } + } + } + + std::vector global_temperature_square_integral (local_temperature_square_integral.size()); + Utilities::MPI::sum (local_temperature_square_integral, this->get_mpi_communicator(), global_temperature_square_integral); + std::vector global_area_integral (local_area_integral.size()); + Utilities::MPI::sum (local_area_integral, this->get_mpi_communicator(), global_area_integral); + const double global_total_temperature_square_integral = Utilities::MPI::sum(local_total_temperature_square_integral, this->get_mpi_communicator()); + const double global_total_area_integral = Utilities::MPI::sum(local_total_area_integral, this->get_mpi_communicator()); + + // compute the RMS temperature for each compositional field and for the selected compositional fields combined + std::vector Trms_per_composition(local_area_integral.size()); + double temperature_square_integral_selected_fields = 0., area_integral_selected_fields = 0.; + + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + { + Trms_per_composition[c] = std::sqrt(global_temperature_square_integral[c]) / + std::sqrt(global_area_integral[c]); + + const std::vector::iterator selected_field_it = std::find(selected_fields.begin(), selected_fields.end(), this->introspection().name_for_compositional_index(c)); + if (selected_field_it != selected_fields.end()) + { + temperature_square_integral_selected_fields += global_temperature_square_integral[c]; + area_integral_selected_fields += global_area_integral[c]; + } + } + + const double Trms_selected_fields = std::sqrt(temperature_square_integral_selected_fields) / std::sqrt(area_integral_selected_fields); + + // compute the RMS temperature over the whole domain + const double Trms_whole_domain = std::sqrt(global_total_temperature_square_integral) / std::sqrt(global_total_area_integral); + + // finally produce something for the statistics file + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + { + statistics.add_value("RMS temperature (C) for composition " + this->introspection().name_for_compositional_index(c), + Trms_per_composition[c]); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + const std::string columns[] = {"RMS temperature (C) for composition " + this->introspection().name_for_compositional_index(c)}; + + for (unsigned int i = 0; i < sizeof(columns) / sizeof(columns[0]); ++i) + { + statistics.set_precision(columns[i], 8); + statistics.set_scientific(columns[i], true); + } + } + + // Also output the RMS temperature for the selected fields + statistics.add_value("RMS temperature (C) for the selected fields", + Trms_selected_fields); + + const std::string column = {"RMS temperature (C) for the selected fields"}; + + statistics.set_precision(column, 8); + statistics.set_scientific(column, true); + + // Also output the RMS temperature for the whole domain + statistics.add_value("RMS temperature (C) for the whole domain", + Trms_whole_domain); + + const std::string column_whole_domain = {"RMS temperature (C) for the whole domain"}; + + statistics.set_precision(column_whole_domain, 8); + statistics.set_scientific(column_whole_domain, true); + + std::ostringstream output; + output.precision(4); + + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + { + output << Trms_per_composition[c] + << " C"; + output << " // "; + } + output << Trms_selected_fields << " C // "; + output << Trms_whole_domain << " C"; + + return std::pair("RMS temperature for compositions, combined selected fields and whole domain:", + output.str()); + } + + + + template + void CompositionTrmsStatistics::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Composition RMS temperature statistics"); + { + prm.declare_entry("Names of selected compositional fields", "", + Patterns::List(Patterns::Anything()), + "A list of names for each of the compositional fields that " + "you want to compute the combined RMS temperature for."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void CompositionTrmsStatistics::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Composition RMS temperature statistics"); + { + selected_fields = Utilities::split_string_list(prm.get("Names of selected compositional fields")); + + AssertThrow((selected_fields.size() > 0) && + (selected_fields.size() <= this->n_compositional_fields()), + ExcMessage("The length of the list of names for the compositional " + "fields for which the RMS temperature is to be summed must be larger than zero " + "and smaller or equal to the number of compositional fields.")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(CompositionTrmsStatistics, + "composition RMS temperature statistics", + "A postprocessor that computes the root-mean-square (RMS) temperature " + "over the area spanned by each compositional field (i.e. where " + "the field values are larger or equal to 0.5). It also computes the RMS " + "temperature over the summed area of a list of fields given by the user, " + "and over the whole domain.") + } +} diff --git a/cookbooks/kinematically_driven_subduction_2d/composition_trms_statistics.h.bak b/cookbooks/kinematically_driven_subduction_2d/composition_trms_statistics.h.bak new file mode 100644 index 00000000000..bcf1f80503c --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/composition_trms_statistics.h.bak @@ -0,0 +1,75 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_postprocess_composition_trms_statistics_h +#define _aspect_postprocess_composition_trms_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes the root mean square temperature + * over the area spanned by each of the compositional fields. + * + * @ingroup Postprocessing + */ + template + class CompositionTrmsStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution to compute the root-mean-square temperature per compositional field. + **/ + std::pair + execute (TableHandler &statistics) override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static void + declare_parameters(ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters(ParameterHandler &prm) override; + /** + * @} + */ + + private: + std::vector selected_fields; + }; + } +} + + +#endif diff --git a/cookbooks/kinematically_driven_subduction_2d/doc/Case1_compositions.prm.bak b/cookbooks/kinematically_driven_subduction_2d/doc/Case1_compositions.prm.bak new file mode 100644 index 00000000000..de24a7eeb08 --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/doc/Case1_compositions.prm.bak @@ -0,0 +1,39 @@ +# We fix composition on the right boundary, +# because we have inflow there. +subsection Boundary composition model + set Fixed composition boundary indicators = right + set List of model names = initial composition +end + +# The overriding plate (OP) and subducting plate (SP) +# are each divided into three different layers: +# a layer of Bulk Oceanic Composition (BOC), +# a layer of Serpentinized HarzBurgite (SHB), +# and a "thermal layer". + +subsection Compositional fields + set Number of fields = 7 + set Names of fields = BOC_OP, BOC_SP, SHB_OP, SHB_SP, thermal_OP, thermal_SP, WZ +end + +subsection Initial composition model + set List of model names = function + + subsection Function + set Function constants = Ax=1475600.0, Az=670000.0, \ + Bx=1500000.0, Bz=670000.0, \ + Cx=1358500.0, Cz=588000.0, \ + Dx=1382900.0, Dz=588000.0, \ + Ex=1530000.0, Ez=560000.0, \ + Fz=663000.0, Gz=662000.0, \ + Hz=631000.0, Iz=630000.0 + set Function expression = if(z>=Fz&z>=((Az-Cz)/(Ax-Cx)*(x-Cx)+Cz),1,0); \ + if(z>=Gz&z<=((Bz-Dz)/(Bx-Dx)*(x-Dx)+Dz),1,0); \ + if(z>=Hz&z>=((Az-Cz)/(Ax-Cx)*(x-Cx)+Cz)&z=Iz&z<=((Bz-Dz)/(Bx-Dx)*(x-Dx)+Dz)&z=Cz&z>=((Az-Cz)/(Ax-Cx)*(x-Cx)+Cz)&z=Ex&z>=Ez&z=((Ez-Dz)/(Ex-Dx)*(x-Dx)+Dz)),1,0); \ + if(z>=Cz&z>((Bz-Dz)/(Bx-Dx)*(x-Dx)+Dz)&z<((Az-Cz)/(Ax-Cx)*(x-Cx)+Cz),1.5,0) + set Variable names = x,z + end +end diff --git a/cookbooks/kinematically_driven_subduction_2d/doc/Case1_materialmodel.prm.bak b/cookbooks/kinematically_driven_subduction_2d/doc/Case1_materialmodel.prm.bak new file mode 100644 index 00000000000..8f4b35a90d9 --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/doc/Case1_materialmodel.prm.bak @@ -0,0 +1,15 @@ +set Nonlinear solver scheme = single Advection, single Stokes + +subsection Material model + set Model name = multicomponent + + subsection Multicomponent + set Reference temperature = 0.0 + set Viscosity averaging scheme = maximum composition + + # BOC_OP, BOC_SP, SHB_OP, SHB_SP, thermal_OP, thermal_SP, WZ + set Viscosities = 1.e20, 1.e23, 1.e20, 1.e23, 1.e23, 1.e23, 1.e23, 1.e20 + set Densities = 3200.0,3250.0,3250.0,3250.0,3250.0,3250.0,3250.0,3250.0 + set Thermal conductivities = 1 + end +end diff --git a/cookbooks/kinematically_driven_subduction_2d/doc/Case1_meshrefinement.prm.bak b/cookbooks/kinematically_driven_subduction_2d/doc/Case1_meshrefinement.prm.bak new file mode 100644 index 00000000000..5ec090c8d17 --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/doc/Case1_meshrefinement.prm.bak @@ -0,0 +1,23 @@ +# The maximum refinement level will be 6+4 levels, +# corresponding to a maximum resolution of ~700 m. +subsection Mesh refinement + set Initial adaptive refinement = 4 + set Initial global refinement = 6 + set Minimum refinement level = 6 + set Normalize individual refinement criteria = true + set Refinement criteria merge operation = plus + set Coarsening fraction = 0.01 + set Refinement fraction = 0.95 + set Run postprocessors on initial refinement = false + set Skip solvers on initial refinement = true + set Skip setup initial conditions on initial refinement = true + set Strategy = minimum refinement function, viscosity + set Time steps between mesh refinement = 16 + + subsection Minimum refinement function + set Coordinate system = depth + set Variable names = x,z,t + set Function constants = vel=150e3, L=100e3, crust=10e3 + set Function expression = if(x560000.0, -5.0/cm, \ + ((((-600.0/550.0)-5.0)/-20.0)*((z/1000.0)-560.0)+5.0)*(-1.0/cm))); \ + 0 + set Variable names = x,z + end +end diff --git a/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_materialmodel.prm.bak b/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_materialmodel.prm.bak new file mode 100644 index 00000000000..4b4372e4618 --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_materialmodel.prm.bak @@ -0,0 +1,13 @@ +subsection Material model + set Model name = multicomponent + + subsection Multicomponent + set Reference temperature = 473.15 + set Densities = 3200.0,3250.0,3250.0,3250.0,3250.0,3250.0,3250.0,3250.0 + set Thermal expansivities = 0 + set Thermal conductivities = 183.33,2.5,2.5,2.5,2.5,2.5,2.5,2.5 + set Heat capacities = 1250.0,750.0,750.0,750.0,750.0,1250.0,1250.0,750.0 + set Viscosity averaging scheme = maximum composition + set Viscosities = 1.e20, 1.e23, 1.e20, 1.e23, 1.e23, 1.e23, 1.e23, 1.e20 + end +end diff --git a/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_postprocessing.prm b/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_postprocessing.prm index 97f6121cceb..9305efc0827 100644 --- a/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_postprocessing.prm +++ b/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_postprocessing.prm @@ -1,5 +1,5 @@ subsection Postprocess - set List of postprocessors = visualization, velocity statistics, heating statistics, maximum depth of field, composition velocity statistics, viscous dissipation statistics, temperature statistics, trench location, isotherm depth, composition RMS temperature statistics + set List of postprocessors = visualization, velocity statistics, heating statistics, temperature statistics, trench location, isotherm depth, composition RMS temperature statistics subsection Composition velocity statistics #Sum the velocities of the fields that make up the subducting plate. diff --git a/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_postprocessing.prm.bak b/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_postprocessing.prm.bak new file mode 100644 index 00000000000..97f6121cceb --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_postprocessing.prm.bak @@ -0,0 +1,20 @@ +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, heating statistics, maximum depth of field, composition velocity statistics, viscous dissipation statistics, temperature statistics, trench location, isotherm depth, composition RMS temperature statistics + + subsection Composition velocity statistics + #Sum the velocities of the fields that make up the subducting plate. + set Names of selected compositional fields = BOC_SP, SHB_SP, thermal_SP + end + + subsection Trench location + set Name of trench compositional field = BOC_OP + end + + subsection Isotherm depth + set Isotherm value = 1073.15 + end + + subsection Composition RMS temperature statistics + set Names of selected compositional fields = BOC_SP, SHB_SP, thermal_SP + end +end diff --git a/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_temperatures.prm.bak b/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_temperatures.prm.bak new file mode 100644 index 00000000000..e6c69a04bf0 --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/doc/Case2a_temperatures.prm.bak @@ -0,0 +1,21 @@ +# We include a shared library with a customized initial temperature plugin and the required isotherm depth, composition RMS temperature, and trench location postprocessors. +set Additional shared libraries = $ASPECT_SOURCE_DIR/cookbooks/kinematically_driven_subduction_2d/libsubduction_plate_cooling.so + +# We fix temperature on the top and bottom, +# as well as on the right boundary because +# we have inflow through the latter. +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top, right + set List of model names = box + + subsection Box + set Bottom temperature = 0 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +subsection Initial temperature model + set List of model names = subduction plate cooling +end diff --git a/cookbooks/kinematically_driven_subduction_2d/doc/Case2b_materialmodel.prm.bak b/cookbooks/kinematically_driven_subduction_2d/doc/Case2b_materialmodel.prm.bak new file mode 100644 index 00000000000..a97345679f2 --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/doc/Case2b_materialmodel.prm.bak @@ -0,0 +1,25 @@ +subsection Material model + set Model name = multicomponent + + subsection Multicomponent + # The benchmark uses two different reference temperatures for the compositions: + # 1573.15 K for the asthenosphere, thermal_OP and thermal_SP, and 473.15 K for + # the rest of the compositions. + # As ASPECT only allows for one reference temperature, we have instead adapted + # the reference density for the mantle compositions. To do this, we took the initial + # temperature and the midpoint depth of the layers and equated the density equation + # using the benchmark reference density rho_0_1 (3200 kg/m3) and temperature T_0_1 (1573.15 K), and + # the density equation using the 473.15 K reference temperature to obtain the new reference density rho_0_2. + # For the left thermal layer, the initial temperature at the midpoint is 1355 K, so + # new reference density can be derived as follows: + # rho_0_1 * (1 - alpha * (T - T_0_1)) = rho_0_2 * (1 - alpha * (T - T_0_2)), + # 3200 * (1 - 2.5e-5 * (1355 - 1573.15)) = rho_0_2 * (1 - 2.5e-5 * (1355 - 473.15)) + # rho_0_2 = 3290.66. + set Reference temperature = 473.15 + set Densities = 3290.66,3000.0,3000.0,3250.0,3250.0,3290.66,3290.66,3200.0 + + # Compared to Case 2a, thermal expansivity is no longer zero and therefore temperature + # feeds into the density and therefore the Stokes equations + set Thermal expansivities = 2.5e-5 + end +end diff --git a/cookbooks/kinematically_driven_subduction_2d/isotherm_depth.cc.bak b/cookbooks/kinematically_driven_subduction_2d/isotherm_depth.cc.bak new file mode 100644 index 00000000000..9e37fd89bd1 --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/isotherm_depth.cc.bak @@ -0,0 +1,152 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include "isotherm_depth.h" +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + IsothermDepth::execute (TableHandler &statistics) + { + // create a quadrature formula based on the temperature element alone. + const Quadrature &quadrature_formula = this->introspection().quadratures.temperature; + const unsigned int n_q_points = quadrature_formula.size(); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_quadrature_points | + update_JxW_values); + + std::vector> position_values(n_q_points); + std::vector temperature_values(n_q_points); + + double local_isotherm_depth = 0.0; + const double max_depth = this->get_geometry_model().maximal_depth(); + const double dT = 1.1; + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + + fe_values.reinit (cell); + + position_values = fe_values.get_quadrature_points(); + + fe_values[this->introspection().extractors.temperature].get_function_values (this->get_solution(), + temperature_values); + + for (unsigned int i=0; i (isotherm_value - dT) && temperature_values[i] < (isotherm_value + dT) && + (max_depth - position_values[i][dim-1]) > local_isotherm_depth) + { + local_isotherm_depth = max_depth - position_values[i][dim-1]; + } + } + } + + // compute the maximum depth over all processors + const double isotherm_depth = + Utilities::MPI::max (local_isotherm_depth, this->get_mpi_communicator()); + + statistics.add_value ("Isotherm depth [m]", isotherm_depth); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + { + const char *columns[] = { "Isotherm depth [m]" + }; + for (unsigned int i=0; i ("Isotherm depth [m]:", + output.str()); + } + + + + template + void IsothermDepth::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Isotherm depth"); + { + prm.declare_entry("Isotherm value", "1573", + Patterns::Double(0), + "The temperature value of the isotherm " + "which maximum depth is tracked. Unit: [K]."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void IsothermDepth::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Isotherm depth"); + { + isotherm_value = prm.get_double("Isotherm value"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(IsothermDepth, + "isotherm depth", + "A postprocessor that computes the maximum depth " + "of a user-given isotherm.") + } +} diff --git a/cookbooks/kinematically_driven_subduction_2d/isotherm_depth.h.bak b/cookbooks/kinematically_driven_subduction_2d/isotherm_depth.h.bak new file mode 100644 index 00000000000..7553b24b75b --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/isotherm_depth.h.bak @@ -0,0 +1,74 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_postprocess_isotherm_depth_h +#define _aspect_postprocess_isotherm_depth_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the deepest point of the last composition. + * + * @ingroup Postprocessing + */ + template + class IsothermDepth : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution to find the deepest point of a user-specified isotherm. + **/ + std::pair + execute (TableHandler &statistics) override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static void + declare_parameters(ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters(ParameterHandler &prm) override; + /** + * @} + */ + + private: + double isotherm_value; + }; + } +} + + +#endif diff --git a/cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case1.prm b/cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case1.prm index ba095e61c31..ba634ce5f0d 100644 --- a/cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case1.prm +++ b/cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case1.prm @@ -174,7 +174,7 @@ subsection Formulation end subsection Postprocess - set List of postprocessors = visualization, velocity statistics, heating statistics, maximum depth of field, composition velocity statistics, viscous dissipation statistics, trench location + set List of postprocessors = visualization, velocity statistics, heating statistics, trench location subsection Visualization set List of output variables = density, viscosity, strain rate, error indicator diff --git a/cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case1.prm.bak b/cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case1.prm.bak new file mode 100644 index 00000000000..ba095e61c31 --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case1.prm.bak @@ -0,0 +1,202 @@ +# This cookbook models oceanic subduction in a 2d +# box of 3000 x 670 km. +# The subducting plate is driven by inflow boundary +# conditions on the top part of the right boundary, +# while a balancing outflow is prescribed underneath. +# Only density and viscosity differ per composition. +# High resolution is required to sufficiently resolve the weak zone +# between the subducting and overriding plate, and consequently +# 100 MPI processes are required. + +# We include a shared library for the trench location postprocessor. +set Additional shared libraries = $ASPECT_SOURCE_DIR/cookbooks/kinematically_driven_subduction_2d/libsubduction_plate_cooling.so + +# 2D +set Dimension = 2 + +# Run for 15 My +set Start time = 0 +set End time = 15.01e6 +set CFL number = 0.5 +set Use years in output instead of seconds = true + +# Linear solver +set Nonlinear solver scheme = single Advection, single Stokes +set Output directory = output-Case1 +set Adiabatic surface temperature = 0 + +# We fix composition on the right boundary, +# because we have inflow there. +subsection Boundary composition model + set Fixed composition boundary indicators = right + set List of model names = initial composition +end + +# We fix temperature on the top and bottom, +# as well as on the right boundary because +# we have inflow through the latter. +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top, right + set List of model names = box + + subsection Box + set Bottom temperature = 0 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, bottom, top + set Prescribed velocity boundary indicators = right x:function + + subsection Function + set Function constants = cm=100.0 #*3600.0*24.0*365.25 + set Function expression = if(z<540000.0, (600.0/550.0)/cm, \ + if(z>560000.0, -5.0/cm, \ + ((((-600.0/550.0)-5.0)/-20.0)*((z/1000.0)-560.0)+5.0)*(-1.0/cm))); \ + 0 + set Variable names = x,z + end +end + +subsection Checkpointing + set Steps between checkpoint = 200 + set Time between checkpoint = 0 +end + +subsection Material model + set Model name = multicomponent + + subsection Multicomponent + set Reference temperature = 0.0 + set Viscosity averaging scheme = maximum composition + + # BOC_OP, BOC_SP, SHB_OP, SHB_SP, thermal_OP, thermal_SP, WZ + set Viscosities = 1.e20, 1.e23, 1.e20, 1.e23, 1.e23, 1.e23, 1.e23, 1.e20 + set Densities = 3200.0,3250.0,3250.0,3250.0,3250.0,3250.0,3250.0,3250.0 + set Thermal conductivities = 1 + end +end + +# The overriding plate (OP) and subducting plate (SP) +# are each divided into three different layers: +# a layer of Bulk Oceanic Composition (BOC), +# a layer of Serpentinized HarzBurgite (SHB), +# and a "thermal layer". + +subsection Compositional fields + set Number of fields = 7 + set Names of fields = BOC_OP, BOC_SP, SHB_OP, SHB_SP, thermal_OP, thermal_SP, WZ +end + +subsection Initial composition model + set List of model names = function + + subsection Function + set Function constants = Ax=1475600.0, Az=670000.0, \ + Bx=1500000.0, Bz=670000.0, \ + Cx=1358500.0, Cz=588000.0, \ + Dx=1382900.0, Dz=588000.0, \ + Ex=1530000.0, Ez=560000.0, \ + Fz=663000.0, Gz=662000.0, \ + Hz=631000.0, Iz=630000.0 + set Function expression = if(z>=Fz&z>=((Az-Cz)/(Ax-Cx)*(x-Cx)+Cz),1,0); \ + if(z>=Gz&z<=((Bz-Dz)/(Bx-Dx)*(x-Dx)+Dz),1,0); \ + if(z>=Hz&z>=((Az-Cz)/(Ax-Cx)*(x-Cx)+Cz)&z=Iz&z<=((Bz-Dz)/(Bx-Dx)*(x-Dx)+Dz)&z=Cz&z>=((Az-Cz)/(Ax-Cx)*(x-Cx)+Cz)&z=Ex&z>=Ez&z=((Ez-Dz)/(Ex-Dx)*(x-Dx)+Dz)),1,0); \ + if(z>=Cz&z>((Bz-Dz)/(Bx-Dx)*(x-Dx)+Dz)&z<((Az-Cz)/(Ax-Cx)*(x-Cx)+Cz),1.5,0) + set Variable names = x,z + end +end + +subsection Discretization +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 3000e3 + set Y extent = 670e3 + set X repetitions = 4 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +# We ignore any temperature effects +subsection Initial temperature model + set List of model names = function + + subsection Function + set Function constants = + set Function expression = 0 + set Variable names = x,y,t + end +end + +# The maximum refinement level will be 6+4 levels, +# corresponding to a maximum resolution of ~700 m. +subsection Mesh refinement + set Initial adaptive refinement = 4 + set Initial global refinement = 6 + set Minimum refinement level = 6 + set Normalize individual refinement criteria = true + set Refinement criteria merge operation = plus + set Coarsening fraction = 0.01 + set Refinement fraction = 0.95 + set Run postprocessors on initial refinement = false + set Skip solvers on initial refinement = true + set Skip setup initial conditions on initial refinement = true + set Strategy = minimum refinement function, viscosity + set Time steps between mesh refinement = 16 + + subsection Minimum refinement function + set Coordinate system = depth + set Variable names = x,z,t + set Function constants = vel=150e3, L=100e3, crust=10e3 + set Function expression = if(x=Fz&z>=((Az-Cz)/(Ax-Cx)*(x-Cx)+Cz),1,0); \ + if(z>=Gz&z<=((Bz-Dz)/(Bx-Dx)*(x-Dx)+Dz),1,0); \ + if(z>=Hz&z>=((Az-Cz)/(Ax-Cx)*(x-Cx)+Cz)&z=Iz&z<=((Bz-Dz)/(Bx-Dx)*(x-Dx)+Dz)&z=Cz&z>=((Az-Cz)/(Ax-Cx)*(x-Cx)+Cz)&z=Ex&z>=Ez&z=((Ez-Dz)/(Ex-Dx)*(x-Dx)+Dz)),1,0); \ + if(z>=Cz&z>((Bz-Dz)/(Bx-Dx)*(x-Dx)+Dz)&z<((Az-Cz)/(Ax-Cx)*(x-Cx)+Cz),1.5,0) + set Variable names = x,z + end +end + +# The initial temperature is prescribed through a plugin +# and uses the plate cooling model for the temperature in both +# plates (the plates have different ages) and an adiabatic +# gradient of 0.25 degrees per km in the sublithospheric +# mantle. +subsection Initial temperature model + set List of model names = subduction plate cooling +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, heating statistics, maximum depth of field, composition velocity statistics, viscous dissipation statistics, temperature statistics, trench location, isotherm depth, composition RMS temperature statistics + + subsection Composition velocity statistics + #Sum the velocities of the fields that make up the subducting plate. + set Names of selected compositional fields = BOC_SP, SHB_SP, thermal_SP + end + + subsection Trench location + set Name of trench compositional field = BOC_OP + end + + subsection Isotherm depth + set Isotherm value = 1073.15 + end + + subsection Composition RMS temperature statistics + set Names of selected compositional fields = BOC_SP, SHB_SP, thermal_SP + end +end diff --git a/cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case2b.prm.bak b/cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case2b.prm.bak new file mode 100644 index 00000000000..648bb11dc00 --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case2b.prm.bak @@ -0,0 +1,38 @@ +# This setup is a modification of the file +# kinematically_driven_subduction_2d_case2a.prm +# to include temperature-dependent density. +set Additional shared libraries = $ASPECT_SOURCE_DIR/cookbooks/kinematically_driven_subduction_2d/libsubduction_plate_cooling.so + +# 2D +set Dimension = 2 + +# Reuse parts of case 2a +include $ASPECT_SOURCE_DIR/cookbooks/kinematically_driven_subduction_2d/kinematically_driven_subduction_2d_case2a.prm + +set Output directory = output-Case2b + +subsection Material model + set Model name = multicomponent + + subsection Multicomponent + # The benchmark uses two different reference temperatures for the compositions: + # 1573.15 K for the asthenosphere, thermal_OP and thermal_SP, and 473.15 K for + # the rest of the compositions. + # As ASPECT only allows for one reference temperature, we have instead adapted + # the reference density for the mantle compositions. To do this, we took the initial + # temperature and the midpoint depth of the layers and equated the density equation + # using the benchmark reference density rho_0_1 (3200 kg/m3) and temperature T_0_1 (1573.15 K), and + # the density equation using the 473.15 K reference temperature to obtain the new reference density rho_0_2. + # For the left thermal layer, the initial temperature at the midpoint is 1355 K, so + # new reference density can be derived as follows: + # rho_0_1 * (1 - alpha * (T - T_0_1)) = rho_0_2 * (1 - alpha * (T - T_0_2)), + # 3200 * (1 - 2.5e-5 * (1355 - 1573.15)) = rho_0_2 * (1 - 2.5e-5 * (1355 - 473.15)) + # rho_0_2 = 3290.66. + set Reference temperature = 473.15 + set Densities = 3290.66,3000.0,3000.0,3250.0,3250.0,3290.66,3290.66,3200.0 + + # Compared to Case 2a, thermal expansivity is no longer zero and therefore temperature + # feeds into the density and therefore the Stokes equations + set Thermal expansivities = 2.5e-5 + end +end diff --git a/cookbooks/kinematically_driven_subduction_2d/subduction_plate_cooling.cc.bak b/cookbooks/kinematically_driven_subduction_2d/subduction_plate_cooling.cc.bak new file mode 100644 index 00000000000..27c7789308c --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/subduction_plate_cooling.cc.bak @@ -0,0 +1,100 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include "subduction_plate_cooling.h" +#include + + +namespace aspect +{ + namespace InitialTemperature + { + template + double + SubductionPlateCooling:: + initial_temperature (const Point &position) const + { + // This initial condition only makes sense if the geometry is a + // box. Throw an error if that is not the case. + AssertThrow(Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage("Subduction plate cooling initial temperature is not implemented " + "for any other geometry model than a box. ") ); + + // Model domain is 3000 x 670 km. + // Geometry constants: + // surface temperature + const double Ts=273.15; + // temperature at the base of the plates + const double Tm = 1573.15; + // the base of the subducting plate at 110 km depth + const double y70 = -110000.0; + // the base of the overriding plate at 82 km depth + const double y40 = -82000.0; + // thermal diffusivity + const double kappa = 1.0e-6; + // the age of the subducting plate + const double t70 = 70e6 * year_in_seconds; + // the age of the overriding plate + const double t40 = 40e6 * year_in_seconds; + + // the temperature to return + double temperature = 0.; + + // Calculate the temperature in the portions of the model domain. + // overriding plate + subduction interface + if (position[0] < 1500000.0) + { + // lithosphere + if (position[1] >= 588000.0) + temperature=Ts+(Tm-Ts)*( ((position[1]-670000.0)/y40) + (2.0/numbers::PI)*(std::exp((-kappa*numbers::PI*numbers::PI*t40)/(y40*y40))*std::sin(numbers::PI*(position[1]-670000.0)/y40) + + 0.5*std::exp((-kappa*2.0*2.0*numbers::PI*numbers::PI*t40)/(y40*y40))*std::sin(2.0*numbers::PI*(position[1]-670000.0)/y40))); + // sublithospheric mantle + else + temperature=-0.25*(position[1]/1000.0)+1720.15; + } + // subducting plate + else + { + // lithosphere + if (position[1] >= 560000.0) + temperature=Ts+(Tm-Ts)*( ((position[1]-670000.0)/y70) + (2.0/numbers::PI)*(std::exp((-kappa*numbers::PI*numbers::PI*t70)/(y70*y70))*std::sin(numbers::PI*(position[1]-670000.0)/y70) + + 0.5*std::exp((-kappa*2.0*2.0*numbers::PI*numbers::PI*t70)/(y70*y70))*std::sin(2.0*numbers::PI*(position[1]-670000.0)/y70))); + // sublithospheric mantle + else + temperature=-0.25*(position[1]/1000.0)+1713.15; + } + return temperature; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(SubductionPlateCooling, + "subduction plate cooling", + "An initial temperature field as specified in Quinquis (2014) " + "using the plate cooling model to prescribe temperatures " + "for an overriding and a subducting plate. ") + } +} diff --git a/cookbooks/kinematically_driven_subduction_2d/subduction_plate_cooling.h.bak b/cookbooks/kinematically_driven_subduction_2d/subduction_plate_cooling.h.bak new file mode 100644 index 00000000000..511abb2eb57 --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/subduction_plate_cooling.h.bak @@ -0,0 +1,52 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_subduction_plate_cooling_h +#define _aspect_initial_temperature_subduction_plate_cooling_h + +#include +#include + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that prescribes the initial temperature field according to the plate cooling model + * and plate geometries implemented in Quinquis (2014). + * + * @ingroup InitialTemperatures + */ + template + class SubductionPlateCooling : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + }; + } +} + +#endif diff --git a/cookbooks/kinematically_driven_subduction_2d/trench_location.cc.bak b/cookbooks/kinematically_driven_subduction_2d/trench_location.cc.bak new file mode 100644 index 00000000000..c0d283ca959 --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/trench_location.cc.bak @@ -0,0 +1,157 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include "trench_location.h" +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + TrenchLocation::execute (TableHandler &statistics) + { + // create a quadrature formula based on the compositional element alone. + AssertThrow(this->introspection().n_compositional_fields > 0, + ExcMessage("This postprocessor cannot be used without compositional fields.")); + const Quadrature &quadrature_formula = this->introspection().face_quadratures.compositional_fields; + + FEFaceValues + fe_face_values(this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_quadrature_points | + update_JxW_values); + + const unsigned int n_q_points = fe_face_values.n_quadrature_points; + + // Vector to store the values of the field that defines the trench. + std::vector compositional_values_trench(n_q_points); + // Vector to store the positions of the quadrature points. + std::vector> position_values(n_q_points); + // For each process, find the right most occurrence of the trench field. + double local_trench_location = 0.; + + const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + + // For cells with a face along the domain surface, compute the trench location + // by looping over these cells and if the trench field is present at a location + // further right than the current local_trench_location, set the local_trench_location + // to this new x-coordinate. + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + for (const unsigned int f : cell->face_indices()) + if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) + { + fe_face_values.reinit(cell,f); + + position_values = fe_face_values.get_quadrature_points(); + + fe_face_values[this->introspection().extractors.compositional_fields[selected_field]].get_function_values(this->get_solution(), compositional_values_trench); + + // Calculate the rightmost occurrence of the selected field per processor. + // A field is counted as present when its value is equal or higher than 0.5. + for (unsigned int q = 0; q < n_q_points; ++q) + { + if (compositional_values_trench[q] >= 0.5 && position_values[q][0] > local_trench_location) + { + local_trench_location = position_values[q][0]; + } + } + } + + // compute the rightmost point over all processors + const double global_trench_location = + Utilities::MPI::max (local_trench_location, this->get_mpi_communicator()); + + statistics.add_value ("Trench location [m]", global_trench_location); + + // also make sure that the other columns filled by the this object + // all show up with sufficient accuracy and in scientific notation + { + const char *columns[] = { "Trench location [m]" + }; + for (unsigned int i=0; i ("Trench location [m]:", + output.str()); + } + + template + void TrenchLocation::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Trench location"); + { + prm.declare_entry("Name of trench compositional field", "", + Patterns::Anything(), + "The name of the trench compositional field that " + "you want to compute the rightmost position for."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void TrenchLocation::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Trench location"); + { + selected_field = this->introspection().compositional_index_for_name(prm.get("Name of trench compositional field")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(TrenchLocation, + "trench location", + "A postprocessor that computes the trench location at the domain surface, " + "i.e., the rightmost point of a given compositional field at the surface.") + } +} diff --git a/cookbooks/kinematically_driven_subduction_2d/trench_location.h.bak b/cookbooks/kinematically_driven_subduction_2d/trench_location.h.bak new file mode 100644 index 00000000000..49f7a64b40d --- /dev/null +++ b/cookbooks/kinematically_driven_subduction_2d/trench_location.h.bak @@ -0,0 +1,75 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_postprocess_trench_location_h +#define _aspect_postprocess_trench_location_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that tracks the most left position of a certain compositional field. + * + * @ingroup Postprocessing + */ + template + class TrenchLocation : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for the most left coordinate of the user-specified compositional field + * along the surface of the domain. + **/ + std::pair + execute (TableHandler &statistics) override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static void + declare_parameters(ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters(ParameterHandler &prm) override; + /** + * @} + */ + + private: + unsigned int selected_field; + }; + } +} + + +#endif diff --git a/cookbooks/latent-heat/doc/material.part.prm.bak b/cookbooks/latent-heat/doc/material.part.prm.bak new file mode 100644 index 00000000000..32723b2f727 --- /dev/null +++ b/cookbooks/latent-heat/doc/material.part.prm.bak @@ -0,0 +1,41 @@ +subsection Material model + set Model name = latent heat + + subsection Latent heat + # The change of density across the phase transition. Together with the + # Clapeyron slope, this is what determines the entropy change. + set Phase transition density jumps = 115.6 + set Corresponding phase for density jump = 0 + + # If the temperature is equal to the phase transition temperature, the + # phase transition will occur at the phase transition depth. However, + # if the temperature deviates from this value, the Clapeyron slope + # determines how much the pressure (and depth) of the phase boundary + # changes. Here, the phase transition will be in the middle of the box + # for T=T1. + set Phase transition depths = 500000 + set Phase transition temperatures = 1000 + set Phase transition Clapeyron slopes = 1e7 + + # We set the width of the phase transition to 5 km. You may want to + # change this parameter to see how latent heating depends on the width + # of the phase transition. + set Phase transition widths = 5000 + set Reference density = 3400 + set Reference specific heat = 1000 + set Reference temperature = 1000 + set Thermal conductivity = 2.38 + + # We set the thermal expansion amd the compressibility to zero, so that + # all temperature (and density) changes are caused by advection, diffusion + # and latent heating. + set Thermal expansion coefficient = 0.0 + set Compressibility = 0.0 + + # Viscosity is constant. + set Thermal viscosity exponent = 0.0 + set Viscosity = 8.44e21 + set Viscosity prefactors = 1.0, 1.0 + set Composition viscosity prefactor = 1.0 + end +end diff --git a/cookbooks/latent-heat/latent-heat.prm.bak b/cookbooks/latent-heat/latent-heat.prm.bak new file mode 100644 index 00000000000..b8b6bc2299c --- /dev/null +++ b/cookbooks/latent-heat/latent-heat.prm.bak @@ -0,0 +1,145 @@ +############### Global parameters +# We use a 2d setup. Since it takes some time for +# the model to reach a steady state we set the +# end time to approximately 15 billion years. + +set Dimension = 2 +set Start time = 0 +set End time = 5e17 +set Use years in output instead of seconds = false +set Output directory = output-latent-heat + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1000000 + set Y extent = 1000000 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +subsection Heating model + # As we only want to look at the effects of latent heating, we disable all + # the other heating terms. + set List of model names = latent heat +end + +############### Boundary conditions +# We only fix the temperature at the upper boundary, the other boundaries +# are isolating. +subsection Boundary temperature model + set Fixed temperature boundary indicators = top + set List of model names = box + + subsection Box + set Top temperature = 1000 + end +end + +# To guarantuee a steady downward flow, we fix the velocity +# at the top and bottom, and set it to free slip on the sides. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = bottom:function, top:function + set Tangential velocity boundary indicators = left, right + + subsection Function + set Function expression = 0;-2.1422e-11 + set Variable names = x,y + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1.0e3 + set Variable names = x,y + end +end + +subsection Material model + set Model name = latent heat + + subsection Latent heat + # The change of density across the phase transition. Together with the + # Clapeyron slope, this is what determines the entropy change. + set Phase transition density jumps = 115.6 + set Corresponding phase for density jump = 0 + + # If the temperature is equal to the phase transition temperature, the + # phase transition will occur at the phase transition depth. However, + # if the temperature deviates from this value, the Clapeyron slope + # determines how much the pressure (and depth) of the phase boundary + # changes. Here, the phase transition will be in the middle of the box + # for T=T1. + set Phase transition depths = 500000 + set Phase transition temperatures = 1000 + set Phase transition Clapeyron slopes = 1e7 + + # We set the width of the phase transition to 5 km. You may want to + # change this parameter to see how latent heating depends on the width + # of the phase transition. + set Phase transition widths = 5000 + set Reference density = 3400 + set Reference specific heat = 1000 + set Reference temperature = 1000 + set Thermal conductivity = 2.38 + + # We set the thermal expansion amd the compressibility to zero, so that + # all temperature (and density) changes are caused by advection, diffusion + # and latent heating. + set Thermal expansion coefficient = 0.0 + set Compressibility = 0.0 + + # Viscosity is constant. + set Thermal viscosity exponent = 0.0 + set Viscosity = 8.44e21 + set Viscosity prefactors = 1.0, 1.0 + set Composition viscosity prefactor = 1.0 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 7 + set Time steps between mesh refinement = 0 +end + +subsection Discretization + subsection Stabilization parameters + # The exponent $\alpha$ in the entropy viscosity stabilization. Units: + # None. + set alpha = 2 + + # The $\beta$ factor in the artificial viscosity stabilization. An + # appropriate value for 2d is 0.052 and 0.078 for 3d. Units: None. + set beta = 0.078 + + # The $c_R$ factor in the entropy viscosity stabilization. Units: None. + set cR = 0.5 + end +end + +subsection Postprocess + set List of postprocessors = visualization + + subsection Visualization + set Number of grouped files = 0 + set Output format = vtu + + # We are only interested in the last timestep (when the system hast reached + # a steady state). For following the development of the system or checking + # if the solution already reached steady state, this parameter can be set + # to a smaller value. + set Time between graphical output = 5e17 + set List of output variables = density + end +end diff --git a/cookbooks/lower_crustal_flow/lower_crustal_flow_obstacle.prm.bak b/cookbooks/lower_crustal_flow/lower_crustal_flow_obstacle.prm.bak new file mode 100644 index 00000000000..3136dab8c9b --- /dev/null +++ b/cookbooks/lower_crustal_flow/lower_crustal_flow_obstacle.prm.bak @@ -0,0 +1,116 @@ +# A simple setup for a lower crustal flow around an obstacle in 3D based on Clark et al, GJI, 2005. + +############### Global parameters + +set Dimension = 3 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = true +set Output directory = output-lower-crustal-flow-obstacle +set Pressure normalization = volume +set Timing output frequency = 0 + +############### Parameters of the linear solver + +subsection Solver parameters + subsection Stokes solver parameters + set Number of cheap Stokes solver steps = 0 + set Maximum number of expensive Stokes solver steps = 3000 + set Stokes solver type = block GMG + end +end + +############### Parameters describing the model + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1200e3 + set Y extent = 600e3 + set Z extent = 15e3 + set X repetitions = 10 + set Y repetitions = 5 + end +end + +subsection Compositional fields + set Number of fields = 1 +end + +# first material is lower crust +# second material is obstacle + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y,z + set Function constants = a=200e3 + set Function expression = if ((x-600e3)^2+(y)^2 < a^2,1,0) + end +end + +subsection Material model + set Model name = simple + set Material averaging = harmonic average + + subsection Simple model + set Viscosity = 2e18 + set Density differential for compositional field 1 = 10 + set Composition viscosity prefactor = 1000 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = front,back + set Zero velocity boundary indicators = bottom,top + set Prescribed velocity boundary indicators = left: function, right:function + + subsection Function + set Variable names = x,y,z + set Function constants = cm=0.01, year=1 , b=7.5e3 + set Function expression = 8*cm/year*(1-((z-b)/b)^2) ; 0 ; 0 + end +end + +############### Parameters describing the temperature field + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the discretization + +subsection Mesh refinement + set Initial global refinement = 3 + set Strategy = composition + set Initial adaptive refinement = 0 + set Refinement fraction = 0.9 + set Coarsening fraction = 0. + set Minimum refinement level = 1 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, pressure statistics + + subsection Visualization + set Output format = vtu + set List of output variables = density, viscosity, strain rate + set Time between graphical output = 0 + end +end diff --git a/cookbooks/magnetic_stripes/magnetic_stripes.cc b/cookbooks/magnetic_stripes/magnetic_stripes.cc index 5a3cd1340f2..0c13a2b6ef9 100644 --- a/cookbooks/magnetic_stripes/magnetic_stripes.cc +++ b/cookbooks/magnetic_stripes/magnetic_stripes.cc @@ -63,7 +63,7 @@ namespace aspect break; } - for (unsigned int i=0; i < in.position.size(); ++i) + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) { const double depth = this->get_geometry_model().depth(in.position[i]); const double reaction_depth = 7000.0; diff --git a/cookbooks/magnetic_stripes/magnetic_stripes.cc.bak b/cookbooks/magnetic_stripes/magnetic_stripes.cc.bak new file mode 100644 index 00000000000..5a3cd1340f2 --- /dev/null +++ b/cookbooks/magnetic_stripes/magnetic_stripes.cc.bak @@ -0,0 +1,153 @@ +/* + Copyright (C) 2022 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + template + class MagneticStripes : public MaterialModel::CompositionReaction + { + public: + + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + static void declare_parameters (ParameterHandler &prm); + void parse_parameters (ParameterHandler &prm) override; + + private: + std::vector reversal_times; + }; + + + template + void + MagneticStripes:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + CompositionReaction::evaluate(in, out); + + int magnetic_orientation = 1; + if (this->simulator_is_past_initialization()) + for (unsigned int i=0; i < reversal_times.size(); ++i) + if (this->get_time() < reversal_times[i]) + { + // magnetic orientation is either 1 (normal) or -1 (reverse) + magnetic_orientation = -2 * (i % 2) + 1; + break; + } + + for (unsigned int i=0; i < in.position.size(); ++i) + { + const double depth = this->get_geometry_model().depth(in.position[i]); + const double reaction_depth = 7000.0; + + for (unsigned int c=0; cn_compositional_fields(); ++c) + { + // Magnetic lineations are only generated when material approaches the surface, + // i.e. above the reaction depth and when the velocity is predominantly upwards. + if (depth < reaction_depth && in.velocity[i][1] > std::abs(in.velocity[i][0])) + out.reaction_terms[i][c] = -in.composition[i][0] + magnetic_orientation; + else + out.reaction_terms[i][c] = 0.0; + } + } + } + + template + void + MagneticStripes::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Magnetic stripes model"); + { + CompositionReaction::declare_parameters (prm); + + prm.declare_entry ("Reversal times", "5.0, 5.0, 2.0, 2.0, 2.092, 2.419, 2.419", + Patterns::List(Patterns::Double(0)), + "Reversal times of the magnetic field." + "Units: yr or s, depending on the ``Use years " + "in output instead of seconds'' parameter."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + MagneticStripes::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Magnetic stripes model"); + { + CompositionReaction::parse_parameters (prm); + + reversal_times = Utilities::string_to_double (Utilities::split_string_list(prm.get ("Reversal times"))); + std::sort (reversal_times.begin(), reversal_times.end()); + + if (this->get_parameters().convert_to_years == true) + for (unsigned int i=0; i0, v * cm_per_year, -v * cm_per_year); 0 + end +end + +subsection Boundary traction model + set Prescribed traction boundary indicators = left y:initial lithostatic pressure, right y:initial lithostatic pressure + + subsection Initial lithostatic pressure + set Representative point = 0,0 + set Number of integration points = 1000 + end +end + +# We then choose a vertical gravity model and describe the +# initial temperature as a constant (being equivalent to a +# plate age of 0). +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = 1600 + end +end + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = 0 + end +end + +subsection Boundary composition model + set Fixed composition boundary indicators = bottom + set Model name = initial composition +end + +subsection Material model + set Model name = magnetic stripes + + subsection Composition reaction model + set Thermal conductivity = 4.7 + set Thermal expansion coefficient = 1e-4 + set Viscosity = 1e23 + end + + subsection Magnetic stripes model + set Reversal times = \ +8.350E+07, 8.272E+07, \ +8.251E+07, 8.243E+07, \ +8.173E+07, 8.155E+07, \ +8.136E+07, 8.135E+07, \ +8.092E+07, 8.046E+07, \ +8.039E+07, 8.028E+07, \ +8.017E+07, 7.992E+07, \ +7.932E+07, 7.921E+07, \ +7.902E+07, 7.888E+07, \ +7.870E+07, 7.861E+07, \ +7.852E+07, 7.827E+07, \ +7.761E+07, 7.736E+07, \ +7.723E+07, 7.693E+07, \ +7.657E+07, 7.641E+07, \ +7.637E+07, 7.633E+07, \ +7.616E+07, 7.613E+07, \ +7.607E+07, 7.594E+07, \ +7.585E+07, 7.543E+07, \ +7.528E+07, 7.524E+07, \ +7.480E+07, 7.448E+07, \ +7.427E+07, 7.419E+07, \ +7.392E+07, 7.386E+07, \ +7.376E+07, 7.362E+07, \ +7.358E+07, 7.255E+07, \ +7.245E+07, 7.240E+07, \ +7.202E+07, 7.197E+07, \ +7.157E+07, 7.142E+07, \ +7.132E+07, 7.110E+07, \ +7.082E+07, 7.079E+07, \ +7.073E+07, 7.068E+07, \ +7.051E+07, 7.036E+07, \ +7.020E+07, 6.999E+07, \ +6.980E+07, 6.942E+07, \ +6.932E+07, 6.889E+07, \ +6.870E+07, 6.861E+07, \ +6.847E+07, 6.835E+07, \ +6.749E+07, 6.721E+07, \ +6.717E+07, 6.701E+07, \ +6.694E+07, 6.677E+07, \ +6.622E+07, 6.589E+07, \ +6.522E+07, 6.472E+07, \ +6.445E+07, 6.337E+07, \ +6.298E+07, 6.278E+07, \ +6.250E+07, 6.218E+07, \ +6.173E+07, 6.164E+07, \ +6.135E+07, 6.125E+07, \ +6.104E+07, 6.101E+07, \ +6.091E+07, 6.075E+07, \ +6.070E+07, 6.043E+07, \ +6.015E+07, 5.997E+07, \ +5.982E+07, 5.970E+07, \ +5.950E+07, 5.938E+07, \ +5.877E+07, 5.872E+07, \ +5.867E+07, 5.832E+07, \ +5.800E+07, 5.785E+07, \ +5.768E+07, 5.755E+07, \ +5.751E+07, 5.695E+07, \ +5.647E+07, 5.553E+07, \ +5.522E+07, 5.499E+07, \ +5.492E+07, 5.476E+07, \ +5.410E+07, 5.384E+07, \ +5.374E+07, 5.340E+07, \ +5.302E+07, 5.256E+07, \ +5.044E+07, 4.996E+07, \ +4.885E+07, 4.856E+07, \ +4.816E+07, 4.797E+07, \ +4.782E+07, 4.716E+07, \ +4.688E+07, 4.603E+07, \ +4.590E+07, 4.565E+07, \ +4.558E+07, 4.539E+07, \ +4.507E+07, 4.395E+07, \ +4.387E+07, 4.337E+07, \ +4.224E+07, 4.198E+07, \ +4.096E+07, 3.971E+07, \ +3.724E+07, 3.559E+07, \ +3.446E+07, 3.379E+07, \ +3.272E+07, 3.255E+07, \ +3.245E+07, 3.176E+07, \ +3.114E+07, 3.084E+07, \ +3.074E+07, 3.070E+07, \ +3.060E+07, 3.015E+07, \ +2.760E+07, 2.711E+07, \ +2.595E+07, 2.559E+07, \ +2.258E+07, 2.222E+07, \ +2.100E+07, 1.987E+07, \ +1.952E+07, 1.876E+07, \ +1.792E+07, 1.589E+07, \ +1.577E+07, 1.476E+07, \ +1.243E+07, 1.216E+07, \ +1.191E+07, 1.050E+07, \ +1.021E+07, 1.013E+07, \ +9.881E+06, 4.425E+06, \ +5.000E+05 + end +end + +# The final part of this input file describes how many times the +# mesh is refined and what to do with the solution once computed +subsection Mesh refinement + set Initial adaptive refinement = 4 + set Initial global refinement = 3 + set Time steps between mesh refinement = 0 + set Strategy = minimum refinement function + + subsection Minimum refinement function + set Variable names = depth, w + set Function expression = if(depth<7000,7,if(depth<10000,6,if(depth<30000,5,if(depth<45000,4,3)))) + end +end + +subsection Postprocess + set List of postprocessors = visualization, temperature statistics, heat flux statistics + + subsection Visualization + set Time between graphical output = 1e5 + set List of output variables = density, heat flux map, vertical heat flux + end +end diff --git a/cookbooks/mantle_convection_with_continents_in_annulus/modelR.prm.bak b/cookbooks/mantle_convection_with_continents_in_annulus/modelR.prm.bak new file mode 100644 index 00000000000..786751a5b6b --- /dev/null +++ b/cookbooks/mantle_convection_with_continents_in_annulus/modelR.prm.bak @@ -0,0 +1,210 @@ +# input file for model R of van der Wiel et al., 2024. + +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 1e9 +set Output directory = output-mantle-convection-annulus +set World builder file = $ASPECT_SOURCE_DIR/cookbooks/mantle_convection_with_continents_in_annulus/world.wb +set CFL number = 0.7 +set Nonlinear solver scheme = single Advection, iterated Stokes +set Max nonlinear iterations = 10 +set Nonlinear solver tolerance = 1e-4 +set Timing output frequency = 10 + +subsection Solver parameters + subsection Stokes solver parameters + set Stokes solver type = block GMG + set Number of cheap Stokes solver steps = 5000 + set Maximum number of expensive Stokes solver steps = 0 + set Linear solver tolerance = 1e-6 + end +end + +subsection Formulation + set Formulation = isentropic compression +end + +subsection Compositional fields + set Number of fields = 2 + set Names of fields = 1_mantle, 3_continent + set Compositional field methods = particles, particles + set Mapped particle properties = 1_mantle: initial 1_mantle, 3_continent: initial 3_continent +end + +subsection Nullspace removal + set Remove nullspace = net rotation +end + +subsection Material model + set Model name = compositing + set Material averaging = harmonic average only viscosity + + subsection Visco Plastic + set Reference temperature = 1600 + set Minimum viscosity = 1e20 + set Maximum viscosity = 6e24 + set Viscous flow law = composite + set Minimum strain rate = 1e-22 + set Reference strain rate = 1e-15 + set Heat capacities = background: 1250, 1_mantle: 1250 | 1250 | 1250 , 3_continent: 1250 + set Prefactors for dislocation creep = background:6.51e-16 , 1_mantle: 6.51e-16| 8.51e-16 | 6.51e-16 , 3_continent:6.51e-28 + set Stress exponents for dislocation creep = background:1 , 1_mantle: 3 | 3 | 1 , 3_continent: 1 + set Activation energies for dislocation creep = background:540e3 , 1_mantle: 500e3 | 500e3 | 530e3 , 3_continent: 540e3 + set Activation volumes for dislocation creep = background:18e-6 , 1_mantle: 1.3e-5 | 1.3e-5 | 1.3e-5 , 3_continent: 18e-6 + set Prefactors for diffusion creep = background:6e-18 , 1_mantle: 6e-17 | 9e-17 | 1e-18 , 3_continent: 6e-20 + set Grain size exponents for diffusion creep = background:1 , 1_mantle: 1 | 1 | 3 , 3_continent: 1 + set Activation energies for diffusion creep = background:166e3 , 1_mantle: 150e3 | 155e3 | 150e3 , 3_continent: 166e3 + set Activation volumes for diffusion creep = background:6.34e-7 , 1_mantle: 6.34e-7 | 14.34e-7 | 12.34e-7 , 3_continent: 6.34e-7 + set Densities = background:3300 , 1_mantle: 3300 | 3500 | 3800 , 3_continent: 2900 + set Grain size = 1 + set Angles of internal friction = 1.43373998 , 1.43373998 , 30 + set Cohesions = 7e6 , 4e6,1e7 + set Phase transition depths = 1_mantle: 410000 | 660000 + set Phase transition temperatures = 1_mantle: 1700 | 1900 + set Phase transition Clapeyron slopes = 1_mantle: 3e6 | -2.5e6 + set Phase transition widths = 1_mantle: 50000 | 50000 + set Use adiabatic pressure in creep viscosity = true + set Constant viscosity prefactors = 1, 1, 1 + end + + subsection Latent heat + # The change of density across the phase transition. Together with the + # Clapeyron slope, this is what determines the entropy change. + set Phase transition density jumps = 273, 341 + set Corresponding phase for density jump = 1, 1 + + # If the temperature is equal to the phase transition temperature, the + # phase transition will occur at the phase transition depth. However, + # if the temperature deviates from this value, the Clapeyron slope + # determines how much the pressure (and depth) of the phase boundary + # changes. Here, the phase transition will be in the middle of the box + # for T=T1. + set Phase transition depths = 1_mantle: 410000 | 660000 + set Phase transition temperatures = 1_mantle: 1700 | 1900 + set Phase transition Clapeyron slopes = 1_mantle: 3e6 | -2.5e6 + set Phase transition widths = 1_mantle: 50000 | 50000 + set Reference specific heat = 1250 + set Thermal conductivity = 6 + set Thermal expansion coefficient = 3e-5 + set Viscosity prefactors = 1,1,1 + set Density differential for compositional field 1 = 400 + set Reference density = 2916 + end + + subsection Compositing + set Viscosity = visco plastic + set Density = latent heat + set Thermal expansion coefficient = latent heat + set Specific heat = latent heat + set Thermal conductivity = latent heat + set Compressibility = latent heat + set Entropy derivative pressure = latent heat + set Entropy derivative temperature = latent heat + set Reaction terms = latent heat + end +end + +subsection Initial composition model + set Model name = world builder +end + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3480000 + set Outer radius = 6370000 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = inner, outer +end + +subsection Heating model + set List of model names = latent heat, adiabatic heating, constant heating, shear heating + + subsection Adiabatic heating + set Use simplified adiabatic heating = true + end + + subsection Constant heating + set Radiogenic heating rate = 5.44e-12 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = outer, inner + set List of model names = spherical constant + + subsection Spherical constant + set Outer temperature = 300 + set Inner temperature = 3700 + end +end + +subsection Initial temperature model + set Model name = world builder +end + +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 9.81 + end +end + +subsection Mesh refinement + set Initial global refinement = 3 + set Initial adaptive refinement = 4 + set Strategy = minimum refinement function, viscosity, velocity + set Time steps between mesh refinement = 1 + + subsection Minimum refinement function + set Coordinate system = spherical + set Function expression = if(r>6000e3, 6, if(r>5000e3,5,3)) + set Variable names = r,phi,t + end +end + +subsection Postprocess + set List of postprocessors = velocity statistics, temperature statistics, visualization, heat flux statistics, depth average, particles, Stokes residual, basic statistics, mobility statistics + + subsection Global statistics + set Write statistics for each nonlinear iteration = true + end + + subsection Depth average + set Time between graphical output = 1e6 + set Number of zones = 100 + end + + subsection Visualization + set Number of grouped files = 1 + set Output format = vtu + set Time between graphical output = 1e6 + set List of output variables = density, viscosity, strain rate, stress, temperature anomaly, spherical velocity components, adiabat, heat flux map, heating, vertical heat flux + end + + subsection Particles + set Time between data output = 1e6 + set Data output format = ascii, vtu + set Number of grouped files = 1 + set Write in background thread = true + end +end + +subsection Particles + set List of particle properties = position, velocity, initial composition, pT path, initial position + set Update ghost particles = true + set Particle generator name = reference cell + set Load balancing strategy = remove and add particles + set Minimum particles per cell = 80 + + subsection Generator + subsection Reference cell + set Number of particles per cell per direction = 4 + end + end +end diff --git a/cookbooks/mid_ocean_ridge/doc/boundary_conditions.part.prm.bak b/cookbooks/mid_ocean_ridge/doc/boundary_conditions.part.prm.bak new file mode 100644 index 00000000000..2033c6387d3 --- /dev/null +++ b/cookbooks/mid_ocean_ridge/doc/boundary_conditions.part.prm.bak @@ -0,0 +1,34 @@ +##################### Velocity ######################## + +# To model the divergent velocitiy field of a mid-ocean ridge, we prescribe +# the plate velocity (pointing away from the ridge) at the top boundary. +# We use a closed boundary with free slip conditions as the left boundary, which +# marks the ridge axis and also acts as a center line for our model, so that +# material can not cross this boundary. +# We prescribe the velocity at the top boundary using a function: +# At the ridge axis, the velocity is zero, at a distance of 10 km from the ridge +# axis or more, the rigid plate uniformly moves away from the ridge with a constant +# speed, and close to the ridge we interpolate between these two conditions. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = top:function + set Tangential velocity boundary indicators = left + + subsection Function + # We choose a half-spreading rate of u0=3cm/yr. + set Function constants = u0=0.03, x0=10000 + set Variable names = x,z + set Function expression = if(x=725e3,1,0);if((y<725e3&y>700e3),1,0) + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = h=750e3, w=3000e3, mantleT=1350 # deg C + set Function expression = \ + if( y < 100e3, \ + (100e3-y)/100e3*(1600-mantleT)+mantleT+293, \ + if(y>650e3, \ + (h-y)/(100e3)*mantleT+293, \ + mantleT+293)) + end +end + +subsection Material model + set Model name = Morency and Doin + + subsection Morency and Doin + set Densities = 3300,2920,2920 + set Activation energies = 500,320,320 + set Coefficient of yield stress increase with depth = 0.25 + set Thermal expansivities = 3.5e-5 + set Stress exponents for viscous rheology = 3 + set Stress exponents for plastic rheology = 30 + set Thermal diffusivity = 0.8e-6 + set Heat capacity = 1.25e3 + set Activation volume = 6.4e-6 + set Reference strain rate = 6.4e-16 + set Preexponential constant for viscous rheology law = 7e11 ## Value used in paper is 1.24e14 + set Cohesive strength of rocks at the surface = 117 + set Reference temperature = 293 + set Minimum strain rate = 5e-19 ## Value used in paper is 1.4e-20 + end +end diff --git a/cookbooks/morency_doin_2004/morency_doin.cc.bak b/cookbooks/morency_doin_2004/morency_doin.cc.bak new file mode 100644 index 00000000000..de787747673 --- /dev/null +++ b/cookbooks/morency_doin_2004/morency_doin.cc.bak @@ -0,0 +1,302 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include "morency_doin.h" +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + void + MorencyDoin:: + evaluate(const MaterialModelInputs &in, + MaterialModelOutputs &out) const + { + const double R = 8.32; // J mol-1 K-1 + const double g = 9.8; // m s-2 + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const Point position = in.position[i]; + const double temperature = in.temperature[i]; + const std::vector composition = in.composition[i]; + const std::vector volume_fractions = MaterialUtilities::compute_composition_fractions(composition); + + SymmetricTensor<2,dim> strain_rate; + if (in.requests_property(MaterialProperties::viscosity)) + strain_rate = in.strain_rate[i]; + + const double depth = this->get_geometry_model().depth(position); // Units: \\si{\\meter} + + // Calculate viscosity + { + double activation_energy = 0.0; + for (unsigned int j=0; j < volume_fractions.size(); ++j) + activation_energy += volume_fractions[j] * activation_energies[j] * 1e3; // Converted to J/mol to make units work + double nv = 0.0; + for (unsigned int j=0; j < volume_fractions.size(); ++j) + nv += volume_fractions[j] * nvs[j]; + double np = 0.0; + for (unsigned int j=0; j < volume_fractions.size(); ++j) + np += volume_fractions[j] * nps[j]; + + const double tauy = tau_0 + gamma*densities[0]*g*depth; + + /** + * Note: The actual second invariant of strain rate is defined as $e_{00}e_{11} - e_{01}^2$, + * (maybe times 1/2 depending on the convention) where e is the second order strain rate + * tensor. The function used here reflects the equations defined in (Morency and Doin, 2004) + * but is otherwise unjustified. Use at your own risk. + */ + const double e2inv = std::sqrt((strain_rate[0][0]*strain_rate[0][0] + strain_rate[0][1]*strain_rate[0][1])/2.0); + + const double edot = std::sqrt(std::pow(e2inv,2) + std::pow(min_strain_rate,2)); + + // Calculate 1/(v_eff^v) and 1/(v_eff^p) + double one_over_veffv = 0.0; + if (temperature != 0.0) + one_over_veffv = 1.0 / (B * std::pow(edot/ref_strain_rate, -1.0+1.0/nv)) + * std::exp(-(activation_energy+activation_volume*densities[0]*g*depth)/(nv*R*temperature)); + const double one_over_veffp = 1.0 / (tauy * (std::pow(edot, -1.0+1.0/np) / std::pow(ref_strain_rate, 1.0/np))); + // Effective viscosity = harmonic mean of diffusion and dislocation creep. + // = (1/(v_eff^v) + 1/(v_eff^p))^-1 + const double veff = std::pow((one_over_veffv + one_over_veffp), -1.0); + + out.viscosities[i] = veff; + } + + // Calculate density + { + double density = 0.0; + for (unsigned int j=0; j < volume_fractions.size(); ++j) + { + // not strictly correct if thermal expansivities are different, since we are interpreting + // these compositions as volume fractions, but the error introduced should not be too bad. + const double temperature_factor = (1.0 - thermal_expansivities[j] * (temperature - reference_T)); + density += volume_fractions[j] * densities[j] * temperature_factor; + } + out.densities[i] = density; + } + + // Thermal expansion coefficients at the given positions. + double thermal_expansivity = 0.0; + for (unsigned int j=0; j < volume_fractions.size(); ++j) + thermal_expansivity += volume_fractions[j] * thermal_expansivities[j]; + out.thermal_expansion_coefficients[i] = thermal_expansivity; + // Specific heat at the given positions. + out.specific_heat[i] = heat_capacity; + // Thermal conductivity at the given positions. + out.thermal_conductivities[i] = thermal_diffusivity * heat_capacity * out.densities[i]; + // Compressibility at the given positions. + // The compressibility is given as + // $\frac 1\rho \frac{\partial\rho}{\partial p}$. + out.compressibilities[i] = 0.0; + // Pressure derivative of entropy at the given positions. + out.entropy_derivative_pressure[i] = 0.0; + // Temperature derivative of entropy at the given positions. + out.entropy_derivative_temperature[i] = 0.0; + // Change in composition due to chemical reactions at the + // given positions. The term reaction_terms[i][c] is the + // change in compositional field c at point i. + for (unsigned int c=0; c + bool + MorencyDoin:: + is_compressible () const + { + return false; + } + + template + void + MorencyDoin::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection ("Morency and Doin"); + { + prm.declare_entry ("Densities", "3300.", + Patterns::List(Patterns::Double(0.)), + "List of densities, $\\rho$, for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}"); + prm.declare_entry ("Activation energies", "500.", + Patterns::List(Patterns::Double(0.)), + "List of activation energies, $E_a$, for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. Units: \\si{\\kilo\\joule\\per\\mole}"); + prm.declare_entry ("Thermal expansivities", "3.5e-5", + Patterns::List(Patterns::Double(0.)), + "List of thermal expansivities for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. Units: \\si{\\per\\kelvin}"); + prm.declare_entry ("Stress exponents for viscous rheology", "3.", + Patterns::List(Patterns::Double(0.)), + "List of stress exponents, $n_v$, for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. Units: None"); + prm.declare_entry ("Stress exponents for plastic rheology", "30.", + Patterns::List(Patterns::Double(0.)), + "List of stress exponents, $n_p$, for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. Units: None"); + prm.declare_entry ("Thermal diffusivity", "0.8e-6", Patterns::Double(0), + "Units: \\si{\\meter\\squared\\per\\second}"); + prm.declare_entry ("Heat capacity", "1.25e3", Patterns::Double(0), + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}"); + prm.declare_entry ("Activation volume", "6.4e-6", Patterns::Double(0), "($V_a$). Units: \\si{\\meter\\cubed\\per\\mole}"); + prm.declare_entry ("Reference strain rate", "6.4e-16", Patterns::Double(0), "($\\dot{\\epsilon}_\\text{ref}$). Units: \\si{\\per\\second}"); + prm.declare_entry ("Preexponential constant for viscous rheology law", "1.24e14", Patterns::Double(0.), "($B$). Units: None"); + prm.declare_entry ("Coefficient of yield stress increase with depth", "0.25", Patterns::Double(0.), "($\\gamma$). Units: None"); + prm.declare_entry ("Cohesive strength of rocks at the surface", "117.", Patterns::Double(0.), "($\\tau_0$). Units: \\si{\\pascal}"); + prm.declare_entry ("Reference temperature", "293.", Patterns::Double(0.), "For calculating density by thermal expansivity. Units: \\si{\\kelvin}"); + prm.declare_entry ("Minimum strain rate", "1.4e-20", Patterns::Double(0.), "Stabilizes strain dependent viscosity. Units: \\si{\\per\\second}"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + MorencyDoin::parse_parameters (ParameterHandler &prm) + { + // increment by one for background: + const unsigned int n_fields = this->n_compositional_fields() + 1; + + prm.enter_subsection("Material model"); + { + prm.enter_subsection ("Morency and Doin"); + { + gamma = prm.get_double("Coefficient of yield stress increase with depth"); + thermal_diffusivity = prm.get_double("Thermal diffusivity"); + heat_capacity = prm.get_double("Heat capacity"); + activation_volume = prm.get_double("Activation volume"); + ref_strain_rate = prm.get_double("Reference strain rate"); + B = prm.get_double("Preexponential constant for viscous rheology law"); + tau_0 = prm.get_double ("Cohesive strength of rocks at the surface"); + min_strain_rate = prm.get_double("Minimum strain rate"); + reference_T = prm.get_double("Reference temperature"); + + std::vector x_values; + + // Parse densities + x_values = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Densities"))); + AssertThrow(x_values.size() == 1u || (x_values.size() == n_fields), + ExcMessage("Length of density list must be either one, or n_compositional_fields+1")); + if (x_values.size() == 1) + densities.assign( n_fields , x_values[0]); + else + densities = x_values; + + // Parse activation energies + x_values = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Activation energies"))); + AssertThrow(x_values.size() == 1u || (x_values.size() == n_fields), + ExcMessage("Length of activation energy list must be either one, or n_compositional_fields+1")); + if (x_values.size() == 1) + activation_energies.assign( n_fields , x_values[0] ); + else + activation_energies = x_values; + + // Parse thermal expansivities + x_values = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Thermal expansivities"))); + AssertThrow(x_values.size() == 1u || (x_values.size() == n_fields), + ExcMessage("Length of thermal expansivity list must be either one, or n_compositional_fields+1")); + if (x_values.size() == 1) + thermal_expansivities.assign( n_fields , x_values[0]); + else + thermal_expansivities = x_values; + + // Parse stress exponents + x_values = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Stress exponents for viscous rheology"))); + AssertThrow(x_values.size() == 1u || (x_values.size() == n_fields), + ExcMessage("Length of nv list must be either one, or n_compositional_fields+1")); + if (x_values.size() == 1) + nvs.assign( n_fields , x_values[0]); + else + nvs = x_values; + x_values = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Stress exponents for plastic rheology"))); + AssertThrow(x_values.size() == 1u || (x_values.size() == n_fields), + ExcMessage("Length of np list must be either one, or n_compositional_fields+1")); + if (x_values.size() == 1) + nps.assign( n_fields , x_values[0]); + else + nps = x_values; + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::temperature | NonlinearDependence::strain_rate | NonlinearDependence::compositional_fields; + this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::temperature | NonlinearDependence::compositional_fields; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(MorencyDoin, + "Morency and Doin", + "An implementation of the visco-plastic rheology described by Morency " + "and Doin in \\cite{MD04}. Compositional fields can each be assigned individual " + "activation energies, reference densities, thermal expansivities, and " + "stress exponents. The effective viscosity is defined as " + "\\[v_\\text{eff} = \\left(\\frac{1}{v_\\text{eff}^v}+\\frac{1}{v_\\text{eff}^p}\\right)^{-1}\\] " + "where " + "\\[v_\\text{eff}^v = B \\left(\\frac{\\dot{\\epsilon}}{\\dot{\\epsilon}_\\text{ref}} " + "\\right)^{-1+1/n_v} exp\\left(\\frac{E_a +V_a \\rho_m g z}{n_v R T}\\right) \\] " + "\\[v_\\text{eff}^p = (\\tau_0 + \\gamma \\rho_m g z) \\left( \\frac{\\dot{\\epsilon}^{-1+1/n_p}} " + "{\\dot{\\epsilon}_\\text{ref}^{1/n_p}} \\right) \\] " + "where $B$ is a scaling constant; $\\dot{\\epsilon}$ is defined as " + "the quadratic sum of the second invariant of the strain rate tensor and " + "a minimum strain rate, $\\dot{\\epsilon}_0$; $\\dot{\\epsilon}_\\text{ref}$ " + "is a reference strain rate; $n_v$, and $n_p$ are stress exponents; $E_a$ " + "is the activation energy; $V_a$ is the activation volume; $\\rho_m$ is the " + "mantle density; $R$ is the gas constant; $T$ is temperature; $\\tau_0$ is " + "the cohesive strength of rocks at the surface; $\\gamma$ is a coefficient " + "of yield stress increase with depth; and $z$ is depth. " + "\n\n" + "\\note{Morency and Doin define the second invariant of the strain " + "rate in a nonstandard way (see \\cite{MD04}. The formulation in the paper is given as " + "$\\epsilon_{II} = \\sqrt{\\frac{1}{2} (\\epsilon_{11}^2 +" + "\\epsilon_{12}^2)}$ where $\\epsilon$ is the strain rate tensor. " + "For consistency, that is also the formulation implemented in this material model.}" + "\n\n" + "The value for the components of this formula and additional parameters are " + "read from the parameter file in subsection 'Material model/Morency and Doin'.") + } +} diff --git a/cookbooks/morency_doin_2004/morency_doin.h.bak b/cookbooks/morency_doin_2004/morency_doin.h.bak new file mode 100644 index 00000000000..11c0b6cd534 --- /dev/null +++ b/cookbooks/morency_doin_2004/morency_doin.h.bak @@ -0,0 +1,125 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_morency_doin_h +#define _aspect_material_model_morency_doin_h + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model based on the rheology described in (Morency and Doin, + * 2004): Brittle-ductile rheology with a viscosity strongly depending on + * temperature and composition. Using pseudo-brittle rheology limits the + * strength of the lithosphere at low temperature. + * + * The effective viscosity is defined as the harmonic mean of two stress- + * dependent viscosity functions: a simple temperature/pressure-dependent, + * non-Newtonian viscosity, and a more strongly stress-dependent, + * "plastic" viscosity. + * + * @f[ v_{eff}^v = B \left(\frac{\dot{\varepsilon}}{\dot{\varepsilon}_{ref}}\right)^{-1+1/n_v} + * exp\left(\frac{E_a +V_a \rho_m g z}{n_v R T}\right) @f] + * @f[ v_{eff}^p = (\tau_0 + \gamma \rho_m g z) \left( \frac{\dot{\varepsilon}^{-1+1/n_p}} + * {\dot{\varepsilon}_{ref}^{1/n_p}} \right) @f] + * @f[ v_{eff} = \left(\frac{1}{v_{eff}^v}+\frac{1}{v_{eff}^p}\right)^{-1} @f] + * + * Where $v_{eff}$ is the effective viscosity, $B$ is a scaling constant, + * $\dot{\varepsilon}$ is related to the second invariant of the strain + * rate tensor, $\dot{\varepsilon}_{ref}$ is a reference strain rate, + * $n_v$ and $n_p$ are stress exponents, $E_a$ is the activation energy, + * $V_a$ is the activation volume, $\rho_m$ is the mantle density, $R$ is + * the gas constant, $T$ is temperature, $\tau_0$ is the cohesive + * strength of rocks at the surface, $\gamma$ is a coefficient of yield + * stress increase with depth, and $z$ is depth. + * + * Several model parameters (reference densities, activation energies, + * thermal expansivities, and stress exponents-- both viscous and plastic) + * can be defined per-compositional field. If a list of values is given + * for any of these parameters, the weighted sum of the values based on + * volume fractions of the compositional fields is used in their place. If + * only one value is given for any of these parameters, all compositions + * are assigned the same value. The first value in the list is the value + * assigned to "background mantle" (regions where the sum of the + * compositional fields is < 1.0). + * + * For more on the material model and its applications, see: Morency, C., + * and M‐P. Doin. "Numerical simulations of the mantle lithosphere + * delamination." Journal of Geophysical Research: Solid Earth + * (1978–2012) 109.B3 (2004) + * + * @ingroup MaterialModels + */ + template + class MorencyDoin : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + + /** + * Evaluate material properties. + */ + void evaluate(const MaterialModelInputs &in, + MaterialModelOutputs &out) const override; + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const override; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + private: + std::vector densities; + std::vector activation_energies; + std::vector thermal_expansivities; + std::vector nvs; // Stress exponent, viscous rheology + std::vector nps;//Stress exponent, plastic rheology + double thermal_diffusivity; + double gamma; // Coefficient of yield stress increase with depth + double heat_capacity; + double activation_volume; + double ref_strain_rate; + double B; // Preexponential constant in the viscous rheology law B + double tau_0; // cohesive strength of rocks at the surface + double reference_T; + double min_strain_rate; + }; + + } +} + +#endif diff --git a/cookbooks/morency_doin_2004/morency_doin.prm b/cookbooks/morency_doin_2004/morency_doin.prm index 40880818d7c..951205a24ca 100644 --- a/cookbooks/morency_doin_2004/morency_doin.prm +++ b/cookbooks/morency_doin_2004/morency_doin.prm @@ -103,7 +103,7 @@ end subsection Solver parameters subsection Stokes solver parameters - set Stokes solver type = block AMG + set Stokes solver type = block AMG end end diff --git a/cookbooks/morency_doin_2004/morency_doin.prm.bak b/cookbooks/morency_doin_2004/morency_doin.prm.bak new file mode 100644 index 00000000000..40880818d7c --- /dev/null +++ b/cookbooks/morency_doin_2004/morency_doin.prm.bak @@ -0,0 +1,113 @@ +set Dimension = 2 +set Maximum time step = 1e4 +set Nonlinear solver scheme = iterated Advection and Stokes +set Output directory = output-morency_doin +set Additional shared libraries = ./libmorency_doin.so + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 3000e3 + set Y extent = 750e3 + set X repetitions = 4 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = top, bottom, left, right +end + +subsection Compositional fields + set Number of fields = 2 + set Names of fields = upper_crust, lower_crust +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if(y>=725e3,1,0);if((y<725e3&y>700e3),1,0) + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = h=750e3, w=3000e3, mantleT=1350 # deg C + set Function expression = \ + if( y < 100e3, \ + (100e3-y)/100e3*(1600-mantleT)+mantleT+293, \ + if(y>650e3, \ + (h-y)/(100e3)*mantleT+293, \ + mantleT+293)) + end +end + +subsection Material model + set Model name = Morency and Doin + + subsection Morency and Doin + set Densities = 3300,2920,2920 + set Activation energies = 500,320,320 + set Coefficient of yield stress increase with depth = 0.25 + set Thermal expansivities = 3.5e-5 + set Stress exponents for viscous rheology = 3 + set Stress exponents for plastic rheology = 30 + set Thermal diffusivity = 0.8e-6 + set Heat capacity = 1.25e3 + set Activation volume = 6.4e-6 + set Reference strain rate = 6.4e-16 + set Preexponential constant for viscous rheology law = 7e11 ## Value used in paper is 1.24e14 + set Cohesive strength of rocks at the surface = 117 + set Reference temperature = 293 + set Minimum strain rate = 5e-19 ## Value used in paper is 1.4e-20 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = initial temperature +end + +subsection Boundary composition model + set List of model names = initial composition +end + +subsection Gravity model + set Model name = vertical +end + +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 3 + set Strategy = minimum refinement function + + subsection Minimum refinement function + set Variable names = d,ignored + set Function expression = if(d<100e3,8,5) + end +end + +subsection Postprocess + set List of postprocessors = depth average + + subsection Depth average + set Number of zones = 500 + set Output format = gnuplot + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Stokes solver type = block AMG + end +end + +subsection Termination criteria + set Termination criteria = end step + set End step = 0 +end diff --git a/cookbooks/multicomponent_steinberger/doc/comp.field.prm.bak b/cookbooks/multicomponent_steinberger/doc/comp.field.prm.bak new file mode 100644 index 00000000000..bbefd054421 --- /dev/null +++ b/cookbooks/multicomponent_steinberger/doc/comp.field.prm.bak @@ -0,0 +1,5 @@ +subsection Compositional fields + set Number of fields = 1 + set Names of fields = basalt_fraction + set Types of fields = chemical composition +end diff --git a/cookbooks/multicomponent_steinberger/doc/comp.setup.prm.bak b/cookbooks/multicomponent_steinberger/doc/comp.setup.prm.bak new file mode 100644 index 00000000000..6e2f96548cd --- /dev/null +++ b/cookbooks/multicomponent_steinberger/doc/comp.setup.prm.bak @@ -0,0 +1,12 @@ +subsection Initial composition model + set Model name = function + + subsection Function + set Coordinate system = cartesian + set Variable names = x, y + set Function constants = a=2744.3e3, size=400e3, k=-7e-7, c=2.9367 + set Function expression = ( (sqrt(x^2+y^2)>=3981.e3 && (x-a)^2+(y-a)^2<=size^2) ? (0.15) : \ + (sqrt(x^2+y^2)<3981.e3 && sqrt(x^2+y^2)>=3481.e3) ? \ + (c+k*sqrt(x^2+y^2)) : (0) ) + end +end diff --git a/cookbooks/multicomponent_steinberger/doc/conductivity.setup.prm.bak b/cookbooks/multicomponent_steinberger/doc/conductivity.setup.prm.bak new file mode 100644 index 00000000000..d13e458712c --- /dev/null +++ b/cookbooks/multicomponent_steinberger/doc/conductivity.setup.prm.bak @@ -0,0 +1,7 @@ +subsection Material model + set Model name = Steinberger + + subsection Steinberger model + set Thermal conductivity formulation = p-T-dependent + end +end diff --git a/cookbooks/multicomponent_steinberger/doc/lookup.part.prm.bak b/cookbooks/multicomponent_steinberger/doc/lookup.part.prm.bak new file mode 100644 index 00000000000..2b260351220 --- /dev/null +++ b/cookbooks/multicomponent_steinberger/doc/lookup.part.prm.bak @@ -0,0 +1,10 @@ +subsection Material model + set Model name = Steinberger + + subsection Steinberger model + set Data directory = $ASPECT_SOURCE_DIR/data/material-model/steinberger/ + set Material file names = pyr_MS95_with_volume_fractions_lo_res.dat, \ + morb_G13_with_volume_fractions_lo_res.dat\ + end + end +end diff --git a/cookbooks/multicomponent_steinberger/doc/temperature.setup.prm.bak b/cookbooks/multicomponent_steinberger/doc/temperature.setup.prm.bak new file mode 100644 index 00000000000..0a93b17b41d --- /dev/null +++ b/cookbooks/multicomponent_steinberger/doc/temperature.setup.prm.bak @@ -0,0 +1,26 @@ +subsection Initial temperature model + set List of model operators = add + set List of model names = adiabatic, function + + subsection Adiabatic + set Age top boundary layer = 5e7 + set Age bottom boundary layer = 7e8 + + subsection Function + set Function constants = k=-7e-7, c=2.9367 + set Variable names = x, y + + # if Number of fields = 2, there should be two function expressions + set Function expression = (sqrt(x^2+y^2)<3981.e3 ? c+k*sqrt(x^2+y^2) : 0 ) + end + end + + subsection Function + set Coordinate system = cartesian + set Variable names = x, y + set Function constants = Tex=450, a=2744.3e3, size=400e3, Tb=3550, Tab=2663.3, age=2.208e16, kappa=1.16e-6, + set Function expression = ( ((x-a)^2+(y-a)^2<=size^2) ? \ + ( max(Tex - (Tb-Tab)*erfc( (-3481e3 + sqrt(x^2+y^2)) /2/sqrt(kappa*age) ),0) ) : \ + (0) ) + end +end diff --git a/cookbooks/multicomponent_steinberger/steinberger_thermochemical_plume.prm.bak b/cookbooks/multicomponent_steinberger/steinberger_thermochemical_plume.prm.bak new file mode 100644 index 00000000000..1a8508145cd --- /dev/null +++ b/cookbooks/multicomponent_steinberger/steinberger_thermochemical_plume.prm.bak @@ -0,0 +1,166 @@ +# This is a cookbook of modeling a thermochemical plumes using the multicomponent +# Steinberger material model. The model setup is similar to Dannberg and Sobolev (2015). + +set Output directory = output-multicomponent-steinberger +set CFL number = 1.0 +set End time = 3e8 +set Adiabatic surface temperature = 1600.0 +set Use years in output instead of seconds = true +set Maximum first time step = 1.e4 + +# Multiple composition setup +subsection Compositional fields + set Number of fields = 1 + set Names of fields = basalt_fraction + set Types of fields = chemical composition +end + +# Prescribe the initial composition. +# The setup is similar to Supplementary Figure 2b (Dannberg and Sobolev, 2015) +# The constants used in the function: +# a = coordinate of the center of the circular compositional anomaly +# size = radius of the compositional anomaly +# k, c = slope and intercept determine the fraction of eclogite change with depth +subsection Initial composition model + set Model name = function + + subsection Function + set Coordinate system = cartesian + set Variable names = x, y + set Function constants = a=2744.3e3, size=400e3, k=-7e-7, c=2.9367 + set Function expression = ( (sqrt(x^2+y^2)>=3981.e3 && (x-a)^2+(y-a)^2<=size^2) ? (0.15) : \ + (sqrt(x^2+y^2)<3981.e3 && sqrt(x^2+y^2)>=3481.e3) ? \ + (c+k*sqrt(x^2+y^2)) : (0) ) + end +end + +# The Material model setup is similar to "steinberger.prm" except we have +# N+1 material file for N compositional fields. The material files are ordered as +# "background, field#1, field#2, ..." +subsection Material model + set Model name = Steinberger + + subsection Steinberger model + set Data directory = $ASPECT_SOURCE_DIR/data/material-model/steinberger/ + set Material file names = pyr_MS95_with_volume_fractions_lo_res.dat, \ + morb_G13_with_volume_fractions_lo_res.dat + set Lateral viscosity file name = temp-viscosity-prefactor.txt + set Radial viscosity file name = radial-visc-simple.txt + set Bilinear interpolation = true + set Latent heat = false + + # We are using default pressure-temperature dependent thermal conductivity. + set Thermal conductivity formulation = p-T-dependent + + # You must set this to false to avoid step-wise viscosity inherited + # from the reference profile "radial-visc-simple.txt". + set Use lateral average temperature for viscosity = false + end +end + +# Prescribe the initial temperature. +# Here we are using half-space cooling model to set up a 50 Ma top boundary +# layer and a 700 Ma bottom boundary layer. The setup of the plume excess +# temperature is similar to Supplementary Figure 2a (Dannberg and Sobolev, 2015) +# and is described by the function. All the expressions in the boundary +# temperature model and the function are added to the adiabatic temperature +# profile because we set the model operators as "add". You can also use +# "subtract, minimum, maximum, replace if valid". + +# The constants used in the function: +# Tex = plume excess temperature +# Tb = bottom temperature +# Tab = the adiabatic bottom temperature, should be consistent with the +# adiabatic surfacetemperature of the model. +# age = must be consistent with the "Age bottom boundary layer" in seconds +# kappa = should be consistent with the characteristic Cp, rho, and k around +# the CMB +subsection Initial temperature model + set List of model operators = add + set List of model names = adiabatic, function + + subsection Adiabatic + set Age top boundary layer = 5e7 + set Age bottom boundary layer = 7e8 + + subsection Function + set Function constants = k=-7e-7, c=2.9367 + set Variable names = x, y + + # if Number of fields = 2, there should be two function expressions + set Function expression = (sqrt(x^2+y^2)<3981.e3 ? c+k*sqrt(x^2+y^2) : 0 ) + end + end + + subsection Function + set Coordinate system = cartesian + set Variable names = x, y + set Function constants = Tex=450, a=2744.3e3, size=400e3, Tb=3550, Tab=2663.3, age=2.208e16, kappa=1.16e-6, + set Function expression = ( ((x-a)^2+(y-a)^2<=size^2) ? \ + ( max(Tex - (Tb-Tab)*erfc( (-3481e3 + sqrt(x^2+y^2)) /2/sqrt(kappa*age) ),0) ) : \ + (0) ) + end +end + +subsection Boundary temperature model + set List of model names = spherical constant + set Fixed temperature boundary indicators = 0,1 + + subsection Spherical constant + set Inner temperature = 3550 + set Outer temperature = 288 + end +end + +# generate visualization and statistic files. +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, basic statistics, temperature statistics, heat flux statistics, depth average + + subsection Visualization + set Interpolate output = false + set Output format = vtu + set List of output variables = depth, material properties, named additional outputs + set Time between graphical output = 5e6 + + subsection Material properties + set List of material properties = viscosity, density, specific heat, thermal conductivity, thermal expansivity, compressibility + end + end +end + +# other model setup +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Opening angle = 90 + set Outer radius = 6371000 + end +end + +# Free slip on all boundaries. +subsection Boundary velocity model + set Tangential velocity boundary indicators = top, bottom, left, right +end + +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 9.81 + end +end + +subsection Heating model + set List of model names = adiabatic heating +end + +subsection Mesh refinement + set Initial adaptive refinement = 1 + set Initial global refinement = 7 + set Refinement fraction = 0.3 + set Coarsening fraction = 0.0 + set Strategy = temperature + set Time steps between mesh refinement = 1 +end diff --git a/cookbooks/muparser_temperature_example/doc/check-initial-condition.part.prm.bak b/cookbooks/muparser_temperature_example/doc/check-initial-condition.part.prm.bak new file mode 100644 index 00000000000..ab4d227ca29 --- /dev/null +++ b/cookbooks/muparser_temperature_example/doc/check-initial-condition.part.prm.bak @@ -0,0 +1,18 @@ +# Dimension, end-time (years) and output directory +# Only does zeroth time-step to show that initial condition works + +set Dimension = 2 +set Use years in output instead of seconds = true +set Start time = 0 +set End time = 0 + +# If you have a large model or a model with large viscosity variation and you +# want to run the 0th timestep more quickly in order to just check in the initial +# condition (IC), you can set these solver tolerance values to larger numbers, but +# this means the solution will not be converged. + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-6 # can set to 1e-3 for checking IC + end +end diff --git a/cookbooks/muparser_temperature_example/doc/mesh-refinement.part.prm.bak b/cookbooks/muparser_temperature_example/doc/mesh-refinement.part.prm.bak new file mode 100644 index 00000000000..aba6e56348e --- /dev/null +++ b/cookbooks/muparser_temperature_example/doc/mesh-refinement.part.prm.bak @@ -0,0 +1,23 @@ +# Refine the upper 150 km of the mesh so lithosphere structure is resolved. +# Function expression asks if the depth is less than the lithosphere depth and +# then refinement level = 7, else refinement level = 0. +# Note, the minimum refinement level for the lower 850 km of the mesh would be +# coarser than the initial one level of global refinement. This would then lead +# to coarsening in the future. +# To avoid this, you may want to set this 'else' value to the same as the number +# of initial global refinement steps. + +subsection Mesh refinement + set Initial global refinement = 3 + set Minimum refinement level = 3 + set Initial adaptive refinement = 4 + set Time steps between mesh refinement = 1 + set Strategy = minimum refinement function + + subsection Minimum refinement function + set Coordinate system = cartesian + set Variable names = x,y + set Function constants = ymax=1.e6, lith=1.5e5 + set Function expression = ((ymax-y<=lith) ? 7 : 0) + end +end diff --git a/cookbooks/muparser_temperature_example/doc/repetitions.part.prm.bak b/cookbooks/muparser_temperature_example/doc/repetitions.part.prm.bak new file mode 100644 index 00000000000..1e5c71fa33f --- /dev/null +++ b/cookbooks/muparser_temperature_example/doc/repetitions.part.prm.bak @@ -0,0 +1,15 @@ +# Want a 2D box 5000 km wide by 1000 km deep (5e6 x 1e6 meters) +# The variable repetitions divides the whole domain into 5 boxes (1000 x 1000 km) +# as the 0th level mesh refinement: this is needed so elements are squares +# and not elongated rectangles. + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 5e6 + set Y extent = 1e6 + set X repetitions = 5 + set Y repetitions = 1 + end +end diff --git a/cookbooks/muparser_temperature_example/doc/temperature.part.prm.bak b/cookbooks/muparser_temperature_example/doc/temperature.part.prm.bak new file mode 100644 index 00000000000..caee45dfda6 --- /dev/null +++ b/cookbooks/muparser_temperature_example/doc/temperature.part.prm.bak @@ -0,0 +1,39 @@ +# Half-space cooling model increasing with age from x>0 to xtr +# For x>xtr, half-space cooling model with a fixed age. +# Note, we use 1-erfc instead of erf because the muparser in dealii +# only knows about erfc. Also, we need to use ymax-y since y=0 at the +# bottom of the box. +# vsub is the velocity of the subducting plate in m/s +# (x/vsub is the age of the subducting plate) +# ageop is the age of the overriding plate in seconds. +# Tm is the mantle temperature, Ts is the surface temperature in kelvin +# kappa is the thermal diffusivity (m^2/s) + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = ymax=1.0e6, xtrm=2.200e6, vsub=7.927e-10, \ + ageop=9.46e14, Tm=1673, Ts=273, kappa=1e-6 + set Function expression = (((x>0.0) && (x<=xtrm)) ? \ + (Ts + (Tm-Ts)*(1-erfc((ymax-y)/(2*sqrt(kappa*(x/vsub)))))) : \ + (x>xtrm) ? \ + (Ts + (Tm-Ts)*(1-erfc((ymax-y)/(2*sqrt(kappa*ageop))))) :\ + (Tm) ) + end +end + +# Set boundary types and values for temperature +# Default is zero-flux (keep for sidewalls), +# so only need set top and bottom to fixed temperature + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1673 + set Top temperature = 273 + end +end diff --git a/cookbooks/muparser_temperature_example/muparser-temperature-example.prm.bak b/cookbooks/muparser_temperature_example/muparser-temperature-example.prm.bak new file mode 100644 index 00000000000..0571836ca36 --- /dev/null +++ b/cookbooks/muparser_temperature_example/muparser-temperature-example.prm.bak @@ -0,0 +1,159 @@ +# Basic parameter file for using a function expression to define the +# initial temperature structure using (? : ) syntax for if-else conditions. +# 2D, Dimensional, Boussinesq, Simple Material Model + +# Dimension, end-time (years) and output directory +# Only does zeroth time-step to show that initial condition works + +set Dimension = 2 +set Use years in output instead of seconds = true +set Start time = 0 +set End time = 0 +set Output directory = output-muparser-temperature-example + +# Parameters Related to the Solver and Pressure Normalization + +set Pressure normalization = surface +set Surface pressure = 0 + +# Even when using the Boussinesq approximation you need to set this parameter +# because this will be the temperature used to calculate the reference density +# used in the advection equation (even if a separate reference temperature is +# specified by the material model) + +set Adiabatic surface temperature = 273 # K + +# If you have a large model or a model with large viscosity variation and you +# want to run the 0th timestep more quickly in order to just check in the initial +# condition (IC), you can set these solver tolerance values to larger numbers, but +# this means the solution will not be converged. + +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-6 # can set to 1e-3 for checking IC + end +end + +# The following is equivalent to the Boussinesq approximation + +subsection Formulation + set Formulation = custom + set Mass conservation = incompressible + set Temperature equation = reference density profile +end + +# Want a 2D box 5000 km wide by 1000 km deep (5e6 x 1e6 meters). +# The variable repetitions divides the whole domain into 5 boxes (1000 x 1000 km) +# as the 0th level mesh refinement: this is needed so elements are squares +# and not elongated rectangles. + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 5e6 + set Y extent = 1e6 + set X repetitions = 5 + set Y repetitions = 1 + end +end + +# Refine the upper 150 km of the mesh so lithosphere structure is resolved. +# Function expression asks if the depth is less than the lithosphere depth and +# then refinement level = 7, else refinement level = 0. +# Note, the minimum refinement level for the lower 850 km of the mesh would be +# coarser than the initial one level of global refinement. This would then lead +# to coarsening in the future. +# To avoid this, you may want to set this 'else' value to the same as the number +# of initial global refinement steps. + +subsection Mesh refinement + set Initial global refinement = 3 + set Minimum refinement level = 3 + set Initial adaptive refinement = 4 + set Time steps between mesh refinement = 1 + set Strategy = minimum refinement function + + subsection Minimum refinement function + set Coordinate system = cartesian + set Variable names = x,y + set Function constants = ymax=1e6,lith=1.5e5 + set Function expression = ((ymax-y<=lith) ? 7 : 0) + end +end + +# Half-space cooling model increasing with age from x>0 to xtrm +# For x>xtrm, half-space cooling model with a fixed age. +# Note, we use 1-erfc instead of erf because the muparser in dealii +# only knows about erfc. Also, we need to use ymax-y since y=0 at the +# bottom of the box. +# vsub is the velocity of the subducting plate in m/s +# (x/vsub is the age of the subducting plate) +# ageop is the age of the overriding plate in seconds. +# Tm is the mantle temperature, Ts is the surface temperature in kelvin +# kappa is the thermal diffusivity (m^2/s) + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = ymax=1.0e6, xtrm=2.200e6, vsub=7.927e-10, \ + ageop=9.46e14, Tm=1673, Ts=273, kappa=1e-6 + set Function expression = (((x>0.0) && (x<=xtrm)) ? \ + (Ts + (Tm-Ts)*(1-erfc((ymax-y)/(2*sqrt(kappa*(x/vsub)))))) : \ + (x>xtrm) ? \ + (Ts + (Tm-Ts)*(1-erfc((ymax-y)/(2*sqrt(kappa*ageop))))) :\ + (Tm) ) + end +end + +# Set boundary types and values for temperature +# Default is zero-flux (keep for sidewalls), so only need set top and bottom to fixed temperature + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1673 + set Top temperature = 273 + end +end + +# Free-slip on all sides (tangential velocity V-perp=0, dV/dn=0) + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3300 # kg/m^3 + set Reference specific heat = 1250 # J/kg/K + set Reference temperature = 273 # K + set Thermal conductivity = 4.125 # W/m/K + set Thermal expansion coefficient = 2e-5 # 1/K + set Viscosity = 1e21 # Pa s + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics + + subsection Visualization + set Output format = gnuplot + set Time between graphical output = 1e6 + set Number of grouped files = 0 + end +end diff --git a/cookbooks/onset_of_convection/onset_of_convection.prm.bak b/cookbooks/onset_of_convection/onset_of_convection.prm.bak new file mode 100644 index 00000000000..1278a31764d --- /dev/null +++ b/cookbooks/onset_of_convection/onset_of_convection.prm.bak @@ -0,0 +1,93 @@ +# This setup is a copy of the +# benchmarks/onset-of-convection/convection-box-base.prm +# contributed by Max Rudolph, with the difference that +# parameter values are specified explicitly in the input file +# (rather than through an ipython notebook). + +set Dimension = 2 +set Use years in output instead of seconds = true +set Output directory = output +set Pressure normalization = surface +set Surface pressure = 0 +set Use conduction timestep = true + +subsection Termination criteria + set Termination criteria = end step + set End step = 100 +end + +subsection Formulation + set Formulation = Boussinesq approximation +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 9.424777e6 # pi * 3e6 + set Y extent = 3e6 + set X repetitions = 3 + set Y repetitions = 1 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = p=1, L=9.424777e6, H=3.0e6, pi=3.1415926536, k=2 + set Function expression = 2500 * (1.0-z/H) - p*cos(k*pi*x/L)*sin(pi*z/H) + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 2500 + set Left temperature = 0 + set Right temperature = 0 + set Top temperature = 0 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 4000 + set Reference specific heat = 1250 + set Reference temperature = 0 + set Thermal conductivity = 4.0 + set Thermal expansion coefficient = 3e-5 + set Viscosity = 1e23 + end +end + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = velocity statistics, visualization + + subsection Visualization + set Time steps between graphical output = 5 + end +end diff --git a/cookbooks/platelike-boundary/doc/boundary.part.prm.bak b/cookbooks/platelike-boundary/doc/boundary.part.prm.bak new file mode 100644 index 00000000000..250d9e69271 --- /dev/null +++ b/cookbooks/platelike-boundary/doc/boundary.part.prm.bak @@ -0,0 +1,10 @@ +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom + set Prescribed velocity boundary indicators = top: function + + subsection Function + set Variable names = x,z,t + set Function constants = pi=3.1415926 + set Function expression = if(x>1+sin(0.5*pi*t), 1, -1); 0 + end +end diff --git a/cookbooks/platelike-boundary/doc/platelike.prm.bak b/cookbooks/platelike-boundary/doc/platelike.prm.bak new file mode 100644 index 00000000000..27250340f5e --- /dev/null +++ b/cookbooks/platelike-boundary/doc/platelike.prm.bak @@ -0,0 +1,91 @@ +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 20 +set Use years in output instead of seconds = false +set Output directory = output-platelike-boundary + +############### Parameters describing the model +# Let us here choose again a box domain of size 2x1 +# where we fix the temperature at the bottom and top, +# allow free slip along the bottom, left and right, +# and prescribe the velocity along the top using the +# `function' description. + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 1 + end +end + +# We then set the temperature to one at the bottom and zero +# at the top: +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Top temperature = 0 + end +end + +# The velocity along the top boundary models a spreading +# center that is moving left and right: +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom + set Prescribed velocity boundary indicators = top: function + + subsection Function + set Variable names = x,z,t + set Function constants = pi=3.1415926 + set Function expression = if(x>1+sin(0.5*pi*t), 1, -1); 0 + end +end + +# We then choose a vertical gravity model and describe the +# initial temperature with a vertical gradient. The default +# strength for gravity is one. The material model is the +# same as before. +subsection Gravity model + set Model name = vertical +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = (1-z) + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal conductivity = 1e-6 + set Thermal expansion coefficient = 1e-4 + set Viscosity = 1 + end +end + +# The final part of this input file describes how many times the +# mesh is refined and what to do with the solution once computed +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, temperature statistics, heat flux statistics + + subsection Visualization + set Time between graphical output = 0.1 + end +end diff --git a/cookbooks/platelike-boundary/platelike-boundary.prm.bak b/cookbooks/platelike-boundary/platelike-boundary.prm.bak new file mode 100644 index 00000000000..b89539d9600 --- /dev/null +++ b/cookbooks/platelike-boundary/platelike-boundary.prm.bak @@ -0,0 +1,96 @@ +# A description of convection in a rectangular box where we prescribe +# temporally variable boundary conditions for the velocity along the top +# boundary. See the manual for more information. + + +############### Global parameters + +set Dimension = 2 +set Start time = 0 +set End time = 20 +set Use years in output instead of seconds = false +set Output directory = output-platelike-boundary + +############### Parameters describing the model +# Let us here choose again a box domain of size 2x1 +# where we fix the temperature at the bottom and top, +# allow free slip along the bottom, left and right, +# and prescribe the velocity along the top using the +# `function' description. + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2 + set Y extent = 1 + end +end + +# We then set the temperature to one at the bottom and zero +# at the top: +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box + + subsection Box + set Bottom temperature = 1 + set Top temperature = 0 + end +end + +# The velocity along the top boundary models a spreading +# center that is moving left and right: +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom + set Prescribed velocity boundary indicators = top: function + + subsection Function + set Variable names = x,z,t + set Function constants = pi=3.1415926 + set Function expression = if(x>1+sin(0.5*pi*t), 1, -1); 0 + end +end + +# We then choose a vertical gravity model and describe the +# initial temperature with a vertical gradient. The default +# strength for gravity is one. The material model is the +# same as before. +subsection Gravity model + set Model name = vertical +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,z + set Function expression = (1-z) + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal conductivity = 1e-6 + set Thermal expansion coefficient = 1e-4 + set Viscosity = 1 + end +end + +# The final part of this input file describes how many times the +# mesh is refined and what to do with the solution once computed +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 5 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, temperature statistics, heat flux statistics + + subsection Visualization + set Time between graphical output = 0.1 + end +end diff --git a/cookbooks/plume_2D_chunk/opening_angle_45degrees.prm.bak b/cookbooks/plume_2D_chunk/opening_angle_45degrees.prm.bak new file mode 100644 index 00000000000..b627610d078 --- /dev/null +++ b/cookbooks/plume_2D_chunk/opening_angle_45degrees.prm.bak @@ -0,0 +1,11 @@ +include ./plume2D.prm + + +subsection Geometry model + set Model name = chunk + + subsection Chunk + set Chunk minimum longitude = 45 + set Chunk maximum longitude = 90 + end +end diff --git a/cookbooks/plume_2D_chunk/opening_angle_90degrees.prm.bak b/cookbooks/plume_2D_chunk/opening_angle_90degrees.prm.bak new file mode 100644 index 00000000000..3b0b3a38693 --- /dev/null +++ b/cookbooks/plume_2D_chunk/opening_angle_90degrees.prm.bak @@ -0,0 +1,11 @@ +include ./plume2D.prm + + +subsection Geometry model + set Model name = chunk + + subsection Chunk + set Chunk minimum longitude = 0 + set Chunk maximum longitude = 90 + end +end diff --git a/cookbooks/plume_2D_chunk/plume2D.prm.bak b/cookbooks/plume_2D_chunk/plume2D.prm.bak new file mode 100644 index 00000000000..658c90f0ceb --- /dev/null +++ b/cookbooks/plume_2D_chunk/plume2D.prm.bak @@ -0,0 +1,104 @@ +# A simple setup for a plume in a 2D chunk based on Kellogg \& King, EPSL 148 (1997). + +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 200e9 +set Output directory = output_plume2D +set Maximum time step = 5e7 +set Nonlinear solver scheme = iterated Advection and Stokes + +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + # Reference temperature and viscosity + set Reference temperature = 273 + + # Limit the viscosity with maximum=1000*eta0 + set Minimum viscosity = 1.25e23 + set Maximum viscosity = 1.25e26 + + # Thermal diffusivity is adjusted to match thermal conductivities + # assumed in assigning the initial geotherm + set Thermal diffusivities = 5.5e-7 + set Heat capacities = 1250. + set Densities = 3250 + set Thermal expansivities = 3e-5 + set Viscous flow law = diffusion + set Activation volumes for diffusion creep = 0 + set Grain size = 1 + + # isoviscous + set Prefactors for diffusion creep = 4e-24 + set Activation energies for diffusion creep = 0 + + # Plasticity parameters - irrelevant + # set to very high value so that it is not used + set Cohesions = 1e15 + end +end + +subsection Geometry model + set Model name = chunk + + subsection Chunk + set Chunk inner radius = 3480000 + set Chunk outer radius = 6371000 + set Chunk minimum longitude = 67.5 + set Chunk maximum longitude = 90 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = 0,1,2,3 +end + +# temperature is set to 273K at the top, i.e. for r>4e6 +# where 4e6 is an arbitrary radius value falling between +# the CMB and the surface. If r<4e6 then we wish to prescribe +# a temperature on the bottom surface: since phi=0 at the +# equator (i.e. x-axis) then the patch is defined by 7pi/164e6,273,if(phi>7*pi/16,3273,2773)) + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1023 + end +end + +subsection Gravity model + set Model name = radial constant + + subsection Vertical + set Magnitude = 9.81 + end +end + +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics + + subsection Visualization + set List of output variables = density, viscosity, vertical heat flux + set Output format = vtu + set Time between graphical output = 10e7 + set Number of grouped files = 0 + end +end diff --git a/cookbooks/plume_2D_chunk/strongly_temperature_dependent.prm.bak b/cookbooks/plume_2D_chunk/strongly_temperature_dependent.prm.bak new file mode 100644 index 00000000000..cf2eb62f09c --- /dev/null +++ b/cookbooks/plume_2D_chunk/strongly_temperature_dependent.prm.bak @@ -0,0 +1,11 @@ +include ./plume2D.prm + + +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + set Prefactors for diffusion creep = 6.26e-23 + set Activation energies for diffusion creep = 74829.6 + end +end diff --git a/cookbooks/plume_2D_chunk/weakly_temperature_dependent.prm.bak b/cookbooks/plume_2D_chunk/weakly_temperature_dependent.prm.bak new file mode 100644 index 00000000000..67f974244e9 --- /dev/null +++ b/cookbooks/plume_2D_chunk/weakly_temperature_dependent.prm.bak @@ -0,0 +1,11 @@ +include ./plume2D.prm + + +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + set Prefactors for diffusion creep = 5.05e-24 + set Activation energies for diffusion creep = 6317.6 + end +end diff --git a/cookbooks/prescribed_velocity/circle.prm.bak b/cookbooks/prescribed_velocity/circle.prm.bak new file mode 100644 index 00000000000..2de956d989b --- /dev/null +++ b/cookbooks/prescribed_velocity/circle.prm.bak @@ -0,0 +1,62 @@ +## First we set up a unit length box model with uniform everything. +set Dimension = 2 +set End time = 0 +set Output directory = output-circle + +# Load the signal library. +set Additional shared libraries = ./libprescribed_velocity.so + +## Turn prescribed velocities on +set Prescribe internal velocities = true + +subsection Geometry model + set Model name = box +end + +subsection Initial temperature model + set Model name = function +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = top, bottom, left, right +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0 + end +end + +subsection Material model + set Model name = simple +end + +subsection Mesh refinement + set Initial global refinement = 7 + set Initial adaptive refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization +end + +subsection Prescribed velocities + subsection Indicator function + set Variable names = x,y,t + + # Return where to prescribe u_x; u_y; u_z + # (last one only used if dimension = 3) + # 1 if velocity should be prescribed, 0 otherwise + set Function expression = if((x-.5)^2+(y-.5)^2<.125,1,0); \ + if((x-.5)^2+(y-.5)^2<.125,1,0) + end + + subsection Velocity function + set Variable names = x,y,t + + # Return u_x; u_y; u_z (u_z only used if in 3d) + set Function expression = 1;1 + end +end diff --git a/cookbooks/prescribed_velocity/corner_flow.prm.bak b/cookbooks/prescribed_velocity/corner_flow.prm.bak new file mode 100644 index 00000000000..1ad5cef1405 --- /dev/null +++ b/cookbooks/prescribed_velocity/corner_flow.prm.bak @@ -0,0 +1,62 @@ +## First we set up a unit length box model with uniform everything. +set Dimension = 2 +set End time = 0 + +# Load the signal library. +set Additional shared libraries = ./libprescribed_velocity.so +set Output directory = output-corner_flow + +## Turn prescribed velocities on +set Prescribe internal velocities = true + +subsection Geometry model + set Model name = box +end + +subsection Initial temperature model + set Model name = function +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = top +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0 + end +end + +subsection Material model + set Model name = simple +end + +subsection Mesh refinement + set Initial global refinement = 7 + set Initial adaptive refinement = 0 +end + +subsection Postprocess + set List of postprocessors = visualization +end + +subsection Prescribed velocities + subsection Indicator function + set Variable names = x,y,t + + # Return where to prescribe u_x; u_y; u_z + # (last one only used if dimension = 3) + # 1 if velocity should be prescribed, 0 otherwise + set Function expression = if(((x>.1)&(x<.9))&(abs(x-(1-y))<.01),1,0); \ + if(((x>.1)&(x<.9))&(abs(x-(1-y))<.01),1,0) + end + + subsection Velocity function + set Variable names = x,y,t + + # Return u_x; u_y; u_z (u_z only used if in 3d) + set Function expression = 1;-1 + end +end diff --git a/cookbooks/prescribed_velocity/doc/minimal.prm.bak b/cookbooks/prescribed_velocity/doc/minimal.prm.bak new file mode 100644 index 00000000000..22583cc03a0 --- /dev/null +++ b/cookbooks/prescribed_velocity/doc/minimal.prm.bak @@ -0,0 +1,24 @@ +# Load the signal library. +set Additional shared libraries = ./libprescribed_velocity.so + +## Turn prescribed velocities on +set Prescribe internal velocities = true + +subsection Prescribed velocities + subsection Indicator function + set Variable names = x,y,t + + # Return where to prescribe u_x; u_y; u_z + # (last one only used if dimension = 3) + # 1 if velocity should be prescribed, 0 otherwise + set Function expression = if((x-.5)^2+(y-.5)^2<.125,1,0); \ + if((x-.5)^2+(y-.5)^2<.125,1,0) + end + + subsection Velocity function + set Variable names = x,y,t + + # Return u_x; u_y; u_z (u_z only used if in 3d) + set Function expression = 1;-1 + end +end diff --git a/cookbooks/prescribed_velocity/prescribed_velocity.cc.bak b/cookbooks/prescribed_velocity/prescribed_velocity.cc.bak new file mode 100644 index 00000000000..5f93f95d584 --- /dev/null +++ b/cookbooks/prescribed_velocity/prescribed_velocity.cc.bak @@ -0,0 +1,301 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + using namespace dealii; + + // Global variables (to be set by parameters) + bool prescribe_internal_velocities; + + // Because we do not initially know what dimension we're in, we need + // function parser objects for both 2d and 3d. + Functions::ParsedFunction<2> prescribed_velocity_indicator_function_2d (2); + Functions::ParsedFunction<3> prescribed_velocity_indicator_function_3d (3); + Functions::ParsedFunction<2> prescribed_velocity_function_2d (2); + Functions::ParsedFunction<3> prescribed_velocity_function_3d (3); + + + + /** + * Declare additional parameters. + */ + void declare_parameters(const unsigned int dim, + ParameterHandler &prm) + { + prm.declare_entry ("Prescribe internal velocities", "false", + Patterns::Bool (), + "Whether or not to use any prescribed internal velocities. " + "Locations in which to prescribe velocities are defined " + "in section ``Prescribed velocities/Indicator function'' " + "and the velocities are defined in section ``Prescribed " + "velocities/Velocity function''. Indicators are evaluated " + "at the center of each cell, and all DOFs associated with " + "the specified velocity component at the indicated cells " + "are constrained." + ); + + prm.enter_subsection ("Prescribed velocities"); + { + prm.enter_subsection ("Indicator function"); + { + if (dim == 2) + Functions::ParsedFunction<2>::declare_parameters (prm, 2); + else + Functions::ParsedFunction<3>::declare_parameters (prm, 3); + } + prm.leave_subsection (); + + prm.enter_subsection ("Velocity function"); + { + if (dim == 2) + Functions::ParsedFunction<2>::declare_parameters (prm, 2); + else + Functions::ParsedFunction<3>::declare_parameters (prm, 3); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + + template + void parse_parameters(const Parameters &, + ParameterHandler &prm) + { + prescribe_internal_velocities = prm.get_bool ("Prescribe internal velocities"); + prm.enter_subsection ("Prescribed velocities"); + { + prm.enter_subsection("Indicator function"); + { + try + { + if (dim == 2) + prescribed_velocity_indicator_function_2d.parse_parameters (prm); + else + prescribed_velocity_indicator_function_3d.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Prescribed velocities.Indicator function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'"; + throw; + } + } + prm.leave_subsection(); + + prm.enter_subsection("Velocity function"); + { + try + { + if (dim == 2) + prescribed_velocity_function_2d.parse_parameters (prm); + else + prescribed_velocity_function_3d.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Prescribed velocities.Velocity function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'"; + throw; + } + } + prm.leave_subsection(); + } + prm.leave_subsection (); + } + + + + /** + * A set of helper functions that either return the point passed to it (if + * the current dimension is the same) or return a dummy value (otherwise). + */ + namespace + { + const Point<2> as_2d(const Point<3> &/*p*/) + { + return Point<2>(); + } + + const Point<2> &as_2d(const Point<2> &p) + { + return p; + } + + const Point<3> as_3d(const Point<2> &/*p*/) + { + return Point<3>(); + } + + const Point<3> &as_3d(const Point<3> &p) + { + return p; + } + + } + + + + /** + * This function is called by a signal which is triggered after the other constraints + * have been calculated. This enables us to define additional constraints in the mass + * matrix on any arbitrary degree of freedom in the model space. + */ + template + void constrain_internal_velocities (const SimulatorAccess &simulator_access, + AffineConstraints ¤t_constraints) + { + if (prescribe_internal_velocities) + { + const Parameters ¶meters = simulator_access.get_parameters(); + const std::vector> points = aspect::Utilities::get_unit_support_points(simulator_access); + const Quadrature quadrature (points); + FEValues fe_values (simulator_access.get_fe(), quadrature, update_quadrature_points); + + // Loop over all cells + for (const auto &cell : simulator_access.get_dof_handler().active_cell_iterators()) + if (!cell->is_artificial()) + { + fe_values.reinit (cell); + std::vector local_dof_indices(simulator_access.get_fe().dofs_per_cell); + cell->get_dof_indices (local_dof_indices); + + for (unsigned int q=0; q= + simulator_access.introspection().component_indices.velocities[0]) + && + (c_idx <= + simulator_access.introspection().component_indices.velocities[dim-1])) + { + // Which velocity component is this DOF associated with? + const unsigned int component_direction + = (c_idx + - simulator_access.introspection().component_indices.velocities[0]); + + // we get time passed as seconds (always) but may want + // to reinterpret it in years + double time = simulator_access.get_time(); + if (simulator_access.convert_output_to_years()) + time /= year_in_seconds; + + prescribed_velocity_indicator_function_2d.set_time (time); + prescribed_velocity_indicator_function_3d.set_time (time); + prescribed_velocity_function_2d.set_time (time); + prescribed_velocity_function_3d.set_time (time); + + const Point p = fe_values.quadrature_point(q); + + // Because we defined and parsed our parameter + // file differently for 2d and 3d we need to + // be sure to query the correct object for + // function values. The function parser + // objects expect points of a certain + // dimension, but Point p will be compiled for + // both 2d and 3d, so we need to do some trickery + // to make this compile. + double indicator, u_i; + if (dim == 2) + { + indicator = prescribed_velocity_indicator_function_2d.value + (as_2d(p), + component_direction); + u_i = prescribed_velocity_function_2d.value + (as_2d(p), + component_direction); + } + else + { + indicator = prescribed_velocity_indicator_function_3d.value + (as_3d(p), + component_direction); + u_i = prescribed_velocity_function_3d.value + (as_3d(p), + component_direction); + } + + if (indicator > 0.5) + { + // Add a constraint of the form dof[q] = u_i + // to the list of constraints. + current_constraints.add_line (local_dof_indices[q]); + // When using a defect correction solver, the constraints should only be set on + // nonlinear iteration 0. + if ( + (parameters.nonlinear_solver!=Parameters::NonlinearSolver::no_Advection_iterated_defect_correction_Stokes && + parameters.nonlinear_solver!=Parameters::NonlinearSolver::single_Advection_iterated_defect_correction_Stokes && + parameters.nonlinear_solver!=Parameters::NonlinearSolver::iterated_Advection_and_defect_correction_Stokes && + parameters.nonlinear_solver!=Parameters::NonlinearSolver::iterated_Advection_and_Newton_Stokes && + parameters.nonlinear_solver!=Parameters::NonlinearSolver::single_Advection_iterated_Newton_Stokes ) || + simulator_access.get_nonlinear_iteration() == 0 + ) + { + current_constraints.set_inhomogeneity (local_dof_indices[q], u_i); + } + } + } + } + } + } + } + + // Connect declare_parameters and parse_parameters to appropriate signals. + void parameter_connector () + { + SimulatorSignals<2>::declare_additional_parameters.connect (&declare_parameters); + SimulatorSignals<3>::declare_additional_parameters.connect (&declare_parameters); + + SimulatorSignals<2>::parse_additional_parameters.connect (&parse_parameters<2>); + SimulatorSignals<3>::parse_additional_parameters.connect (&parse_parameters<3>); + } + + // Connect constraints function to correct signal. + template + void signal_connector (SimulatorSignals &signals) + { + signals.post_constraints_creation.connect (&constrain_internal_velocities); + } + + // Tell ASPECT to send signals to the connector functions + ASPECT_REGISTER_SIGNALS_PARAMETER_CONNECTOR(parameter_connector) + ASPECT_REGISTER_SIGNALS_CONNECTOR(signal_connector<2>, signal_connector<3>) +} diff --git a/cookbooks/prescribed_velocity_ascii_data/doc/prescribed_velocity_ascii_data.prm.0.out.bak b/cookbooks/prescribed_velocity_ascii_data/doc/prescribed_velocity_ascii_data.prm.0.out.bak new file mode 100644 index 00000000000..e4b8e68491c --- /dev/null +++ b/cookbooks/prescribed_velocity_ascii_data/doc/prescribed_velocity_ascii_data.prm.0.out.bak @@ -0,0 +1,2 @@ +# Load the signal library. +set Additional shared libraries = ./libprescribed_velocity_ascii_data.so diff --git a/cookbooks/prescribed_velocity_ascii_data/doc/prescribed_velocity_ascii_data.prm.1.out.bak b/cookbooks/prescribed_velocity_ascii_data/doc/prescribed_velocity_ascii_data.prm.1.out.bak new file mode 100644 index 00000000000..1c6dc373bfb --- /dev/null +++ b/cookbooks/prescribed_velocity_ascii_data/doc/prescribed_velocity_ascii_data.prm.1.out.bak @@ -0,0 +1,18 @@ +# Turn prescribed velocities on +set Prescribe internal velocities = true + +# Use the Ascii data plugin to read in the prescribed velocity ASCII file +# In this cookbook, we use the initial composition file. +subsection Prescribed velocities + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/cookbooks/prescribed_velocity_ascii_data/ + set Data file name = aspect_name_initial_composition.txt + end + + subsection Velocity function + set Variable names = x,y,t + + # Return u_x; u_y; u_z (u_z only used if in 3d) + set Function expression = 0;0 + end +end diff --git a/cookbooks/prescribed_velocity_ascii_data/doc/prescribed_velocity_ascii_data.prm.2.out.bak b/cookbooks/prescribed_velocity_ascii_data/doc/prescribed_velocity_ascii_data.prm.2.out.bak new file mode 100644 index 00000000000..f82ce39d5ad --- /dev/null +++ b/cookbooks/prescribed_velocity_ascii_data/doc/prescribed_velocity_ascii_data.prm.2.out.bak @@ -0,0 +1,8 @@ +subsection Initial temperature model + set Model name = ascii data + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/cookbooks/prescribed_velocity_ascii_data/ + set Data file name = aspect_name_initial_temperature.txt + end +end diff --git a/cookbooks/prescribed_velocity_ascii_data/prescribed_velocity_ascii_data.cc.bak b/cookbooks/prescribed_velocity_ascii_data/prescribed_velocity_ascii_data.cc.bak new file mode 100644 index 00000000000..80feb22cb17 --- /dev/null +++ b/cookbooks/prescribed_velocity_ascii_data/prescribed_velocity_ascii_data.cc.bak @@ -0,0 +1,311 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + using namespace dealii; + + // Global variables (to be set by parameters) + bool prescribe_internal_velocities; + bool prescribed_velocity_ascii_file_loaded; + + // Because we do not initially know what dimension we're in, we need + // function parser objects for both 2d and 3d. + + aspect::Utilities::AsciiDataBase<2> prescribed_velocity_data_file_2d; + aspect::Utilities::AsciiDataBase<3> prescribed_velocity_data_file_3d; + + aspect::Utilities::StructuredDataLookup<2> prescribed_velocity_field_data_2d(1, 1.); + aspect::Utilities::StructuredDataLookup<3> prescribed_velocity_field_data_3d(1, 1.); + + Functions::ParsedFunction<2> prescribed_velocity_function_2d (2); + Functions::ParsedFunction<3> prescribed_velocity_function_3d (3); + + + + /** + * Declare additional parameters. + */ + void declare_parameters(const unsigned int dim, + ParameterHandler &prm) + { + prm.declare_entry ("Prescribe internal velocities", "false", + Patterns::Bool (), + "Whether or not to use any prescribed internal velocities. " + "Locations in which to prescribe velocities are defined " + "in section ``Prescribed velocities/Indicator function'' " + "and the velocities are defined in section ``Prescribed " + "velocities/Velocity function''. Indicators are evaluated " + "at the center of each cell, and all DOFs associated with " + "the specified velocity component at the indicated cells " + "are constrained." + ); + + prm.enter_subsection ("Prescribed velocities"); + { + { + if (dim == 2) + prescribed_velocity_data_file_2d.declare_parameters(prm, "./", "prescribed_velocities.txt", "Ascii data model"); + else + prescribed_velocity_data_file_3d.declare_parameters(prm, "./", "prescribed_velocities.txt", "Ascii data model"); + } + + prm.enter_subsection ("Velocity function"); + { + if (dim == 2) + Functions::ParsedFunction<2>::declare_parameters (prm, 2); + else + Functions::ParsedFunction<3>::declare_parameters (prm, 3); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + + template + void parse_parameters(const Parameters &, + ParameterHandler &prm) + { + prescribe_internal_velocities = prm.get_bool ("Prescribe internal velocities"); + prm.enter_subsection ("Prescribed velocities"); + { + { + if (dim == 2) + prescribed_velocity_data_file_2d.parse_parameters(prm, "Ascii data model"); + else + prescribed_velocity_data_file_3d.parse_parameters(prm, "Ascii data model"); + } + + prm.enter_subsection("Velocity function"); + { + try + { + if (dim == 2) + prescribed_velocity_function_2d.parse_parameters (prm); + else + prescribed_velocity_function_3d.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Prescribed velocities.Velocity function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'"; + throw; + } + } + prm.leave_subsection(); + } + prm.leave_subsection (); + + prescribed_velocity_ascii_file_loaded = false; + } + + + + /** + * A set of helper functions that either return the point passed to it (if + * the current dimension is the same) or return a dummy value (otherwise). + */ + namespace + { + Point<2> as_2d(const Point<3> &/*p*/) + { + Assert (false, ExcInternalError()); + return Point<2>(); + } + + Point<2> as_2d(const Point<2> &p) + { + return p; + } + + Point<3> as_3d(const Point<2> &/*p*/) + { + Assert (false, ExcInternalError()); + return Point<3>(); + } + + Point<3> as_3d(const Point<3> &p) + { + return p; + } + + } + + + + /** + * This function is called by a signal which is triggered after the other constraints + * have been calculated. This enables us to define additional constraints in the mass + * matrix on any arbitrary degree of freedom in the model space. + */ + template + void constrain_internal_velocities (const SimulatorAccess &simulator_access, + AffineConstraints ¤t_constraints) + { + if (!prescribed_velocity_ascii_file_loaded) + { + if (dim == 2) + { + const std::string filename = prescribed_velocity_data_file_2d.data_directory + prescribed_velocity_data_file_2d.data_file_name; + prescribed_velocity_field_data_2d.load_file(filename, simulator_access.get_mpi_communicator()); + + std::cout << "Loaded 2D prescribed velocity ascii file" << std::endl; + } + else + { + const std::string filename = prescribed_velocity_data_file_3d.data_directory + prescribed_velocity_data_file_3d.data_file_name; + prescribed_velocity_field_data_3d.load_file(filename, simulator_access.get_mpi_communicator()); + + std::cout << "Loaded 3D prescribed velocity ascii file" << std::endl; + } + prescribed_velocity_ascii_file_loaded = true; + } + + if (prescribe_internal_velocities) + { + const Parameters ¶meters = simulator_access.get_parameters(); + const std::vector> points = aspect::Utilities::get_unit_support_points(simulator_access); + const Quadrature quadrature (points); + FEValues fe_values (simulator_access.get_fe(), quadrature, update_quadrature_points); + typename DoFHandler::active_cell_iterator cell; + + // Loop over all cells + for (const auto &cell : simulator_access.get_dof_handler().active_cell_iterators()) + if (! cell->is_artificial()) + { + fe_values.reinit (cell); + std::vector local_dof_indices(simulator_access.get_fe().dofs_per_cell); + cell->get_dof_indices (local_dof_indices); + + // we get time passed as seconds (always) but may want + // to reinterpret it in years + double time = simulator_access.get_time(); + if (simulator_access.convert_output_to_years()) + time /= year_in_seconds; + + prescribed_velocity_function_2d.set_time (time); + prescribed_velocity_function_3d.set_time (time); + + for (unsigned int q=0; q= + simulator_access.introspection().component_indices.velocities[0]) + && + (c_idx <= + simulator_access.introspection().component_indices.velocities[dim-1])) + { + // Which velocity component is this DOF associated with? + const unsigned int component_direction + = (c_idx + - simulator_access.introspection().component_indices.velocities[0]); + + const Point p = fe_values.quadrature_point(q); + + // Because we defined and parsed our parameter + // file differently for 2d and 3d we need to + // be sure to query the correct object for + // function values. The function parser + // objects expect points of a certain + // dimension, but Point p will be compiled for + // both 2d and 3d, so we need to do some trickery + // to make this compile. + double indicator, u_i; + if (dim == 2) + { + indicator = prescribed_velocity_field_data_2d.get_data(as_2d(p),0); + u_i = prescribed_velocity_function_2d.value + (as_2d(p), + component_direction); + } + else + { + indicator = prescribed_velocity_field_data_3d.get_data(as_3d(p),0); + u_i = prescribed_velocity_function_3d.value + (as_3d(p), + component_direction); + } + + if (indicator > 0.5) + { + // Add a constraint of the form dof[q] = u_i + // to the list of constraints. + current_constraints.add_line (local_dof_indices[q]); + // When using a defect correction solver, the constraints should only be set on + // nonlinear iteration 0. + if ( + (parameters.nonlinear_solver!=Parameters::NonlinearSolver::no_Advection_iterated_defect_correction_Stokes && + parameters.nonlinear_solver!=Parameters::NonlinearSolver::single_Advection_iterated_defect_correction_Stokes && + parameters.nonlinear_solver!=Parameters::NonlinearSolver::iterated_Advection_and_defect_correction_Stokes && + parameters.nonlinear_solver!=Parameters::NonlinearSolver::iterated_Advection_and_Newton_Stokes && + parameters.nonlinear_solver!=Parameters::NonlinearSolver::single_Advection_iterated_Newton_Stokes ) || + simulator_access.get_nonlinear_iteration() == 0 + ) + { + current_constraints.set_inhomogeneity (local_dof_indices[q], u_i); + } + } + } + } + } + } + } + + // Connect declare_parameters and parse_parameters to appropriate signals. + void parameter_connector () + { + SimulatorSignals<2>::declare_additional_parameters.connect (&declare_parameters); + SimulatorSignals<3>::declare_additional_parameters.connect (&declare_parameters); + + SimulatorSignals<2>::parse_additional_parameters.connect (&parse_parameters<2>); + SimulatorSignals<3>::parse_additional_parameters.connect (&parse_parameters<3>); + } + + // Connect constraints function to correct signal. + template + void signal_connector (SimulatorSignals &signals) + { + signals.post_constraints_creation.connect (&constrain_internal_velocities); + } + + // Tell ASPECT to send signals to the connector functions + ASPECT_REGISTER_SIGNALS_PARAMETER_CONNECTOR(parameter_connector) + ASPECT_REGISTER_SIGNALS_CONNECTOR(signal_connector<2>, signal_connector<3>) +} diff --git a/cookbooks/prescribed_velocity_ascii_data/prescribed_velocity_ascii_data.prm.bak b/cookbooks/prescribed_velocity_ascii_data/prescribed_velocity_ascii_data.prm.bak new file mode 100644 index 00000000000..ee0efe59bc1 --- /dev/null +++ b/cookbooks/prescribed_velocity_ascii_data/prescribed_velocity_ascii_data.prm.bak @@ -0,0 +1,152 @@ +# Before running this cookbook, you must first compile the shared library +# (with cmake . && make) and also run the local python file +# (python make_ascii_files_from_png.py) + + +## First we set the dimension +set Dimension = 2 +set Surface pressure = 0 +set Adiabatic surface temperature = 1500 +set CFL number = 1.0 +set End time = 1e7 +set Maximum time step = 1e5 +set Resume computation = false +set Pressure normalization = surface +set Use years in output instead of seconds = true +set Nonlinear solver scheme = single Advection, iterated Stokes +set Output directory = output-prescribed_velocity_ascii_data + +# Load the signal library. +set Additional shared libraries = ./libprescribed_velocity_ascii_data.so + +# Turn prescribed velocities on +set Prescribe internal velocities = true + +subsection Discretization + # The polynomial degree to use for the velocity variables in the Stokes + # system. Units: None. + set Stokes velocity polynomial degree = 2 + + # The polynomial degree to use for the temperature variable. Units: None. + set Temperature polynomial degree = 2 + + # Whether to use a Stokes discretization that is locally conservative at the + # expense of a larger number of degrees of freedom (true), or to go with a + # cheaper discretization that does not locally conserve mass, although it is + # globally conservative (false). + set Use locally conservative discretization = false + + subsection Stabilization parameters + # The exponent $\alpha$ in the entropy viscosity stabilization. Units: + # None. + set alpha = 2 + + # The $\beta$ factor in the artificial viscosity stabilization. An + # appropriate value for 2d is 0.052 and 0.078 for 3d. Units: None. + set beta = 0.078 + + # The $c_R$ factor in the entropy viscosity stabilization. Units: None. + set cR = 0.5 + end +end + +subsection Geometry model + set Model name = box + + # The extents of the box in km is the same as the width + # and height of the drawing + subsection Box + set X extent = 799000 + set Y extent = 499000 + set X repetitions = 192 + set Y repetitions = 120 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +# We need one compositional field that will be assigned +# the values read in from the ascii data plugin. +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = ascii data + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/cookbooks/prescribed_velocity_ascii_data/ + set Data file name = aspect_name_initial_composition.txt + end +end + +# Use the Ascii data plugin to read in the prescribed velocity ASCII file +# In this cookbook, we use the initial composition file. +subsection Prescribed velocities + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/cookbooks/prescribed_velocity_ascii_data/ + set Data file name = aspect_name_initial_composition.txt + end + + subsection Velocity function + set Variable names = x,y,t + + # Return u_x; u_y; u_z (u_z only used if in 3d) + set Function expression = 0;0 + end +end + +subsection Initial temperature model + set Model name = ascii data + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/cookbooks/prescribed_velocity_ascii_data/ + set Data file name = aspect_name_initial_temperature.txt + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = top, bottom, left, right +end + +subsection Material model + set Model name = multicomponent + + subsection Multicomponent + set Reference temperature = 0.0 + set Densities = 3300 + set Specific heats = 2500 + set Thermal conductivities = 4.7 + set Thermal expansivities = 6e-5 + set Viscosities = 1.e19 + set Viscosity averaging scheme = arithmetic + end +end + +# this plugin really doesn't like mesh refinement yet... +subsection Mesh refinement + set Initial global refinement = 0 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 + set Strategy = strain rate, composition, temperature +end + +subsection Postprocess + set List of postprocessors = visualization + + subsection Visualization + set Interpolate output = true + set Time between graphical output = 1 + set List of output variables = material properties, nonadiabatic temperature, nonadiabatic pressure, strain rate + + subsection Material properties + set List of material properties = density, viscosity, thermal expansivity, reaction terms + end + end +end diff --git a/cookbooks/shell_3d_postprocess/doc/shell_3d_postprocess.part.prm.bak b/cookbooks/shell_3d_postprocess/doc/shell_3d_postprocess.part.prm.bak new file mode 100644 index 00000000000..f11a192f75a --- /dev/null +++ b/cookbooks/shell_3d_postprocess/doc/shell_3d_postprocess.part.prm.bak @@ -0,0 +1,9 @@ +subsection Postprocess + set List of postprocessors = velocity statistics, dynamic topography, visualization, basic statistics, geoid + + subsection Visualization + set Output format = vtu + set List of output variables = geoid, dynamic topography, density, viscosity, gravity + set Number of grouped files = 1 + end +end diff --git a/cookbooks/shell_3d_postprocess/shell_3d_postprocess.prm.bak b/cookbooks/shell_3d_postprocess/shell_3d_postprocess.prm.bak new file mode 100644 index 00000000000..c7685effbe4 --- /dev/null +++ b/cookbooks/shell_3d_postprocess/shell_3d_postprocess.prm.bak @@ -0,0 +1,108 @@ +# A description of convection in a 3d spherical shell with +# a prescribed initial condition based on a harmonic +# perturbation + +# Define the number of space dimensions we would like to +# work in: +set Dimension = 3 + +# Specify the time you want to let the model run for in +# years and the output directory. Here we only calculate +# the instantaneous solution. +set End time = 0 +set Use years in output instead of seconds = true +set Output directory = output-shell_3d_postprocess + +# The following variables describe how the pressure should +# be normalized. Here, we choose a zero average pressure +# at the surface of the domain +set Pressure normalization = surface +set Surface pressure = 0 + +# Here we specify the geometry of the domain, which is +# a spherical shell with inner radius of 3481km and +# outer radius of 6371km +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Outer radius = 6371000 + end +end + +# This section specifies the temperature at the boundary of +# the domain. Here we set the temperature to be constant at +# bottom and top. +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom,top + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 2000 + set Outer temperature = 1000 + end +end + +# This section describes the gravity field, which is pointing +# towards the Earth's center with the same magnitude of 10 m/s^2 +# everywhere +subsection Gravity model + set Model name = radial constant + + subsection Radial constant + set Magnitude = 10 + end +end + +# This section prescribes the initial condition in the temperature +# field, which is chosen as a degree n=4, l=2 perturbation +subsection Initial temperature model + set Model name = harmonic perturbation + + subsection Harmonic perturbation + set Lateral wave number one = 4 + set Lateral wave number two = 2 + set Magnitude = 500 + set Reference temperature = 1600 + end +end + +# The material model is based on the simple material model, which assumes +# a constant density, and other parameters as stated below. +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3300 + set Viscosity = 1e21 + set Thermal expansion coefficient = 3e-5 + set Reference temperature = 1600 + set Thermal conductivity = 4.125 + set Reference specific heat = 1250 + end +end + +# For this calculation we only do 2 global refinement steps. This resolution +# is too low to fully resolve the mantle flow, however it does capture +# the main features. +subsection Mesh refinement + set Initial global refinement = 2 + set Initial adaptive refinement = 0 +end + +# We assume free slip at the inner and outer boundary +subsection Boundary velocity model + set Tangential velocity boundary indicators = bottom,top +end + +# We output the density, velocity, dynamic topography and geoid anomalies +subsection Postprocess + set List of postprocessors = velocity statistics, dynamic topography, visualization, basic statistics, geoid + + subsection Visualization + set Output format = vtu + set List of output variables = geoid, dynamic topography, density, viscosity, gravity + set Number of grouped files = 1 + end +end diff --git a/cookbooks/shell_simple_2d/doc/shearheat.part.prm.bak b/cookbooks/shell_simple_2d/doc/shearheat.part.prm.bak new file mode 100644 index 00000000000..333f2ea44d1 --- /dev/null +++ b/cookbooks/shell_simple_2d/doc/shearheat.part.prm.bak @@ -0,0 +1,3 @@ +subsection Heating model + set List of model names = +end diff --git a/cookbooks/shell_simple_2d/doc/shell.prm.bak b/cookbooks/shell_simple_2d/doc/shell.prm.bak new file mode 100644 index 00000000000..cb189517d7b --- /dev/null +++ b/cookbooks/shell_simple_2d/doc/shell.prm.bak @@ -0,0 +1,72 @@ +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 1.5e9 +set Output directory = output-shell_simple_2d + +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal expansion coefficient = 4e-5 + set Viscosity = 1e22 + end +end + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Outer radius = 6336000 + set Opening angle = 90 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = inner + set Tangential velocity boundary indicators = outer, left, right +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = inner, outer + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 4273 + set Outer temperature = 973 + end +end + +subsection Heating model + set List of model names = shear heating +end + +subsection Initial temperature model + set Model name = spherical hexagonal perturbation +end + +subsection Gravity model + set Model name = ascii data +end + +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 4 + set Strategy = temperature + set Time steps between mesh refinement = 15 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, \ + heat flux statistics, depth average + + subsection Visualization + set Output format = vtu + set Time between graphical output = 1e6 + set Number of grouped files = 0 + end + + subsection Depth average + set Time between graphical output = 1e6 + end +end diff --git a/cookbooks/shell_simple_2d/shell_simple_2d.prm.bak b/cookbooks/shell_simple_2d/shell_simple_2d.prm.bak new file mode 100644 index 00000000000..bb20fef1fb7 --- /dev/null +++ b/cookbooks/shell_simple_2d/shell_simple_2d.prm.bak @@ -0,0 +1,82 @@ +# A simple setup for convection in a quarter of a 2d shell. See the +# manual for more information. + + +set Dimension = 2 +set Use years in output instead of seconds = true +set End time = 1.5e9 +set Output directory = output-shell_simple_2d + +subsection Material model + set Model name = simple + set Material averaging = harmonic average only viscosity + + subsection Simple model + set Thermal expansion coefficient = 4e-5 + set Viscosity = 1e22 + end +end + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Outer radius = 6336000 + set Opening angle = 90 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = bottom + set Tangential velocity boundary indicators = top, left, right +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 4273 + set Outer temperature = 973 + end +end + +subsection Heating model + set List of model names = shear heating +end + +subsection Initial temperature model + set Model name = spherical hexagonal perturbation +end + +subsection Gravity model + set Model name = ascii data +end + +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 4 + set Strategy = temperature + set Time steps between mesh refinement = 15 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics, depth average + + subsection Visualization + set Output format = vtu + set Time between graphical output = 1e6 + set Number of grouped files = 0 + end + + subsection Depth average + set Time between graphical output = 1e6 + end +end + +subsection Solver parameters + subsection Stokes solver parameters + set Stokes solver type = block GMG + end +end diff --git a/cookbooks/shell_simple_2d_smoothing/doc/shell_simple_2d_smoothing.part.prm.bak b/cookbooks/shell_simple_2d_smoothing/doc/shell_simple_2d_smoothing.part.prm.bak new file mode 100644 index 00000000000..db5ffdbc80c --- /dev/null +++ b/cookbooks/shell_simple_2d_smoothing/doc/shell_simple_2d_smoothing.part.prm.bak @@ -0,0 +1,20 @@ +subsection Discretization + set Temperature polynomial degree = 2 + + subsection Stabilization parameters + set Use artificial viscosity smoothing = true + end +end + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if(sqrt(x*x+y*y)<4000000,1,0) + end +end diff --git a/cookbooks/shell_simple_2d_smoothing/shell_simple_2d_smoothing.prm.bak b/cookbooks/shell_simple_2d_smoothing/shell_simple_2d_smoothing.prm.bak new file mode 100644 index 00000000000..99903b5d2c4 --- /dev/null +++ b/cookbooks/shell_simple_2d_smoothing/shell_simple_2d_smoothing.prm.bak @@ -0,0 +1,95 @@ +# An extension of the 2d shell simple cookbook that is used to show the +# benefits of using the artificial viscosity smoothing feature. See the +# manual for more information. + +set Dimension = 2 +set Use years in output instead of seconds = false +set End time = 1.5e16 +set Output directory = output-shell_simple_2d_smoothing + +subsection Discretization + set Temperature polynomial degree = 2 + + subsection Stabilization parameters + set Use artificial viscosity smoothing = true + end +end + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if(sqrt(x*x+y*y)<4000000,1,0) + end +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal expansion coefficient = 4e-5 + set Viscosity = 1e22 + end +end + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Outer radius = 6336000 + set Opening angle = 90 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = bottom + set Tangential velocity boundary indicators = top, left, right +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 4273 + set Outer temperature = 973 + end +end + +subsection Initial temperature model + set Model name = spherical hexagonal perturbation +end + +subsection Gravity model + set Model name = ascii data +end + +subsection Mesh refinement + set Initial global refinement = 6 + set Initial adaptive refinement = 0 + set Strategy = temperature +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics, depth average + + subsection Visualization + set Output format = vtu + set Time between graphical output = 1e6 + set Number of grouped files = 0 + end + + subsection Depth average + set Time between graphical output = 115 + end +end + +subsection Heating model + set List of model names = shear heating +end diff --git a/cookbooks/shell_simple_3d/doc/amr.part.prm.bak b/cookbooks/shell_simple_3d/doc/amr.part.prm.bak new file mode 100644 index 00000000000..eec6a37b436 --- /dev/null +++ b/cookbooks/shell_simple_3d/doc/amr.part.prm.bak @@ -0,0 +1,6 @@ +subsection Mesh refinement + set Initial global refinement = 2 + set Initial adaptive refinement = 3 + set Strategy = temperature + set Time steps between mesh refinement = 15 +end diff --git a/cookbooks/shell_simple_3d/doc/checkpoint.part.prm.bak b/cookbooks/shell_simple_3d/doc/checkpoint.part.prm.bak new file mode 100644 index 00000000000..595a2feeb79 --- /dev/null +++ b/cookbooks/shell_simple_3d/doc/checkpoint.part.prm.bak @@ -0,0 +1,3 @@ +subsection Checkpointing + set Steps between checkpoint = 50 +end diff --git a/cookbooks/shell_simple_3d/doc/part1.part.prm.bak b/cookbooks/shell_simple_3d/doc/part1.part.prm.bak new file mode 100644 index 00000000000..18a2f7b7edf --- /dev/null +++ b/cookbooks/shell_simple_3d/doc/part1.part.prm.bak @@ -0,0 +1,13 @@ +set Dimension = 3 +set Use years in output instead of seconds = true +set End time = 1.5e9 +set Output directory = output-shell_simple_3d + +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal expansion coefficient = 4e-5 + set Viscosity = 1e22 + end +end diff --git a/cookbooks/shell_simple_3d/doc/part2.part.prm.bak b/cookbooks/shell_simple_3d/doc/part2.part.prm.bak new file mode 100644 index 00000000000..6ab568f2f99 --- /dev/null +++ b/cookbooks/shell_simple_3d/doc/part2.part.prm.bak @@ -0,0 +1,13 @@ +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Outer radius = 6336000 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = inner + set Tangential velocity boundary indicators = outer +end diff --git a/cookbooks/shell_simple_3d/doc/part3.part.prm.bak b/cookbooks/shell_simple_3d/doc/part3.part.prm.bak new file mode 100644 index 00000000000..0a9933ad22e --- /dev/null +++ b/cookbooks/shell_simple_3d/doc/part3.part.prm.bak @@ -0,0 +1,9 @@ +subsection Boundary temperature model + set Fixed temperature boundary indicators = inner, outer + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 1973 + set Outer temperature = 973 + end +end diff --git a/cookbooks/shell_simple_3d/doc/part4.part.prm.bak b/cookbooks/shell_simple_3d/doc/part4.part.prm.bak new file mode 100644 index 00000000000..3080dc59b3e --- /dev/null +++ b/cookbooks/shell_simple_3d/doc/part4.part.prm.bak @@ -0,0 +1,11 @@ +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1473 + end +end + +subsection Gravity model + set Model name = ascii data +end diff --git a/cookbooks/shell_simple_3d/doc/postprocess.part.prm.bak b/cookbooks/shell_simple_3d/doc/postprocess.part.prm.bak new file mode 100644 index 00000000000..1538ade53e3 --- /dev/null +++ b/cookbooks/shell_simple_3d/doc/postprocess.part.prm.bak @@ -0,0 +1,16 @@ +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, \ + temperature statistics, heat flux statistics, \ + depth average + + subsection Visualization + set Output format = vtu + set Time between graphical output = 1e6 + set Number of grouped files = 1 + end + + subsection Depth average + set Time between graphical output = 1.5e6 + set Output format = vtu + end +end diff --git a/cookbooks/shell_simple_3d/shell_simple_3d.prm.bak b/cookbooks/shell_simple_3d/shell_simple_3d.prm.bak new file mode 100644 index 00000000000..756c25ce7f3 --- /dev/null +++ b/cookbooks/shell_simple_3d/shell_simple_3d.prm.bak @@ -0,0 +1,79 @@ +# A simple setup for convection in a 3d shell. See the +# manual for more information. + + +set Dimension = 3 +set Use years in output instead of seconds = true +set End time = 1.5e9 +set Output directory = output-shell_simple_3d + +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal expansion coefficient = 4e-5 + set Viscosity = 1e22 + end +end + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Outer radius = 6336000 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = bottom + set Tangential velocity boundary indicators = top +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 1973 + set Outer temperature = 973 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1.473e3 + end +end + +subsection Gravity model + set Model name = ascii data +end + +subsection Mesh refinement + set Initial global refinement = 2 + set Initial adaptive refinement = 3 + set Strategy = temperature + set Time steps between mesh refinement = 15 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics, depth average + + subsection Visualization + set Output format = vtu + set Time between graphical output = 1e6 + set Number of grouped files = 1 + end + + subsection Depth average + set Time between graphical output = 1.5e6 + set Output format = vtu + end +end + +subsection Checkpointing + set Steps between checkpoint = 50 +end diff --git a/cookbooks/sinker-with-averaging/doc/conservative.prm.bak b/cookbooks/sinker-with-averaging/doc/conservative.prm.bak new file mode 100644 index 00000000000..be1f44bba29 --- /dev/null +++ b/cookbooks/sinker-with-averaging/doc/conservative.prm.bak @@ -0,0 +1,3 @@ +subsection Discretization + set Use locally conservative discretization = true +end diff --git a/cookbooks/sinker-with-averaging/doc/full.prm.bak b/cookbooks/sinker-with-averaging/doc/full.prm.bak new file mode 100644 index 00000000000..fbe58455e1b --- /dev/null +++ b/cookbooks/sinker-with-averaging/doc/full.prm.bak @@ -0,0 +1,86 @@ +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output_sinker-with-averaging +set Pressure normalization = volume + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1.0000 + set Y extent = 1.0000 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = left, right, bottom, top +end + +subsection Material model + set Model name = simple + set Material averaging = none + + subsection Simple model + set Reference density = 1 + set Viscosity = 1 + set Thermal expansion coefficient = 0 + set Composition viscosity prefactor = 1e6 + set Density differential for compositional field 1 = 10 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +############### Parameters describing the temperature field +# Note: The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the compositional field +# Note: The compositional field is what drives the flow +# in this example + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if( (sqrt((x-0.5)^2+(y-0.5)^2)>0.22) , 0 , 1 ) + end +end + +############### Parameters describing the discretization + +subsection Mesh refinement + set Initial global refinement = 6 + set Initial adaptive refinement = 0 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, composition statistics + + subsection Visualization + set Output format = vtu + set Time between graphical output = 0 + set List of output variables = density, viscosity + end +end diff --git a/cookbooks/sinker-with-averaging/doc/harmonic.prm.bak b/cookbooks/sinker-with-averaging/doc/harmonic.prm.bak new file mode 100644 index 00000000000..7cad0231baf --- /dev/null +++ b/cookbooks/sinker-with-averaging/doc/harmonic.prm.bak @@ -0,0 +1,3 @@ +subsection Material model + set Material averaging = harmonic average +end diff --git a/cookbooks/sinker-with-averaging/sinker-with-averaging.prm.bak b/cookbooks/sinker-with-averaging/sinker-with-averaging.prm.bak new file mode 100644 index 00000000000..e11a84c2755 --- /dev/null +++ b/cookbooks/sinker-with-averaging/sinker-with-averaging.prm.bak @@ -0,0 +1,86 @@ +set Dimension = 2 +set Start time = 0 +set End time = 0 +set Output directory = output-sinker-with-averaging +set Pressure normalization = volume + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1.0000 + set Y extent = 1.0000 + end +end + +subsection Boundary velocity model + set Zero velocity boundary indicators = left, right, bottom, top +end + +subsection Material model + set Model name = simple + set Material averaging = none + + subsection Simple model + set Reference density = 1 + set Viscosity = 1 + set Thermal expansion coefficient = 0 + set Composition viscosity prefactor = 1e6 + set Density differential for compositional field 1 = 10 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 1 + end +end + +############### Parameters describing the temperature field +# Note: The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the compositional field +# Note: The compositional field is what drives the flow +# in this example + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function expression = if( (sqrt((x-0.5)^2+(y-0.5)^2)>0.22) , 0 , 1 ) + end +end + +############### Parameters describing the discretization + +subsection Mesh refinement + set Initial global refinement = 6 + set Initial adaptive refinement = 0 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, composition statistics + + subsection Visualization + set Output format = vtu + set Time between graphical output = 0 + set List of output variables = density, viscosity + end +end diff --git a/cookbooks/steinberger/doc/geometry.part.prm.bak b/cookbooks/steinberger/doc/geometry.part.prm.bak new file mode 100644 index 00000000000..9d29fe02553 --- /dev/null +++ b/cookbooks/steinberger/doc/geometry.part.prm.bak @@ -0,0 +1,10 @@ +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Opening angle = 90 + set Outer radius = 6371000 + set Phi periodic = true + end +end diff --git a/cookbooks/steinberger/doc/lookup.part.prm.bak b/cookbooks/steinberger/doc/lookup.part.prm.bak new file mode 100644 index 00000000000..e8d3aade1b7 --- /dev/null +++ b/cookbooks/steinberger/doc/lookup.part.prm.bak @@ -0,0 +1,11 @@ +subsection Material model + set Model name = Steinberger + + # Parameters controlling the equation of state. + subsection Steinberger model + set Data directory = $ASPECT_SOURCE_DIR/data/material-model/steinberger/ + set Material file names = pyr-ringwood88.txt + set Bilinear interpolation = true + set Latent heat = false + end +end diff --git a/cookbooks/steinberger/doc/nullspace.part.prm.bak b/cookbooks/steinberger/doc/nullspace.part.prm.bak new file mode 100644 index 00000000000..fc64ac917eb --- /dev/null +++ b/cookbooks/steinberger/doc/nullspace.part.prm.bak @@ -0,0 +1,3 @@ +subsection Nullspace removal + set Remove nullspace = net rotation +end diff --git a/cookbooks/steinberger/doc/projected_density.part.prm.bak b/cookbooks/steinberger/doc/projected_density.part.prm.bak new file mode 100644 index 00000000000..a80f7e617ca --- /dev/null +++ b/cookbooks/steinberger/doc/projected_density.part.prm.bak @@ -0,0 +1,11 @@ +subsection Formulation + set Mass conservation = projected density field + set Temperature equation = real density +end + +subsection Compositional fields + set Number of fields = 1 + set Names of fields = density_field + set Types of fields = density + set Compositional field methods = prescribed field +end diff --git a/cookbooks/steinberger/doc/rheology.part.prm.bak b/cookbooks/steinberger/doc/rheology.part.prm.bak new file mode 100644 index 00000000000..d01af634ea1 --- /dev/null +++ b/cookbooks/steinberger/doc/rheology.part.prm.bak @@ -0,0 +1,11 @@ +subsection Material model + # Parameters controlling the rheology. + subsection Steinberger model + set Lateral viscosity file name = temp-viscosity-prefactor.txt + set Radial viscosity file name = radial-visc-simple.txt + set Use lateral average temperature for viscosity = false + set Maximum lateral viscosity variation = 1e3 + set Maximum viscosity = 5e23 + set Minimum viscosity = 1e20 + end +end diff --git a/cookbooks/steinberger/doc/rheology2.part.prm.bak b/cookbooks/steinberger/doc/rheology2.part.prm.bak new file mode 100644 index 00000000000..ea3ad01b6db --- /dev/null +++ b/cookbooks/steinberger/doc/rheology2.part.prm.bak @@ -0,0 +1,5 @@ +subsection Material model + subsection Steinberger model + set Radial viscosity file name = radial-visc-continuous.txt + end +end diff --git a/cookbooks/steinberger/steinberger.prm.bak b/cookbooks/steinberger/steinberger.prm.bak new file mode 100644 index 00000000000..cdd7266c2c0 --- /dev/null +++ b/cookbooks/steinberger/steinberger.prm.bak @@ -0,0 +1,215 @@ +# This is a cookbook for a convection model with realistic material properties. +# Specifically, it uses material properties read in from a look-up table +# computed with mineral physics software and the projected density approximation. +# It is a quarter of a spherical shell and uses periodic boundary conditions. + +set Dimension = 2 +set End time = 3e8 +set Adiabatic surface temperature = 1613.0 +set Output directory = output-steinberger + +# Because the model is compressible, we use a nonlinear solver. +# We here choose a tolerance of 1e-3 to limit model runtime, but in a +# research application one would test what tolerance would be required +# to obtain a sufficiently accurate solution, and 1e-3 is a quite large +# value. +set Nonlinear solver scheme = iterated Advection and Stokes +set Nonlinear solver tolerance = 1e-3 + +# We run a 2d convection model in a quarter of a spherical shell. +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Opening angle = 90 + set Outer radius = 6371000 + set Phi periodic = true + end +end + +# Both the top and bottom boundaries allow for free slip. +subsection Boundary velocity model + set Tangential velocity boundary indicators = top, bottom +end + +# Because the model has periodic side boundary conditions and free +# slip at top and bottom, there is a rotational nullspace. We fix this +# by setting the net rotation to zero. +subsection Nullspace removal + set Remove nullspace = net rotation +end + +# We use the gravity model from PREM. +subsection Gravity model + set Model name = ascii data +end + +# The temperature is prescribed at the top and bottom boundaries. +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 3773 + set Outer temperature = 273 + end +end + +# The initial temperature model consists of an adiabatic profile, +# thermal boundary layers at the surface and the core-mantle boundary, +# and a small harmonic perturbation to initiate convection. +subsection Initial temperature model + set List of model names = adiabatic, function + + subsection Function + set Coordinate system = spherical + set Variable names = r, phi + set Function constants = r0 = 3481000, r1 = 6371000 + set Function expression = 30 * sin((r-r0)/(r1-r0)*pi)*sin(16*phi) + 20 * sin(2*(r-r0)/(r1-r0)*pi)*sin(12*phi) + end + + subsection Adiabatic + set Age top boundary layer = 1e8 + set Age bottom boundary layer = 1e8 + end +end + +# The model uses the Steinberger material model, which uses a viscosity +# profile constrained by mineral physics and the geoid, and which can read +# in material properties from a look-up table. +subsection Material model + set Model name = Steinberger + + subsection Steinberger model + # This data directory contains the files for the viscosity profile, + # the lateral viscosity variations due to temperature, and all + # material files containing look-up tables computed by mineral physics + # software providing density, thermal expansivity and specific heat. + set Data directory = $ASPECT_SOURCE_DIR/data/material-model/steinberger/ + set Lateral viscosity file name = temp-viscosity-prefactor.txt + set Material file names = pyr-ringwood88.txt + set Radial viscosity file name = radial-visc-simple.txt + + # Because of the resolution in this cookbook we limit the lateral viscosity + # variations to three orders of magnitude in both directions (for a total of + # six orders of magnitude). We then additionally limit the overall viscosity + # between 1e20 Pa s and 5e23 Pa s. This allows the features of the flow field + # to be resolved. In the Earth, we would expect higher viscosities in the + # lithosphere and lower viscosities in plumes and near the core-mantle boundary. + # In addition, this model only accounts for diffusion creep, so the + # lithosphere has a high viscosity and forms a stagnant lid on top of the + # model. In order to have more realistic subduction in a model like this, + # one would have to either prescribe plate velocities at the surface + # (forcing plates to subduct) or take into account plastic yielding (so that + # the lithosphere can break). + set Maximum lateral viscosity variation = 1e3 + set Maximum viscosity = 5e23 + set Minimum viscosity = 1e20 + + # We base our viscosity profile on the adiabat computed based on the + # material properties used in the model rather than the laterally + # averaged temperature. + set Use lateral average temperature for viscosity = false + + # We do not want to include latent heat in our model, mainly because it + # can lead to a lot of numerical problems. In a research application, a + # model like this should include latent heat. In that case, the formatting + # of the look-up table determines if this parameter needs to be set to true + # or false. If the look-up table contains the effective thermal expansivity + # and specific heat, which includes the effect of phase transformations, + # then this parameter still needs to be set to false, because latent heat is + # already included automatically when using the properties from the look-up + # table. If the look-up table contains thermal expansivity and specific heat + # without the effect of phase transitions, then this parameters can be set + # to true to compute latent heat effects based on the pressure and + # temperature derivatives of the specific enthalpy (using the approach of + # Nakagawa et al., 2009). + set Latent heat = false + end +end + +# Our material model is compressible and includes the temperature gradient +# caused by adiabatic heating. Consequently, we include both adiabatic heating +# and shear heating. +subsection Heating model + set List of model names = adiabatic heating, shear heating +end + +# Since our model is compressible, the most accurate way to solve the mass +# conservation equation implemented in ASPECT is to use the 'projected density +# approximation'. This way, ASPECT will compute the density gradients in the +# mass conservation directly from the density field (interpolated onto the +# finite element grid) rather than approximating it with a reference profile +# or temperature/pressure derivatives of the density. The temperature equation +# uses the real density (rather than a reference profile) as well. +subsection Formulation + set Mass conservation = projected density field + set Temperature equation = real density +end + +# In order to use the projected density approximation, the model needs a +# compositional field that the density values can be interpolated on. Here, this +# field is called 'density_field'. We assign the field the type 'density', so +# that ASPECT knows that this is the field it should use to compute the density +# gradient required to solve the equations. ASPECT does not need to solve an +# equation for this field, it only needs to interpolate the density values onto +# it. This is covered by the compositional field method 'prescribed field'. +# For fields of this type, the material model provides the values that should be +# interpolated onto the field. +subsection Compositional fields + set Number of fields = 1 + set Names of fields = density_field + set Types of fields = density + set Compositional field methods = prescribed field +end + +# We refine the mesh near the boundaries, and where temperature variations are +# large. In addition, we make sure that in the transition zone, where both the +# viscosity and the density change a lot, we use the highest refinement level. +subsection Mesh refinement + set Initial adaptive refinement = 1 + set Initial global refinement = 5 + set Refinement fraction = 0.95 + set Coarsening fraction = 0.05 + set Strategy = temperature, boundary, minimum refinement function + set Time steps between mesh refinement = 5 + + subsection Boundary + set Boundary refinement indicators = top, bottom + end + + subsection Minimum refinement function + set Coordinate system = depth + set Variable names = depth, phi + set Function expression = if(depth<700000, 6, 5) + end +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics + + subsection Visualization + set Output format = vtu + set List of output variables = material properties, nonadiabatic temperature, named additional outputs + set Time between graphical output = 1e6 + end +end + +# This model is compressible and has moderately strong viscosity variations. +# To make sure the Stokes solver converges, we increase the GMRES solver restart +# length. This takes more time for each iteration, but the solver usually +# converges within fewer iterations. We also increase the number of cheap Stokes +# solver steps because the cheap solver can often already solve the problem, and +# it is quicker than the expensive solver. +subsection Solver parameters + subsection Stokes solver parameters + set GMRES solver restart length = 200 + set Number of cheap Stokes solver steps = 500 + end +end + +# We also write out checkpoints in case we want to restart the simulation. +subsection Checkpointing + set Steps between checkpoint = 10 +end diff --git a/cookbooks/stokes/doc/stokeslaw.prm.bak b/cookbooks/stokes/doc/stokeslaw.prm.bak new file mode 100644 index 00000000000..8b31c9a9958 --- /dev/null +++ b/cookbooks/stokes/doc/stokeslaw.prm.bak @@ -0,0 +1,118 @@ +############### Global parameters +# We use a 3d setup. Since we are only interested +# in a steady state solution, we set the end time +# equal to the start time to force a single time +# step before the program terminates. + +set Dimension = 3 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = false +set Output directory = output-stokes + +############### Parameters describing the model +# The setup is a 3d box with edge length 2890000 in which +# all 6 sides have free slip boundary conditions. Because +# the temperature plays no role in this model we need not +# bother to describe temperature boundary conditions or +# the material parameters that pertain to the temperature. + + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2890000 + set Y extent = 2890000 + set Z extent = 2890000 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, front, back, bottom, top +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3300 + set Viscosity = 1e22 + set Density differential for compositional field 1 = 100 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +############### Parameters describing the temperature field +# As above, there is no need to set anything for the +# temperature boundary conditions. + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the compositional field +# This, however, is the more important part: We need to describe +# the compositional field and its influence on the density +# function. The following blocks say that we want to +# advect a single compositional field and that we give it an +# initial value that is zero outside a sphere of radius +# r=200000m and centered at the point (p,p,p) with +# p=1445000 (which is half the diameter of the box) and one inside. +# The last block re-opens the material model and sets the +# density differential per unit change in compositional field to +# 100. + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y,z + set Function constants = r=200000,p=1445000 + set Function expression = if(sqrt((x-p)*(x-p)+(y-p)*(y-p)+(z-p)*(z-p)) > r, 0, 1) + end +end + +############### Parameters describing the discretization +# The following parameters describe how often we want to refine +# the mesh globally and adaptively, what fraction of cells should +# be refined in each adaptive refinement step, and what refinement +# indicator to use when refining the mesh adaptively. + +subsection Mesh refinement + set Initial adaptive refinement = 4 + set Initial global refinement = 4 + set Refinement fraction = 0.2 + set Strategy = velocity +end + +############### Parameters describing what to do with the solution +# The final section allows us to choose which postprocessors to +# run at the end of each time step. We select to generate graphical +# output that will consist of the primary variables (velocity, pressure, +# temperature and the compositional fields) as well as the density and +# viscosity. We also select to compute some statistics about the +# velocity field. + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics + + subsection Visualization + set List of output variables = density, viscosity + end +end diff --git a/cookbooks/stokes/stokes.prm.bak b/cookbooks/stokes/stokes.prm.bak new file mode 100644 index 00000000000..2f441647282 --- /dev/null +++ b/cookbooks/stokes/stokes.prm.bak @@ -0,0 +1,121 @@ +# A description of the Stokes benchmark for which an analytic solution +# is available. See the manual for more information. + +############### Global parameters +# We use a 3d setup. Since we are only interested +# in a steady state solution, we set the end time +# equal to the start time to force a single time +# step before the program terminates. + +set Dimension = 3 +set Start time = 0 +set End time = 0 +set Use years in output instead of seconds = false +set Output directory = output-stokes + +############### Parameters describing the model +# The setup is a 3d box with edge length 2890000 in which +# all 6 sides have free slip boundary conditions. Because +# the temperature plays no role in this model we need not +# bother to describe temperature boundary conditions or +# the material parameters that pertain to the temperature. + + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 2890000 + set Y extent = 2890000 + set Z extent = 2890000 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, front, back, bottom, top +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3300 + set Viscosity = 1e22 + set Density differential for compositional field 1 = 100 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +############### Parameters describing the temperature field +# As above, there is no need to set anything for the +# temperature boundary conditions. + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the compositional field +# This, however, is the more important part: We need to describe +# the compositional field and its influence on the density +# function. The following blocks say that we want to +# advect a single compositional field and that we give it an +# initial value that is zero outside a sphere of radius +# r=200000m and centered at the point (p,p,p) with +# p=1445000 (which is half the diameter of the box) and one inside. +# The last block re-opens the material model and sets the +# density differential per unit change in compositional field to +# 100. + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y,z + set Function constants = r=2e5, p=1.445e6 + set Function expression = if(sqrt((x-p)*(x-p)+(y-p)*(y-p)+(z-p)*(z-p)) > r, 0, 1) + end +end + +############### Parameters describing the discretization +# The following parameters describe how often we want to refine +# the mesh globally and adaptively, what fraction of cells should +# be refined in each adaptive refinement step, and what refinement +# indicator to use when refining the mesh adaptively. + +subsection Mesh refinement + set Initial adaptive refinement = 4 + set Initial global refinement = 4 + set Refinement fraction = 0.2 + set Strategy = velocity +end + +############### Parameters describing what to do with the solution +# The final section allows us to choose which postprocessors to +# run at the end of each time step. We select to generate graphical +# output that will consist of the primary variables (velocity, pressure, +# temperature and the compositional fields) as well as the density and +# viscosity. We also select to compute some statistics about the +# velocity field. + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics + + subsection Visualization + set List of output variables = density, viscosity + end +end diff --git a/cookbooks/subduction_initiation/subduction_initiation.prm.base.bak b/cookbooks/subduction_initiation/subduction_initiation.prm.base.bak new file mode 100644 index 00000000000..dac596f3a7a --- /dev/null +++ b/cookbooks/subduction_initiation/subduction_initiation.prm.base.bak @@ -0,0 +1,51 @@ +# Parameter file for replicating Matsumoto & Tomoda 1983 + +set Dimension = 2 +set Start time = 0 +set End time = 50e6 +set Use years in output instead of seconds = true +set CFL number = 0.25 +set Pressure normalization = surface + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 400e3 + set Y extent = 180e3 + set X repetitions = 2 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 9.81 + end +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top + set List of model names = box +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +subsection Mesh refinement + set Initial adaptive refinement = 2 + set Initial global refinement = 5 + set Refinement fraction = 0.9 + set Strategy = composition + set Coarsening fraction = 0 +end diff --git a/cookbooks/subduction_initiation/subduction_initiation_compositional_fields.prm.bak b/cookbooks/subduction_initiation/subduction_initiation_compositional_fields.prm.bak new file mode 100644 index 00000000000..c4bd2e3bd3b --- /dev/null +++ b/cookbooks/subduction_initiation/subduction_initiation_compositional_fields.prm.bak @@ -0,0 +1,50 @@ +# Parameter file for replicating Matsumoto & Tomoda 1983 + +include subduction_initiation.prm.base + +set Output directory = output-subduction-initiation-comp + +#materials are: +# asthenosphere left, +# asthenosphere right, +# lithosphere left, +# lithosphere right, +# water. + +subsection Material model + set Model name = multicomponent + + subsection Multicomponent + set Densities = 3200, 3200, 3300, 3300, 1030 + set Viscosities = 1e21, 1e21, 1e22, 1e22, 1e18 + set Viscosity averaging scheme = harmonic + set Thermal expansivities = 0 + end +end + +subsection Compositional fields + set Number of fields = 4 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = L0=300e3, H=180e3 + set Function expression = if((x>=L0 && yH-60e3 && y<=H-10e3),1,0) ;\ + if((x>=L0 && y>=H-18e3 && y<=H-8e3),1,0) ;\ + if((x<=L0 && y>H-10e3) || (x>=L0 && y>H-8e3),1,0) + end +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, composition statistics, pressure statistics, material statistics, global statistics + + subsection Visualization + set List of output variables = density, viscosity, strain rate + set Time between graphical output = 0 + set Interpolate output = false + end +end diff --git a/cookbooks/subduction_initiation/subduction_initiation_particle_in_cell.prm.bak b/cookbooks/subduction_initiation/subduction_initiation_particle_in_cell.prm.bak new file mode 100644 index 00000000000..e6abe384d17 --- /dev/null +++ b/cookbooks/subduction_initiation/subduction_initiation_particle_in_cell.prm.bak @@ -0,0 +1,66 @@ +# Parameter file for replicating Matsumoto & Tomoda 1983 + +include subduction_initiation.prm.base + +set Output directory = output-subduction-initiation-pic + +subsection Material model + set Model name = multicomponent + set Material averaging = harmonic average + + subsection Multicomponent + set Densities = 0, 3200, 3200, 3300, 3300, 1030 + set Viscosities = 1e30, 1e21, 1e21, 1e22, 1e22, 1e18 + set Viscosity averaging scheme = harmonic + set Thermal expansivities = 0 + end +end + +subsection Compositional fields + set Number of fields = 5 + set Names of fields = asth_left, asth_right, left_lith, right_lith, water + set Compositional field methods = particles, particles, particles, particles, particles + set Mapped particle properties = asth_left:initial asth_left, asth_right:initial asth_right, left_lith:initial left_lith, right_lith:initial right_lith, water: initial water +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = L0=300e3 + set Function expression = if((x<=L0 && y<=120e3),1,0) ;\ + if((x>=L0 && y<162e3),1,0) ;\ + if((x<=L0 && y>120e3 && y<=170e3),1,0) ;\ + if((x>=L0 && y>=162e3 && y<=172e3),1,0) ;\ + if((x<=L0 && y>170e3) || (x>=L0 && y>172e3),1,0) + end +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, composition statistics, pressure statistics, material statistics, global statistics, particles + + subsection Visualization + set List of output variables = density, viscosity, strain rate + set Time between graphical output = 0 + set Interpolate output = false + end + + subsection Particles + set Time between data output = 0 + set Data output format = vtu + end +end + +subsection Particles + set List of particle properties = initial composition, velocity + set Particle generator name = random uniform + set Interpolation scheme = cell average + set Update ghost particles = true + + subsection Generator + subsection Probability density function + set Number of particles = 350000 + end + end +end diff --git a/cookbooks/tian_parameterization_kinematic_slab/coupled-two-phase-tian-parameterization-kinematic-slab.prm.bak b/cookbooks/tian_parameterization_kinematic_slab/coupled-two-phase-tian-parameterization-kinematic-slab.prm.bak new file mode 100644 index 00000000000..6258c76a5b1 --- /dev/null +++ b/cookbooks/tian_parameterization_kinematic_slab/coupled-two-phase-tian-parameterization-kinematic-slab.prm.bak @@ -0,0 +1,303 @@ +# This cookbook simulates a kinematically-driven 2D subduction system containing +# distinct lithologies for the mantle wedge and subducting sediment, +# mid-ocean ridge basalt (MORB), gabbro, peridotite. Lithologies within the slab +# are prescribed to an initial hydration state after a period of equilibration, and +# subsequently dehydrate as they subduct. This cookbook utlizes the existing melt framework +# within ASPECT which governs the mechanical coupling of a solid and fluid phase (see +# https://doi.org/10.1093/gji/ggw329) but introduces solid-volatile reactions +# that are governed by an approximation +# published by Tian et al., 2019 (https://doi.org/10.1029/2019GC008488). +# In detail, the model simulates the upper 20 km of a subducting slab with a dip +# of 45 degrees and a convergence rate of 5 cm/yr. The Cartesian box is rotated +# such that the x-axis aligns with the slab surface and the y-axis is orthogonal +# to the slab surface, while gravity is imposed at an angle of 45 degrees. A surface pressure +# of 1 GPa is imposed to account for the model simulating a portion of the slab +# that is already subducted. For stability, the slab first subducts for 100 kyr before +# the hydration is added, and the slab surface temperature diffuses to the mantle over +# 10 km perpendicular to the slab surface. From the slab surface to the base of the model, +# the composition is comprised of a 5 km thick layer of sediment with 3 wt% water, +# below is a 7 km thick layer of MORB with 2 wt% water, and below that is an +# 8 km thick layer of gabbro with 1 wt% water. + +set Adiabatic surface temperature = 1600 +set Nonlinear solver scheme = iterated Advection and Stokes + +# We choose a low number of iterations and less restrictive nonlinear solver tolerance +# for model efficiency. During the initial pulse of dehydration (for 3 time steps), +# solvers do not quite converge to 1e-4, but achieve the convergence criteria for the +# rest of the model run time. For a production model, a tolerance of at least 1e-5 +# should be selected. Reaching these tolerances may require on the order of +# 50-100 nonlinear iterations, and the maximum number of nonlinear iterations +# will need to be increased accordingly. +set Max nonlinear iterations = 25 +set Nonlinear solver tolerance = 1e-4 +set Dimension = 2 +set End time = 2e6 + +# Set the 'Surface pressure' to 1 GPa to simulate a slab that is at depth. +set Surface pressure = 1e9 +set Maximum time step = 1000 +set Use operator splitting = true +set Output directory = output_coupled_two_phase_tian_parameterization_kinematic_slab + +# Checkpoint the model so that a restart can be done if needed. +subsection Checkpointing + set Steps between checkpoint = 20 +end + +subsection Discretization + # We choose relatively large values for the stabilization parameters: + # However, note that in an application model with a higher resolution, + # we would choose much smaller values for the stabilization parameters. + subsection Stabilization parameters + set beta = 0.5 + set cR = 1 + end +end + +subsection Solver parameters + # Set a stricter linear solver tolerance to ensure convergence + subsection Stokes solver parameters + set Linear solver tolerance = 1e-10 + set Number of cheap Stokes solver steps = 1000 + end +end + +# Initialize the compositional fields. When using the tian approximation +# Fluid-solid reaction scheme in the Reactive Fluid Transport material +# model, the fields 'porosity', 'bound_fluid', 'peridotite', 'gabbro', +# 'MORB', and 'sediment' are all required compositional fields. This is +# because they are all treated as special fields by the material model. +# The 4 lithologies ('sediment', 'MORB', 'gabbro', 'peridotite') are used +# to determine the equilibrium wt% of water that can be incorporated into +# the corresponding lithology at the model P-T conditions. Free fluid +# ('porosity') is then partitioned into/out of the solid depending on the +# current wt% water within the lithology ('bound_fluid'), and how much 'porosity' +# is present. +subsection Compositional fields + set Number of fields = 6 + set Names of fields = porosity, bound_fluid, peridotite, gabbro, MORB, sediment + set Compositional field methods = field, field, field, field, field, field +end + +# Initially, the interior of the model is just the periodite mantle. +# The composition (4 lithologies, porosity, bound_fluid) +# evolves through the composition boundary conditions specified below. +subsection Initial composition model + set Model name = function + + subsection Function + set Function expression = 0; 0; 1; 0; 0; 0 + end +end + +# The slab begins at the left most boundary, at first consisting solely of dry +# lithologic layers. After 100 kyr, the incoming sediment is hydrated +# (initial_bound_) variablesto 3 wt% water, MORB to 2 wt% water, and gabbro +# to 1 wt% water. +subsection Boundary composition model + set Fixed composition boundary indicators = left + set List of model names = function + + subsection Function + set Function constants = initial_porosity=0, initial_bound_sediment=0.03, initial_bound_MORB=0.02, initial_bound_gabbro=0.01, \ + sediment_min=0, sediment_max=5e3, MORB_min=5e3, MORB_max=12e3, gabbro_min=12e3, gabbro_max=20e3, \ + onset_time=100e3, slab_thickness=20e3 + set Function expression = initial_porosity; \ + if( t<=onset_time, 0, \ + if( (y<=slab_thickness - sediment_min) & (y>slab_thickness - sediment_max), initial_bound_sediment, \ + if( (y<=slab_thickness - MORB_min) & (y>slab_thickness - MORB_max), initial_bound_MORB, \ + if( (y<=slab_thickness - gabbro_min) & (y>slab_thickness - gabbro_max), initial_bound_gabbro, 0.0) \ + ) \ + ) \ + ); \ + if(y>slab_thickness, 1, 0); \ + if(y<=8e3, 1, 0); \ + if(y>8e3 & y<=15e3, 1, 0); \ + if(y>15e3 & y<=slab_thickness, 1, 0) + end +end + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 100e3 + set Y extent = 100e3 + set Y repetitions = 2 + set X repetitions = 2 + end +end + +# Refine the mesh globally from 50 km to 3.125 km resolution through four global refinements. +# Next, adaptively refine the mesh as a function of the porosity. +subsection Mesh refinement + set Coarsening fraction = 0.05 + set Refinement fraction = 0.8 + set Initial adaptive refinement = 1 + set Initial global refinement = 4 + set Strategy = composition threshold, minimum refinement function + set Time steps between mesh refinement = 2 + + # Minimum of 4 global refinements + subsection Minimum refinement function + set Function expression = 4 + end + + # Refine where the porosity is bigger than 1e-6. Other compositions + # are set to 1e50 to ensure that we do not refine based on these + # compositions. + subsection Composition threshold + set Compositional field thresholds = 1e-6, 1e50, 1e50, 1e50, 1e50, 1e50 + end +end + +# Impose a gravity vector at an angle of 45 degrees. This +# accounts for the fact that the slab is subducting with a dip +# of 45 degrees and the x-axis of our model aligns parallel to the +# slab surface. +subsection Gravity model + set Model name = function + + subsection Function + set Variable names = x,y + set Function constants = angle=0.7071067811865476 + set Function expression = 9.81*angle; -9.81*angle + end +end + +# Initial temperature is a constant value of 1500 K +# The temperature field evolves through the imposed boundary conditions +# outlined below. +subsection Initial temperature model + set Model name = function + + subsection Function + set Coordinate system = cartesian + set Variable names = x,y + set Function constants = Tmantle=1500 + set Function expression = Tmantle + end +end + +# Fix the temperature on the left boundary to ensure that +# the incoming slab is always colder than the mantle. The +# temperature is unconstrained on other boundaries. +subsection Boundary temperature model + set Fixed temperature boundary indicators = left + set List of model names = function + + subsection Function + set Coordinate system = cartesian + set Variable names = x,y + set Function constants = Tmantle=1500, Tslab=600, slab_thickness=20e3 + set Function expression = if(y<=slab_thickness, Tslab - 200*y/slab_thickness, Tmantle) + end +end + +subsection Material model + set Model name = reactive fluid transport + set Material averaging = harmonic average only viscosity + + # Use the reactive fluid transport model composited with the visco plastic material model. + # We use the tian approximation method for the solid-fluid reactions, and place a maximum + # wt% water on the 4 lithologies. We choose fluid properties appropriate for water, and + # set the Fluid reaction time scale for operator splitting to be 50 kyr. This parameter + # controls the timescales for the dehydration/hydration reactions, and decreasing this value + # will tend to make convergence more difficult since fluids will be released from the solid + # phase more rapidly, increasing compaction pressure gradients. An important parameter that + # can help inform model stability is the compaction length, which is defined as: + # sqrt((eta_c + 4/3*eta_s) * k/eta_f) + # Where k is the permeability, and eta_c, eta_s, and eta_f are the compaction viscosity, + # shear viscosity, and fluid viscosity respectively. Ensuring that the mesh can resolve the + # compaction length will aid in convergence. The compaction length for this problem at the + # reference permeability (1e-6), the minimum shear viscosity (1e19 Pa s), and a compaction + # viscosity of 1e19 Pa s results in a compaction length of ~4.8 km. Our mesh has a maximum + # resolution of ~1.6 km^2, meaning that the compaction length scales are adequately resolved. + subsection Reactive Fluid Transport Model + set Base model = visco plastic + set Reference fluid density = 1000 # density of water + set Shear to bulk viscosity ratio = 0.1 + set Reference fluid viscosity = 1 + set Reference permeability = 1e-6 + set Exponential fluid weakening factor = 30 + set Fluid compressibility = 0 + set Fluid reaction time scale for operator splitting = 5e4 + set Fluid-solid reaction scheme = tian approximation + + # We limit the bound water in the gabbro, MORB, and sediment to their initial + # values to encourage water to hydrate the overlying mantle. The polynomials defined + # in Tian et al., 2019 also reach very large values at low P-T conditions, and so limiting + # the weight percent to reasonable values is recommended. + set Maximum weight percent water in peridotite = 2 + set Maximum weight percent water in gabbro = 1 + set Maximum weight percent water in MORB = 2 + set Maximum weight percent water in sediment = 3 + end + + subsection Visco Plastic + # Use the composite flow law to simulate dislocation and diffusion creep + # of dry olivine with the parameters from Hirth & Kohlstaedt 2004 (10.1029/138GM06). + # This will be inconsistent with the physical state of the model (the solid is hydrated), + # but ongoing work will introduce a more self-consistent coupling between the hydration + # state and the rheology. + set Viscosity averaging scheme = harmonic + set Viscous flow law = composite + set Prefactors for diffusion creep = 4.5e-15 + set Stress exponents for diffusion creep = 1.0 + set Activation energies for diffusion creep = 375e3 + set Activation volumes for diffusion creep = 8.2e-6 + set Prefactors for dislocation creep = 7.4e-15 + set Stress exponents for dislocation creep = 3.5 + set Activation energies for dislocation creep = 530e3 + set Activation volumes for dislocation creep = 14e-6 + set Angles of internal friction = 0 + set Cohesions = 1e50 + + # Limit the minimum and maximum viscosity to four orders of + # magnitude to improve solver convergence behavior. + set Minimum viscosity = 1e19 + set Maximum viscosity = 1e23 + end +end + +# Define the velocity on all boundaries such that the velocity is 5 cm/yr on the bottom +# boundary and the left/right boundaries from 0<=y<=20 km (slab). For y>20 km, the velocity +# linearly decreases from 5 cm/yr to 2 cm/yr, approximating corner flow and the decreasing +# viscous coupling of the mantle wedge with distance from the slab surface. +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left: function, bottom: function, top: function, right: function + + subsection Function + set Coordinate system = cartesian + set Function constants = basal_v = 0.05, top_v = 0.02, slab_depth = 20e3, ymax = 100e3 + set Variable names = x, y + set Function expression = if(y<=slab_depth, 0.05, 0.05 - (basal_v - top_v) * (y - slab_depth) / (ymax - slab_depth)); 0 + end +end + +# To fully couple the solid-fluid phases, Include melt transport must be set to true. The reactive +# fluid transport model and the tian approximation can still be used when Include melt transport is +# set to false, but this does not fully couple the solid-fluid phases. The uncoupled case is +# presented in the investigated in the other .prm file in this cookbook. +subsection Melt settings + set Include melt transport = true +end + +# Output every 50 kyr, and visualize the melt material properties which allows us to look at the +# compaction viscosities and compaction pressures. +subsection Postprocess + set List of postprocessors = visualization, composition statistics, velocity statistics + + subsection Visualization + set List of output variables = density, viscosity, thermal expansivity, melt material properties, melt fraction + set Output format = vtu + set Time between graphical output = 5e4 + set Interpolate output = true + set Number of grouped files = 0 + + subsection Melt material properties + set List of properties = fluid density, permeability, fluid viscosity, compaction viscosity + end + end +end diff --git a/cookbooks/tian_parameterization_kinematic_slab/uncoupled-two-phase-tian-parameterization-kinematic-slab.prm.bak b/cookbooks/tian_parameterization_kinematic_slab/uncoupled-two-phase-tian-parameterization-kinematic-slab.prm.bak new file mode 100644 index 00000000000..5cccb864ff4 --- /dev/null +++ b/cookbooks/tian_parameterization_kinematic_slab/uncoupled-two-phase-tian-parameterization-kinematic-slab.prm.bak @@ -0,0 +1,36 @@ +# This input file creates a model with the same setup as the model generated by +# coupled-two-phase-tian-parameterization-kinematic-slab.prm, with the only difference +# being that the solid-fluid reactions in this parameter file are not fully coupled. +# Instead, the fluid is advected only with the Darcy velocity. See +# coupled-two-phase-tian-parameterization-kinematic-slab.prm for more details on the model +# setup. + +include $ASPECT_SOURCE_DIR/cookbooks/tian_parameterization_kinematic_slab/coupled-two-phase-tian-parameterization-kinematic-slab.prm + +set Output directory = output_uncoupled_two_phase_tian_parameterization_kinematic_slab + +subsection Solver parameters + subsection Stokes solver parameters + # As the system of equations being solved is simpler, the linear solver tolerance can be reduced + # to improve efficiency. Note that in production models this value should be tested and decreased + # until it no longer has an effect on the model results when using the "iterated Advection and Stokes" + set Linear solver tolerance = 1e-8 + set Number of cheap Stokes solver steps = 1000 + end +end + +subsection Compositional fields + set Compositional field methods = darcy field, field, field, field, field, field +end + +subsection Melt settings + set Include melt transport = false +end + +subsection Postprocess + set List of postprocessors = visualization, composition statistics, velocity statistics + + subsection Visualization + set List of output variables = density, viscosity, thermal expansivity, melt fraction + end +end diff --git a/cookbooks/tomography_based_plate_motions/2D_slice_with_faults_and_cratons.prm.bak b/cookbooks/tomography_based_plate_motions/2D_slice_with_faults_and_cratons.prm.bak new file mode 100644 index 00000000000..a8defb6d961 --- /dev/null +++ b/cookbooks/tomography_based_plate_motions/2D_slice_with_faults_and_cratons.prm.bak @@ -0,0 +1,246 @@ +# This cookbook demonstrates how we can set up instantaneous mantle flow models +# using available geophysical constraints. To avoid large computational cost, +# this model is a 2D spherical shell with imposed plate boundaries and driven +# by mantle forces arising from observed mantle heterogeneity. +# The generated mantle flow field at the surface can be compared with the observed +# surface deformation and the fit can be used to constrain the physical state +# of the mantle. +# We define plate boundaries and cratons using WorldBuilder. + +set Additional shared libraries = $ASPECT_SOURCE_DIR/cookbooks/tomography_based_plate_motions/plugins/libtomography_based_plate_motions.release.so +set Dimension = 2 +set Use years in output instead of seconds = true +set Output directory = 2D-slice-with-faults-cratons +set World builder file = $ASPECT_SOURCE_DIR/cookbooks/tomography_based_plate_motions/input_data/world_builder_smac_cratons_faults_2D.json +set Nonlinear solver scheme = iterated Advection and Stokes +set Start time = 0 +set End time = 0 +set Adiabatic surface temperature = 1573.0 + +# We use matrix-free solver and geometric multigrid preconditioner +# to reduce memory consumption. +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-4 + set Stokes solver type = block GMG + set Number of cheap Stokes solver steps = 500 + set GMRES solver restart length = 400 + set Maximum number of expensive Stokes solver steps = 0 + set Use full A block as preconditioner = true + set Linear solver A block tolerance = 1e-2 + end +end + +# The reference profile uses hydrostatic equations to define adiabatic pressure +# and temperatures. The difference with existing compute profile plugin is that this +# plugin uses reference densities from PREM below a certain depth defined by the +# uppermost mantle thickness parameter to compute the adiabatic conditions. +subsection Adiabatic conditions model + set Model name = reference profile + + subsection Reference profile + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/data/1D_reference_profiles/ + set Data file name = prem.txt + end + end +end + +# We use the spherical shell geometry using the real Earth radius values. +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Outer radius = 6371000 + end +end + +# We use adaptive refinement to better resolve the plate boundaries and +# the near-surface heterogeneity +subsection Mesh refinement + set Initial adaptive refinement = 1 + set Initial global refinement = 4 + set Strategy = minimum refinement function + set Skip solvers on initial refinement = true + + subsection Minimum refinement function + set Variable names = depth, y + set Function expression = if (depth < 350000, 5, 4) + end +end + +subsection Compositional fields + set Number of fields = 6 + set Names of fields = grain_size, Vp, Vs, vs_anomaly, faults, continents + set Compositional field methods = static, static, static, static, static, static +end + +# We use world builder to define the complex geometery of plate boundaries ("faults") +# and cratons ("continents") in our model. +subsection Initial composition model + set List of model names = ascii data, world builder + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/cookbooks/tomography_based_plate_motions/input_data/ + set Data file name = LLNL_model_cropped_cratons_faults.txt.gz + set Slice dataset in 2D plane = true + end + + subsection World builder + set List of relevant compositions = faults, continents + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = bottom, top +end + +# We set the net rotation of the velocities at the surface to zero. +# This is useful for comparison with the observed GPS velocities in the no +# net rotation frame. +subsection Nullspace removal + set Remove nullspace = net surface rotation +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = spherical constant + + subsection Spherical constant + set Inner temperature = 3700 + set Outer temperature = 273 + end +end + +# We set initial temperatures purely from an ASCII data file. +# The only reason we also activate the adiabatic boundary plugin is that it +# allows us to to read a dataset of lithospheric thicknesses that we use to +# determine reference density, thermal expansivity, and compressibility. +subsection Initial temperature model + set List of model names = ascii data, adiabatic boundary + set List of model operators = maximum + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/cookbooks/tomography_based_plate_motions/input_data/ + set Data file name = upper_mantle_TM1_2D.txt + end + + subsection Adiabatic boundary + set Data directory = $ASPECT_SOURCE_DIR/cookbooks/tomography_based_plate_motions/input_data/ + set Data file name = LAB_CAM2016_2D.txt + set Adiabatic temperature gradient = 0 + set Isotherm temperature = 274 + set Surface temperature = 273 + end +end + +# We do not solve for the temperature field and instead prescribe temperatures +# in our material model using the initial temperature distribution and +# temperatures computed from the input tomography data. +subsection Temperature field + set Temperature method = prescribed field +end + +subsection Heating model + set List of model names = adiabatic heating, shear heating +end + +subsection Gravity model + set Model name = ascii data +end + +# The material model uses diffusion/dislocation creep with prefactors, activation +# energies and volumes for each major mantle phase chosen to facilitate combined +# diffusion/dislocation creep in the upper mantle and transition zone, and diffusion +# creep as the dominant deformation mechanism in the lower mantle. +subsection Material model + set Model name = tomography based plate motions + set Material averaging = harmonic average only viscosity + + subsection Tomography based plate motions model + set Average specific grain boundary energy = 1.0,1.0,1.0,1.0 + set Use equilibrium grain size = false + set Minimum viscosity = 1e19 + set Maximum viscosity = 1e24 + set Diffusion activation energy = 375000,231000,270000,299000 + set Diffusion activation volume = 6e-6,6e-6,6e-6,2e-6 + set Diffusion creep exponent = 1.0,1.0,1.0,1.0 + set Diffusion creep grain size exponent = 3,3,3,3 + set Diffusion creep prefactor = 1.25E-015,6.12E-019,2.94E-017,5.4E-022 + set Dislocation activation energy = 530000,530000,530000,530000 + set Dislocation activation volume = 1.40E-005,1.70E-005,1.70E-005,0.0 + set Dislocation creep exponent = 3.5,3.5,3.5,3.5 + set Dislocation creep prefactor = 8.33E-015,2.05e-12,2.05e-19,1.e-40 #1e-100, 1e-100, 1e-100, 1e-100 + set Geometric constant = 3,3,3,3 + set Grain growth activation energy = 400000,662000,414000,299000 + set Grain growth activation volume = 0.0,0.0,0.0,1.5e-6 + set Grain growth exponent = 3,3,4.5,5.0 + set Grain growth rate constant = 1.92e-10,3.02e-4,7.63e-22,5.00E-026 + set Work fraction for boundary area change = 0.1,0.1,0.1,0.1 + set Reference compressibility = 4e-12 + set Reference density = 3400 + set Reference specific heat = 1200 + set Thermal conductivity = 4 + set Thermal expansion coefficient = 2.0e-5 + set Maximum temperature dependence of viscosity = 1e6 + set Phase transition Clapeyron slopes = 0,0,0 + set Phase transition depths = 410000,520000,660000 + set Phase transition temperatures = 1950,1950,1950 + set Phase transition widths = 0,0,0 + set Reciprocal required strain = 10 + set Recrystallized grain size = 0.0,0.0,1e-4 + set Uppermost mantle thickness = 300000 + + # The following parameters govern whether we want to scale the laterally + # averaged viscosity to a reference profile, and the location of that + # profile. + set Use depth dependent viscosity = true + + # This tells us how we want to scale the input Vs anomalies to compute density/temperature + # anomalies. By default, the model uses a constant scaling factor, but in this cookbook we use + # depth-dependent scaling factors taken from input ascii files. + set Use depth dependent density scaling = true + set Use depth dependent temperature scaling = true + set Use faults = true + set Use cratons = true + set Asthenosphere viscosity = 1e20 + set Fault viscosity = 1e19 + + subsection Ascii data model + set Data directory = $ASPECT_SOURCE_DIR/cookbooks/tomography_based_plate_motions/input_data/viscosity_profiles/ + set Data file name = steinberger_source-1.txt + end + + subsection Density velocity scaling + set Data file name = rho_vs_scaling.txt + end + + subsection Temperature velocity scaling + set Data file name = dT_vs_scaling.txt + end + + subsection Thermal expansivity profile + set Data directory = $ASPECT_SOURCE_DIR/cookbooks/tomography_based_plate_motions/input_data/ + set Data file name = thermal_expansivity_steinberger_calderwood.txt + end + + subsection Crustal depths + set Data directory = $ASPECT_SOURCE_DIR/cookbooks/tomography_based_plate_motions/input_data/ + set Data file name = crustal_structure_2D.txt + end + end +end + +subsection Formulation + set Mass conservation = reference density profile +end + +subsection Postprocess + set List of postprocessors = boundary velocity residual statistics, velocity boundary statistics, visualization, heat flux statistics, depth average + + subsection Visualization + set List of output variables = adiabat, material properties, gravity, nonadiabatic temperature, heat flux map, strain rate, boundary velocity residual, named additional outputs + set Output format = vtu + end +end diff --git a/cookbooks/tomography_based_plate_motions/doc/tomography_based_plate_motions.part.prm.bak b/cookbooks/tomography_based_plate_motions/doc/tomography_based_plate_motions.part.prm.bak new file mode 100644 index 00000000000..74f5416bbeb --- /dev/null +++ b/cookbooks/tomography_based_plate_motions/doc/tomography_based_plate_motions.part.prm.bak @@ -0,0 +1,53 @@ +subsection Compositional fields + set Number of fields = 6 + set Names of fields = grain_size, Vp, Vs, vs_anomaly, faults, continents + set Compositional field methods = static, static, static, static, static, static +end + +subsection Initial composition model + set List of model names = ascii data, world builder + + subsection Ascii data model + set Data directory = ../../input_data/ + set Data file name = LLNL_model_cropped_cratons_faults.txt.gz + set Slice dataset in 2D plane = true + end + + subsection World builder + set List of relevant compositions = faults, continents + end +end + +subsection Temperature field + set Temperature method = prescribed field +end + +subsection Material model + set Model name = tomography based plate motions + set Material averaging = harmonic average only viscosity + + subsection Tomography based plate motions model + set Uppermost mantle thickness = 300000 + set Use depth dependent viscosity = true + set Use depth dependent density scaling = true + set Use depth dependent temperature scaling = true + set Use faults = true + set Fault viscosity = 1e19 + set Use cratons = true + set Craton viscosity = 1e25 + set Asthenosphere viscosity = 1e20 + + subsection Ascii data model + set Data directory = ../../input_data/viscosity_profiles/ + set Data file name = steinberger_source-1.txt + end + + subsection Density velocity scaling + set Data file name = rho_vs_scaling.txt + end + + subsection Temperature velocity scaling + set Data file name = dT_vs_scaling.txt + end + end +end diff --git a/cookbooks/tomography_based_plate_motions/plugins/reference_profile.cc.bak b/cookbooks/tomography_based_plate_motions/plugins/reference_profile.cc.bak new file mode 100644 index 00000000000..ee4ef975af3 --- /dev/null +++ b/cookbooks/tomography_based_plate_motions/plugins/reference_profile.cc.bak @@ -0,0 +1,457 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include "reference_profile.h" +#include "tomography_based_plate_motions.h" +#include +#include + +#include + + +namespace aspect +{ + namespace AdiabaticConditions + { + template + ReferenceProfile::ReferenceProfile() + : + initialized(false), + surface_condition_function(2) + {} + + + + template + void + ReferenceProfile::update() + { + if (use_surface_condition_function) + { + initialized = false; + surface_condition_function.set_time(this->get_time()); + initialize(); + } + } + + + template + void + ReferenceProfile::initialize() + { + if (initialized) + return; + + reference_profile.initialize(this->get_mpi_communicator()); + density_index = reference_profile.get_column_index_from_name("density"); + + temperatures.resize(n_points, numbers::signaling_nan()); + pressures.resize(n_points, numbers::signaling_nan()); + densities.resize(n_points, numbers::signaling_nan()); + + delta_z = this->get_geometry_model().maximal_depth() / (n_points-1); + + MaterialModel::MaterialModelInputs in(1, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(1, this->n_compositional_fields()); + + // Constant properties on the reference profile + in.strain_rate.resize(0); + in.velocity[0] = Tensor <1,dim> (); + in.requested_properties = MaterialModel::MaterialProperties::equation_of_state_properties; + + // Check whether gravity is pointing up / out or down / in. In the normal case it should + // point down / in and therefore gravity should be positive, leading to increasing + // adiabatic pressures and temperatures with depth. In some cases it will point up / out + // (e.g. for backward advection), in which case the pressures and temperatures should + // decrease with depth and therefore gravity has to be negative in the following equations. + const Tensor <1,dim> g = this->get_gravity_model().gravity_vector(this->get_geometry_model().representative_point(0)); + const Point point_surf = this->get_geometry_model().representative_point(0); + const Point point_bot = this->get_geometry_model().representative_point(this->get_geometry_model().maximal_depth()); + const int gravity_direction = (g * (point_bot - point_surf) >= 0) ? + 1 : + -1; + + // We want to use different values for the densities in the uppermost vs the lower part of the mantle. + double uppermost_mantle_thickness = 0.0; + if (Plugins::plugin_type_matches>(this->get_material_model())) + { + const MaterialModel::TomographyBasedPlateMotions &material_model + = Plugins::get_plugin_as_type> (this->get_material_model()); + + uppermost_mantle_thickness = material_model.get_depth_of_base_of_uppermost_mantle(); + } + + + // now integrate downward using the explicit Euler method for simplicity + // + // note: p'(z) = rho(p,T) * |g| + // T'(z) = alpha |g| T / C_p + for (unsigned int i=0; iget_geometry_model().maximal_depth(); + const double outer_radius = this->get_geometry_model().representative_point(0.).norm(); + + double density = reference_profile.get_data_component(Point<1>(outer_radius - current_depth),density_index); + + if (i==0) + { + if (!use_surface_condition_function) + { + pressures[0] = this->get_surface_pressure(); + temperatures[0] = this->get_adiabatic_surface_temperature(); + } + else + { + pressures[0] = surface_condition_function.value(Point<1>(0.0),0); + temperatures[0] = surface_condition_function.value(Point<1>(0.0),1); + } + } + else + { + // We only want to use the PREM densities in the part of the model that also + // uses seismic velocities to determine the densities. Otherwise, use the density + // computed by the material model. + if (current_depth < uppermost_mantle_thickness) + density = out.densities[0]; + + const double alpha = out.thermal_expansion_coefficients[0]; + // Handle the case that cp is zero (happens in simple Stokes test problems like sol_cx). By setting + // 1/cp = 0.0 we will have a constant temperature profile with depth. + const double one_over_cp = (out.specific_heat[0]>0.0) ? 1.0/out.specific_heat[0] : 0.0; + // get the magnitude of gravity. we assume + // that gravity always points along the depth direction. this + // may not strictly be true always but is likely a good enough + // approximation here. + const double gravity = gravity_direction * this->get_gravity_model().gravity_vector(in.position[0]).norm(); + + pressures[i] = pressures[i-1] + density * gravity * delta_z; + temperatures[i] = (this->include_adiabatic_heating()) + ? + temperatures[i-1] * (1 + alpha * gravity * delta_z * one_over_cp) + : + temperatures[0]; + } + + const Point representative_point = this->get_geometry_model().representative_point (current_depth); + const Tensor <1,dim> g = this->get_gravity_model().gravity_vector(representative_point); + + in.position[0] = representative_point; + in.temperature[0] = temperatures[i]; + in.pressure[0] = pressures[i]; + + // we approximate the pressure gradient by extrapolating the values + // from the two points above + if (i>0) + in.pressure_gradient[0] = g/(g.norm() != 0.0 ? g.norm() : 1.0) + * (pressures[i] - pressures[i-1]) / delta_z; + else + in.pressure_gradient[0] = Tensor <1,dim> (); + + if (reference_composition == initial_composition) + for (unsigned int c=0; cn_compositional_fields(); ++c) + in.composition[0][c] = this->get_initial_composition_manager().initial_composition(representative_point, c); + else if (reference_composition == reference_function) + { + const double depth = this->get_geometry_model().depth(representative_point); + const Point<1> p(depth); + for (unsigned int c=0; cn_compositional_fields(); ++c) + in.composition[0][c] = composition_function->value(p, c); + } + else + AssertThrow(false,ExcNotImplemented()); + + densities[i] = density; + + this->get_material_model().evaluate(in, out); + + // Make sure we get the first point of the profile right. We can only assign the correct + // value after the material model has been evaluated. + if (current_depth < uppermost_mantle_thickness && i==0) + densities[i] = out.densities[0]; + } + + if (gravity_direction == 1 && this->get_surface_pressure() >= 0) + { + Assert (*std::min_element (pressures.begin(), pressures.end()) >= + -std::numeric_limits::epsilon() * pressures.size(), + ExcMessage("Adiabatic ReferenceProfile encountered a negative pressure of " + + dealii::Utilities::to_string(*std::min_element (pressures.begin(), pressures.end())))); + } + else if (gravity_direction == -1 && this->get_surface_pressure() <= 0) + { + Assert (*std::max_element (pressures.begin(), pressures.end()) <= + std::numeric_limits::epsilon() * pressures.size(), + ExcMessage("Adiabatic ReferenceProfile encountered a positive pressure of " + + dealii::Utilities::to_string(*std::max_element (pressures.begin(), pressures.end())))); + } + + Assert (*std::min_element (temperatures.begin(), temperatures.end()) >= + -std::numeric_limits::epsilon() * temperatures.size(), + ExcMessage("Adiabatic ReferenceProfile encountered a negative temperature.")); + + + initialized = true; + } + + + + template + bool + ReferenceProfile::is_initialized() const + { + return initialized; + } + + + + template + double ReferenceProfile::pressure (const Point &p) const + { + return get_property(p,pressures); + } + + + + template + double ReferenceProfile::temperature (const Point &p) const + { + return get_property(p,temperatures); + } + + + + template + double ReferenceProfile::density (const Point &p) const + { + return get_property(p,densities); + } + + + + template + double ReferenceProfile::density_derivative (const Point &p) const + { + const double z = this->get_geometry_model().depth(p); + + if (z >= this->get_geometry_model().maximal_depth()) + { + Assert (z <= this->get_geometry_model().maximal_depth() + delta_z, + ExcInternalError()); + return (densities.back() - densities[densities.size()-2]) / delta_z; + } + + if (z < 0) + { + Assert (z >= -delta_z, ExcInternalError()); + return (densities[1] - densities.front()) / delta_z; + } + + // if z/delta_z is within [k-eps, k+eps] of a whole number k, round it down to k-1 + const unsigned int i = static_cast((z/delta_z) * (1. - 2. * std::numeric_limits::epsilon())); + Assert (i < densities.size() - 1, ExcInternalError()); + + return (densities[i+1]-densities[i])/delta_z; + } + + + + template + double ReferenceProfile::get_property (const Point &p, + const std::vector &property) const + { + const double z = this->get_geometry_model().depth(p); + + if (z >= this->get_geometry_model().maximal_depth()) + { + Assert (z <= this->get_geometry_model().maximal_depth() + delta_z, + ExcInternalError()); + return property.back(); + } + + if (z <= 0) + { + Assert (z >= -delta_z, ExcInternalError()); + return property.front(); + } + + const double floating_index = z/delta_z; + const unsigned int i = static_cast(floating_index); + + // If p is close to an existing value use that one. This prevents + // asking for values at i+1 while initializing i+1 (when p is at the + // depth of index i). + if (std::abs(floating_index-std::floor(floating_index+0.5)) < 1e-6) + return property[i]; + + Assert (i+1 < property.size(), ExcInternalError()); + + // now do the linear interpolation + const double d = floating_index - i; + Assert ((d>=0) && (d<=1), ExcInternalError()); + + return d*property[i+1] + (1.-d)*property[i]; + } + + + + + template + void + ReferenceProfile::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Adiabatic conditions model"); + { + prm.enter_subsection("Reference profile"); + { + Functions::ParsedFunction<1>::declare_parameters (prm, 1); + prm.declare_entry("Composition reference profile","initial composition", + Patterns::Selection("initial composition|function"), + "Select how the reference profile for composition " + "is computed. This profile is used to evaluate the " + "material model, when computing the pressure and " + "temperature profile."); + prm.declare_entry ("Number of points", "1000", + Patterns::Integer (5), + "The number of points we use to compute the adiabatic " + "profile. The higher the number of points, the more accurate " + "the downward integration from the adiabatic surface " + "temperature will be."); + prm.declare_entry ("Use surface condition function", "false", + Patterns::Bool(), + "Whether to use the 'Surface condition function' to determine surface " + "conditions, or the 'Adiabatic surface temperature' and 'Surface pressure' " + "parameters. If this is set to true the reference profile is updated " + "every timestep. The function expression of the function should be " + "independent of space, but can depend on time 't'. The function must " + "return two components, the first one being reference surface pressure, " + "the second one being reference surface temperature."); + + prm.enter_subsection("Surface condition function"); + { + Functions::ParsedFunction<1>::declare_parameters (prm, 2); + } + prm.leave_subsection(); + + + Utilities::AsciiDataBase::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/tests/adiabatic-conditions/ascii-data/test/", + ""); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + ReferenceProfile::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Adiabatic conditions model"); + { + prm.enter_subsection("Reference profile"); + { + const std::string composition_profile = prm.get("Composition reference profile"); + + if (composition_profile == "initial composition") + reference_composition = initial_composition; + else if (composition_profile == "function") + reference_composition = reference_function; + else + AssertThrow(false, ExcNotImplemented()); + + if ((this->n_compositional_fields() > 0) && (reference_composition == reference_function)) + { + composition_function + = std::make_unique>(this->n_compositional_fields()); + try + { + composition_function->parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Adiabatic conditions model.compute profile'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + } + + n_points = prm.get_integer ("Number of points"); + use_surface_condition_function = prm.get_bool("Use surface condition function"); + if (use_surface_condition_function) + { + prm.enter_subsection("Surface condition function"); + try + { + surface_condition_function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Adiabatic conditions model.Initial profile.Surface condition function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + + prm.leave_subsection(); + } + + reference_profile.parse_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace AdiabaticConditions + { + ASPECT_REGISTER_ADIABATIC_CONDITIONS_MODEL(ReferenceProfile, + "reference profile", + "A model in which the adiabatic profile is " + "calculated by solving the hydrostatic equations for " + "pressure and temperature in depth. " + "The gravity is assumed to be in depth direction " + "and the composition is either given by the initial " + "composition at reference points or computed " + "as a reference depth-function. " + "All material parameters are computed by the " + "material model plugin. The surface conditions are " + "either constant or changing over time as prescribed " + "by a user-provided function.") + } +} diff --git a/cookbooks/tomography_based_plate_motions/plugins/reference_profile.h.bak b/cookbooks/tomography_based_plate_motions/plugins/reference_profile.h.bak new file mode 100644 index 00000000000..9208fe70c82 --- /dev/null +++ b/cookbooks/tomography_based_plate_motions/plugins/reference_profile.h.bak @@ -0,0 +1,214 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_cookbooks_tomography_based_plate_motions_reference_profile_h +#define _aspect_cookbooks_tomography_based_plate_motions_reference_profile_h + + +#include + +#include + +namespace aspect +{ + namespace AdiabaticConditions + { + using namespace dealii; + + /** + * A model similar to the compute profile model + * in which the adiabatic profile is + * calculated by solving the hydrostatic equations for + * pressure and temperature in depth. + * The difference is that we use densities from + * an input reference profile to be consistent + * with the reference seismic profile against which + * the tomography model is generated. + * In regions where we do not use tomography model, + * the reference densities come from the material model. + * The gravity is assumed to be in depth direction + * and the composition is either given by the initial + * composition at reference points or computed + * as a reference depth-function. + * All material parameters are computed by the + * material model plugin. The surface conditions are + * either constant or changing over time as prescribed + * by an user-provided function. + */ + template + class ReferenceProfile : public Interface + { + public: + /** + * Constructor. Initialize variables. + */ + ReferenceProfile (); + + /** + * Initialization function. Because this function is called after + * initializing the SimulatorAccess, all of the necessary information + * is available to calculate the adiabatic profile. It computes the + * adiabatic conditions along a vertical transect of the geometry + * based on the given material model and other quantities. + */ + void initialize () override; + + /** + * Update function. By default does nothing, but if a time-dependent + * surface condition function is used, this will reinitialize the + * adiabatic profile with the current conditions. + */ + void update () override; + + /** + * Some plugins need to know whether the adiabatic conditions are + * already calculated. This is for example the case for the simple + * compressible material model, which uses the adiabatic temperature + * as reference temperature to calculate the density. For the + * calculation of the adiabatic conditions this functionality is + * simply switched off, because we are always on the reference + * profile. This way the plugin behaves differently at initialization + * time of the adiabatic conditions and during the main model run. + */ + bool is_initialized() const override; + + /** + * Return the adiabatic temperature at a given point of the domain. + */ + double temperature (const Point &p) const override; + + /** + * Return the adiabatic pressure at a given point of the domain. + */ + double pressure (const Point &p) const override; + + /** + * Return the reference density at a given point of the domain. + */ + double density (const Point &p) const override; + + /** + * Return the derivative of the density with respect to depth + * at the given point @p p. + */ + double density_derivative (const Point &p) const override; + + /** + * Declare the parameters for the input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * Whether the adiabatic conditions are already calculated. This is + * important for plugins that are used by the adiabatic conditions but + * also depend on the adiabatic conditions. This way they can behave + * differently in initialization and model run. + */ + bool initialized; + + /** + * Number of points at which we compute the adiabatic values. + */ + unsigned int n_points; + + /** + * Vectors of values of temperatures, pressures and densities on a transect into + * depth at which we have computed them. The public member functions + * of this class interpolate linearly between these points. + */ + std::vector temperatures; + std::vector pressures; + std::vector densities; + + /** + * Interval spacing between each two data points in the tables above + * with regard to the depth coordinate. + */ + double delta_z; + + /** + * An enum describing the different options to compute the reference + * profile for composition. + */ + enum CompositionProfile + { + initial_composition, + reference_function + }; + + /** + * Selected option to compute the reference profile for composition. + */ + CompositionProfile reference_composition; + + /** + * Function object that computes the reference composition profile + * if the reference_composition variable is set to function. + */ + std::unique_ptr> composition_function; + + /** + * Whether to use the surface_conditions_function to determine surface + * conditions, or the adiabatic_surface_temperature and surface_pressure + * parameters. If this is set to true the reference profile is updated + * every timestep. + */ + bool use_surface_condition_function; + + /** + * ParsedFunction: If provided in the inpute file it prescribes + * (surface pressure(t), surface temperature(t)). + */ + Functions::ParsedFunction<1> surface_condition_function; + + /** + * Internal helper function. Returns the reference property at a + * given point of the domain. + */ + double get_property (const Point &p, + const std::vector &property) const; + + + /** + * A reference profile for density and seismic velocities. + */ + Utilities::AsciiDataProfile reference_profile; + + /** + * The column index of the density column in the reference profile file. + */ + unsigned int density_index; + }; + } +} + + +#endif diff --git a/cookbooks/tomography_based_plate_motions/plugins/tomography_based_plate_motions.cc b/cookbooks/tomography_based_plate_motions/plugins/tomography_based_plate_motions.cc index d3c61e9a379..8a9fde17252 100644 --- a/cookbooks/tomography_based_plate_motions/plugins/tomography_based_plate_motions.cc +++ b/cookbooks/tomography_based_plate_motions/plugins/tomography_based_plate_motions.cc @@ -1635,7 +1635,7 @@ namespace aspect // reduce grain size. if (out.template get_additional_output>() == nullptr) { - const unsigned int n_points = out.viscosities.size(); + const unsigned int n_points = out.n_evaluation_points(); out.additional_outputs.push_back( std::make_unique> (n_points)); } @@ -1643,7 +1643,7 @@ namespace aspect // We need the prescribed field outputs to interpolate the grain size onto a compositional field. if (out.template get_additional_output>() == nullptr) { - const unsigned int n_points = out.viscosities.size(); + const unsigned int n_points = out.n_evaluation_points(); out.additional_outputs.push_back( std::make_unique> (n_points, this->n_compositional_fields())); } @@ -1652,7 +1652,7 @@ namespace aspect if (use_table_properties && out.template get_additional_output>() == nullptr) { - const unsigned int n_points = out.viscosities.size(); + const unsigned int n_points = out.n_evaluation_points(); out.additional_outputs.push_back( std::make_unique> (n_points)); } @@ -1660,7 +1660,7 @@ namespace aspect if (this->get_parameters().temperature_method == Parameters::AdvectionFieldMethod::prescribed_field && out.template get_additional_output>() == nullptr) { - const unsigned int n_points = out.viscosities.size(); + const unsigned int n_points = out.n_evaluation_points(); out.additional_outputs.push_back( std::make_unique> (n_points)); } @@ -1668,14 +1668,14 @@ namespace aspect // We need additional field outputs for the unscaled viscosity if (out.template get_additional_output>() == nullptr) { - const unsigned int n_points = out.viscosities.size(); + const unsigned int n_points = out.n_evaluation_points(); out.additional_outputs.push_back( std::make_unique> (n_points)); } if (out.template get_additional_output>() == nullptr) { - const unsigned int n_points = out.viscosities.size(); + const unsigned int n_points = out.n_evaluation_points(); out.additional_outputs.push_back( std::make_unique> (n_points)); } diff --git a/cookbooks/tomography_based_plate_motions/plugins/tomography_based_plate_motions.cc.bak b/cookbooks/tomography_based_plate_motions/plugins/tomography_based_plate_motions.cc.bak new file mode 100644 index 00000000000..d3c61e9a379 --- /dev/null +++ b/cookbooks/tomography_based_plate_motions/plugins/tomography_based_plate_motions.cc.bak @@ -0,0 +1,1726 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include "tomography_based_plate_motions.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +using namespace dealii; + +namespace aspect +{ + namespace MaterialModel + { + namespace + { + /** + * Additional output fields for the viscosity prior to scaling to be added to + * the MaterialModel::MaterialModelOutputs structure and filled in the + * MaterialModel::Interface::evaluate() function. + */ + template + class UnscaledViscosityAdditionalOutputs : public NamedAdditionalMaterialOutputs + { + public: + UnscaledViscosityAdditionalOutputs(const unsigned int n_points) + : NamedAdditionalMaterialOutputs(std::vector(1, "unscaled_viscosity"), + n_points) + {} + }; + + /** + * Additional output fields for the the material type, describing if we are in the + * crust/lithosphere/asthenosphere/lower mantle. + */ + template + class MaterialTypeAdditionalOutputs : public NamedAdditionalMaterialOutputs + { + public: + MaterialTypeAdditionalOutputs(const unsigned int n_points) + : NamedAdditionalMaterialOutputs(std::vector(1, "material_type"), + n_points) + {} + }; + } + } + + + namespace internal + { + namespace + { + template + class FunctorDepthAverageUnscaledViscosity: public internal::FunctorBase + { + public: + FunctorDepthAverageUnscaledViscosity() + {} + + bool need_material_properties() const override + { + return true; + } + + void + create_additional_material_model_outputs (const unsigned int n_points, + MaterialModel::MaterialModelOutputs &outputs) const override + { + if (outputs.template get_additional_output>() == nullptr) + { + outputs.additional_outputs.push_back( + std::make_unique> (n_points)); + } + } + + void operator()(const MaterialModel::MaterialModelInputs &, + const MaterialModel::MaterialModelOutputs &out, + const FEValues &, + const LinearAlgebra::BlockVector &, + std::vector &output) override + { + const MaterialModel::UnscaledViscosityAdditionalOutputs *unscaled_viscosity_outputs + = out.template get_additional_output>(); + + Assert(unscaled_viscosity_outputs != nullptr,ExcInternalError()); + + for (unsigned int q=0; qoutput_values[0][q]; + } + }; + } + } + + namespace MaterialModel + { + template + void + TomographyBasedPlateMotions::initialize() + { + // Get reference viscosity profile from the ascii data + if (use_depth_dependent_viscosity) + reference_viscosity_coordinates = reference_viscosity_profile->get_interpolation_point_coordinates(); + + // Get column index for density scaling + if (use_depth_dependent_rho_vs) + { + rho_vs_depth_profile.initialize(this->get_mpi_communicator()); + density_scaling_index = rho_vs_depth_profile.get_column_index_from_name("density_scaling"); + } + + if (use_depth_dependent_thermal_expansivity) + { + thermal_expansivity_profile.initialize(this->get_mpi_communicator()); + thermal_expansivity_column_index = thermal_expansivity_profile.get_column_index_from_name("thermal_expansivity"); + } + + if (use_depth_dependent_dT_vs) + { + dT_vs_depth_profile.initialize(this->get_mpi_communicator()); + temperature_scaling_index = dT_vs_depth_profile.get_column_index_from_name("temperature_scaling"); + } + + // Get column for crustal depths + std::set surface_boundary_set; + surface_boundary_set.insert(this->get_geometry_model().translate_symbolic_boundary_name_to_id("top")); + crustal_boundary_depth.initialize(surface_boundary_set, 1); + + // The update() function updates the profile that stores the laterally averaged viscosity. + // This is needed to compute the viscosity in the material model (since the viscosities are rescaled + // so that the lateral average matches the reference profile). Since the viscosity depends on both + // temperature and velocity, we want to update the lateral average profile after each temperature + // and Stokes solve. + this->get_signals().post_stokes_solver.connect([&](const SimulatorAccess &, + const unsigned int , + const unsigned int , + const SolverControl &, + const SolverControl &) + { + this->update(); + }); + + this->get_signals().post_advection_solver.connect([&](const SimulatorAccess &, + const unsigned int , + const unsigned int , + const SolverControl &) + { + this->update(); + }); + + n_material_data = material_file_names.size(); + for (unsigned i = 0; i < n_material_data; i++) + { + if (material_file_format == perplex) + material_lookup.emplace_back(std::make_shared + (data_directory+material_file_names[i], + /*use_bilinear_interpolation*/ true, + this->get_mpi_communicator())); + else if (material_file_format == hefesto) + material_lookup.emplace_back(std::make_shared + (data_directory+material_file_names[i], + data_directory+derivatives_file_names[i], + /*use_bilinear_interpolation*/ true, + this->get_mpi_communicator())); + else + AssertThrow (false, ExcNotImplemented()); + } + } + + + + template + void + TomographyBasedPlateMotions::update() + { + if (use_depth_dependent_viscosity) + { + std::vector>> lateral_averaging_properties; + lateral_averaging_properties.emplace_back(std::make_unique>()); + + std::vector> averages = + this->get_lateral_averaging().compute_lateral_averages(reference_viscosity_coordinates, + lateral_averaging_properties); + + average_viscosity_profile = std::move(averages[0]); + + for (const auto &lateral_viscosity_average: average_viscosity_profile) + AssertThrow(numbers::is_finite(lateral_viscosity_average), + ExcMessage("In computing depth averages, there is at" + " least one depth band that does not have" + " any quadrature points in it." + " Consider reducing number of depth layers" + " for averaging.")); + } + } + + + + template + std::pair + TomographyBasedPlateMotions::get_reference_viscosity (const double depth) const + { + // Make maximal depth slightly larger to ensure depth < maximal_depth + const double maximal_depth = this->get_geometry_model().maximal_depth() * + (1.0+std::numeric_limits::epsilon()); + (void) maximal_depth; + + Assert(depth < maximal_depth, ExcInternalError()); + Assert(depth > -maximal_depth*std::numeric_limits::epsilon(), ExcInternalError()); + + unsigned int depth_index; + if (depth < reference_viscosity_coordinates.front()) + { + depth_index = 0; + } + else if (depth > reference_viscosity_coordinates.back()) + { + depth_index = reference_viscosity_coordinates.size() - 1; + } + else + { + depth_index = std::distance(reference_viscosity_coordinates.begin(), + std::lower_bound(reference_viscosity_coordinates.begin(), + reference_viscosity_coordinates.end(), + depth)); + } + if (depth_index > 0) + --depth_index; + + // When evaluating reference viscosity, evaluate at the next lower depth that is stored + // in the reference profile instead of the actual depth. This makes the profile piecewise + // constant. This will be specific to the viscosity profile used (and ignore the entry with + // the largest depth in the profile). + double reference_viscosity = reference_viscosity_profile->compute_viscosity(reference_viscosity_coordinates.at(depth_index)); + + // By default, ashtenosphere_viscosity is set to the second layer in the reference profile. + if (depth_index == 1) + reference_viscosity = asthenosphere_viscosity; + + return std::make_pair (reference_viscosity, depth_index); + } + + + + template + double + TomographyBasedPlateMotions::get_depth_of_base_of_uppermost_mantle () const + { + return depth_to_base_of_uppermost_mantle; + } + + + + template + double + TomographyBasedPlateMotions::compute_viscosity_scaling (const double depth) const + { + Assert(average_viscosity_profile.size() != 0, + ExcMessage("The average viscosity profile has not yet been computed. " + "Unable to scale viscosities")); + + const std::pair reference_viscosity_and_depth_index = get_reference_viscosity (depth); + + const double average_viscosity = std::pow(10, average_viscosity_profile[reference_viscosity_and_depth_index.second]); + + return reference_viscosity_and_depth_index.first / average_viscosity; + } + + + + template + void + TomographyBasedPlateMotions::compute_equilibrium_grain_size(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const + { + PrescribedFieldOutputs *prescribed_field_out = out.template get_additional_output>(); + DislocationViscosityOutputs *disl_viscosities_out = out.template get_additional_output>(); + + UnscaledViscosityAdditionalOutputs *unscaled_viscosity_out = + out.template get_additional_output>(); + + const InitialTemperature::AdiabaticBoundary &adiabatic_boundary = + initial_temperature_manager->template get_matching_initial_temperature_model>(); + + const unsigned int surface_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("outer"); + + const unsigned int grain_size_index = this->introspection().compositional_index_for_name("grain_size"); + + const unsigned int craton_index = (use_cratons) + ? + this->introspection().compositional_index_for_name("continents") + : + numbers::invalid_unsigned_int; + + unsigned int ridge_index = numbers::invalid_unsigned_int; + unsigned int trench_index = numbers::invalid_unsigned_int; + unsigned int fault_index = numbers::invalid_unsigned_int; + + if (use_faults) + { + if (use_varying_fault_viscosity) + { + ridge_index = this->introspection().compositional_index_for_name("ridges"); + trench_index = this->introspection().compositional_index_for_name("trenches"); + } + else + fault_index = this->introspection().compositional_index_for_name("faults"); + } + + for (unsigned int i=0; iget_geometry_model().depth(in.position[i]); + + // Use the adiabatic pressure instead of the real one, because of oscillations + const double pressure = (this->get_adiabatic_conditions().is_initialized()) + ? + this->get_adiabatic_conditions().pressure(in.position[i]) + : + in.pressure[i]; + + Assert(pressure >= 0.0, + ExcMessage("Pressure has to be non-negative for the viscosity computation. Instead it is: " + + std::to_string(pressure))); + + double lithosphere_thickness = 100.e3; + // Get variable lithosphere using an adiabatic boundary ascii file + // Only use ascii data boundary file if not using a constant thickness for lithosphere + if (this->get_adiabatic_conditions().is_initialized() && !use_constant_lithosphere_thickness) + lithosphere_thickness = adiabatic_boundary.get_data_component(surface_boundary_id, in.position[i], 0); + + const unsigned int phase_index = get_phase_index(in.position[i], in.temperature[i], pressure); + + // Computed according to equation (7) in Dannberg et al., 2016, using the paleowattmeter grain size. + // Austin and Evans (2007): Paleowattmeters: A scaling relation for dynamically recrystallized grain size. Geology 35, 343-346. + const double prefactor = geometric_constant[phase_index] * grain_boundary_energy[phase_index] * grain_growth_rate_constant[phase_index] + / (boundary_area_change_work_fraction[phase_index] * grain_growth_exponent[phase_index]); + const double exponential = std::exp(- (grain_growth_activation_energy[phase_index] + pressure * grain_growth_activation_volume[phase_index]) + / (constants::gas_constant * in.temperature[i])); + + // get the dislocation viscosity to compute the dislocation strain rate + // If we do not have the strain rate yet, set it to a low value. + // TODO: make minimum strain rate an input parameter + const SymmetricTensor<2,dim> shear_strain_rate = in.strain_rate[i] - 1./dim * trace(in.strain_rate[i]) * unit_symmetric_tensor(); + const double second_strain_rate_invariant = std::sqrt(std::abs(second_invariant(shear_strain_rate))); + + // TODO: if we update the interface of the diffusion_viscosity and dislocation_viscosity functions, + // we don't need this vector anymore + std::vector composition (in.composition[i]); + double grain_size = in.composition[i][grain_size_index]; + grain_size = std::max(min_grain_size, grain_size); + + // Only consider dislocation creep and equilibrium grain size if we have a sufficient strain rate + if (std::abs(second_strain_rate_invariant > 1e-30)) + { + unsigned int j = 0; + double old_grain_size = 0.0; + + // because the diffusion viscosity depends on the grain size itself, and we need it to compute the dislocation strain rate, + // we have to iterate in the computation of the equilibrium grain size + while ((std::abs((grain_size-old_grain_size) / grain_size) > dislocation_viscosity_iteration_threshold) + && (j < dislocation_viscosity_iteration_number)) + { + composition[grain_size_index] = std::max(min_grain_size, grain_size); + const double diff_viscosity = diffusion_viscosity(in.temperature[i], pressure, composition, in.strain_rate[i], in.position[i]); + const double disl_viscosity = dislocation_viscosity(in.temperature[i], pressure, composition, in.strain_rate[i], in.position[i], diff_viscosity); + + if (disl_viscosities_out != nullptr) + { + disl_viscosities_out->diffusion_viscosities[i] = diff_viscosity; + disl_viscosities_out->dislocation_viscosities[i] = std::min(std::max(min_eta,disl_viscosity),1e30); + } + + out.viscosities[i] = diff_viscosity * disl_viscosity / (disl_viscosity + diff_viscosity); + + Assert(out.viscosities[i] > 0.0, + ExcMessage("Negative viscosity is not allowed. Current viscosity is: " + std::to_string(out.viscosities[i]))); + + // This follows from Equation (S25 - S30) + const double dislocation_strain_rate_invariant = second_strain_rate_invariant + * out.viscosities[i] / disl_viscosity; + const double stress_term = 4.0 * out.viscosities[i] * second_strain_rate_invariant * dislocation_strain_rate_invariant; + + old_grain_size = grain_size; + + if (equilibrate_grain_size) + grain_size = 0.9 * old_grain_size + 0.1 * std::pow(prefactor/stress_term * exponential,1./(1+grain_growth_exponent[phase_index])); + + ++j; + } + } + else + { + out.viscosities[i] = diffusion_viscosity(in.temperature[i], pressure, composition, in.strain_rate[i], in.position[i]); + + if (disl_viscosities_out != nullptr) + { + disl_viscosities_out->diffusion_viscosities[i] = out.viscosities[i]; + disl_viscosities_out->dislocation_viscosities[i] = 1e30; + } + } + + if (unscaled_viscosity_out != nullptr) + unscaled_viscosity_out->output_values[0][i] = std::log10(out.viscosities[i]); + + if (use_depth_dependent_viscosity) + { + const double viscosity_scaling_below_this_depth = 60e3; + + // Scale viscosity so that laterally averaged viscosity == reference viscosity profile + // Only scale if average viscosity is already available and we are below a specified depth. + if (average_viscosity_profile.size() != 0 && depth > viscosity_scaling_below_this_depth) + out.viscosities[i] *= compute_viscosity_scaling(this->get_geometry_model().depth(in.position[i])); + } + + // We assume a constant lithospheric viscosity if using constant thickness lithosphere + // based on Tutu et al., (2018). + if (use_constant_lithosphere_thickness && depth <= lithosphere_thickness) + out.viscosities[i] = 1e24; + + // Ensure we respect viscosity bounds + out.viscosities[i] = std::min(std::max(min_eta, out.viscosities[i]),max_eta); + + // This represents the viscosity with respect to which we want to define cratons/faults. + const double background_viscosity_log = std::log10(out.viscosities[i]); + + // If using faults, use the composition value to compute the viscosity instead + // We extend the faults to depths 40 km more than the lithospheric depths because otherwise + // faults do not extend through the lithosphere in our high-resolution models. + if (use_faults) + { + if (use_varying_fault_viscosity) + { + if (in.composition[i][ridge_index] > 0. && depth <= lithosphere_thickness + 40e3) + out.viscosities[i] = std::pow(10, + std::log10(ridge_viscosity) * in.composition[i][ridge_index] + + background_viscosity_log * (1. - in.composition[i][ridge_index])); + if (in.composition[i][trench_index] > 0. && depth <= lithosphere_thickness + 40e3) + out.viscosities[i] = std::pow(10, + std::log10(trench_viscosity) * in.composition[i][trench_index] + + background_viscosity_log * (1. - in.composition[i][trench_index])); + } + + else + { + if (in.composition[i][fault_index] > 0. && depth <= lithosphere_thickness + 40e3) + out.viscosities[i] = std::pow(10, + std::log10(fault_viscosity) * in.composition[i][fault_index] + + background_viscosity_log * (1. - in.composition[i][fault_index])); + } + } + + // If using cratons, use the composition value to compute the viscosity instead. The cratons in the + // compositional field extend until 300 km (Becker 2006, Miller and Becker, 2012), we assume that the + // cratonic keels are stiffer than the surrounding lithosphere + if (use_cratons && in.composition[i][craton_index] > 0. && depth <= lithosphere_thickness) + { + out.viscosities[i] = std::pow(10, + std::log10(craton_viscosity) * in.composition[i][craton_index] + + background_viscosity_log * (1. - in.composition[i][craton_index])); + } + + Assert(out.viscosities[i] > 0, + ExcMessage("Viscosity has to be positive. Instead it is: " + std::to_string(out.viscosities[i]))); + + // Fill the prescribed outputs for grain size and assign faults to a prescribed field for diffusion. + if (prescribed_field_out != nullptr) + for (unsigned int c=0; cprescribed_field_outputs[i][c] = std::max(min_grain_size, grain_size); + else if (c == fault_index) + prescribed_field_out->prescribed_field_outputs[i][c] = in.composition[i][fault_index]; + else + prescribed_field_out->prescribed_field_outputs[i][c] = 0.; + } + + if (this->get_nonlinear_iteration() == 0 && use_depth_dependent_viscosity) + out.viscosities[i] = get_reference_viscosity(depth).first; + } + } + + + + template + double + TomographyBasedPlateMotions:: + phase_function (const Point &position, + const double temperature, + const double pressure, + const unsigned int phase) const + { + Assert(phase < transition_depths.size(), + ExcMessage("Error: Phase index is too large. This phase index does not exist!")); + + // if we already have the adiabatic conditions, we can use them + if (this->get_adiabatic_conditions().is_initialized()) + { + // first, get the pressure at which the phase transition occurs normally + const Point transition_point = this->get_geometry_model().representative_point(transition_depths[phase]); + const double transition_pressure = this->get_adiabatic_conditions().pressure(transition_point); + + // then calculate the deviation from the transition point (both in temperature + // and in pressure) + const double pressure_deviation = pressure - transition_pressure + - transition_slopes[phase] * (temperature - transition_temperatures[phase]); + + // last, calculate the percentage of material that has undergone the transition + return (pressure_deviation > 0) ? 1 : 0; + } + + // if we do not have the adiabatic conditions, we have to use the depth instead + // this is less precise, because we do not have the exact pressure gradient, instead we use pressure/depth + // (this is for calculating e.g. the density in the adiabatic profile) + else + { + const double depth = this->get_geometry_model().depth(position); + const double depth_deviation = (pressure > 0 + ? + depth - transition_depths[phase] + - transition_slopes[phase] * (depth / pressure) * (temperature - transition_temperatures[phase]) + : + depth - transition_depths[phase] + - transition_slopes[phase] / (this->get_gravity_model().gravity_vector(position).norm() * reference_rho) + * (temperature - transition_temperatures[phase])); + + return (depth_deviation > 0) ? 1 : 0; + } + } + + + + template + unsigned int + TomographyBasedPlateMotions:: + get_phase_index (const Point &position, + const double temperature, + const double pressure) const + { + Assert(grain_growth_activation_energy.size()>0, + ExcMessage("Error: No grain evolution parameters are given!")); + + unsigned int phase_index = 0; + if (transition_depths.size()>0) + if (phase_function(position, temperature, pressure, transition_depths.size()-1) == 1) + phase_index = transition_depths.size(); + + for (unsigned int j=1; j + double + TomographyBasedPlateMotions:: + diffusion_viscosity (const double temperature, + const double pressure, + const std::vector &composition, + const SymmetricTensor<2,dim> &strain_rate, + const Point &position) const + { + const SymmetricTensor<2,dim> shear_strain_rate = strain_rate - 1./dim * trace(strain_rate) * unit_symmetric_tensor(); + const double second_strain_rate_invariant = std::sqrt(std::abs(second_invariant(shear_strain_rate))); + + const double grain_size = composition[this->introspection().compositional_index_for_name("grain_size")]; + + // Currently this will never be called without adiabatic_conditions initialized, but just in case + const double adiabatic_pressure = this->get_adiabatic_conditions().is_initialized() + ? + this->get_adiabatic_conditions().pressure(position) + : + pressure; + + // find out in which phase we are + const unsigned int phase_index = get_phase_index(position, temperature, adiabatic_pressure); + + Assert(temperature > 0.0, + ExcMessage("Temperature has to be positive for diffusion creep. Instead it is: " + std::to_string(temperature))); + Assert(pressure >= 0.0, + ExcMessage("Adiabatic pressure has to be non-negative for diffusion creep. Instead it is: " + std::to_string(adiabatic_pressure))); + + double energy_term = std::exp((diffusion_activation_energy[phase_index] + diffusion_activation_volume[phase_index] * adiabatic_pressure) + / (diffusion_creep_exponent[phase_index] * constants::gas_constant * temperature)); + + Assert(energy_term > 0.0, + ExcMessage("Energy term has to be positive for diffusion creep. Instead it is: " + std::to_string(energy_term))); + + // If the adiabatic profile is already calculated we can use it to limit + // variations in viscosity due to temperature. + if (this->get_adiabatic_conditions().is_initialized()) + { + const double adiabatic_temperature = this->get_adiabatic_conditions().temperature(position); + Assert(adiabatic_temperature > 0.0, + ExcMessage("Adiabatic temperature has to be positive for diffusion creep. Instead it is: " + std::to_string(adiabatic_temperature))); + + const double adiabatic_energy_term + = std::exp((diffusion_activation_energy[phase_index] + diffusion_activation_volume[phase_index] * adiabatic_pressure) + / (diffusion_creep_exponent[phase_index] * constants::gas_constant * adiabatic_temperature)); + + Assert(adiabatic_energy_term > 0.0, + ExcMessage("Adiabatic energy term has to be positive for diffusion creep. Instead it is: " + std::to_string(adiabatic_energy_term))); + + const double temperature_dependence = energy_term / adiabatic_energy_term; + if (temperature_dependence > max_temperature_dependence_of_eta) + energy_term = adiabatic_energy_term * max_temperature_dependence_of_eta; + if (temperature_dependence < 1.0 / max_temperature_dependence_of_eta) + energy_term = adiabatic_energy_term / max_temperature_dependence_of_eta; + } + + const double strain_rate_dependence = (1.0 - diffusion_creep_exponent[phase_index]) / diffusion_creep_exponent[phase_index]; + + const double diffusion_viscosity = std::pow(diffusion_creep_prefactor[phase_index],-1.0/diffusion_creep_exponent[phase_index]) + * std::pow(second_strain_rate_invariant,strain_rate_dependence) + * std::pow(grain_size, diffusion_creep_grain_size_exponent[phase_index]/diffusion_creep_exponent[phase_index]) + * energy_term; + + Assert(diffusion_viscosity > 0.0, + ExcMessage("Diffusion viscosity has to be positive. Instead it is: " + std::to_string(diffusion_viscosity))); + + return diffusion_viscosity; + } + + + + template + double + TomographyBasedPlateMotions:: + dislocation_viscosity (const double temperature, + const double pressure, + const std::vector &composition, + const SymmetricTensor<2,dim> &strain_rate, + const Point &position, + const double viscosity_guess) const + { + const double diff_viscosity = diffusion_viscosity(temperature,pressure,composition,strain_rate,position); + + // If we do not have the strain rate yet, set it to a low value. + // TODO: make minimum strain rate an input parameter + const SymmetricTensor<2,dim> shear_strain_rate = strain_rate - 1./dim * trace(strain_rate) * unit_symmetric_tensor(); + const double second_strain_rate_invariant = std::max(std::sqrt(std::abs(second_invariant(shear_strain_rate))),1e-30); + + // Start the iteration with the full strain rate + double dis_viscosity = viscosity_guess; + if (viscosity_guess == 0) + dis_viscosity = dislocation_viscosity_fixed_strain_rate(temperature,pressure,second_strain_rate_invariant,position); + + double dis_viscosity_old = 0; + unsigned int i = 0; + while ((std::abs((dis_viscosity-dis_viscosity_old) / dis_viscosity) > dislocation_viscosity_iteration_threshold) + && (i < dislocation_viscosity_iteration_number)) + { + const double dislocation_strain_rate = diff_viscosity / (diff_viscosity + dis_viscosity) * second_strain_rate_invariant; + dis_viscosity_old = dis_viscosity; + dis_viscosity = dislocation_viscosity_fixed_strain_rate(temperature, + pressure, + dislocation_strain_rate, + position); + + Assert(dis_viscosity > 0.0, + ExcMessage("Encountered negative dislocation viscosity in iteration " + std::to_string(i) + + ". Dislocation viscosity is: " + std::to_string(dis_viscosity))); + ++i; + } + + Assert(i + double + TomographyBasedPlateMotions:: + dislocation_viscosity_fixed_strain_rate (const double temperature, + const double pressure, + const double second_strain_rate_invariant, + const Point &position) const + { + Assert(temperature > 0.0, + ExcMessage("Temperature has to be positive for dislocation creep. Instead it is: " + std::to_string(temperature))); + Assert(pressure >= 0.0, + ExcMessage("Pressure has to be non-negative for dislocation creep. Instead it is: " + std::to_string(pressure))); + + // find out in which phase we are + const unsigned int phase_index = get_phase_index(position, temperature, pressure); + + double energy_term = std::exp((dislocation_activation_energy[phase_index] + dislocation_activation_volume[phase_index] * pressure) + / (dislocation_creep_exponent[phase_index] * constants::gas_constant * temperature)); + + Assert(energy_term > 0.0, + ExcMessage("Energy term has to be positive for dislocation creep. Instead it is: " + std::to_string(energy_term))); + + // If we are past the initialization of the adiabatic profile, use it to + // limit viscosity variations due to temperature. + if (this->get_adiabatic_conditions().is_initialized()) + { + const double adiabatic_energy_term + = exp((dislocation_activation_energy[phase_index] + dislocation_activation_volume[phase_index] * pressure) + / (dislocation_creep_exponent[phase_index] * constants::gas_constant * this->get_adiabatic_conditions().temperature(position))); + + Assert(adiabatic_energy_term > 0.0, + ExcMessage("Adiabatic energy term has to be positive for dislocation creep. Instead it is: " + std::to_string(adiabatic_energy_term))); + + const double temperature_dependence = energy_term / adiabatic_energy_term; + if (temperature_dependence > max_temperature_dependence_of_eta) + energy_term = adiabatic_energy_term * max_temperature_dependence_of_eta; + if (temperature_dependence < 1.0 / max_temperature_dependence_of_eta) + energy_term = adiabatic_energy_term / max_temperature_dependence_of_eta; + } + + const double strain_rate_dependence = (1.0 - dislocation_creep_exponent[phase_index]) / dislocation_creep_exponent[phase_index]; + + const double dislocation_viscosity = std::pow(dislocation_creep_prefactor[phase_index],-1.0/dislocation_creep_exponent[phase_index]) + * std::pow(second_strain_rate_invariant,strain_rate_dependence) + * energy_term; + + Assert(dislocation_viscosity > 0.0, + ExcMessage("Dislocation viscosity has to be positive. Instead it is: " + std::to_string(dislocation_viscosity))); + + return dislocation_viscosity; + } + + + + template + double + TomographyBasedPlateMotions:: + seismic_Vp (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &/*position*/) const + { + AssertThrow ((reference_compressibility != 0.0) || use_table_properties, + ExcMessage("Currently only compressible models are supported.")); + + if (n_material_data == 1) + return material_lookup[0]->seismic_Vp(temperature,pressure); + else + { + double vp = 0.0; + for (unsigned i = 0; i < n_material_data; i++) + vp += compositional_fields[i] * material_lookup[i]->seismic_Vp(temperature,pressure); + return vp; + } + } + + + + template + double + TomographyBasedPlateMotions:: + seismic_Vs (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &/*position*/) const + { + AssertThrow ((reference_compressibility != 0.0) || use_table_properties, + ExcMessage("Currently only compressible models are supported.")); + + if (n_material_data == 1) + return material_lookup[0]->seismic_Vs(temperature,pressure); + else + { + double vs = 0.0; + for (unsigned i = 0; i < n_material_data; i++) + vs += compositional_fields[i] * material_lookup[i]->seismic_Vs(temperature,pressure); + return vs; + } + } + + + + template + double + TomographyBasedPlateMotions:: + density (const double temperature, + const double pressure, + const std::vector &compositional_fields, /*composition*/ + const Point &) const + { + double rho = 0.0; + if (n_material_data == 1) + { + return material_lookup[0]->density(temperature,pressure); + } + else + { + for (unsigned i = 0; i < n_material_data; i++) + rho += compositional_fields[i] * material_lookup[i]->density(temperature,pressure); + return rho; + } + } + + + + template + bool + TomographyBasedPlateMotions:: + is_compressible () const + { + return (reference_compressibility != 0) + || use_table_properties; + } + + + + template + double + TomographyBasedPlateMotions:: + compressibility (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const + { + double dRhodp = 0.0; + if (n_material_data == 1) + dRhodp = material_lookup[0]->dRhodp(temperature,pressure); + else + { + for (unsigned i = 0; i < n_material_data; i++) + dRhodp += compositional_fields[i] * material_lookup[i]->dRhodp(temperature,pressure); + } + const double rho = density(temperature,pressure,compositional_fields,position); + return (1/rho)*dRhodp; + } + + + + template + double + TomographyBasedPlateMotions:: + thermal_expansivity (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &) const + { + if (n_material_data == 1) + return material_lookup[0]->thermal_expansivity(temperature,pressure); + else + { + double alpha = 0.0; + for (unsigned i = 0; i < n_material_data; i++) + alpha += compositional_fields[i] * material_lookup[i]->thermal_expansivity(temperature,pressure); + return alpha; + } + } + + + + template + void + TomographyBasedPlateMotions:: + evaluate(const typename Interface::MaterialModelInputs &in, typename Interface::MaterialModelOutputs &out) const + { + // Determine some properties that are constant for all points + const unsigned int vs_anomaly_index = this->introspection().compositional_index_for_name("vs_anomaly"); + const unsigned int surface_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("outer"); + + const unsigned int craton_index = (use_cratons) + ? + this->introspection().compositional_index_for_name("continents") + : + numbers::invalid_unsigned_int; + + if (initial_temperature_manager == nullptr) + const_cast>&>(initial_temperature_manager) + = this->get_initial_temperature_manager_pointer(); + + const InitialTemperature::AdiabaticBoundary &adiabatic_boundary = + initial_temperature_manager->template get_matching_initial_temperature_model>(); + + // This function will fill the outputs for grain size, viscosity, and dislocation viscosity + if (in.requests_property(MaterialProperties::viscosity)) + compute_equilibrium_grain_size(in, out); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + // Use the adiabatic pressure instead of the real one, because of oscillations + const double pressure = (this->get_adiabatic_conditions().is_initialized()) + ? + this->get_adiabatic_conditions().pressure(in.position[i]) + : + in.pressure[i]; + + out.thermal_conductivities[i] = k_value; + out.specific_heat[i] = reference_specific_heat; + + for (unsigned int c=0; cget_geometry_model().depth(in.position[i]); + const double delta_log_vs = in.composition[i][vs_anomaly_index]; + + // For computing the adiabatic conditions, we want to use the temperature it hands + // over as input. Once the adiabatic conditions are computed, we want to use the + // temperature based on seismic tomography and the input temperature model. + double new_temperature = in.temperature[i]; + + // For the adiabatic conditions, assume a characteristic crustal and lithosphere thickness. + double crustal_thickness = 40000.; + double lithosphere_thickness = 100000.; + + if (this->get_adiabatic_conditions().is_initialized()) + { + // Get variable lithosphere and crustal depths using an adiabatic boundary ascii file + lithosphere_thickness = adiabatic_boundary.get_data_component(surface_boundary_id, in.position[i], 0); + crustal_thickness = crustal_boundary_depth.get_data_component(surface_boundary_id, in.position[i], 0); + + if (use_constant_lithosphere_thickness) + lithosphere_thickness = 100e3; + + // This variable stores the seismic tomography based temperatures + double mantle_temperature; + + // This does not work when it is called before the adiabatic conditions are initialized, because + // the AsciiDataBoundary plugin needs the time, which is not yet initialized at that point. + const double initial_temperature = initial_temperature_manager->initial_temperature(in.position[i]); + const double reference_temperature = this->get_adiabatic_conditions().temperature(in.position[i]); + + if (use_depth_dependent_dT_vs) + { + // We use the dlnvs/dT profile from Steinberger and Calderwood (2006). The values in profile are in units 1/K . + mantle_temperature = reference_temperature + + delta_log_vs * dT_vs_depth_profile.get_data_component(Point<1>(depth), temperature_scaling_index); + } + + else + { + // compute the temperature below the asthenosphere using the parameters given in the table by Becker (2006). + mantle_temperature = reference_temperature + delta_log_vs * -4.2 * 1785.; + } + + const double sigmoid_width = 2.e4; + const double sigmoid = 1.0 / (1.0 + std::exp( (depth_to_base_of_uppermost_mantle - depth)/sigmoid_width)); + + new_temperature = initial_temperature + (mantle_temperature - initial_temperature) * sigmoid; + } + + if (PrescribedTemperatureOutputs *prescribed_temperature_out = out.template get_additional_output>()) + prescribed_temperature_out->prescribed_temperature_outputs[i] = new_temperature; + + if (use_table_properties) + { + // fill seismic velocities outputs if they exist + if (SeismicAdditionalOutputs *seismic_out = out.template get_additional_output>()) + { + seismic_out->vp[i] = seismic_Vp(in.temperature[i], in.pressure[i], in.composition[i], in.position[i]); + seismic_out->vs[i] = seismic_Vs(in.temperature[i], in.pressure[i], in.composition[i], in.position[i]); + } + + out.densities[i] = density(new_temperature, pressure, in.composition[i], in.position[i]); + out.thermal_expansion_coefficients[i] = thermal_expansivity(new_temperature, pressure, in.composition[i], in.position[i]); + out.compressibilities[i] = compressibility(new_temperature, pressure, in.composition[i], in.position[i]); + } + else + { + // Temperature and density of the upper part of the mantle are computed separately, + // based on Tutu et al. (2018). + double deltaT = new_temperature - 293.; + + unsigned int material_type = 0; + + // Density computation + if (depth <= crustal_thickness) + { + out.thermal_expansion_coefficients[i] = 2.7e-5; + out.compressibilities[i] = 1./6.3e10; + out.densities[i] = 2.85e3 * (1. - out.thermal_expansion_coefficients[i] * deltaT + + pressure * out.compressibilities[i]); + material_type = 1; + } + else if (depth > crustal_thickness && depth <= lithosphere_thickness) + { + out.thermal_expansion_coefficients[i] = 3.e-5; + out.compressibilities[i] = 1./12.2e10; + + // Use adiabatic density increase when using constant lithosphere, Tutu et al., (2018) + if (use_constant_lithosphere_thickness) + deltaT = this->get_adiabatic_conditions().temperature(in.position[i]) - 293; + + out.densities[i] = 3.27e3 * (1. - out.thermal_expansion_coefficients[i] * deltaT + + pressure * out.compressibilities[i]); + material_type = 2; + + if (use_cratons) + { + // Density increase along adiabatic profile + const double craton_density = 3.27e3 * ( 1. - out.thermal_expansion_coefficients[i] * + (this->get_adiabatic_conditions().temperature(in.position[i]) - 293) + + pressure * out.compressibilities[i]); + + out.densities[i] = craton_density * in.composition[i][craton_index] + + out.densities[i] * (1. - in.composition[i][craton_index]); + } + } + else if (depth > lithosphere_thickness && depth <= depth_to_base_of_uppermost_mantle) + { + out.thermal_expansion_coefficients[i] = 3.e-5; + out.compressibilities[i] = 1./12.2e10; + out.densities[i] = 3.3e3 * (1. - out.thermal_expansion_coefficients[i] * deltaT + + pressure * out.compressibilities[i]); + material_type = 3; + } + else + { + // Densities below 300 km are computed using the scaling relationship from the velocity anomalies + double density_vs_scaling; + if (use_depth_dependent_rho_vs) + density_vs_scaling = rho_vs_depth_profile.get_data_component(Point<1>(depth), density_scaling_index); + else + // Values from Becker (2006), GJI + density_vs_scaling = 0.15; + + double density_anomaly = delta_log_vs * density_vs_scaling; + + if (!this->get_adiabatic_conditions().is_initialized()) + density_anomaly = 0; + + // We only want to use the reference densities in the part of the model that also + // uses seismic velocities to determine the densities. Otherwise, use the density + // computed by the material model. + const double reference_density = this->get_adiabatic_conditions().is_initialized() + ? + this->get_adiabatic_conditions().density(in.position[i]) + : + reference_rho; + + out.densities[i] = reference_density * (1. + density_anomaly); + + if (use_depth_dependent_thermal_expansivity) + out.thermal_expansion_coefficients[i] = thermal_expansivity_profile.get_data_component(Point<1>(depth), thermal_expansivity_column_index); + else + out.thermal_expansion_coefficients[i] = thermal_alpha; + + out.compressibilities[i] = reference_compressibility; + + material_type = 4; + } + + if (MaterialTypeAdditionalOutputs *material_type_out = out.template get_additional_output>()) + material_type_out->output_values[0][i] = material_type; + } + } + } + + + + template + void + TomographyBasedPlateMotions::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Tomography based plate motions model"); + { + prm.declare_entry ("Reference density", "3300", + Patterns::Double (0), + "The reference density $\\rho_0$. Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference temperature", "293", + Patterns::Double (0), + "The reference temperature $T_0$. Units: \\si{\\kelvin}."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Reference specific heat", "1250", + Patterns::Double (0), + "The value of the specific heat $cp$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Thermal expansion coefficient", "2e-5", + Patterns::Double (0), + "The value of the thermal expansion coefficient $\\alpha$. " + "Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Reference compressibility", "4e-12", + Patterns::Double (0), + "The value of the reference compressibility. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("Phase transition depths", "", + Patterns::List (Patterns::Double(0)), + "A list of depths where phase transitions occur. Values must " + "monotonically increase. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Phase transition temperatures", "", + Patterns::List (Patterns::Double(0)), + "A list of temperatures where phase transitions occur. Higher or lower " + "temperatures lead to phase transition occurring in smaller or greater " + "depths than given in Phase transition depths, depending on the " + "Clapeyron slope given in Phase transition Clapeyron slopes. " + "List must have the same number of entries as Phase transition depths. " + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Phase transition widths", "", + Patterns::List (Patterns::Double(0)), + "A list of widths for each phase transition. This is only use to specify " + "the region where the recrystallized grain size is assigned after material " + "has crossed a phase transition and should accordingly be chosen similar " + "to the maximum cell width expected at the phase transition." + "List must have the same number of entries as Phase transition depths. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Phase transition Clapeyron slopes", "", + Patterns::List (Patterns::Double()), + "A list of Clapeyron slopes for each phase transition. A positive " + "Clapeyron slope indicates that the phase transition will occur in " + "a greater depth, if the temperature is higher than the one given in " + "Phase transition temperatures and in a smaller depth, if the " + "temperature is smaller than the one given in Phase transition temperatures. " + "For negative slopes the other way round. " + "List must have the same number of entries as Phase transition depths. " + "Units: \\si{\\pascal\\per\\kelvin}."); + prm.declare_entry ("Grain growth activation energy", "3.5e5", + Patterns::List (Patterns::Double(0)), + "The activation energy for grain growth $E_g$. " + "Units: \\si{\\joule\\per\\mole}."); + prm.declare_entry ("Grain growth activation volume", "8e-6", + Patterns::List (Patterns::Double(0)), + "The activation volume for grain growth $V_g$. " + "Units: \\si{\\meter\\cubed\\per\\mole}."); + prm.declare_entry ("Grain growth exponent", "3", + Patterns::List (Patterns::Double(0)), + "The exponent of the grain growth law $p_g$. This is an experimentally determined " + "grain growth constant. " + "Units: none."); + prm.declare_entry ("Grain growth rate constant", "1.5e-5", + Patterns::List (Patterns::Double(0)), + "The prefactor for the Ostwald ripening grain growth law $G_0$. " + "This is dependent on water content, which is assumed to be " + "50 H/$10^6$ Si for the default value. " + "Units: \\si{\\meter}$^{p_g}$\\si{\\per\\second}."); + prm.declare_entry ("Minimum grain size", "5e-6", + Patterns::Double(0), + "The minimum allowable grain size. The grain size will be limited to be " + "larger than this value. This can be used to damp out oscillations, or " + "to limit the viscosity variation due to grain size. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Reciprocal required strain", "10", + Patterns::List (Patterns::Double(0)), + "This parameter ($\\lambda$) gives an estimate of the strain necessary " + "to achieve a new grain size. "); + prm.declare_entry ("Recrystallized grain size", "", + Patterns::List (Patterns::Double(0)), + "The grain size $d_{ph}$ to that a phase will be reduced to when crossing a phase transition. " + "When set to zero, grain size will not be reduced. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Use equilibrium grain size", "true", + Patterns::Bool (), + "A flag indicating whether the computation should use the equilibrium grain size " + "when computing the viscosity (if true), or use a constant grain size instead (if " + "false)."); + prm.declare_entry ("Average specific grain boundary energy", "1.0", + Patterns::List (Patterns::Double(0)), + "The average specific grain boundary energy $\\gamma$. " + "Units: \\si{\\joule\\per\\meter\\squared}."); + prm.declare_entry ("Work fraction for boundary area change", "0.1", + Patterns::List (Patterns::Double(0)), + "The fraction $\\chi$ of work done by dislocation creep to change the grain boundary area. " + "Units: \\si{\\joule\\per\\meter\\squared}."); + prm.declare_entry ("Geometric constant", "3", + Patterns::List (Patterns::Double(0)), + "The geometric constant $c$ used in the paleowattmeter grain size reduction law. " + "Units: none."); + prm.declare_entry ("Dislocation viscosity iteration threshold", "1e-3", + Patterns::Double(0), + "We need to perform an iteration inside the computation " + "of the dislocation viscosity, because it depends on the " + "dislocation strain rate, which depends on the dislocation " + "viscosity itself. This number determines the termination " + "accuracy, i.e. if the dislocation viscosity changes by less " + "than this factor we terminate the iteration."); + prm.declare_entry ("Dislocation viscosity iteration number", "100", + Patterns::Integer(0), + "We need to perform an iteration inside the computation " + "of the dislocation viscosity, because it depends on the " + "dislocation strain rate, which depends on the dislocation " + "viscosity itself. This number determines the maximum " + "number of iterations that are performed. "); + prm.declare_entry ("Dislocation creep exponent", "3.5", + Patterns::List (Patterns::Double(0)), + "The power-law exponent $n_{dis}$ for dislocation creep. " + "Units: none."); + prm.declare_entry ("Dislocation activation energy", "4.8e5", + Patterns::List (Patterns::Double(0)), + "The activation energy for dislocation creep $E_{dis}$. " + "Units: \\si{\\joule\\per\\mole}."); + prm.declare_entry ("Dislocation activation volume", "1.1e-5", + Patterns::List (Patterns::Double(0)), + "The activation volume for dislocation creep $V_{dis}$. " + "Units: \\si{\\meter\\cubed\\per\\mole}."); + prm.declare_entry ("Dislocation creep prefactor", "4.5e-15", + Patterns::List (Patterns::Double(0)), + "The prefactor for the dislocation creep law $A_{dis}$. " + "Units: \\si{\\pascal}$^{-n_{dis}}$\\si{\\per\\second}."); + prm.declare_entry ("Diffusion creep exponent", "1", + Patterns::List (Patterns::Double(0)), + "The power-law exponent $n_{diff}$ for diffusion creep. " + "Units: none."); + prm.declare_entry ("Diffusion activation energy", "3.35e5", + Patterns::List (Patterns::Double(0)), + "The activation energy for diffusion creep $E_{diff}$. " + "Units: \\si{\\joule\\per\\mole}."); + prm.declare_entry ("Diffusion activation volume", "4e-6", + Patterns::List (Patterns::Double(0)), + "The activation volume for diffusion creep $V_{diff}$. " + "Units: \\si{\\meter\\cubed\\per\\mole}."); + prm.declare_entry ("Diffusion creep prefactor", "7.4e-15", + Patterns::List (Patterns::Double(0)), + "The prefactor for the diffusion creep law $A_{diff}$. " + "Units: \\si{\\meter}$^{p_{diff}}$\\si{\\pascal}$^{-n_{diff}}$\\si{\\per\\second}."); + prm.declare_entry ("Diffusion creep grain size exponent", "3", + Patterns::List (Patterns::Double(0)), + "The diffusion creep grain size exponent $p_{diff}$ that determines the " + "dependence of viscosity on grain size. " + "Units: none."); + prm.declare_entry ("Maximum temperature dependence of viscosity", "100", + Patterns::Double (1.0), + "The factor by which viscosity at adiabatic temperature and ambient temperature " + "are allowed to differ (a value of x means that the viscosity can be x times higher " + "or x times lower compared to the value at adiabatic temperature. This parameter " + "is introduced to limit local viscosity contrasts, but still allow for a widely " + "varying viscosity over the whole mantle range. " + "Units: none."); + prm.declare_entry ("Minimum viscosity", "1e18", + Patterns::Double (0), + "The minimum viscosity that is allowed in the whole model domain. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Maximum viscosity", "1e26", + Patterns::Double (0), + "The maximum viscosity that is allowed in the whole model domain. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Data directory", "$ASPECT_SOURCE_DIR/data/material-model/steinberger/", + Patterns::DirectoryName (), + "The path to the model data. The path may also include the special " + "text '$ASPECT_SOURCE_DIR' which will be interpreted as the path " + "in which the ASPECT source files were located when ASPECT was " + "compiled. This interpretation allows, for example, to reference " + "files located in the 'data/' subdirectory of ASPECT. "); + prm.declare_entry ("Material file names", "pyr-ringwood88.txt", + Patterns::List (Patterns::Anything()), + "The file names of the material data. " + "List with as many components as active " + "compositional fields (material data is assumed to " + "be in order with the ordering of the fields). "); + prm.declare_entry ("Derivatives file names", "", + Patterns::List (Patterns::Anything()), + "The file names of the enthalpy derivatives data. " + "List with as many components as active " + "compositional fields (material data is assumed to " + "be in order with the ordering of the fields). "); + prm.declare_entry ("Use table properties", "false", + Patterns::Bool(), + "This parameter determines whether to use the table properties " + "also for density, thermal expansivity and specific heat. " + "If false the properties are generated as in the " + "simple compressible plugin."); + prm.declare_entry ("Material file format", "perplex", + Patterns::Selection ("perplex|hefesto"), + "The material file format to be read in the property " + "tables."); + prm.declare_entry ("Use depth dependent viscosity", "false", + Patterns::Bool (), + "This parameter value determines if we want to use the layered depth dependent " + "rheology, which is input as an ascii data file."); + prm.declare_entry ("Use faults", "false", + Patterns::Bool (), + "This parameter value determines if we want to use the faults/plate boundaries as " + "a composition field, currently input as a world builder file."); + prm.declare_entry ("Fault viscosity", "1e20", + Patterns::Double(0), + "This parameter value determines the viscosity of faults or plate boundaries. " + "We would want to have weak faults/plate boundaries relative to the surrounding " + "lithosphere. " + "Units: \\si{\\pascal\\second}"); + prm.declare_entry ("Asthenosphere viscosity", "2.4e20", + Patterns::Double(0), + "This parameter value determines the asthenosphere layer in the reference file. " + "Units: \\si{\\pascal\\second}"); + prm.declare_entry ("Use cratons", "false", + Patterns::Bool (), + "This parameter value determines if we want to use cratons as viscous and neutrally " + "buoyant composition field, currently input as a world builder file."); + prm.declare_entry ("Craton viscosity", "1e25", + Patterns::Double(0), + "This parameter value determines the viscosity of cratons. We would want to have " + "strong cratons relative to the surrounding lithosphere." + "Units: \\si{\\pascal\\second}"); + prm.declare_entry ("Use depth dependent density scaling", "false", + Patterns::Bool (), + "This parameter value determines if we want to use depth-dependent scaling files " + "for computing the density from seismic velocities (if true) or use a constant " + "value (if false)."); + prm.declare_entry ("Use thermal expansivity profile", "true", + Patterns::Bool (), + "This parameter determines if we use a depth-dependent thermal expansivity read " + "from a data file (if true), or if we use the constant reference value given by " + "the 'Thermal expansion coefficient' (if false). In the case that material " + "properties are read from a look-up table, as determined by the input parameter " + "'Use table properties', this value is irrelevant and will be ignored."); + prm.declare_entry ("Uppermost mantle thickness", "300000", + Patterns::Double (0), + "The depth of the base of the uppermost mantle, which marks the transition between " + "using the temperature model of Tutu et al. (above) and derived from seismic " + "tomography (below). " + "Units: \\si{\\meter}."); + prm.declare_entry ("Use depth dependent temperature scaling", "false", + Patterns::Bool (), + "This parameter value determines if we want to use a depth-dependent scaling read " + "in from a data file for computing the temperature from seismic velocities (if true) " + "or use a constant value (if false)."); + prm.declare_entry ("Use varying fault viscosity", "false", + Patterns::Bool (), + "This parameter value determines if we want to use different viscosities for ridges " + "and trenches. We think that ridges are already weakened by the high temperatures " + "and by prescribing additional weak zones, we are making plates surrounded by ridges " + "faster than observed."); + prm.declare_entry ("Use constant lithosphere thickness", "false", + Patterns::Bool (), + "This parameter value determines if we want to a lithosphere with a constant thickness. " + "We can evaluate the effects of lithospheric thickness variations on the surface plate " + "motions using this. Currently, this parameter sets the lithosphere to a constant " + "thickness of 100 km."); + // Varying fault parameters + prm.enter_subsection("Varying fault viscosity"); + { + prm.declare_entry ("Ridge viscosity", "1e22", + Patterns::Double(0), + "This parameter value determines the viscosity of faults at the ridges. " + "Units: \\si{\\pascal\\second}"); + prm.declare_entry ("Trench viscosity", "1e20", + Patterns::Double(0), + "This parameter value determines the viscosity of faults at the trenches. " + "Units: \\si{\\pascal\\second}"); + } + prm.leave_subsection(); + // Depth-dependent viscosity parameters + Rheology::AsciiDepthProfile::declare_parameters(prm); + + // Depth-dependent density scaling parameters + Utilities::AsciiDataBase::declare_parameters(prm, "$ASPECT_SOURCE_DIR/cookbooks/tomography_based_plate_motions/input_data/", "rho_vs_scaling.txt", + "Density velocity scaling"); + + // Depth-dependent density scaling parameters + Utilities::AsciiDataBase::declare_parameters(prm, "$ASPECT_SOURCE_DIR/cookbooks/tomography_based_plate_motions/input_data/", "dT_vs_scaling.txt", + "Temperature velocity scaling"); + + // Depth-dependent thermal expansivity parameters + Utilities::AsciiDataBase::declare_parameters(prm, "$ASPECT_SOURCE_DIR/cookbooks/tomography_based_plate_motions/input_data/", + "thermal_expansivity_steinberger_calderwood.txt", "Thermal expansivity profile"); + + // Crustal boundary depths parameters + Utilities::AsciiDataBoundary::declare_parameters(prm, "$ASPECT_SOURCE_DIR/cookbooks/tomography_based_plate_motions/input_data/", + "crustal_structure.txt", "Crustal depths"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + TomographyBasedPlateMotions::parse_parameters (ParameterHandler &prm) + { + AssertThrow (this->introspection().compositional_name_exists("grain_size"), + ExcMessage("The 'grain size' material model only works if a compositional " + "field with name 'grain_size' is present. Please use another material " + "model or add such a field.")); + + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Tomography based plate motions model"); + { + reference_rho = prm.get_double ("Reference density"); + k_value = prm.get_double ("Thermal conductivity"); + reference_specific_heat = prm.get_double ("Reference specific heat"); + thermal_alpha = prm.get_double ("Thermal expansion coefficient"); + reference_compressibility = prm.get_double ("Reference compressibility"); + + + transition_depths = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Phase transition depths"))); + transition_temperatures = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Phase transition temperatures"))); + transition_slopes = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Phase transition Clapeyron slopes"))); + recrystallized_grain_size = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Recrystallized grain size"))); + transition_widths = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Phase transition widths"))); + + if (transition_temperatures.size() != transition_depths.size() || + transition_slopes.size() != transition_depths.size() || + transition_widths.size() != transition_depths.size() || + recrystallized_grain_size.size() != transition_depths.size() ) + AssertThrow(false, + ExcMessage("Error: At least one list that gives input parameters for the phase transitions has the wrong size.")); + + if (transition_depths.size()>1) + for (unsigned int i=0; i>(); + reference_viscosity_profile->initialize_simulator (this->get_simulator()); + reference_viscosity_profile->parse_parameters(prm); + reference_viscosity_profile->initialize(); + } + + if (use_depth_dependent_rho_vs) + rho_vs_depth_profile.parse_parameters(prm, "Density velocity scaling"); + + if (use_depth_dependent_thermal_expansivity) + thermal_expansivity_profile.parse_parameters(prm, "Thermal expansivity profile"); + + if (use_depth_dependent_dT_vs) + dT_vs_depth_profile.parse_parameters(prm, "Temperature velocity scaling"); + + crustal_boundary_depth.initialize_simulator (this->get_simulator()); + crustal_boundary_depth.parse_parameters(prm, "Crustal depths"); + + // Make sure the grain size field comes after all potential material + // data fields. Otherwise our material model calculation uses the + // wrong compositional fields. + if (use_table_properties && material_file_names.size() > 1) + { + AssertThrow(this->introspection().compositional_index_for_name("grain_size") >= material_file_names.size(), + ExcMessage("The compositional fields indicating the major element composition need to be first in the " + "list of compositional fields, but the grain size field seems to have a lower index than the number " + "of provided data files. This is likely inconsistent. Please check the number of provided data " + "files and the order of compositional fields.")); + } + + if (prm.get ("Material file format") == "perplex") + material_file_format = perplex; + else if (prm.get ("Material file format") == "hefesto") + material_file_format = hefesto; + else + AssertThrow (false, ExcNotImplemented()); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + + // Declare dependencies on solution variables + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + + this->model_dependence.viscosity = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::strain_rate + | NonlinearDependence::compositional_fields; + + this->model_dependence.density = NonlinearDependence::none; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + + if (use_table_properties) + { + this->model_dependence.density |= NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + this->model_dependence.specific_heat = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + } + else + { + if (thermal_alpha != 0) + this->model_dependence.density |=NonlinearDependence::temperature; + if (reference_compressibility != 0) + this->model_dependence.density |=NonlinearDependence::pressure; + } + } + + + + template + void + TomographyBasedPlateMotions::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + // These properties are useful as output, but will also be used by the + // heating model to reduce shear heating by the amount of work done to + // reduce grain size. + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.viscosities.size(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + + // We need the prescribed field outputs to interpolate the grain size onto a compositional field. + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.viscosities.size(); + out.additional_outputs.push_back( + std::make_unique> (n_points, this->n_compositional_fields())); + } + + // These properties are only output properties. But we should only create them if they are filled. + if (use_table_properties + && out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.viscosities.size(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + + if (this->get_parameters().temperature_method == Parameters::AdvectionFieldMethod::prescribed_field && + out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.viscosities.size(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + + // We need additional field outputs for the unscaled viscosity + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.viscosities.size(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.viscosities.size(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(TomographyBasedPlateMotions, + "tomography based plate motions", + "A material model that relies on compositional " + "fields that correspond to the average grain sizes of a " + "mineral phase and source terms that determine the grain " + "size evolution in terms of the strain rate, " + "temperature, phase transitions, and the creep regime. " + "This material model only works if a compositional field " + "named 'grain_size' is present. " + "In the diffusion creep regime, the viscosity depends " + "on this grain size field. " + "We use the grain size evolution laws described in \\cite{Behn2009}. " + "Other material parameters are either prescribed similar " + "to the 'simple' material model, or read from data files " + "that were generated by the Perplex or Hefesto software. " + "This material model is described in more detail in " + "\\citet{dannberg2017}.") + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + namespace + { + +#define INSTANTIATE(dim) \ + template class UnscaledViscosityAdditionalOutputs; + + ASPECT_INSTANTIATE(INSTANTIATE) +#undef INSTANTIATE + } + } +} diff --git a/cookbooks/tomography_based_plate_motions/plugins/tomography_based_plate_motions.h.bak b/cookbooks/tomography_based_plate_motions/plugins/tomography_based_plate_motions.h.bak new file mode 100644 index 00000000000..6846e88afe1 --- /dev/null +++ b/cookbooks/tomography_based_plate_motions/plugins/tomography_based_plate_motions.h.bak @@ -0,0 +1,513 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_cookbooks_tomography_based_plate_motions_h +#define _aspect_cookbooks_tomography_based_plate_motions_h + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + + /** + * A material model to set up mantle flow models based on + * an input tomography model and a temperature model. + * The viscosity is computed based on dislocation and diffusion + * creep with lateral averages scaled to a reference viscosity + * profile. + * This material model only works if a compositional field + * named 'grain_size' is present. In the diffusion + * creep regime, the viscosity depends on this grain size. + * The model allows the user to prescribe different viscosity at + * fault boundaries and in continental regions at locations defined + * by the the compositional field 'faults' or 'cratons', respectively. + * The material model also allows the option to compute and use + * equilibrium grain size following paleowattmeter approximation + * by Austin and Evans, (2007), Paleowattmeters: "A scaling relation for + * dynamically recrystallized grain size", Geology, 35, 343. + * Other material parameters are either based on (1) an input tomography + * model and scaling profiles between temperature/density relative to + * the seismic velocity anomalies or a temperature model and constant + * thermal expansivities and compressibilities relative to a reference + * temperature, as done in Osei Tutu et al., (2018): "Evaluating the influence + * of plate boundary friction and mantle viscosity on plate velocities", + * Geochem. Geophys. Geosyst., 19 (3), 642–666, or (2) prescribed similar to + * the 'simple' material model, or (3) read from data files + * that were generated by the Perplex or Hefesto software. The material model + * is described in more detail in Dannberg, J., Z. Eilon, U. Faul, + * R. Gassmöller, P. Moulik, and R. Myhill (2017): "The importance of + * grain size to mantle dynamics and seismological observations", + * Geochem. Geophys. Geosyst., 18, 3034–3061, doi:10.1002/2017GC006944., + * and in Saxena, A., Dannberg J., Gassmöller, Fraters, M., Heister, T., & Styron, (2023): + * "High-resolution mantle flow models reveal importance of plate boundary geometry and slab pull + * forces on generating tectonic plate motions", J. Geophys. Research.:Solid Earth, + * 128, e2022JB025877. + + * @ingroup MaterialModels + */ + template + class TomographyBasedPlateMotions : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. Loads the material data and sets up + * pointers. Gets the reference viscosity profile from a file. + */ + void + initialize () override; + + /** + * Compute the laterally averaged viscosity + */ + void + update() override; + + /** + * Compute the reference viscosity against which the viscosities in the model + * are scaled. The reference viscosity is from a depth-dependent ascii profile and + * the function returns as the second parameter in the pair the support point in + * that profile that has the next smaller depth value than the input parameter + * @p depth. + */ + std::pair + get_reference_viscosity (const double depth) const; + + /** + * Return the depth of the base of the uppermost mantle. Below that depth, + * material properties are based on seismic tomography. Above that depth, material + * properties are computed based on the model of Tutu et al., 2018. + */ + double + get_depth_of_base_of_uppermost_mantle () const; + + /** + * Compute the scaling factors for each depth layer such that the laterally + * averaged viscosiy in that layer is the same as the reference vicosity. + */ + double + compute_viscosity_scaling (const double depth) const; + + /** + * Return whether the model is compressible or not. + */ + bool + is_compressible () const override; + + void + evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + /** + * @} + */ + + protected: + double reference_rho; + double thermal_alpha; + double reference_specific_heat; + + /** + * The constant compressibility. + */ + double reference_compressibility; + + /** + * The thermal conductivity. + */ + double k_value; + + /** + * Parameters controlling the grain size evolution. + */ + std::vector grain_growth_activation_energy; + std::vector grain_growth_activation_volume; + std::vector grain_growth_rate_constant; + std::vector grain_growth_exponent; + double minimum_grain_size; + std::vector reciprocal_required_strain; + std::vector recrystallized_grain_size; + bool equilibrate_grain_size; + + /** + * Parameters controlling the dynamic grain recrystallization. + * (following paleowattmeter as described in Austin, N. J., & Evans, B. + * (2007). Paleowattmeters: A scaling relation for dynamically + * recrystallized grain size. Geology, 35(4), 343-346.). + */ + std::vector grain_boundary_energy; + std::vector boundary_area_change_work_fraction; + std::vector geometric_constant; + + /** + * Parameters controlling the viscosity. + */ + double dislocation_viscosity_iteration_threshold; + unsigned int dislocation_viscosity_iteration_number; + std::vector dislocation_creep_exponent; + std::vector dislocation_activation_energy; + std::vector dislocation_activation_volume; + std::vector dislocation_creep_prefactor; + std::vector diffusion_creep_exponent; + std::vector diffusion_activation_energy; + std::vector diffusion_activation_volume; + std::vector diffusion_creep_prefactor; + std::vector diffusion_creep_grain_size_exponent; + + /** + * Reference viscosity profile coordinates, and the corresponding viscosity. + */ + std::vector reference_viscosity_coordinates; + std::unique_ptr> reference_viscosity_profile; + + /** + * A reference profile for density scaling. + */ + Utilities::AsciiDataProfile rho_vs_depth_profile; + + /** + * The column indices of the density scaling column in the ascii profile file. + */ + unsigned int density_scaling_index; + + + /** + * A reference profile for the thermal expansivity. + */ + Utilities::AsciiDataProfile thermal_expansivity_profile; + unsigned int thermal_expansivity_column_index; + + /** + * A reference profile for temperatura scaling. Values are from Steinberger and + * Calderwood, 2006. + */ + Utilities::AsciiDataProfile dT_vs_depth_profile; + + /** + * The column indices of the density scaling column in the ascii profile file. + */ + unsigned int temperature_scaling_index; + + /** + * An object of ascii data boundary to input crustal depths. + */ + Utilities::AsciiDataBoundary crustal_boundary_depth; + + /** + * A depth-profile of the laterally averaged viscosity in each layer + * in the current model. Can be used to compare (and potentially scale) + * the computed viscosity to the reference profile. + */ + std::vector average_viscosity_profile; + + /** + * Variable returned to determine if the evaluate () function is called and + * viscosities are computed. Initially, it is set to false and then updated + * to true in the update () function. + */ + bool initialized; + + /** + * Because of the nonlinear nature of this material model many + * parameters need to be kept within bounds to ensure stability of the + * solution. These bounds can be adjusted as input parameters. + */ + double max_temperature_dependence_of_eta; + double min_eta; + double max_eta; + double min_specific_heat; + double max_specific_heat; + double min_thermal_expansivity; + double max_thermal_expansivity; + unsigned int max_latent_heat_substeps; + double min_grain_size; + + double diffusion_viscosity (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const SymmetricTensor<2,dim> &strain_rate, + const Point &position) const; + + /** + * Compute the equilibrium grain size for a given temperature and + * pressure. + * This computation is based on the rate of grain size growth + * (Ostwald ripening) or reduction (due to dynamic recrystallization + * and phase transformations) in dependence on temperature, pressure, + * strain rate, mineral phase and creep regime. + * We use the grain size growth laws as for example described + * in Behn, M. D., Hirth, G., & Elsenbeck, J. R. (2009). Implications + * of grain size evolution on the seismic structure of the oceanic + * upper mantle. Earth and Planetary Science Letters, 282(1), 178-189. + * + * For the rate of grain size reduction due to dynamic crystallization, + * we use paleowattmeter approximation (Austins and + * Evans, 2007). + */ + void compute_equilibrium_grain_size (const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const; + + /** + * This function calculates the dislocation viscosity. For this purpose + * we need the dislocation component of the strain rate, which we can + * only compute by knowing the dislocation viscosity. Therefore, we + * iteratively solve for the dislocation viscosity and update the + * dislocation strain rate in each iteration using the new value + * obtained for the dislocation viscosity. The iteration is started + * with a dislocation viscosity calculated for the whole strain rate + * unless a guess for the viscosity is provided, which can reduce the + * number of iterations significantly. + */ + double dislocation_viscosity (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const SymmetricTensor<2,dim> &strain_rate, + const Point &position, + const double viscosity_guess = 0) const; + + /** + * This function calculates the dislocation viscosity for a given + * dislocation strain rate. + */ + double dislocation_viscosity_fixed_strain_rate (const double temperature, + const double pressure, + const double second_strain_rate_invariant, + const Point &position) const; + + double density (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + /** + * The column indices of the density column in the reference profile file. + */ + unsigned int density_index; + + double compressibility (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + double thermal_expansivity (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + /** + * Returns the p-wave velocity as calculated by HeFESTo. + */ + double seismic_Vp (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + /** + * Returns the s-wave velocity as calculated by HeFESTo. + */ + double seismic_Vs (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + /** + * Function that defines the phase transition interface + * (0 above, 1 below the phase transition). This is done + * individually for each transition and summed up in the end. + */ + double + phase_function (const Point &position, + const double temperature, + const double pressure, + const unsigned int phase) const; + + /** + * Function that returns the phase for a given + * position, temperature, pressure and compositional + * field index. + */ + unsigned int + get_phase_index (const Point &position, + const double temperature, + const double pressure) const; + + + /** + * Lists of depth, width, and Clapeyron slopes for the different phase + * transitions and in which phase they occur. + */ + std::vector transition_depths; + std::vector transition_temperatures; + std::vector transition_slopes; + std::vector transition_widths; + + + /** + * The following variables are properties of the material files + * we read in. + */ + std::string data_directory; + std::vector material_file_names; + std::vector derivatives_file_names; + unsigned int n_material_data; + bool use_table_properties; + + /** + * Parameter value that determines whether to read the viscosity with depth + * from an ascii data file. + */ + bool use_depth_dependent_viscosity; + + /** + * Parameter value that determines whether to read the density scaling with depth + * from an ascii data file. + */ + bool use_depth_dependent_rho_vs; + + /** + * Parameter value that determines whether to read the thermal expansivity + * from an ascii data file. + */ + bool use_depth_dependent_thermal_expansivity; + + /** + * Parameter value that determines whether to read the temperature scaling with depth + * from an ascii data file. + */ + bool use_depth_dependent_dT_vs; + + /** + * Parameter that determines if faults or plate boundaries are used as another + * compositional field. + */ + bool use_faults; + + /** + * Parameter that determines the viscosity of faults or plate boundaries. + */ + double fault_viscosity; + + /** + * Parameter that determines if ridges or trenches have different viscosities + */ + bool use_varying_fault_viscosity; + + /** + * Parameter that determines if lithospheric depths vary or not + */ + bool use_constant_lithosphere_thickness; + + /** + * Parameter that determines the viscosity of faults at ridges. + */ + double ridge_viscosity; + + /** + * Parameter that determines the viscosity of faults at trenches. + */ + double trench_viscosity; + + /** + * Parameter that determines the asthenosphere viscosity. By default, use + * the value from the Steinberger & Calderwood reference viscosity profile. + */ + double asthenosphere_viscosity; + + /** + * Parameter that determines if we want to use viscous and neutrally buoyant cratons as + * another compositional field. + */ + bool use_cratons; + + /** + * Parameter that determines the viscosity for cratons. + */ + double craton_viscosity; + + /** + * Approximate lithosphere thickness used to separate the regions of + * temperature derived from seismic tomography and linear temperature + * gradient. + */ + double lithosphere_thickness; + + /** + * Parameter used to describe the uppermost mantle based on Tutu (2018). + */ + double depth_to_base_of_uppermost_mantle; + + /** + * The format of the provided material files. Currently we support + * the PERPLEX and HeFESTo data formats. + */ + enum formats + { + perplex, + hefesto + } material_file_format; + + /** + * List of pointers to objects that read and process data we get from + * material data files. There is one pointer/object per compositional + * field provided. + */ + std::vector> material_lookup; + + /** + * A shared pointer to the initial temperature object + * that ensures that the current object can continue + * to access the initial composition object beyond the + * first time step. + */ + std::shared_ptr> initial_temperature_manager; + }; + + } +} + +#endif diff --git a/cookbooks/transform_fault_behn_2007/doc/material.part.prm.bak b/cookbooks/transform_fault_behn_2007/doc/material.part.prm.bak new file mode 100644 index 00000000000..28c51d6c0ca --- /dev/null +++ b/cookbooks/transform_fault_behn_2007/doc/material.part.prm.bak @@ -0,0 +1,12 @@ +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + set Reference temperature = 1573.15 + set Heat capacities = 1000 + set Densities = 3300 # Value from Behn et al., 2007 + set Thermal expansivities = 0 # Thermal buoyancy is ignored in Behn et al., 2007 + set Define thermal conductivities = true + set Thermal conductivities = 3.5 + end +end diff --git a/cookbooks/transform_fault_behn_2007/doc/temperature.part.prm.bak b/cookbooks/transform_fault_behn_2007/doc/temperature.part.prm.bak new file mode 100644 index 00000000000..3cfa8800283 --- /dev/null +++ b/cookbooks/transform_fault_behn_2007/doc/temperature.part.prm.bak @@ -0,0 +1,28 @@ +# We use the Geodynamic World Builder to create the initial temperature. +# Therefore, we have to specify the location of the GWB input file +# that we want to use. The file we use here is located in the cookbooks +# folder of the GWB repository. See the corresponding tutorial in the +# Geodynamic World Builder on how to create this file. +set World builder file = $ASPECT_SOURCE_DIR/contrib/world_builder/cookbooks/3d_cartesian_transform_fault/3d_cartesian_transform_fault.wb + +# Note that the adiabatic surface temperature should be consistent with the +# value assumed in the GWB input file, given in the parameter 'potential +# mantle temperature'. +set Adiabatic surface temperature = 1573.15 + +# The initial temperature comes form the Geodynamic World Builder. +subsection Initial temperature model + set List of model names = world builder +end + +# We prescribe the surface temperature at the top and the mantle potential temperature +# at the bottom. +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = box + + subsection Box + set Top temperature = 273.15 + set Bottom temperature = 1573.15 + end +end diff --git a/cookbooks/transform_fault_behn_2007/temperature_dependent.prm.bak b/cookbooks/transform_fault_behn_2007/temperature_dependent.prm.bak new file mode 100644 index 00000000000..f4791b31f2d --- /dev/null +++ b/cookbooks/transform_fault_behn_2007/temperature_dependent.prm.bak @@ -0,0 +1,24 @@ +# This is a model of a mid-ocean ridge with a transform fault, +# specifically, it is a model that reproduces the setup of Behn et +# al., 2007: Thermal structure of oceanic transform faults. +# This input file covers case 2 from that publication (with a +# temperature-dependent viscosity). + +include ./transform_fault_behn_2007.prm + +set World builder file = $ASPECT_SOURCE_DIR/contrib/world_builder/cookbooks/3d_cartesian_transform_fault/3d_cartesian_transform_fault.wb +set Output directory = transform-fault-behn-2007-temperature-dependent +set Dimension = 3 + +# In case 2, viscosity is temperature-dependent with an +# activation energy of 250 kJ/mol. We also need to scale the +# prefactor to account for the different formulation of the +# diffusion creep flow law. +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + set Prefactors for diffusion creep = 9.99479239e-12 + set Activation energies for diffusion creep = 250e3 + end +end diff --git a/cookbooks/transform_fault_behn_2007/transform_fault_behn_2007.prm.bak b/cookbooks/transform_fault_behn_2007/transform_fault_behn_2007.prm.bak new file mode 100644 index 00000000000..d2e8a8f2aa7 --- /dev/null +++ b/cookbooks/transform_fault_behn_2007/transform_fault_behn_2007.prm.bak @@ -0,0 +1,203 @@ +# This is a model of a mid-ocean ridge with a transform fault, +# specifically, it is a model that reproduces the setup of Behn et +# al., 2007: Thermal structure of oceanic transform faults. +# This input file covers case 1 from that publication (with a +# constant viscosity). + +# We use the Geodynamic World Builder to create the initial temperature. +# Therefore, we have to specify the location of the GWB input file +# that we want to use. The file we use here is located in the cookbooks +# folder of the GWB repository. See the corresponding tutorial in the +# Geodynamic World Builder on how to create this file. +set World builder file = $ASPECT_SOURCE_DIR/contrib/world_builder/cookbooks/3d_cartesian_transform_fault/3d_cartesian_transform_fault.wb + +# We run the model for 10 million years. +set End time = 1e7 +set Output directory = transform-fault-behn-2007 +set Dimension = 3 + +# We set the average pressure at the surface to 0. +set Pressure normalization = surface +set Surface pressure = 0 + +# Note that the adiabatic surface temperature should be consistent with the +# value assumed in the GWB input file, given in the parameter 'potential +# mantle temperature'. +set Adiabatic surface temperature = 1573.15 +set Nonlinear solver scheme = iterated Advection and Stokes +set Nonlinear solver tolerance = 1e-5 +set Max nonlinear iterations = 50 + +# We use the geometric multigrid solver, but because this is a difficult +# linear problem to solve with a large viscosity contrast, we increase the +# number of cheap iterations and the restart length to make sure it +# converges. +subsection Solver parameters + subsection Stokes solver parameters + set GMRES solver restart length = 200 + set Number of cheap Stokes solver steps = 5000 + set Stokes solver type = block GMG + end +end + +# The model is a box with a width of 250 x 100 km and a depth of 100 km. +# The number of X, Y and Z repetitions determine the shape of the coarsest +# mesh cells (that will then be refined adaptively) relative to the +# shape of the box. To achieve an aspect ratio of approximately one +# for the cells, we choose more X than Y and Z repetitions. +# Note that the geometry should be consistent with the geometry assumed in +# in the GWB input file. Specifically, that means making sure that the +# whole model domain lies inside the area prescribed by the coordinates +# of the oceanic plate feature given in the GWB input file. +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 250000 + set Y extent = 100000 + set Z extent = 100000 + set X repetitions = 5 + set Y repetitions = 2 + set Z repetitions = 2 + end +end + +# Since we model an oceanic plate moving away from the ridge axis, we +# prescribe the plate velocity of 3 cm/yr at the surface. Depending on +# the side of the transform fault we are on, the velocity points either +# in negative or positive x direction. +# As per Behn et al., 2007: The base of the model is stress free. +# Symmetric boundary conditions are imposed on the sides of the model space +# parallel to the spreading direction, and the boundaries perpendicular to +# spreading are open to convective flux (we prescribe the lithostatic +# pressure). +subsection Boundary velocity model + set Tangential velocity boundary indicators = front, back + set Prescribed velocity boundary indicators = top: function + + subsection Function + set Function constants = spreading_rate=0.03 + set Variable names = x,y,z + set Function expression = if(x<50000 || (x<200000 && y<50000), -spreading_rate, spreading_rate); 0; 0 + end +end + +# We prescribe a boundary traction in vertical direction at the bottom and +# and right boundaries, setting it to the lithostatic pressure to allow +# for free in- and outflow of material. +subsection Boundary traction model + set Prescribed traction boundary indicators = right:initial lithostatic pressure, left:initial lithostatic pressure, bottom:initial lithostatic pressure + + # We choose the representative point at 125 km from the ridge, which + # is in the middle between the distance of the old (200 km) and young + # (50 km) ridge segment at each side. + subsection Initial lithostatic pressure + set Number of integration points = 1000 + set Representative point = 175000,0,0 + end +end + +# The initial temperature comes form the Geodynamic World Builder. +subsection Initial temperature model + set List of model names = world builder +end + +# We prescribe the surface temperature at the top and the mantle potential temperature +# at the bottom. +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = box + + subsection Box + set Top temperature = 273.15 + set Bottom temperature = 1573.15 + end +end + +subsection Material model + # Because we use the GMG solver, we need to average the viscosity. + set Material averaging = project to Q1 only viscosity + set Model name = visco plastic + + subsection Visco Plastic + # Reference temperature and viscosity + set Reference temperature = 1573.15 + + # Limit the viscosity. The maximum value is 1e23 Pa s as given in + # Behn et al. 2007. The minimum value should never be reached, since + # the viscosity should never drop below the reference value of + # 1e19 Pa s. + set Minimum viscosity = 1e18 + set Maximum viscosity = 1e23 + set Heat capacities = 1000 + set Densities = 3300 # Value from Behn et al., 2007 + set Thermal expansivities = 0 # Thermal buoyancy is ignored in Behn et al., 2007 + set Define thermal conductivities = true + set Thermal conductivities = 3.5 + set Viscous flow law = diffusion + set Activation volumes for diffusion creep = 0 + set Grain size = 1 + + # The reference viscosity is 1e19 Pa s, and viscosity does + # not depend on pressure. + # Case 1 in Behn et al. (2007) has a constant viscosity as used here. + set Prefactors for diffusion creep = 5e-20 + set Activation energies for diffusion creep = 0 + + # Plasticity parameters - irrelevant + # set to very high value so that it is not used + set Cohesions = 1e15 + end +end + +# The gravity points downward and is set to 10. +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +# The highest resolution in Behn et al is 3.75 km near the transform fault. +# The coarse cells have a size of 50 km, which corresponds to 4 global +# refinements. +subsection Mesh refinement + set Time steps between mesh refinement = 0 + set Initial global refinement = 4 + set Initial adaptive refinement = 0 # For a higher resolution near the transform fault, set this to 2 + set Strategy = minimum refinement function + set Skip solvers on initial refinement = true + set Minimum refinement level = 4 + + # Using initial adpative refinements 2 would allow for an increased + # resolution near the transform faults. + subsection Minimum refinement function + set Coordinate system = cartesian + set Function expression = if((x<60000 && x>40000 && y>45000 && z>70000) || (x<210000 && x>190000 && y<=55000 && z>70000) || ((x>40000 && x<210000 && y>40000 && y<60000 && z>70000)), 6, 4) + set Variable names = x,y,z + end +end + +# The model does not include any heating terms. +subsection Heating model + set List of model names = +end + +# Below, we describe the variables we want to include in the graphical output. +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, mass flux statistics + + subsection Visualization + set List of output variables = material properties, nonadiabatic temperature, strain rate, melt fraction + set Point-wise stress and strain = true + set Number of grouped files = 0 + set Interpolate output = false + set Output format = vtu + set Time between graphical output = 1e5 + + subsection Material properties + set List of material properties = density, viscosity, thermal expansivity, thermal conductivity + end + end +end diff --git a/cookbooks/van-keken-vof/doc/amr.part.prm.bak b/cookbooks/van-keken-vof/doc/amr.part.prm.bak new file mode 100644 index 00000000000..5dab825f0a7 --- /dev/null +++ b/cookbooks/van-keken-vof/doc/amr.part.prm.bak @@ -0,0 +1,8 @@ +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Strategy = volume of fluid interface + set Initial global refinement = 6 + set Time steps between mesh refinement = 0 + set Coarsening fraction = 0.05 + set Refinement fraction = 0.3 +end diff --git a/cookbooks/van-keken-vof/doc/main.part.prm.bak b/cookbooks/van-keken-vof/doc/main.part.prm.bak new file mode 100644 index 00000000000..27ad1a66648 --- /dev/null +++ b/cookbooks/van-keken-vof/doc/main.part.prm.bak @@ -0,0 +1,19 @@ +subsection Compositional fields + set Number of fields = 1 + set Compositional field methods = volume of fluid +end + +subsection Volume of Fluid + set Number initialization samples = 16 +end + +subsection Initial composition model + set Model name = function + set Volume of fluid initialization type = C_1:level set + + subsection Function + set Variable names = x,z + set Function constants = pi=3.1415926 + set Function expression = 0.2+0.02*cos(pi*x/0.9142)-z + end +end diff --git a/cookbooks/van-keken-vof/doc/postprocess.part.prm.bak b/cookbooks/van-keken-vof/doc/postprocess.part.prm.bak new file mode 100644 index 00000000000..7783beaae07 --- /dev/null +++ b/cookbooks/van-keken-vof/doc/postprocess.part.prm.bak @@ -0,0 +1,13 @@ +subsection Postprocess + set List of postprocessors = visualization, velocity statistics + + subsection Visualization + set List of output variables = volume of fluid values + set Output format = vtu + set Time between graphical output = 100 + + subsection Volume of Fluid + set Output interface reconstruction contour = true + end + end +end diff --git a/cookbooks/van-keken-vof/doc/variation.part.prm.bak b/cookbooks/van-keken-vof/doc/variation.part.prm.bak new file mode 100644 index 00000000000..7a9ef22da72 --- /dev/null +++ b/cookbooks/van-keken-vof/doc/variation.part.prm.bak @@ -0,0 +1,10 @@ +subsection Initial composition model + set Model name = function + set Volume of fluid initialization type = C_1:level set + + subsection Function + set Variable names = x,z + set Function constants = pi=3.1415926, a=0.02 + set Function expression = 0.2+a*cos(pi*x/0.9142)-z + end +end diff --git a/cookbooks/van-keken-vof/van-keken-vof.prm.bak b/cookbooks/van-keken-vof/van-keken-vof.prm.bak new file mode 100644 index 00000000000..8ad9be7a63e --- /dev/null +++ b/cookbooks/van-keken-vof/van-keken-vof.prm.bak @@ -0,0 +1,108 @@ +# A description of the van Keken et al. thermochemical composition benchmark. See the manual for more +# information. + +set Dimension = 2 +set Start time = 0 +set End time = 2000 +set Use years in output instead of seconds = false +set CFL number = 0.5 +set Output directory = output-van-keken-vof + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 0.9142 + set Y extent = 1.0000 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right + set Zero velocity boundary indicators = bottom, top +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 1010 + set Viscosity = 1e2 + set Thermal expansion coefficient = 0 + set Density differential for compositional field 1 = -10 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +############### Parameters describing the temperature field +# Note: The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the compositional field +# Note: The compositional field is what drives the flow +# in this example + +subsection Compositional fields + set Number of fields = 1 + set Compositional field methods = volume of fluid +end + +subsection Volume of Fluid + set Number initialization samples = 16 +end + +subsection Initial composition model + set Model name = function + set Volume of fluid initialization type = C_1:level set + + subsection Function + set Variable names = x,z + set Function constants = pi=3.1415926 + set Function expression = 0.2+0.02*cos(pi*x/0.9142)-z + end +end + +############### Parameters describing the discretization + +subsection Discretization + set Use discontinuous composition discretization = true +end + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Strategy = volume of fluid interface + set Initial global refinement = 6 + set Time steps between mesh refinement = 0 + set Coarsening fraction = 0.05 + set Refinement fraction = 0.3 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, composition statistics + + subsection Visualization + set List of output variables = volume of fluid values + set Output format = vtu + set Time between graphical output = 100 + + subsection Volume of Fluid + set Output interface reconstruction contour = true + end + end +end diff --git a/cookbooks/van-keken/doc/main.part.prm.bak b/cookbooks/van-keken/doc/main.part.prm.bak new file mode 100644 index 00000000000..d63eb35aab1 --- /dev/null +++ b/cookbooks/van-keken/doc/main.part.prm.bak @@ -0,0 +1,19 @@ +subsection Material model + set Model name = simple + + subsection Simple model + set Viscosity = 1e2 + set Thermal expansion coefficient = 0 + set Density differential for compositional field 1 = -10 + end +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = pi=3.14159 + set Function expression = if( (z>0.2+0.02*cos(pi*x/0.9142)) , 0 , 1 ) + end +end diff --git a/cookbooks/van-keken/doc/postprocess.part.prm.bak b/cookbooks/van-keken/doc/postprocess.part.prm.bak new file mode 100644 index 00000000000..3c96e051be4 --- /dev/null +++ b/cookbooks/van-keken/doc/postprocess.part.prm.bak @@ -0,0 +1,3 @@ +subsection Postprocess + set List of postprocessors = velocity statistics +end diff --git a/cookbooks/van-keken/doc/smooth.part.prm.bak b/cookbooks/van-keken/doc/smooth.part.prm.bak new file mode 100644 index 00000000000..055cc6480b4 --- /dev/null +++ b/cookbooks/van-keken/doc/smooth.part.prm.bak @@ -0,0 +1,9 @@ +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = pi=3.14159 + set Function expression = 0.5*(1+tanh((0.2+0.02*cos(pi*x/0.9142)-z)/0.02)) + end +end diff --git a/cookbooks/van-keken/van-keken-discontinuous.prm.bak b/cookbooks/van-keken/van-keken-discontinuous.prm.bak new file mode 100644 index 00000000000..407f2a4cf9a --- /dev/null +++ b/cookbooks/van-keken/van-keken-discontinuous.prm.bak @@ -0,0 +1,93 @@ +# A description of the van Keken et al. benchmark. See the manual for more +# information. + +set Dimension = 2 +set Start time = 0 +set End time = 2000 +set Use years in output instead of seconds = false +set CFL number = 1.0 +set Output directory = output-van-keken-discontinuous + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 0.9142 + set Y extent = 1.0000 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right + set Zero velocity boundary indicators = bottom, top +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 1010 + set Viscosity = 1e2 + set Thermal expansion coefficient = 0 + set Density differential for compositional field 1 = -10 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +############### Parameters describing the temperature field +# Note: The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the compositional field +# Note: The compositional field is what drives the flow +# in this example + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = pi=3.1415926 + set Function expression = if( (z>0.2+0.02*cos(pi*x/0.9142)) , 0 , 1 ) + end +end + +############### Parameters describing the discretization + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Strategy = composition + set Initial global refinement = 7 + set Time steps between mesh refinement = 0 + set Coarsening fraction = 0.05 + set Refinement fraction = 0.3 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, composition statistics + + subsection Visualization + set Output format = vtu + set Time between graphical output = 100 + end +end diff --git a/cookbooks/van-keken/van-keken-smooth.prm.bak b/cookbooks/van-keken/van-keken-smooth.prm.bak new file mode 100644 index 00000000000..1bf4eb236a3 --- /dev/null +++ b/cookbooks/van-keken/van-keken-smooth.prm.bak @@ -0,0 +1,94 @@ +# A description of the van Keken et al. benchmark using smooth initial +# conditions instead of the discontinuous ones in +# van-keken-discontinuous.prm. See the manual for more information. + +set Dimension = 2 +set Start time = 0 +set End time = 2000 +set Use years in output instead of seconds = false +set CFL number = 1.0 +set Output directory = output-van-keken-smooth + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 0.9142 + set Y extent = 1.0000 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right + set Zero velocity boundary indicators = bottom, top +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 1010 + set Viscosity = 1e2 + set Thermal expansion coefficient = 0 + set Density differential for compositional field 1 = -10 + end +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10 + end +end + +############### Parameters describing the temperature field +# Note: The temperature plays no role in this model + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 0 + end +end + +############### Parameters describing the compositional field +# Note: The compositional field is what drives the flow +# in this example + +subsection Compositional fields + set Number of fields = 1 +end + +subsection Initial composition model + set Model name = function + + subsection Function + set Variable names = x,z + set Function constants = pi=3.1415926 + set Function expression = 0.5*(1+tanh((0.2+0.02*cos(pi*x/0.9142)-z)/0.02)) + end +end + +############### Parameters describing the discretization + +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Strategy = composition + set Initial global refinement = 7 + set Time steps between mesh refinement = 0 + set Coarsening fraction = 0.05 + set Refinement fraction = 0.3 +end + +############### Parameters describing what to do with the solution + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, composition statistics + + subsection Visualization + set Output format = vtu + set Time between graphical output = 100 + end +end diff --git a/cookbooks/vankeken_subduction/plugin/van_Keken_mesh.cc.bak b/cookbooks/vankeken_subduction/plugin/van_Keken_mesh.cc.bak new file mode 100644 index 00000000000..b0236866b0f --- /dev/null +++ b/cookbooks/vankeken_subduction/plugin/van_Keken_mesh.cc.bak @@ -0,0 +1,367 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace GeometryModel + { + using namespace dealii; + + /** + * A geometry model based on the 2D Cartesian van Keken 2008 subduction + * benchmark. A custom mesh that is better suited to deal with + * the unique constraints of this benchmark is necessary to obtain a + * continuous pressure field. + * + * Because this mesh is highly specific, many of these functions are + * present only because of the way that we need to interface with the + * GeometryModel class, but they return nothing. + */ + + template + class vanKeken : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + vanKeken(); + + /** + * Generate a coarse mesh for the geometry described by this class. + */ + void create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const override; + + double length_scale () const override; + + /** + * Return the depth that corresponds to the given + * position. The documentation of the base class (see + * GeometryModel::Interface::depth()) describes in detail how + * "depth" is interpreted in general. + */ + double depth(const Point &position) const override; + + + double height_above_reference_surface(const Point &position) const override; + + /** + * @copydoc Interface::representative_point() + */ + Point representative_point(const double depth) const override; + + /** + * @copydoc Interface::maximal_depth() + */ + double maximal_depth() const override; + + /** + * Return the set of boundary indicators that are used by this model. + * This information is used to determine what boundary indicators can + * be used in the input file. + */ + std::set + get_used_boundary_indicators () const override; + + /** + * Return symbolic names for all boundary components. Their names are + * described in the documentation of this plugin, at the bottom of the + * .cc file. + */ + std::map + get_symbolic_boundary_names_map () const override; + + /** + * Return whether the given point lies within the domain specified + * by the geometry. This function does not take into account + * initial or dynamic surface topography. + */ + bool + point_is_in_domain(const Point &point) const override; + + /** + * Returns what the natural coordinate system for this geometry model is, + * which in this case is cartesian. + */ + aspect::Utilities::Coordinates::CoordinateSystem natural_coordinate_system() const override; + + /** + * Declare the parameters this class takes through input files. However, + * for this geometry there are no parameters. + */ + static + void + declare_parameters (ParameterHandler &); + + /** + * Read the parameters this class declares from the parameter file. + * Again, there are no parameters to be declared for this class. + */ + void + parse_parameters (ParameterHandler &) override; + }; + + + + template + vanKeken::vanKeken() + {} + + template <> + void + vanKeken<2>:: + create_coarse_mesh (parallel::distributed::Triangulation<2> &coarse_grid) const + { + const std::vector> vertices = + { + // 0 1 2 3 4 + {0.0, 0.0}, {50e3, 0.0}, {330e3, 0.0}, {600e3, 0.0}, {660e3, 0.0}, + // 5 6 7 8 9 + {0.0, 300e3}, {50e3, 300e3}, {233e3, 183e3}, {330e3, 270e3}, {660e3, 270e3}, + // 10 11 12 13 + {50e3, 550e3}, {660e3, 550e3}, {0.0, 600e3}, {660e3, 600e3} + }; + + // Next, we have to define the cells and the vertices they contain. + const std::vector::vertices_per_cell>> + cell_vertices = + { + {{0, 1, 5, 6}}, + {{8, 9, 10, 11}}, + {{10, 11, 12, 13}}, + {{1, 2, 6, 7}}, + {{2, 3, 7, 8}}, + {{3, 4, 8, 9}}, + {{5, 6, 12, 10}}, + {{6, 7, 10, 8}} + }; + + std::vector> cells(cell_vertices.size(), CellData<2>()); + for (unsigned int i = 0; i < cell_vertices.size(); ++i) + { + for (unsigned int j = 0; j < cell_vertices[i].size(); ++j) + cells[i].vertices[j] = cell_vertices[i][j]; + cells[i].material_id = 0; + } + + // Here we define the boundaries and the corresponding boundary id + // explicitly, based on the vertices that lie on them + SubCellData subcell_data; + subcell_data.boundary_lines.resize(10); + + subcell_data.boundary_lines[0].vertices = {0,1}; + subcell_data.boundary_lines[0].boundary_id = 0; + + subcell_data.boundary_lines[1].vertices = {1,2}; + subcell_data.boundary_lines[1].boundary_id = 0; + + subcell_data.boundary_lines[2].vertices = {2,3}; + subcell_data.boundary_lines[2].boundary_id = 0; + + subcell_data.boundary_lines[3].vertices = {3,4}; + subcell_data.boundary_lines[3].boundary_id = 0; + + subcell_data.boundary_lines[4].vertices = {4,9}; + subcell_data.boundary_lines[4].boundary_id = 3; + + subcell_data.boundary_lines[5].vertices = {9,11}; + subcell_data.boundary_lines[5].boundary_id = 3; + + subcell_data.boundary_lines[6].vertices = {11,13}; + subcell_data.boundary_lines[6].boundary_id = 3; + + subcell_data.boundary_lines[7].vertices = {13,12}; + subcell_data.boundary_lines[7].boundary_id = 1; + + subcell_data.boundary_lines[8].vertices = {12,5}; + subcell_data.boundary_lines[8].boundary_id = 2; + + subcell_data.boundary_lines[9].vertices = {5,0}; + subcell_data.boundary_lines[9].boundary_id = 2; + + GridTools::consistently_order_cells(cells); + + // Then create the actual mesh: + coarse_grid.create_triangulation(vertices, cells, subcell_data); + } + + + // Not allow to be 3D + template <> + void + vanKeken<3>:: + create_coarse_mesh (parallel::distributed::Triangulation<3> &) const + { + Assert (false, ExcNotImplemented()); + } + + + template + std::set + vanKeken:: + get_used_boundary_indicators () const + { + std::set s; + for (unsigned int i=0; i<2*dim; ++i) + s.insert (i); + return s; + } + + + + template <> + std::map + vanKeken<2>:: + get_symbolic_boundary_names_map () const + { + static const std::pair mapping[] + = { std::pair ("bottom", 0), + std::pair ("top", 1), + std::pair ("left", 2), + std::pair ("right", 3) + }; + return std::map (std::begin(mapping), + std::end(mapping)); + } + + template <> + std::map + vanKeken<3>:: + get_symbolic_boundary_names_map () const + { + Assert (false, ExcNotImplemented()); + std::map empty; + return empty; + } + + + + template + double + vanKeken:: + length_scale () const + { + return 1e4; + } + + template + double + vanKeken::depth(const Point &position) const + { + // Get the surface x (,y) point + Point surface_point; + for (unsigned int d=0; d + double + vanKeken::height_above_reference_surface(const Point &) const + { + return 0.0; + } + + + + template + Point + vanKeken::representative_point(const double depth) const + { + Point p; + p(dim-1) = depth; + return p; + } + + + + template + double + vanKeken::maximal_depth() const + { + return 600e3; + } + + + + template + bool + vanKeken::point_is_in_domain(const Point &) const + { + return true; + } + + + template + aspect::Utilities::Coordinates::CoordinateSystem + vanKeken::natural_coordinate_system() const + { + return aspect::Utilities::Coordinates::CoordinateSystem::cartesian; + } + + + + template + void + vanKeken::declare_parameters (ParameterHandler &) + {} + + + + template + void + vanKeken::parse_parameters (ParameterHandler &) + {} + } +} + +// explicit instantiations +namespace aspect +{ + namespace GeometryModel + { + ASPECT_REGISTER_GEOMETRY_MODEL(vanKeken, + "vanKeken box", + "A specialized geometry model used for the van Keken 2008 " + "corner flow style subduction benchmark. While the geometry " + "described by this plugin is just a square, a mesh consisting of non-square cells " + "is required to allow the boundaries of the mesh to lie along " + "the slab-mantle wedge interface, which allows the pressure " + "solution to be continuous." + ) + } +} diff --git a/cookbooks/vankeken_subduction/vankeken_corner_flow.prm.bak b/cookbooks/vankeken_subduction/vankeken_corner_flow.prm.bak new file mode 100644 index 00000000000..67f8fb1fdfc --- /dev/null +++ b/cookbooks/vankeken_subduction/vankeken_corner_flow.prm.bak @@ -0,0 +1,157 @@ +# This is a cookbook which aims to replicate the corner flow style subduction outlined +# in van Keken et al., 2008. In this cookbook, a slab with a thermal age of 50 Myr is +# subducted beneath a 50 km thick overriding plate at a constant dip of 45 degrees. The +# velocity is prescribed to be 5 cm/yr in the subducting plate, and 0 in the overriding +# plate. Due to these constraints, and the way that ASPECT usually generates a mesh, +# a custom mesh is used to prevent an ill-posed pressure solution at the triple point +# intersection between the mantle wedge, overriding plate, and down going plate. + +# Load the prescribed velocity and pressure library +set Additional shared libraries = ./plugin/libvankeken_subduction.so +set Dimension = 2 +set Output directory = vankeken-output +set Use years in output instead of seconds = true +set Pressure normalization = no +set Surface pressure = 0 +set Use conduction timestep = true +set End time = 3.4e8 +set Resume computation = false +set Adiabatic surface temperature = 1600 + +# Turn prescribed velocities on, this is necessary for the subducting +# and overriding plates. +set Prescribe internal velocities = true + +# Solver parameters +subsection Solver parameters + subsection Stokes solver parameters + set Stokes solver type = block AMG + set Maximum number of expensive Stokes solver steps = 1000 + end +end + +# q2q1 discretization +subsection Discretization + set Stokes velocity polynomial degree = 2 + set Use locally conservative discretization = false +end + +# Incompressible +subsection Formulation + set Formulation = Boussinesq approximation +end + +# Use the specialized geometry model for this cookbook +subsection Geometry model + set Model name = vanKeken box +end + +# Checkpoint every 200 steps +subsection Checkpointing + set Steps between checkpoint = 200 +end + +# Prescribe a half space cooling model on the left boundary and in the overriding plate +subsection Initial temperature model + set Model name = function + + subsection Function + set Variable names = x,y,t + + # H is the model Y extent, Hl is the overriding plate thickness, TS is the surface temperature + # T0 is the temperature at the base of the slab + set Function constants = H=6.0e5, Hl=5.0e4, TS=273.0, T0=1573.0, kappa=0.7272e-6, t50=1.5778463e15 + set Function expression = if(x<=(H-y),TS+(T0-TS)*(1.0-erfc( (H-y)/(2.0*sqrt(kappa*t50))) ), \ + if(x>(H-y) & y>(H-Hl), TS+(T0-TS)*(H-y)/Hl, \ + T0 ) ) + end +end + +# Bottom and right boundary is open +subsection Boundary traction model + set Prescribed traction boundary indicators = bottom:zero traction +end + +# Keep the temperature fixed on the left, top and right boundaries +subsection Boundary temperature model + set List of model names = initial temperature + set Fixed temperature boundary indicators = top, left, right +end + +# Prescribe a velocity of 5 cm/yr on the left boundary, 0 on the top +subsection Boundary velocity model + set Prescribed velocity boundary indicators = left: function, top:function + + subsection Function + set Variable names = x,y,t + set Function constants = H=6.01e5, v=0.035355339 + set Function expression = if( x<=(H-y), v, 0.0) ; \ + if( x<=(H-y),-v, 0.0 ) + end +end + +# No gravity +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 0. + end +end + +# Use the visco plastic material model and specify and isoviscous material with +# a viscosiy of 1e20 Pa s +subsection Material model + set Model name = simpler + + subsection Simpler model + set Reference density = 3300.0 + set Thermal expansion coefficient = 0.000035 + set Thermal conductivity = 3.0 + set Viscosity = 1e20 + set Reference specific heat = 1250.0 + end +end + +subsection Mesh refinement + set Initial global refinement = 5 + set Initial adaptive refinement = 0 + set Time steps between mesh refinement = 0 + set Run postprocessors on initial refinement = true + set Refinement fraction = 1.0 + set Coarsening fraction = 0.0 +end + +subsection Prescribed velocities + subsection Indicator function + set Variable names = x,y,t + + # Return where to prescribe u_x; u_y + # 1 if velocity should be prescribed, 0 otherwise + + set Function constants = H=6.0e5, W=6.6e5, de=100 + set Function expression = if( abs(H-y-x)<=de | (y>=601e3 - x & y>=550e3), 1, 0); \ + if( abs(H-y-x)<=de | (y>=601e3 - x & y>=550e3), 1, 0) + end + + subsection Velocity function + set Variable names = x,y,t + + # Return the prescribed u_x; u_y; + set Function constants = H=6.0e5, W=6.6e5, de=100, v=0.035355339, s2yr=31557600 + set Function expression = if(abs(H-y-x)<=de, v/s2yr, 0.0); \ + if(abs(H-y-x)<=de, -v/s2yr, 0.0) + end +end + +# Postprocessing +subsection Postprocess + set List of postprocessors = visualization, temperature statistics, velocity statistics + + subsection Visualization + set List of output variables = density, viscosity, strain rate, stress second invariant, heat flux map, depth + set Output format = vtu + set Interpolate output = true + set Time between graphical output = 1e7 + end +end diff --git a/cookbooks/visualizing_phase_diagram/doc/harzburgite.prm.bak b/cookbooks/visualizing_phase_diagram/doc/harzburgite.prm.bak new file mode 100644 index 00000000000..42ac5feb2bc --- /dev/null +++ b/cookbooks/visualizing_phase_diagram/doc/harzburgite.prm.bak @@ -0,0 +1,9 @@ +# initial composition model +subsection Initial composition model + set List of model names = function + + subsection Function + set Coordinate system = cartesian + set Function expression = 1.0 # change this to one + end +end diff --git a/cookbooks/visualizing_phase_diagram/doc/material_model.prm.bak b/cookbooks/visualizing_phase_diagram/doc/material_model.prm.bak new file mode 100644 index 00000000000..a25c3ad00d5 --- /dev/null +++ b/cookbooks/visualizing_phase_diagram/doc/material_model.prm.bak @@ -0,0 +1,15 @@ +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + set Reference temperature = 273 + set Maximum viscosity = 1e24 + set Phase transition depths = background:410e3|520e3|560e3|670e3|670e3|670e3|670e3, spharz: 410e3|520e3|560e3|670e3|670e3|670e3|670e3 + set Phase transition widths = background:5e3|5e3|5e3|5e3|5e3|5e3|5e3, spharz: 5e3|5e3|5e3|5e3|5e3|5e3|5e3 + set Phase transition temperatures = background:1662.0|1662.0|1662.0|1662.0|1662.0|1662.0|1662.0, spharz: 1662.0|1662.0|1662.0|1662.0|1662.0|1662.0|1662.0 + set Phase transition Clapeyron slopes = background:4e6|4.1e6|4e6|-2e6|4e6|-3.1e6|1.3e6, spharz: 4e6|4.1e6|4e6|-2e6|4e6|-3.1e6|1.3e6 + set Densities = 3300.0 + set Heat capacities = background: 3300.0|3394.4|3442.1|3453.2|3617.6|3691.5|3774.7|3929.1, spharz: 3235.0|3372.3|3441.7|3441.7|3680.8|3717.8|3759.4|3836.6 + set Thermal expansivities = 0.0 + end +end diff --git a/cookbooks/visualizing_phase_diagram/doc/steinberg.prm.bak b/cookbooks/visualizing_phase_diagram/doc/steinberg.prm.bak new file mode 100644 index 00000000000..3c01f3bd620 --- /dev/null +++ b/cookbooks/visualizing_phase_diagram/doc/steinberg.prm.bak @@ -0,0 +1,17 @@ +subsection Material model + set Model name = Steinberger + + subsection Steinberger model + set Data directory = $ASPECT_SOURCE_DIR/data/material-model/steinberger/ + set Lateral viscosity file name = temp-viscosity-prefactor.txt + set Material file names = pyr-ringwood88.txt + set Radial viscosity file name = radial-visc.txt + set Maximum lateral viscosity variation = 1e2 + set Maximum viscosity = 1e23 + set Minimum viscosity = 1e19 + set Use lateral average temperature for viscosity = true + set Number lateral average bands = 10 + set Bilinear interpolation = true + set Latent heat = false + end +end diff --git a/cookbooks/visualizing_phase_diagram/visualizing_phase_diagram.prm.bak b/cookbooks/visualizing_phase_diagram/visualizing_phase_diagram.prm.bak new file mode 100644 index 00000000000..dd7743d98ff --- /dev/null +++ b/cookbooks/visualizing_phase_diagram/visualizing_phase_diagram.prm.bak @@ -0,0 +1,131 @@ +# This prm file is used to generate a phase diagram. +# This could be useful for densities, viscosities in a material model. + +set Dimension = 2 +set CFL number = 1.0 +set End time = 0 +set Adiabatic surface temperature = 1673.0 +set Output directory = output +set Use years in output instead of seconds = true +set Nonlinear solver scheme = no Advection, no Stokes + +# Model geometry +subsection Geometry model + set Model name = box + + subsection Box + set X repetitions = 50 + set Y repetitions = 50 + set X extent = 800e3 + set Y extent = 800e3 + end +end + +# Mesh refinement specifications +subsection Mesh refinement + set Initial adaptive refinement = 0 + set Initial global refinement = 0 + set Time steps between mesh refinement = 0 +end + +subsection Gravity model + set Model name = vertical + + subsection Vertical + set Magnitude = 10.0 + end +end + +# Temperature boundary and initial conditions +subsection Boundary temperature model + set Fixed temperature boundary indicators = left, right + set List of model names = box + + subsection Box + set Left temperature = 273 + set Right temperature = 2273 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Coordinate system = cartesian + set Variable names = x, y + set Function constants = XMAX=800e3, Tl=273.0, Tr=2273 + set Function expression = Tl * (x - XMAX)/(-XMAX) + Tr * x / XMAX + end +end + +# Uncomment this part for Steinberger model and pyrolitic lookup table +#subsection Material model +# set Model name = Steinberger +# subsection Steinberger model +# set Data directory = $ASPECT_SOURCE_DIR/data/material-model/steinberger/ +# set Lateral viscosity file name = temp-viscosity-prefactor.txt +# set Material file names = pyr-ringwood88.txt +# set Radial viscosity file name = radial-visc.txt +# +# set Maximum lateral viscosity variation = 1e2 +# set Maximum viscosity = 1e23 +# set Minimum viscosity = 1e19 +# +# set Use lateral average temperature for viscosity = true +# set Number lateral average bands = 10 +# +# set Bilinear interpolation = true +# set Latent heat = false +# end +#end + +# Comment the following 3 sections for steinberg model and pyrolitic lookup table +# Fields of composition +subsection Compositional fields + set Number of fields = 1 + set Names of fields = spharz + set Compositional field methods = field +end + +# Initial composition model +subsection Initial composition model + set List of model names = function + + subsection Function + set Coordinate system = cartesian + set Function expression = 0.0 + end +end + +# Value for material model +# Set Densities to a constant value and thermal expansivity to 0.0 to have a constant pressure gradient +# Set Values of Heat capacities to values of reference densities of pyrolitic phases +subsection Material model + set Model name = visco plastic + + subsection Visco Plastic + set Reference temperature = 273 + set Maximum viscosity = 1e24 + set Phase transition depths = background:410e3|520e3|560e3|670e3|670e3|670e3|670e3, spharz: 410e3|520e3|560e3|670e3|670e3|670e3|670e3 + set Phase transition widths = background:5e3|5e3|5e3|5e3|5e3|5e3|5e3, spharz: 5e3|5e3|5e3|5e3|5e3|5e3|5e3 + set Phase transition temperatures = background:1662.0|1662.0|1662.0|1662.0|1662.0|1662.0|1662.0, spharz: 1662.0|1662.0|1662.0|1662.0|1662.0|1662.0|1662.0 + set Phase transition Clapeyron slopes = background:4e6|4.1e6|4e6|-2e6|4e6|-3.1e6|1.3e6, spharz: 4e6|4.1e6|4e6|-2e6|4e6|-3.1e6|1.3e6 + set Densities = 3300.0 + set Heat capacities = background: 3300.0|3394.4|3442.1|3453.2|3617.6|3691.5|3774.7|3929.1, spharz: 3235.0|3372.3|3441.7|3441.7|3680.8|3717.8|3759.4|3836.6 + set Thermal expansivities = 0.0 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = top, bottom, left, right +end + +subsection Postprocess + set List of postprocessors = visualization + + subsection Visualization + set Output format = vtu + set List of output variables = density, thermal expansivity, specific heat + set Time between graphical output = 0e6 + end +end diff --git a/doc/logo/logo.prm.bak b/doc/logo/logo.prm.bak new file mode 100644 index 00000000000..6ce430cd233 --- /dev/null +++ b/doc/logo/logo.prm.bak @@ -0,0 +1,111 @@ +# A simple setup for convection in a 2d shell. +# This model was used to generate ASPECT's logo, which can be recreated using +# the ASPECT version and dependencies specified below, and using the paraview +# state file and the output file in output/ and ParaView version 5.8.1. +# Alternatively the docker image gassmoeller/aspect-logo contains this version +# of ASPECT as a precompiled binary. The docker image can be rebuild from the +# Dockerfile in this path. +# +# To recreate the output in paraview, load the state, adjust the file paths, +# and create a screenshot without the mesh with 4x the suggested resolution on +# a 1080p screen (6160 x 3176 px) and with a transparent background. +# For the mesh output disable the background, enable the mesh, and create a +# screenshot with 2x the suggested resolution on a 1080p screen (3080 x 1588 +# px). Then crop the resulting figures to content and use in the .svg. +# +#----------------------------------------------------------------------------- +#-- This is ASPECT, the Advanced Solver for Problems in Earth's ConvecTion. +#-- . version 2.2.0-pre (master, 148bb56fe) +#-- . using deal.II 9.0.1 +#-- . with 32 bit indices and vectorization level 1 (128 bits) +#-- . using Trilinos 12.10.1 +#-- . using p4est 2.0.0 +#-- . running in OPTIMIZED mode +#-- . running with 6 MPI processes +#----------------------------------------------------------------------------- + +set Dimension = 2 +set Use years in output instead of seconds = true +set Output directory = output-logo +set Use conduction timestep = true + +subsection Material model + set Model name = simple + + subsection Simple model + set Thermal expansion coefficient = 4e-5 + set Viscosity = 2e22 + end +end + +subsection Geometry model + set Model name = spherical shell + + subsection Spherical shell + set Inner radius = 3481000 + set Outer radius = 6371000 + set Opening angle = 360 + end +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = bottom, top +end + +subsection Boundary temperature model + set Fixed temperature boundary indicators = top, bottom + set List of model names = constant + + subsection Constant + set Boundary indicator to temperature mappings = \ + top: 273, bottom: 4273 + end +end + +subsection Initial temperature model + set Model name = function + + subsection Function + set Function expression = 1973 + end +end + +subsection Gravity model + set Model name = radial constant +end + +subsection Nullspace removal + set Remove nullspace = net rotation +end + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 2 + set Refinement fraction = 0.6 + set Strategy = temperature + set Time steps between mesh refinement = 3 + set Minimum refinement level = 3 +end + +# We increase the solver tolerance to speed things up +subsection Solver parameters + subsection Stokes solver parameters + set Linear solver tolerance = 1e-3 + end +end + +subsection Postprocess + set List of postprocessors = visualization + + subsection Visualization + set Output format = vtu + set Time between graphical output = 6.51092e8 + set Number of grouped files = 1 + end +end + +subsection Termination criteria + set Checkpoint on termination = true + set Termination criteria = end step + set End step = 1430 +end diff --git a/doc/manual/cookbooks/overview/doc/boundary-conditions.part.prm.bak b/doc/manual/cookbooks/overview/doc/boundary-conditions.part.prm.bak new file mode 100644 index 00000000000..e48524ae495 --- /dev/null +++ b/doc/manual/cookbooks/overview/doc/boundary-conditions.part.prm.bak @@ -0,0 +1,7 @@ +subsection Boundary temperature model + set Fixed temperature boundary indicators = bottom, top +end + +subsection Boundary velocity model + set Tangential velocity boundary indicators = left, right, bottom, top +end diff --git a/doc/manual/cookbooks/overview/doc/dim.part.prm.bak b/doc/manual/cookbooks/overview/doc/dim.part.prm.bak new file mode 100644 index 00000000000..03df82cc72b --- /dev/null +++ b/doc/manual/cookbooks/overview/doc/dim.part.prm.bak @@ -0,0 +1 @@ +set Dimension = 2 diff --git a/doc/manual/cookbooks/overview/doc/geometry.part.prm.bak b/doc/manual/cookbooks/overview/doc/geometry.part.prm.bak new file mode 100644 index 00000000000..2e755469d64 --- /dev/null +++ b/doc/manual/cookbooks/overview/doc/geometry.part.prm.bak @@ -0,0 +1,10 @@ +set Dimension = 2 + +subsection Geometry model + set Model name = box + + subsection Box + set X extent = 1 + set Y extent = 1 + end +end diff --git a/doc/manual/cookbooks/overview/doc/gmg-average.part.prm.bak b/doc/manual/cookbooks/overview/doc/gmg-average.part.prm.bak new file mode 100644 index 00000000000..7cad0231baf --- /dev/null +++ b/doc/manual/cookbooks/overview/doc/gmg-average.part.prm.bak @@ -0,0 +1,3 @@ +subsection Material model + set Material averaging = harmonic average +end diff --git a/doc/manual/cookbooks/overview/doc/gmg-enable.part.prm.bak b/doc/manual/cookbooks/overview/doc/gmg-enable.part.prm.bak new file mode 100644 index 00000000000..e4097ad02cc --- /dev/null +++ b/doc/manual/cookbooks/overview/doc/gmg-enable.part.prm.bak @@ -0,0 +1,5 @@ +subsection Solver parameters + subsection Stokes solver parameters + set Stokes solver type = block GMG + end +end diff --git a/doc/manual/cookbooks/overview/doc/simple.prm.bak b/doc/manual/cookbooks/overview/doc/simple.prm.bak new file mode 100644 index 00000000000..b5eec069e06 --- /dev/null +++ b/doc/manual/cookbooks/overview/doc/simple.prm.bak @@ -0,0 +1,16 @@ +set Dimension = 2 +set End time = 1.5e9 +set Output directory = output + +subsection Geometry model + set Model name = spherical shell +end + +subsection Mesh refinement + set Initial global refinement = 4 + set Initial adaptive refinement = 1 +end + +subsection Postprocess + set List of postprocessors = visualization, velocity statistics, temperature statistics, heat flux statistics, depth average +end diff --git a/doc/manual/cookbooks/overview/doc/structure.part.prm.bak b/doc/manual/cookbooks/overview/doc/structure.part.prm.bak new file mode 100644 index 00000000000..08f98273467 --- /dev/null +++ b/doc/manual/cookbooks/overview/doc/structure.part.prm.bak @@ -0,0 +1,20 @@ +set Dimension = 2 +set Resume computation = false +set End time = 1e10 +set CFL number = 1.0 +set Output directory = output + +subsection Mesh refinement + set Initial adaptive refinement = 1 + set Initial global refinement = 4 +end + +subsection Material model + set Model name = simple + + subsection Simple model + set Reference density = 3300 + set Reference temperature = 293 + set Viscosity = 5e24 + end +end diff --git a/doc/manual/empty.prm.bak b/doc/manual/empty.prm.bak new file mode 100644 index 00000000000..b24c465d5e6 --- /dev/null +++ b/doc/manual/empty.prm.bak @@ -0,0 +1,32 @@ +# this nearly empty .prm is used to generate parameters.tex +# by running aspect. +# sadly we need to set a few where there are no default values: + +set End time = 0.0 + +subsection Geometry model + set Model name = box +end + +subsection Material model + set Model name = simple +end + +subsection Gravity model + set Model name = vertical +end + +subsection Boundary temperature model + set List of model names = box + set Fixed temperature boundary indicators = left, right, bottom, top +end + +subsection Initial temperature model + set Model name = adiabatic +end + +subsection Solver parameters + subsection Stokes solver parameters + set Use direct solver for Stokes system = true + end +end diff --git a/include/aspect/adiabatic_conditions/ascii_data.h.bak b/include/aspect/adiabatic_conditions/ascii_data.h.bak new file mode 100644 index 00000000000..fc9ca54d8e2 --- /dev/null +++ b/include/aspect/adiabatic_conditions/ascii_data.h.bak @@ -0,0 +1,130 @@ +/* + Copyright (C) 2016 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_adiabatic_conditions_ascii_data_h +#define _aspect_adiabatic_conditions_ascii_data_h + + +#include +#include + +#include + + +namespace aspect +{ + namespace AdiabaticConditions + { + using namespace dealii; + + /** + * A simple class that reads adiabatic conditions from a file. + */ + template + class AsciiData : public Utilities::AsciiDataProfile, public Interface + { + public: + /** + * Constructor. Initialize variables. + */ + AsciiData (); + + /** + * Initialization function. Because this function is called after + * initializing the SimulatorAccess, all of the necessary information + * is available to calculate the adiabatic profile. It computes the + * adiabatic conditions along a vertical transect of the geometry + * based on the given material model and other quantities. + */ + void initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataProfile::initialize; + + /** + * Some plugins need to know whether the adiabatic conditions are + * already calculated. This is for example the case for the simple + * compressible material model, which uses the adiabatic temperature + * as reference temperature to calculate the density. For the + * calculation of the adiabatic conditions this functionality is + * simply switched off, because we are always on the reference + * profile. This way the plugin behaves differently at initialization + * time of the adiabatic conditions and during the main model run. + */ + bool is_initialized() const override; + + /** + * Return the adiabatic temperature at a given point of the domain. + */ + double temperature (const Point &p) const override; + + /** + * Return the adiabatic pressure at a given point of the domain. + */ + double pressure (const Point &p) const override; + + /** + * Return the reference density at a given point of the domain. + */ + double density (const Point &p) const override; + + /** + * Return the derivative of the density with respect to depth + * at the given point @p p. + */ + double density_derivative (const Point &p) const override; + + /** + * Declare the parameters for the input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * Whether the adiabatic conditions are already calculated. This is + * important for plugins that are used by the adiabatic conditions but + * also depend on the adiabatic conditions. This way they can behave + * differently in initialization and model run. + */ + bool initialized; + + /** + * The column indices of the temperature, pressure, and density column + * in the data file. + */ + unsigned int temperature_index; + unsigned int pressure_index; + unsigned int density_index; + }; + } +} + + +#endif diff --git a/include/aspect/adiabatic_conditions/compute_entropy_profile.h.bak b/include/aspect/adiabatic_conditions/compute_entropy_profile.h.bak new file mode 100644 index 00000000000..77d6d7a4dc5 --- /dev/null +++ b/include/aspect/adiabatic_conditions/compute_entropy_profile.h.bak @@ -0,0 +1,147 @@ +/* + Copyright (C) 2016 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_adiabatic_conditions_compute_entropy_profile_h +#define _aspect_adiabatic_conditions_compute_entropy_profile_h + + +#include + +namespace aspect +{ + namespace AdiabaticConditions + { + using namespace dealii; + + /** + * A model in which the adiabatic profile is + * calculated by solving the hydrostatic equations for + * pressure and entropy in depth. + * Of course the entropy along an adiabat is constant. + * This plugin requires the material model to provide an + * additional output object of type PrescribedTemperatureOutputs. + * It also requires that there is a compositional field named + * 'entropy' that represents the entropy of the material. + */ + template + class ComputeEntropyProfile : public Interface + { + public: + /** + * Constructor. Initialize variables. + */ + ComputeEntropyProfile (); + + /** + * Initialization function. Because this function is called after + * initializing the SimulatorAccess, all of the necessary information + * is available to calculate the adiabatic profile. It computes the + * adiabatic conditions along a vertical transect of the geometry + * based on the given material model and other quantities. + */ + void initialize () override; + + /** + * Some plugins need to know whether the adiabatic conditions are + * already calculated. This is for example the case for the simple + * compressible material model, which uses the adiabatic temperature + * as reference temperature to calculate the density. For the + * calculation of the adiabatic conditions this functionality is + * simply switched off, because we are always on the reference + * profile. This way the plugin behaves differently at initialization + * time of the adiabatic conditions and during the main model run. + */ + bool is_initialized() const override; + + /** + * Return the adiabatic temperature at a given point of the domain. + */ + double temperature (const Point &p) const override; + + /** + * Return the adiabatic pressure at a given point of the domain. + */ + double pressure (const Point &p) const override; + + /** + * Return the reference density at a given point of the domain. + */ + double density (const Point &p) const override; + + /** + * Return the derivative of the density with respect to depth + * at the given point @p p. + */ + double density_derivative (const Point &p) const override; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Whether the adiabatic conditions are already calculated. This is + * important for plugins that are used by the adiabatic conditions but + * also depend on the adiabatic conditions. This way they can behave + * differently in initialization and model run. + */ + bool initialized; + + /** + * Number of points at which we compute the adiabatic values. + */ + unsigned int n_points; + + /** + * Starting entropy for the profile. + */ + double surface_entropy; + + /** + * Vectors of values of temperatures and pressures on a transect into + * depth at which we have computed them. The public member functions + * of this class interpolate linearly between these points. + */ + std::vector temperatures; + std::vector pressures; + std::vector densities; + + /** + * Interval spacing between each two data points in the tables above + * with regard to the depth coordinate. + */ + double delta_z; + + /** + * Internal helper function. Returns the reference property at a + * given point of the domain. + */ + double get_property (const Point &p, + const std::vector &property) const; + }; + } +} + + +#endif diff --git a/include/aspect/adiabatic_conditions/compute_profile.h.bak b/include/aspect/adiabatic_conditions/compute_profile.h.bak new file mode 100644 index 00000000000..d0d2f01e76b --- /dev/null +++ b/include/aspect/adiabatic_conditions/compute_profile.h.bak @@ -0,0 +1,200 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_adiabatic_conditions_compute_profile_h +#define _aspect_adiabatic_conditions_compute_profile_h + + +#include + +#include + +namespace aspect +{ + namespace AdiabaticConditions + { + using namespace dealii; + + /** + * A model in which the adiabatic profile is calculated by solving the + * hydrostatic equations for pressure and temperature in depth. The + * gravity is assumed to be in depth direction and the composition is + * either given by the initial composition at reference points or computed + * as a reference depth-function. All material parameters are computed by + * the material model plugin. The surface conditions are either constant + * or changing over time as prescribed by an user-provided function. + */ + template + class ComputeProfile : public Interface + { + public: + /** + * Constructor. Initialize variables. + */ + ComputeProfile (); + + /** + * Initialization function. Because this function is called after + * initializing the SimulatorAccess, all of the necessary information + * is available to calculate the adiabatic profile. It computes the + * adiabatic conditions along a vertical transect of the geometry + * based on the given material model and other quantities. + */ + void initialize () override; + + /** + * Update function. By default does nothing, but if a time-dependent + * surface condition function is used, this will reinitialize the + * adiabatic profile with the current conditions. + */ + void update () override; + + /** + * Some plugins need to know whether the adiabatic conditions are + * already calculated. This is for example the case for the simple + * compressible material model, which uses the adiabatic temperature + * as reference temperature to calculate the density. For the + * calculation of the adiabatic conditions this functionality is + * simply switched off, because we are always on the reference + * profile. This way the plugin behaves differently at initialization + * time of the adiabatic conditions and during the main model run. + */ + bool is_initialized() const override; + + /** + * Return the adiabatic temperature at a given point of the domain. + */ + double temperature (const Point &p) const override; + + /** + * Return the adiabatic pressure at a given point of the domain. + */ + double pressure (const Point &p) const override; + + /** + * Return the reference density at a given point of the domain. + */ + double density (const Point &p) const override; + + /** + * Return the derivative of the density with respect to depth + * at the given point @p p. + */ + double density_derivative (const Point &p) const override; + + /** + * Declare the parameters for the input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * Whether the adiabatic conditions are already calculated. This is + * important for plugins that are used by the adiabatic conditions but + * also depend on the adiabatic conditions. This way they can behave + * differently in initialization and model run. + */ + bool initialized; + + /** + * Number of points at which we compute the adiabatic values. + */ + unsigned int n_points; + + /** + * Vectors of values of temperatures and pressures on a transect into + * depth at which we have computed them. The public member functions + * of this class interpolate linearly between these points. + */ + std::vector temperatures; + std::vector pressures; + std::vector densities; + + /** + * Interval spacing between each two data points in the tables above + * with regard to the depth coordinate. + */ + double delta_z; + + /** + * An enum describing the different options to compute the reference + * profile for composition. + */ + enum CompositionProfile + { + initial_composition, + reference_function + }; + + /** + * Selected option to compute the reference profile for composition. + */ + CompositionProfile reference_composition; + + /** + * Function object that computes the reference composition profile + * if the reference_composition variable is set to function. + */ + std::unique_ptr> composition_function; + + /** + * Whether to use the surface_conditions_function to determine surface + * conditions, or the adiabatic_surface_temperature and surface_pressure + * parameters. If this is set to true the reference profile is updated + * every timestep. + */ + bool use_surface_condition_function; + + /** + * ParsedFunction: If provided in the input file it prescribes + * (surface pressure(t), surface temperature(t)). + */ + Functions::ParsedFunction<1> surface_condition_function; + + /** + * A shared pointer to the initial composition object + * that ensures that the current object can continue + * to access the initial composition object beyond the + * first time step. + */ + std::shared_ptr> initial_composition_manager; + + /** + * Internal helper function. Returns the reference property at a + * given point of the domain. + */ + double get_property (const Point &p, + const std::vector &property) const; + }; + } +} + + +#endif diff --git a/include/aspect/adiabatic_conditions/function.h.bak b/include/aspect/adiabatic_conditions/function.h.bak new file mode 100644 index 00000000000..e124766473d --- /dev/null +++ b/include/aspect/adiabatic_conditions/function.h.bak @@ -0,0 +1,107 @@ +/* + Copyright (C) 2016 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_adiabatic_conditions_function_h +#define _aspect_adiabatic_conditions_function_h + + +#include +#include +#include + + +namespace aspect +{ + namespace AdiabaticConditions + { + using namespace dealii; + + /** + * A simple class that sets the adiabatic conditions based on given + * a given function with three components: temperature, pressure, density. + */ + template + class Function : public Interface + { + public: + /** + * Constructor. Initialize variables. + */ + Function (); + + /** + * Initialization function. + */ + void initialize () override; + + /** + * Some plugins need to know whether the adiabatic conditions are + * already calculated, this is always true for the Function class. + */ + bool is_initialized() const override; + + /** + * Return the adiabatic temperature at a given point of the domain. + */ + double temperature (const Point &p) const override; + + + /** + * Return the adiabatic pressure at a given point of the domain. + */ + double pressure (const Point &p) const override; + + /** + * Return the reference_density at a given point of the domain. + */ + double density (const Point &p) const override; + + /** + * Return the derivative of the density with respect to depth + * at the given point @p p. + */ + double density_derivative (const Point &p) const override; + + /** + * Declare the parameters for the input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * ParsedFunction: depth->(temperature, pressure, density) + */ + Functions::ParsedFunction<1> function; + }; + } +} + + +#endif diff --git a/include/aspect/adiabatic_conditions/interface.h.bak b/include/aspect/adiabatic_conditions/interface.h.bak new file mode 100644 index 00000000000..6f662e0bd9b --- /dev/null +++ b/include/aspect/adiabatic_conditions/interface.h.bak @@ -0,0 +1,226 @@ +/* + Copyright (C) 2013 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_adiabatic_conditions_interface_h +#define _aspect_adiabatic_conditions_interface_h + +#include +#include +#include +#include +#include + + +namespace aspect +{ + /** + * A namespace for the definition of things that have to do with describing + * the calculation of a reference adiabatic profile. + * + * @ingroup AdiabaticConditions + */ + namespace AdiabaticConditions + { + using namespace dealii; + + /** + * Base class for classes that describe adiabatic conditions, + * i.e. that starts at the top of the domain and integrate + * pressure and temperature as we go down into depth. There are + * several ways to do this (time-dependent or constant, using + * laterally averaged values or a reference profile), therefore we + * allow for user written plugins. + * + * @ingroup AdiabaticConditions + */ + template + class Interface: public SimulatorAccess, public Plugins::InterfaceBase + { + public: + /** + * Some plugins need to know whether the adiabatic conditions are + * already calculated. Namely all plugins that are needed to create + * the adiabatic conditions but themselves depend on the adiabatic + * profile. Utilizing this function they may behave differently on + * initialization of the adiabatic conditions and at model runtime. + */ + virtual + bool + is_initialized () const = 0; + + /** + * Return the adiabatic temperature at a given point of the domain. + */ + virtual + double temperature (const Point &p) const = 0; + + /** + * Return the adiabatic pressure at a given point of the domain. + */ + virtual + double pressure (const Point &p) const = 0; + + /** + * Return the reference_density at a given point of the domain. + */ + virtual + double density (const Point &p) const = 0; + + /** + * Return the derivative of the density with respect to depth + * at the given point @p p. + */ + virtual + double density_derivative (const Point &p) const = 0; + + /** + * Return the adiabatic temperature profile as a vector of values + * corresponding to increasing depth. + * + * @param values The output vector of depth averaged values. The + * function takes the pre-existing size of this vector as the number + * of depth slices. + * + * @deprecated: This function is deprecated. + * Use the function temperature() for specific positions instead. + */ + DEAL_II_DEPRECATED + virtual + void get_adiabatic_temperature_profile(std::vector &values) const; + + /** + * Like get_adiabatic_temperature_profile() but for the pressure. + * + * @deprecated: This function is deprecated. + * Use the function pressure() for specific positions instead. + */ + DEAL_II_DEPRECATED + virtual + void get_adiabatic_pressure_profile(std::vector &values) const; + + /** + * Like get_adiabatic_temperature_profile() but for the density. + * + * @deprecated: This function is deprecated. + * Use the function density() for specific positions instead. + */ + DEAL_II_DEPRECATED + virtual + void get_adiabatic_density_profile(std::vector &values) const; + + /** + * Like get_adiabatic_temperature_profile() but for the density derivative. + * + * @deprecated: This function is deprecated. + * Use the function density_derivative() for specific positions instead. + */ + DEAL_II_DEPRECATED + virtual + void get_adiabatic_density_derivative_profile(std::vector &values) const; + }; + + + /** + * Register a adiabatic conditions model so that it can be selected from + * the parameter file. + * + * @param name A string that identifies the adiabatic conditions model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this model wants to read from input + * files. + * @param factory_function A pointer to a function that can create an + * object of this adiabatic conditions model. + * + * @ingroup AdiabaticConditions + */ + template + void + register_adiabatic_conditions (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * A function that given the name of a model returns a pointer to an + * object that describes it. Ownership of the pointer is transferred to + * the caller. + * + * The model object returned is not yet initialized and has not read its + * runtime parameters yet. + * + * @ingroup AdiabaticConditions + */ + template + std::unique_ptr> + create_adiabatic_conditions (ParameterHandler &prm); + + + /** + * Declare the runtime parameters of the registered adiabatic conditions + * model. + * + * @ingroup AdiabaticConditions + */ + template + void + declare_parameters (ParameterHandler &prm); + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + template + void + write_plugin_graph (std::ostream &output_stream); + + + /** + * Given a class name, a name, and a description for the parameter file + * for a adiabatic conditions model, register it with the functions that + * can declare their parameters and create these objects. + * + * @ingroup AdiabaticConditions + */ +#define ASPECT_REGISTER_ADIABATIC_CONDITIONS_MODEL(classname, name, description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_ADIABATIC_CONDITIONS_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::AdiabaticConditions::register_adiabatic_conditions<2>, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::AdiabaticConditions::register_adiabatic_conditions<3>, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/boundary_composition/ascii_data.h.bak b/include/aspect/boundary_composition/ascii_data.h.bak new file mode 100644 index 00000000000..cfa883422fe --- /dev/null +++ b/include/aspect/boundary_composition/ascii_data.h.bak @@ -0,0 +1,99 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_composition_ascii_data_h +#define _aspect_boundary_composition_ascii_data_h + +#include + +#include +#include + + +namespace aspect +{ + namespace BoundaryComposition + { + using namespace dealii; + + /** + * A class that implements prescribed boundary conditions determined from + * a AsciiData input file. + * + * @ingroup BoundaryCompositions + */ + template + class AsciiData : public Utilities::AsciiDataBoundary, public Interface + { + public: + /** + * Empty Constructor. + */ + AsciiData (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataBoundary::initialize; + + /** + * A function that is called at the beginning of each time step. For + * the current plugin, this function loads the next data files if + * necessary and outputs a warning if the end of the set of data files + * is reached. + */ + void + update () override; + + /** + * Return the boundary composition as a function of position. For the + * current class, this function returns value from the text files. + * + * @copydoc aspect::BoundaryComposition::Interface::boundary_composition() + */ + double + boundary_composition (const types::boundary_id boundary_indicator, + const Point &position, + const unsigned int compositional_field) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_composition/box.h.bak b/include/aspect/boundary_composition/box.h.bak new file mode 100644 index 00000000000..3e5ea1f3a55 --- /dev/null +++ b/include/aspect/boundary_composition/box.h.bak @@ -0,0 +1,84 @@ +/* + Copyright (C) 2013 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_composition_box_h +#define _aspect_boundary_composition_box_h + +#include +#include + + +namespace aspect +{ + namespace BoundaryComposition + { + /** + * A class that implements a composition boundary condition for a box + * geometry. + * + * @ingroup BoundaryCompositions + */ + template + class Box : public Interface, public SimulatorAccess + { + public: + /** + * This function returns user-defined constant compositions at the + * boundaries. + * + * @copydoc aspect::BoundaryComposition::Interface::boundary_composition() + */ + double boundary_composition (const types::boundary_id boundary_indicator, + const Point &position, + const unsigned int compositional_field) const override; + + /** + * This function performs some basic sanity checks on the parameter + * values previously read from the input file. + */ + void initialize () override; + + /** + * Declare the parameters this class takes through input files. This + * class declares the inner and outer boundary compositions. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The values of the various composition variables on each of the + * 2*dim boundaries of the box. + */ + std::vector composition_values[2*dim]; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_composition/function.h.bak b/include/aspect/boundary_composition/function.h.bak new file mode 100644 index 00000000000..89040ac4563 --- /dev/null +++ b/include/aspect/boundary_composition/function.h.bak @@ -0,0 +1,96 @@ +/* + Copyright (C) 2014 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_boundary_composition_function_h +#define _aspect_boundary_composition_function_h + +#include +#include +#include + +#include + +namespace aspect +{ + namespace BoundaryComposition + { + using namespace dealii; + + /** + * A class that implements boundary composition based on a functional + * description provided in the input file. + * + * @ingroup BoundaryCompositions + */ + template + class Function : public Interface, public SimulatorAccess + { + public: + /** + * Return the boundary composition as a function of position and time. + * + * @copydoc aspect::BoundaryComposition::Interface::boundary_composition() + */ + double boundary_composition (const types::boundary_id boundary_indicator, + const Point &position, + const unsigned int compositional_field) const override; + /** + * A function that is called at the beginning of each time step to + * indicate what the model time is for which the boundary values will + * next be evaluated. For the current class, the function passes to + * the parsed function what the current time is. + */ + void update () override; + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A function object representing the compositional fields. + */ + std::unique_ptr> function; + + /** + * The coordinate representation to evaluate the function. Possible + * choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_composition/initial_composition.h.bak b/include/aspect/boundary_composition/initial_composition.h.bak new file mode 100644 index 00000000000..a40fe81135d --- /dev/null +++ b/include/aspect/boundary_composition/initial_composition.h.bak @@ -0,0 +1,114 @@ +/* + Copyright (C) 2013 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_composition_initial_composition_h +#define _aspect_boundary_composition_initial_composition_h + +#include +#include +#include + + +namespace aspect +{ + namespace BoundaryComposition + { + /** + * A class that implements a composition boundary condition for a + * spherical shell geometry in which the composition at the inner and + * outer surfaces (i.e. at the core-mantle and the + * mantle-lithosphere/atmosphere boundaries) are constant. + * + * @ingroup BoundaryCompositions + */ + template + class InitialComposition : public Interface, public SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run. + * + * This specific function makes sure that the objects that describe + * initial conditions remain available throughout the run of the + * program. + */ + void + initialize () override; + + /** + * This function returns the boundary compositions that are defined + * by the initial conditions. + * + * @copydoc aspect::BoundaryComposition::Interface::boundary_composition() + */ + double boundary_composition (const types::boundary_id boundary_indicator, + const Point &position, + const unsigned int compositional_field) const override; + + /** + * Return the minimal composition on that part of the boundary on + * which Dirichlet conditions are posed. + */ + virtual + double minimal_composition (const std::set &fixed_boundary_ids) const; + + /** + * Return the maximal composition on that part of the boundary on + * which Dirichlet conditions are posed. + */ + virtual + double maximal_composition (const std::set &fixed_boundary_ids) const; + + /** + * Declare the parameters this class takes through input files. This + * class declares the inner and outer boundary compositions. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Compositions at the inner and outer boundaries. + */ + double min_composition; + double max_composition; + + /** + * A shared pointer to the initial composition object + * that ensures that the current object can continue + * to access the initial composition object beyond the + * first time step. + */ + std::shared_ptr> initial_composition; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_composition/interface.h.bak b/include/aspect/boundary_composition/interface.h.bak new file mode 100644 index 00000000000..1d3e2213ad8 --- /dev/null +++ b/include/aspect/boundary_composition/interface.h.bak @@ -0,0 +1,323 @@ +/* + Copyright (C) 2013 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_composition_interface_h +#define _aspect_boundary_composition_interface_h + +#include +#include +#include +#include + +#include +#include + +#include +#include + + +namespace aspect +{ + /** + * A namespace for the definition of things that have to do with describing + * the boundary values for the composition. + * + * @ingroup BoundaryCompositions + */ + namespace BoundaryComposition + { + using namespace dealii; + + /** + * Base class for classes that describe composition boundary values. + * + * @ingroup BoundaryCompositions + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Return the composition that is to hold at a particular position on + * the boundary of the domain. + * + * @param boundary_indicator The boundary indicator of the part of the + * boundary of the domain on which the point is located at which we + * are requesting the composition. + * @param position The position of the point at which we ask for the + * composition. + * @param compositional_field The index of the compositional field + * between 0 and @p parameters.n_compositional_fields. + * @return Boundary value of the compositional field @p + * compositional_field at the position @p position. + */ + virtual + double + boundary_composition (const types::boundary_id boundary_indicator, + const Point &position, + const unsigned int compositional_field) const = 0; + }; + + /** + * A class that manages all boundary composition objects. + * + * @ingroup BoundaryCompositions + */ + template + class Manager : public Plugins::ManagerBase>, public SimulatorAccess + { + public: + /** + * Destructor. Made virtual since this class has virtual member + * functions. + */ + ~Manager () override; + + /** + * A function that is called at the beginning of each time step and + * calls the corresponding functions of all created plugins. + * + * The point of this function is to allow complex boundary composition + * models to do an initialization step once at the beginning of each + * time step. An example would be a model that needs to call an + * external program to compute the composition change at a boundary. + */ + void + update () override; + + /** + * Declare the parameters of all known boundary composition plugins, as + * well as the ones this class has itself. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * This determines which boundary composition objects will be created; + * then let these objects read their parameters as well. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * A function that calls the boundary_composition functions of all the + * individual boundary composition objects and uses the stored operators + * to combine them. + */ + double + boundary_composition (const types::boundary_id boundary_indicator, + const Point &position, + const unsigned int compositional_field) const; + + /** + * A function that is used to register boundary composition objects in such + * a way that the Manager can deal with all of them without having to + * know them by name. This allows the files in which individual + * plugins are implemented to register these plugins, rather than also + * having to modify the Manager class by adding the new boundary + * composition plugin class. + * + * @param name A string that identifies the boundary composition model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this boundary composition model + * wants to read from input files. + * @param factory_function A pointer to a function that can create an + * object of this boundary composition model. + */ + static + void + register_boundary_composition (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + + /** + * Return a list of names of all boundary composition models currently + * used in the computation, as specified in the input file. + */ + const std::vector & + get_active_boundary_composition_names () const; + + /** + * Return a list of pointers to all boundary composition models + * currently used in the computation, as specified in the input file. + */ + const std::list>> & + get_active_boundary_composition_conditions () const; + + /** + * Go through the list of all boundary composition models that have been selected + * in the input file (and are consequently currently active) and return + * true if one of them has the desired type specified by the template + * argument. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,BoundaryCompositionType>::value>> + bool + has_matching_boundary_composition_model () const; + + /** + * Go through the list of all boundary composition models that have been selected + * in the input file (and are consequently currently active) and see + * if one of them has the type specified by the template + * argument or can be cast to that type. If so, return a reference + * to it. If no boundary composition model is active that matches the given type, + * throw an exception. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,BoundaryCompositionType>::value>> + const BoundaryCompositionType & + get_matching_boundary_composition_model () const; + + /* + * Return a set of boundary indicators for which boundary + * compositions are prescribed. + */ + const std::set & + get_fixed_composition_boundary_indicators() const; + + /* + * Return whether Dirichlet boundary conditions will be applied + * on parts of the boundaries where material flows out. + */ + bool + allows_fixed_composition_on_outflow_boundaries() const; + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + + /** + * Exception. + */ + DeclException1 (ExcBoundaryCompositionNameNotFound, + std::string, + << "Could not find entry <" + << arg1 + << "> among the names of registered boundary composition objects."); + private: + /** + * A list of names of boundary composition objects that have been requested + * in the parameter file. + */ + std::vector model_names; + + /** + * A list of enums of boundary composition operators that have been + * requested in the parameter file. Each name is associated + * with a model_name, and is used to modify the composition + * boundary with the values from the current plugin. + */ + std::vector model_operators; + + /** + * A set of boundary ids on which the boundary_composition_objects + * will be applied. + */ + std::set fixed_composition_boundary_indicators; + + /** + * Whether we allow the composition to be fixed on parts of the boundary + * where material flows out of the domain. + */ + bool allow_fixed_composition_on_outflow_boundaries; + }; + + + + template + template + inline + bool + Manager::has_matching_boundary_composition_model () const + { + return this->template has_matching_plugin_object(); + } + + + + template + template + inline + const BoundaryCompositionType & + Manager::get_matching_boundary_composition_model () const + { + return this->template get_matching_plugin_object(); + } + + + + /** + * Return a string that consists of the names of boundary composition models that can + * be selected. These names are separated by a vertical line '|' so + * that the string can be an input to the deal.II classes + * Patterns::Selection or Patterns::MultipleSelection. + */ + template + std::string + get_valid_model_names_pattern (); + + + /** + * Given a class name, a name, and a description for the parameter file + * for a boundary composition model, register it with the functions that + * can declare their parameters and create these objects. + * + * @ingroup BoundaryCompositions + */ +#define ASPECT_REGISTER_BOUNDARY_COMPOSITION_MODEL(classname, name, description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_BOUNDARY_COMPOSITION_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::BoundaryComposition::Manager<2>::register_boundary_composition, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::BoundaryComposition::Manager<3>::register_boundary_composition, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/boundary_composition/spherical_constant.h.bak b/include/aspect/boundary_composition/spherical_constant.h.bak new file mode 100644 index 00000000000..f43e75347fc --- /dev/null +++ b/include/aspect/boundary_composition/spherical_constant.h.bak @@ -0,0 +1,95 @@ +/* + Copyright (C) 2013 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_composition_spherical_constant_h +#define _aspect_boundary_composition_spherical_constant_h + +#include + +#include + + +namespace aspect +{ + namespace BoundaryComposition + { + /** + * A class that implements a composition boundary condition for a + * spherical shell geometry in which the composition at the inner and + * outer surfaces (i.e. at the core-mantle and the + * mantle-lithosphere/atmosphere boundaries) are constant. + * This class works for the sphere, spherical shell, + * chunk and ellipsoidal chunk geometries. + * + * @ingroup BoundaryCompositions + */ + template + class SphericalConstant : public Interface, public SimulatorAccess + { + public: + /** + * Initialize some variables. + */ + void + initialize() override; + + /** + * This function returns the constant compositions read from the + * parameter file for the inner and outer boundaries. + * + * @copydoc aspect::BoundaryComposition::Interface::boundary_composition() + */ + double boundary_composition (const types::boundary_id boundary_indicator, + const Point &position, + const unsigned int compositional_field) const override; + + /** + * Declare the parameters this class takes through input files. This + * class declares the inner and outer boundary compositions. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Compositions at the inner and outer boundaries. + */ + std::vector inner_composition; + std::vector outer_composition; + + /** + * Boundary indicators for the inner and outer boundaries. + */ + types::boundary_id inner_boundary_indicator; + types::boundary_id outer_boundary_indicator; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_composition/two_merged_boxes.h.bak b/include/aspect/boundary_composition/two_merged_boxes.h.bak new file mode 100644 index 00000000000..2044061e5b2 --- /dev/null +++ b/include/aspect/boundary_composition/two_merged_boxes.h.bak @@ -0,0 +1,84 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_composition_two_merged_boxes_h +#define _aspect_boundary_composition_two_merged_boxes_h + +#include +#include + + +namespace aspect +{ + namespace BoundaryComposition + { + /** + * A class that implements a composition boundary condition for a + * box geometry with additional boundary indicators for the + * lithospheric part of the left and right (and front and back in 3D) boundaries. + * + * @ingroup BoundaryCompositions + */ + template + class TwoMergedBoxes : public Interface, public SimulatorAccess + { + public: + /** + * This function returns constant compositions at the boundaries. + * + * @copydoc aspect::BoundaryComposition::Interface::boundary_composition() + */ + double boundary_composition (const types::boundary_id boundary_indicator, + const Point &position, + const unsigned int compositional_field) const override; + + /** + * Declare the parameters this class takes through input files. This + * class declares the inner and outer boundary compositions. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * This function performs some basic sanity checks on the parameter + * values previously read from the input file. + */ + void initialize () override; + + private: + /** + * The values of the various composition variables on each of the + * 2*dim+2*(dim-1) boundaries of the box. + */ + std::vector composition_values[2*dim+2*(dim-1)]; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_fluid_pressure/density.h.bak b/include/aspect/boundary_fluid_pressure/density.h.bak new file mode 100644 index 00000000000..49df8a34b65 --- /dev/null +++ b/include/aspect/boundary_fluid_pressure/density.h.bak @@ -0,0 +1,92 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_fluid_pressure_density_h +#define _aspect_boundary_fluid_pressure_density_h + +#include +#include + + +namespace aspect +{ + namespace BoundaryFluidPressure + { + /** + * A class that implements simple fluid pressure boundary conditions + * based on the fluid or solid density from the material model. + * + * The fluid pressure gradient can either be set to + * $\rho_s \textbf{g}$ (solid density times gravity) or to + * $\rho_f \textbf{g}$ (fluid density times gravity). + * + * @ingroup BoundaryFluidPressures + */ + template + class Density : public Interface, public SimulatorAccess + { + public: + /** + * @copydoc Interface::fluid_pressure_gradient + */ + void fluid_pressure_gradient ( + const types::boundary_id boundary_indicator, + const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + const std::vector> &normal_vectors, + std::vector &fluid_pressure_gradient_outputs + ) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Identify which density to use to compute the fluid pressure + * gradient at the model boundary. + */ + struct DensityFormulation + { + enum Kind + { + solid_density, + fluid_density, + average_density + }; + }; + + typename DensityFormulation::Kind density_formulation; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_fluid_pressure/interface.h.bak b/include/aspect/boundary_fluid_pressure/interface.h.bak new file mode 100644 index 00000000000..0ef7bc96a95 --- /dev/null +++ b/include/aspect/boundary_fluid_pressure/interface.h.bak @@ -0,0 +1,166 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_fluid_pressure_interface_h +#define _aspect_boundary_fluid_pressure_interface_h + +#include +#include + +namespace aspect +{ + /** + * A namespace for the definition of things that have to do with describing + * the boundary values for fluid pressure for computations with melt + * transport. + * + * @ingroup BoundaryFluidPressures + */ + namespace BoundaryFluidPressure + { + using namespace dealii; + + /** + * Base class + * + * @ingroup BoundaryFluidPressures + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Compute the component of the gradient of the fluid pressure + * in the direction normal to a boundary for a list of quadrature + * points. + * + * The return value can typically contain @p material_model_outputs.fluid_densities[q] + * or @p material_model_outputs.densities[q], multiplied by the gravity vector + * and dotted with the normal. + * If the solid density is used, fluid is only flowing in or out due to differences in + * dynamic pressure, if the fluid density is used, melt flows in with the same velocity + * as inflowing solid material. + * + * @param boundary_indicator The boundary indicator of the part of the + * boundary of the domain on which the point is located at which we + * are requesting the fluid pressure gradients. + * @param material_model_inputs The material property inputs. + * @param material_model_outputs The material property outputs. + * @param normal_vectors A normal vector for each point. + * @param fluid_pressure_gradient_outputs Result to be filled. + */ + virtual + void fluid_pressure_gradient ( + const types::boundary_id boundary_indicator, + const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + const std::vector> &normal_vectors, + std::vector &fluid_pressure_gradient_outputs + ) const = 0; + }; + + + /** + * Register a fluid pressure boundary model so that it can be selected from + * the parameter file. + * + * @param name A string that identifies the fluid pressure boundary model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this fluid pressure boundary model + * wants to read from input files. + * @param factory_function A pointer to a function that can create an + * object of this fluid pressure boundary model. + * + * @ingroup BoundaryFluidPressures + */ + template + void + register_boundary_fluid_pressure (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * A function that given the name of a model returns a pointer to an + * object that describes it. Ownership of the pointer is transferred to + * the caller. + * + * The model object returned is not yet initialized and has not + * read its runtime parameters yet. + * + * @ingroup BoundaryFluidPressures + */ + template + std::unique_ptr> + create_boundary_fluid_pressure (ParameterHandler &prm); + + + /** + * Declare the runtime parameters of the registered fluid pressure boundary + * models. + * + * @ingroup BoundaryFluidPressures + */ + template + void + declare_parameters (ParameterHandler &prm); + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + template + void + write_plugin_graph (std::ostream &output_stream); + + + /** + * Given a class name, a name, and a description for the parameter file + * for a fluid pressure boundary model, register it with the functions that + * can declare their parameters and create these objects. + * + * @ingroup BoundaryFluidPressures + */ +#define ASPECT_REGISTER_BOUNDARY_FLUID_PRESSURE_MODEL(classname, name, description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_BOUNDARY_FLUID_PRESSURE_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::BoundaryFluidPressure::register_boundary_fluid_pressure<2>, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::BoundaryFluidPressure::register_boundary_fluid_pressure<3>, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/boundary_heat_flux/function.h.bak b/include/aspect/boundary_heat_flux/function.h.bak new file mode 100644 index 00000000000..ee10be8d535 --- /dev/null +++ b/include/aspect/boundary_heat_flux/function.h.bak @@ -0,0 +1,99 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_heat_flux_function_h +#define _aspect_boundary_heat_flux_function_h + +#include +#include +#include + +#include + +namespace aspect +{ + namespace BoundaryHeatFlux + { + using namespace dealii; + + /** + * A class that implements heat flux boundary conditions based on a + * functional description provided in the input file. + * + * @ingroup BoundaryHeatFlux + */ + template + class Function : public Interface, public SimulatorAccess + { + public: + /** + * Return the boundary heat flux as a function of position. + */ + std::vector> + heat_flux (const types::boundary_id boundary_indicator, + const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + const std::vector> &normal_vectors) const override; + + /** + * A function that is called at the beginning of each time step to + * indicate what the model time is for which the boundary values will + * next be evaluated. For the current class, the function passes to + * the parsed function what the current time is. + */ + void update () override; + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A function object representing the boundary heat flux. + */ + Functions::ParsedFunction boundary_heat_flux_function; + + /** + * The coordinate representation to evaluate the function. Possible + * choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_heat_flux/interface.h.bak b/include/aspect/boundary_heat_flux/interface.h.bak new file mode 100644 index 00000000000..79fe574da6f --- /dev/null +++ b/include/aspect/boundary_heat_flux/interface.h.bak @@ -0,0 +1,158 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_heat_flux_interface_h +#define _aspect_boundary_heat_flux_interface_h + +#include +#include + +namespace aspect +{ + /** + * A namespace for the definition of things that have to do with describing + * the boundary heat flux values. + * + * @ingroup BoundaryHeatFlux + */ + namespace BoundaryHeatFlux + { + using namespace dealii; + + /** + * Base class + * + * @ingroup BoundaryHeatFlux + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Compute the heat flux for a list of quadrature points. + * + * The return value would typically be computed as the product of the thermal + * conductivity @p material_model_outputs.thermal_conductivities[q] and the + * temperature gradient at the boundary. + * + * @param boundary_indicator The boundary indicator of the part of the + * boundary of the domain on which the point is located at which we + * are requesting the fluid pressure gradients. + * @param material_model_inputs The material property inputs. + * @param material_model_outputs The material property outputs. + * @param normal_vectors The normal vector at each quadrature point. + * @return A vector of heat flux vectors at the evaluation points. + */ + virtual + std::vector> + heat_flux (const types::boundary_id boundary_indicator, + const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + const std::vector> &normal_vectors) const = 0; + }; + + + /** + * Register a boundary heat flux model so that it can be selected from + * the parameter file. + * + * @param name A string that identifies the fluid pressure boundary model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this boundary heat flux model + * wants to read from input files. + * @param factory_function A pointer to a function that can create an + * object of this boundary heat flux model. + * + * @ingroup BoundaryHeatFlux + */ + template + void + register_boundary_heat_flux (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * A function that given the name of a model returns a pointer to an + * object that describes it. Ownership of the pointer is transferred to + * the caller. + * + * The model object returned is not yet initialized and has not + * read its runtime parameters yet. + * + * @ingroup BoundaryHeatFlux + */ + template + std::unique_ptr> + create_boundary_heat_flux (ParameterHandler &prm); + + + /** + * Declare the runtime parameters of the registered boundary heat flux + * models. + * + * @ingroup BoundaryHeatFlux + */ + template + void + declare_parameters (ParameterHandler &prm); + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + template + void + write_plugin_graph (std::ostream &output_stream); + + + /** + * Given a class name, a name, and a description for the parameter file + * for a boundary heat flux model, register it with the functions that + * can declare their parameters and create these objects. + * + * @ingroup BoundaryHeatFlux + */ +#define ASPECT_REGISTER_BOUNDARY_HEAT_FLUX_MODEL(classname, name, description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_BOUNDARY_HEAT_FLUX_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::BoundaryHeatFlux::register_boundary_heat_flux<2>, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::BoundaryHeatFlux::register_boundary_heat_flux<3>, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/boundary_temperature/ascii_data.h.bak b/include/aspect/boundary_temperature/ascii_data.h.bak new file mode 100644 index 00000000000..a71860d79b3 --- /dev/null +++ b/include/aspect/boundary_temperature/ascii_data.h.bak @@ -0,0 +1,115 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_temperature_ascii_data_h +#define _aspect_boundary_temperature_ascii_data_h + +#include +#include +#include + + +namespace aspect +{ + namespace BoundaryTemperature + { + using namespace dealii; + + /** + * A class that implements prescribed data boundary conditions determined + * from a AsciiData input file. + * + * @ingroup BoundaryTemperatures + */ + template + class AsciiData : public Utilities::AsciiDataBoundary, public Interface + { + public: + /** + * Empty Constructor. + */ + AsciiData (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataBoundary::initialize; + + /** + * A function that is called at the beginning of each time step. For + * the current plugin, this function loads the next data files if + * necessary and outputs a warning if the end of the set of data files + * is reached. + */ + void update () override; + + /** + * Return the boundary temperature as a function of position. For the + * current class, this function returns value from the text files. + * + * @copydoc aspect::BoundaryTemperature::Interface::boundary_temperature() + */ + double + boundary_temperature (const types::boundary_id boundary_indicator, + const Point &position) const override; + + /** + * Return the minimal the temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double minimal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Return the maximal the temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double maximal_temperature (const std::set &fixed_boundary_ids) const override; + + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_temperature/box.h.bak b/include/aspect/boundary_temperature/box.h.bak new file mode 100644 index 00000000000..425c98d3fbf --- /dev/null +++ b/include/aspect/boundary_temperature/box.h.bak @@ -0,0 +1,91 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_temperature_box_h +#define _aspect_boundary_temperature_box_h + +#include +#include + + +namespace aspect +{ + namespace BoundaryTemperature + { + /** + * A class that implements a temperature boundary condition for a box + * geometry. + * + * @ingroup BoundaryTemperatures + */ + template + class Box : public Interface, public SimulatorAccess + { + public: + /** + * This function returns user-defined constant temperatures at the + * boundaries. + * + * @copydoc aspect::BoundaryTemperature::Interface::boundary_temperature() + */ + double boundary_temperature (const types::boundary_id boundary_indicator, + const Point &position) const override; + + /** + * Return the minimal the temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double minimal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Return the maximal the temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double maximal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Declare the parameters this class takes through input files. This + * class declares the inner and outer boundary temperatures. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + double temperature_[2*dim]; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_temperature/constant.h.bak b/include/aspect/boundary_temperature/constant.h.bak new file mode 100644 index 00000000000..36afaeedd3e --- /dev/null +++ b/include/aspect/boundary_temperature/constant.h.bak @@ -0,0 +1,97 @@ +/* + Copyright (C) 2014 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_temperature_constant_h +#define _aspect_boundary_temperature_constant_h + +#include +#include +#include + + +namespace aspect +{ + namespace BoundaryTemperature + { + /** + * A class that implements a temperature boundary condition for an + * arbitrary geometry, where it returns a constant value for a given + * boundary indicator. Takes an ordered list of temperatures, where the + * position in the list corresponds to the indicator for that temperature. + * + * @ingroup BoundaryTemperatures + */ + template + class Constant : public Interface, public SimulatorAccess + { + public: + /** + * This function returns user-defined constant temperatures at the + * boundaries of arbitrary geometries. + * + * @copydoc aspect::BoundaryTemperature::Interface::boundary_temperature() + */ + double boundary_temperature (const types::boundary_id boundary_indicator, + const Point &position) const override; + + /** + * Return the minimal the temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double minimal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Return the maximal the temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double maximal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Declare the parameters this class takes through input files. This + * class declares the inner and outer boundary temperatures. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Temperatures at the boundaries. + */ + std::map boundary_temperatures; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_temperature/dynamic_core.h.bak b/include/aspect/boundary_temperature/dynamic_core.h.bak new file mode 100644 index 00000000000..ff27245121d --- /dev/null +++ b/include/aspect/boundary_temperature/dynamic_core.h.bak @@ -0,0 +1,517 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + + +#ifndef _aspect_boundary_temperature_dynamic_core_h +#define _aspect_boundary_temperature_dynamic_core_h + +#include +#include + +namespace aspect +{ + namespace BoundaryTemperature + { + + /** + * Data structure for core energy balance calculation + */ + namespace internal + { + struct CoreData + { + /** + * Energy for specific heat, radioactive heating, gravitational contribution, + * adiabatic contribution, and latent heat. These variables are updated each time step. + */ + double Qs,Qr,Qg,Qk,Ql; + + /** + * Entropy for specific heat, radioactive heating, gravitational contribution, + * adiabatic contribution, latent heat, and heat solution. These entropy terms are not + * used for solving the core evolution. However, the total excess entropy + * (dE = Es*dT/dt+Er+El*dR/dt+Eg*dR/dt+Eh*dR/dt-Ek) is useful to determine the core is active or not. + * For dE>0, the core is likely to be active and generating magnetic field. These variables are updated each time step as well. + */ + double Es,Er,Eg,Ek,El,Eh; + + /** + * Parameters for core evolution + * Ri inner core radius + * Ti core-mantle boundary (CMB) temperature + * Xi light component concentration in liquid core + */ + double Ri,Ti,Xi; + + /** + * Core-mantle boundary heat flux (Q) and core radioactive heating rate (H) + */ + double Q,H; + + /** + * Time step for core energy balance solver + */ + double dt; + + /** + * The changing rate of inner core radius, CMB temperature, and light component + * concentration. + */ + double dR_dt,dT_dt,dX_dt; + + /** + * Other energy source into the core + */ + double Q_OES; + + bool is_initialized; + }; + } + + + /** + * A class that implements a temperature boundary condition for a spherical + * shell geometry in which the temperature at the outer surfaces are constant + * and the core-mantle boundaries (CMB) temperature is calculated by core energy balance. + * The formulation of the core energy balance is from \cite NPB+04 . + * @ingroup BoundaryTemperatures + */ + template + class DynamicCore : public Interface, public aspect::SimulatorAccess + { + public: + /** + * Constructor + */ + DynamicCore(); + + /** + * Return the temperature that is to hold at a particular location on the + * boundary of the domain. This function returns the temperatures + * at the inner and outer boundaries. + * + * @param boundary_indicator The boundary indicator of the part of the boundary + * of the domain on which the point is located at which we are requesting the + * temperature. + * @param location The location of the point at which we ask for the temperature. + */ + double boundary_temperature (const types::boundary_id boundary_indicator, + const Point &location) const override; + + /** + * Return the minimal temperature on that part of the boundary + * on which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double minimal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Return the maximal temperature on that part of the boundary + * on which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double maximal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Declare the parameters this class takes through input files. + * This class declares the inner and outer boundary temperatures. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter + * file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * This function update the core-mantle boundary (CMB) temperature by + * the core energy balance solver using the core-mantle boundary heat flux. + */ + void update() override; + + /** + * Pass core data to other modules + */ + const internal::CoreData & + get_core_data() const; + + /** + * Check if other energy source in the core is in use. The 'other energy source' is used for external core energy source. + * For example if someone want to test the early lunar core powered by precession + * (Dwyer, C. A., et al. (2011). "A long-lived lunar dynamo driven by continuous mechanical stirring." Nature 479(7372): 212-214.) + */ + bool + is_OES_used() const; + + + private: + + /** + * Data for core energy balance + * it get updated each time step. + */ + internal::CoreData core_data; + + /** + * Temperature at the inner boundary. + */ + double inner_temperature; + + /** + * Temperatures at the outer boundaries. + */ + double outer_temperature; + + /** + * Initial CMB temperature changing rate + */ + double init_dT_dt; + + /** + * Initial inner core radius changing rate + */ + double init_dR_dt; + + /** + * Initial light composition changing rate + */ + double init_dX_dt; + + /** + * Flag for determining the initial call for update(). + */ + bool is_first_call; + + /** + * Core radius + */ + double Rc; + + /** + * (Heat capacity) * density + */ + double CpRho; + + /** + * Initial light composition concentration + */ + double X_init; + + /** + * Partition coefficient of the light element + */ + double Delta; + + /** + * Gravitational acceleration + */ + double g; + + /** + * Pressure at the core mantle boundary + */ + double P_CMB; + + /** + * Pressure at the center of the core + */ + double P_Core; + + /** + * Parameters for core solidus following: + * if not dependent on composition + * Tm(p)= Tm0*(1-Theta)*(1+Tm1*p+Tm2*p^2) + * if depend on composition X + * Tm(p)= Tm0*(1-Theta*X)*(1+Tm1*p+Tm2*p^2) + */ + double Tm0; + double Tm1; + double Tm2; + double Theta; + bool composition_dependency; + + /** + * If using the Fe-FeS system solidus from Buono & Walker (2011) instead. + */ + bool use_bw11; + + //Variables for formulation of \cite NPB+04 + /** + * Compressibility at zero pressure + */ + double K0; + + /** + * Thermal expansivity + */ + double Alpha; + + /** + * Density at zero pressure + */ + double Rho_0; + + /** + * Density at the center of the planet + */ + double Rho_cen; + + /** + * Latent heat of fusion + */ + double Lh; + + /** + * Heat of reaction + */ + double Rh; + + /** + * Compositional expansion coefficient + */ + double Beta_c; + + /** + * Heat conductivity of the core + */ + double k_c; + + /** + * Heat capacity + */ + double Cp; + + /** + * Number of radioheating element in core + */ + unsigned int n_radioheating_elements; + + /** + * Heating rates of different elements + */ + std::vector heating_rate; + + /** + * Half life of different elements + */ + std::vector half_life; + + /** + * Initial concentration of different elements + */ + std::vector initial_concentration; + + /** + * Two length scales in \cite NPB+04 . + */ + double L; + double D; + + /** + * Mass of the core + */ + double Mc; + + /** + * Max iterations for the core energy balance solver. + */ + int max_steps; + + /** + * Temperature correction value for adiabatic + */ + double dTa; + + /** + * Other energy source into the core, e.g. the mechanical stirring of the moon. + */ + std::string name_OES; + struct str_data_OES + { + double t; + double w; + }; + std::vector data_OES; + void read_data_OES(); + double get_OES(double t) const; + + + + /** + * Solve core energy balance for each time step. + * When solving the change in core-mantle boundary temperature T, inner core radius R, and + * light component (e.g. S, O, Si) composition X, the following relations has to be respected: + * 1. At the inner core boundary the adiabatic temperature should be equal to solidus temperature + * 2. The following energy production rate should be balanced in core: + * Heat flux at core-mantle boundary Q + * Specific heat Qs*dT/dt + * Radioactive heating Qr + * Gravitational contribution Qg*dR/dt + * Latent heat Ql*dR/dt + * So that Q+Qs*dT/dt+Qr+Qg*dR/dt*Ql*dR/dt=0 + * 3. The light component composition X depends on inner core radius (See function get_X() ), + * and core solidus may dependent on X as well. + * This becomes a small nonlinear problem. Directly iterate through the above three equations doesn't + * converge well. Alternatively we solve the inner core radius by bisection method. + * A single solution between fully liquid and fully solid core is expected. Otherwise this function will throw exception and terminate. + * + * At Earth core condition, a inner core is forming at the center of the Earth and surrounded by a liquid outer core. + * However, the core solidus is influenced by light components (e.g. S) and its slope is very closed to core adiabatic. So there is an alternative + * scenario that the crystallization happens first at the core mantle boundary instead of at the center, which is called a 'snowing core' + * (Stewart, A. J., et al. (2007). "Mars: a new core-crystallization regime." Science 316(5829): 1323-1325.). This also + * provides a valid solution for the solver. So the returning bool is set to true for normal core, and false for 'snowing core'. + * TODO: The current code is only able to treat normal core scenario, treating 'snowing core' scenario may be possible and could be added. + */ + bool solve_time_step(double &X, double &T, double &R); + + /** + * Compute the difference between solidus and adiabatic at inner + * core boundary for a given inner core radius. + */ + double get_dT(double r) const; + + /** + * Use energy balance to calculate core mantle boundary temperature + * with a given inner core radius. + */ + double get_Tc(double r) const; + + /** + * Get the solidus temperature at inner core boundary + * with a given inner core radius. + */ + double get_Ts(double r) const; + + /** + * Compute the core solidus at certain pressure + */ + double get_solidus(double X,double p) const; + + /** + * Get initial inner core radius with given initial core mantle temperature. + */ + double get_initial_Ri(double T); + + /** + * Get the light composition concentration in the outer core from given + * inner core radius r + */ + double get_X(double r) const; + + /** + * Compute the mass inside certain radius within the core_data. + */ + double get_Mass(double r) const; + + /** + * Calculate Sn(B,R), referring to \cite NPB+04 . + */ + double fun_Sn(double B,double R,double n) const; + + /** + * Calculate density at given r + */ + double get_Rho(double r) const; + + /** + * Calculate gravitational acceleration at given r + */ + double get_g(double r) const; + + /** + * Calculate the core temperature at given r + * Tc is the temperature at CMB + */ + double get_T(double Tc, double r) const; + + /** + * Calculate pressure at given r + */ + double get_Pressure(double r) const; + + /** + * Calculate the gravitational potential at given r + */ + double get_gravity_potential(double r) const; + + /** + * Calculate energy and entropy change rate factor (regarding the core + * cooling rated Tc/dt) Qs and Es with given core-mantle boundary (CMB) + * temperature Tc + */ + void get_specific_heating(double Tc, double &Qs,double &Es); + + /** + * Calculate energy and entropy change rate factor (regarding the + * radioactive heating rate H) Qr and Er with given CMB temperature Tc + */ + void get_radio_heating(double Tc, double &Qr, double &Er); + + /** + * Calculate energy and entropy change rate factor (regarding the inner core + * growth rate dR/dt) Qg and Eg with given Tc(CMB temperature), r(inner core + * radius), X(light composition concentration) + */ + void get_gravity_heating(double Tc, double r,double X,double &Qg,double &Eg); + + /** + * Calculate energy and entropy change rate factor (regarding the core + * cooling rate Tc/dt) Qk and Ek with given Tc(CMB temperature) + */ + void get_adiabatic_heating(double Tc, double &Ek, double &Qk); + + /** + * Calculate energy and entropy change rate factor (regarding the inner core + * growth rate dR/dt) Ql and El with given Tc(CMB temperature), r(inner core + * radius) + */ + void get_latent_heating(double Tc, double r, double &El, double &Ql); + + /** + * Calculate entropy of heat of solution Eh + */ + void get_heat_solution(double Tc, double r, double X, double &Eh); + + /** + * return radio heating rate at certain time + */ + double get_radioheating_rate() const; + + /** + * Update the data for core dynamic simulation, the data will be used + * in the next timestep and for postprocess. + */ + void update_core_data(); + + }; + } +} + + +#endif diff --git a/include/aspect/boundary_temperature/function.h.bak b/include/aspect/boundary_temperature/function.h.bak new file mode 100644 index 00000000000..d5bc2e49f84 --- /dev/null +++ b/include/aspect/boundary_temperature/function.h.bak @@ -0,0 +1,129 @@ +/* + Copyright (C) 2014 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_temperature_function_h +#define _aspect_boundary_temperature_function_h + +#include +#include +#include + +#include + +namespace aspect +{ + namespace BoundaryTemperature + { + using namespace dealii; + + /** + * A class that implements boundary temperature based on a functional + * description provided in the input file. + * + * @ingroup BoundaryTemperatures + */ + template + class Function : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + Function (); + + /** + * Return the boundary temperature as a function of position and time. + * + * @copydoc aspect::BoundaryTemperature::Interface::boundary_temperature() + */ + double + boundary_temperature (const types::boundary_id boundary_indicator, + const Point &position) const override; + + /** + * A function that is called at the beginning of each time step to + * indicate what the model time is for which the boundary values will + * next be evaluated. For the current class, the function passes to + * the parsed function what the current time is. + */ + void update () override; + + /** + * Return the minimal temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double minimal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Return the maximal temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double maximal_temperature (const std::set &fixed_boundary_ids) const override; + + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A function object representing the temperature. + */ + Functions::ParsedFunction boundary_temperature_function; + + /** + * Temperatures at the inner and outer boundaries. + */ + double min_temperature; + double max_temperature; + + /** + * The coordinate representation to evaluate the function. Possible + * choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_temperature/initial_temperature.h.bak b/include/aspect/boundary_temperature/initial_temperature.h.bak new file mode 100644 index 00000000000..2d6bf322ae3 --- /dev/null +++ b/include/aspect/boundary_temperature/initial_temperature.h.bak @@ -0,0 +1,115 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_temperature_initial_temperature_h +#define _aspect_boundary_temperature_initial_temperature_h + +#include +#include +#include + +namespace aspect +{ + namespace BoundaryTemperature + { + /** + * A class that implements a temperature boundary condition for an + * arbitrary geometry in which the temperature at the boundaries are the + * same as in the initial conditions. + * + * @ingroup BoundaryTemperatures + */ + template + class InitialTemperature : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run. + * + * This specific function makes sure that the objects that describe + * initial conditions remain available throughout the run of the + * program. + */ + void + initialize () override; + + /** + * This function returns the boundary temperatures that are defined + * by the initial conditions. + * + * @copydoc aspect::BoundaryTemperature::Interface::boundary_temperature() + */ + double boundary_temperature (const types::boundary_id boundary_indicator, + const Point &position) const override; + + /** + * Return the minimal the temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double minimal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Return the maximal the temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double maximal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Declare the parameters this class takes through input files. This + * class declares the inner and outer boundary temperatures. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Temperatures at the inner and outer boundaries. + */ + double min_temperature; + double max_temperature; + + /** + * A shared pointer to the initial temperature object + * that ensures that the current object can continue + * to access the initial temperature object beyond the + * first time step. + */ + std::shared_ptr> initial_temperature; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_temperature/interface.h.bak b/include/aspect/boundary_temperature/interface.h.bak new file mode 100644 index 00000000000..7b694b5f515 --- /dev/null +++ b/include/aspect/boundary_temperature/interface.h.bak @@ -0,0 +1,355 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_temperature_interface_h +#define _aspect_boundary_temperature_interface_h + +#include +#include +#include +#include + +#include +#include + +#include +#include + + +namespace aspect +{ + template class SimulatorAccess; + + /** + * A namespace for the definition of things that have to do with describing + * the boundary values for the temperature. + * + * @ingroup BoundaryTemperatures + */ + namespace BoundaryTemperature + { + using namespace dealii; + + /** + * Base class for classes that describe temperature boundary values. + * + * @ingroup BoundaryTemperatures + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Return the temperature that is to hold at a particular position on + * the boundary of the domain. + * + * @param boundary_indicator The boundary indicator of the part of the + * boundary of the domain on which the point is located at which we + * are requesting the temperature. + * @param position The position of the point at which we ask for the + * temperature. + * + * @return Boundary temperature at position @p position. + */ + virtual + double boundary_temperature (const types::boundary_id boundary_indicator, + const Point &position) const = 0; + + /** + * Return the minimal temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + virtual + double minimal_temperature (const std::set &fixed_boundary_ids + = std::set()) const = 0; + + /** + * Return the maximal temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + virtual + double maximal_temperature (const std::set &fixed_boundary_ids + = std::set()) const = 0; + }; + + + /** + * A class that manages all boundary temperature objects. + * + * @ingroup BoundaryTemperatures + */ + template + class Manager : public Plugins::ManagerBase>, public SimulatorAccess + { + public: + /** + * Destructor. Made virtual since this class has virtual member + * functions. + */ + ~Manager () override; + + /** + * A function that is called at the beginning of each time step and + * calls the corresponding functions of all created plugins. + * + * The point of this function is to allow complex boundary temperature + * models to do an initialization step once at the beginning of each + * time step. An example would be a model that needs to call an + * external program to compute the temperature change at a boundary. + */ + void + update () override; + + /** + * Declare the parameters of all known boundary temperature plugins, as + * well as the ones this class has itself. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * This determines which boundary temperature objects will be created; + * then let these objects read their parameters as well. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * A function that calls the boundary_temperature functions of all the + * individual boundary temperature objects and uses the stored operators + * to combine them. + */ + double + boundary_temperature (const types::boundary_id boundary_indicator, + const Point &position) const; + + /** + * Return the minimal temperature of all selected plugins on that + * part of the boundary on which Dirichlet conditions are posed. + */ + double minimal_temperature (const std::set &fixed_boundary_ids + = std::set()) const; + + /** + * Return the maximal temperature of all selected plugins on that + * part of the boundary on which Dirichlet conditions are posed. + */ + double maximal_temperature (const std::set &fixed_boundary_ids + = std::set()) const; + + /** + * A function that is used to register boundary temperature objects in such + * a way that the Manager can deal with all of them without having to + * know them by name. This allows the files in which individual + * plugins are implemented to register these plugins, rather than also + * having to modify the Manager class by adding the new boundary + * temperature plugin class. + * + * @param name A string that identifies the boundary temperature model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this boundary temperature model + * wants to read from input files. + * @param factory_function A pointer to a function that can create an + * object of this boundary temperature model. + */ + static + void + register_boundary_temperature (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + + /** + * Return a list of names of all boundary temperature models currently + * used in the computation, as specified in the input file. + */ + const std::vector & + get_active_boundary_temperature_names () const; + + /** + * Return a list of pointers to all boundary temperature models + * currently used in the computation, as specified in the input file. + */ + const std::list>> & + get_active_boundary_temperature_conditions () const; + + /** + * Go through the list of all boundary temperature models that have been selected + * in the input file (and are consequently currently active) and return + * true if one of them has the desired type specified by the template + * argument. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,BoundaryTemperatureType>::value>> + bool + has_matching_boundary_temperature_model () const; + + /** + * Go through the list of all boundary temperature models that have been selected + * in the input file (and are consequently currently active) and see + * if one of them has the type specified by the template + * argument or can be cast to that type. If so, return a reference + * to it. If no boundary temperature model is active that matches the given type, + * throw an exception. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,BoundaryTemperatureType>::value>> + const BoundaryTemperatureType & + get_matching_boundary_temperature_model () const; + + /* + * Return a set of boundary indicators for which boundary + * temperatures are prescribed. + */ + const std::set & + get_fixed_temperature_boundary_indicators() const; + + /* + * Return whether Dirichlet boundary conditions will be applied + * on parts of the boundaries where material flows out. + */ + bool + allows_fixed_temperature_on_outflow_boundaries() const; + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + + /** + * Exception. + */ + DeclException1 (ExcBoundaryTemperatureNameNotFound, + std::string, + << "Could not find entry <" + << arg1 + << "> among the names of registered boundary temperature objects."); + private: + /** + * A list of names of boundary temperature objects that have been requested + * in the parameter file. + */ + std::vector model_names; + + /** + * A list of enums of boundary temperature operators that have been + * requested in the parameter file. Each name is associated + * with a model_name, and is used to modify the temperature + * boundary with the values from the current plugin. + */ + std::vector model_operators; + + /** + * A set of boundary ids on which the boundary_temperature_objects + * will be applied. + */ + std::set fixed_temperature_boundary_indicators; + + /** + * Whether we allow the temperature to be fixed on parts of the boundary + * where material flows out of the domain. + */ + bool allow_fixed_temperature_on_outflow_boundaries; + }; + + + + template + template + inline + bool + Manager::has_matching_boundary_temperature_model () const + { + return this->template has_matching_plugin_object(); + } + + + template + template + inline + const BoundaryTemperatureType & + Manager::get_matching_boundary_temperature_model () const + { + return this->template get_matching_plugin_object(); + } + + + /** + * Return a string that consists of the names of boundary temperature models that can + * be selected. These names are separated by a vertical line '|' so + * that the string can be an input to the deal.II classes + * Patterns::Selection or Patterns::MultipleSelection. + */ + template + std::string + get_valid_model_names_pattern (); + + + /** + * Given a class name, a name, and a description for the parameter file + * for a boundary temperature model, register it with the functions that + * can declare their parameters and create these objects. + * + * @ingroup BoundaryTemperatures + */ +#define ASPECT_REGISTER_BOUNDARY_TEMPERATURE_MODEL(classname, name, description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_BOUNDARY_TEMPERATURE_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::BoundaryTemperature::Manager<2>::register_boundary_temperature, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::BoundaryTemperature::Manager<3>::register_boundary_temperature, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/boundary_temperature/spherical_constant.h.bak b/include/aspect/boundary_temperature/spherical_constant.h.bak new file mode 100644 index 00000000000..5ff209a774f --- /dev/null +++ b/include/aspect/boundary_temperature/spherical_constant.h.bak @@ -0,0 +1,109 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_temperature_spherical_constant_h +#define _aspect_boundary_temperature_spherical_constant_h + +#include + +#include + +namespace aspect +{ + namespace BoundaryTemperature + { + /** + * A class that implements a temperature boundary condition for a + * spherical shell geometry in which the temperature at the inner and + * outer surfaces (i.e. at the core-mantle and the + * mantle-lithosphere/atmosphere boundaries) are constant. + * + * @ingroup BoundaryTemperatures + */ + template + class SphericalConstant : public Interface, public SimulatorAccess + { + public: + /** + * Initialize some variables. + */ + void + initialize() override; + + /** + * This function returns the constant compositions read from the + * parameter file for the inner and outer boundaries. + * + * @copydoc aspect::BoundaryTemperature::Interface::boundary_temperature() + */ + double boundary_temperature (const types::boundary_id boundary_indicator, + const Point &position) const override; + + /** + * Return the minimal the temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double minimal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Return the maximal the temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double maximal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Declare the parameters this class takes through input files. This + * class declares the inner and outer boundary temperatures. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Temperatures at the inner and outer boundaries. + */ + double inner_temperature; + double outer_temperature; + + /** + * The boundary indicator for the inner and outer boundaries. + */ + types::boundary_id inner_boundary_indicator; + types::boundary_id outer_boundary_indicator; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_temperature/two_merged_boxes.h.bak b/include/aspect/boundary_temperature/two_merged_boxes.h.bak new file mode 100644 index 00000000000..bbbac87ca35 --- /dev/null +++ b/include/aspect/boundary_temperature/two_merged_boxes.h.bak @@ -0,0 +1,96 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_temperature_two_merged_boxes_h +#define _aspect_boundary_temperature_two_merged_boxes_h + +#include + +#include + + +namespace aspect +{ + namespace BoundaryTemperature + { + /** + * A class that implements a temperature boundary condition for a + * box geometry with additional boundary indicators for the + * lithospheric part of left and right (and front and back in 3D) boundaries. + * + * @ingroup BoundaryTemperatures + */ + template + class TwoMergedBoxes : public Interface, public SimulatorAccess + { + public: + /** + * This function returns constant compositions at the boundaries. + * + * @copydoc aspect::BoundaryTemperature::Interface::boundary_temperature() + */ + double boundary_temperature (const types::boundary_id boundary_indicator, + const Point &position) const override; + + /** + * Return the minimal the temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double minimal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Return the maximal the temperature on that part of the boundary on + * which Dirichlet conditions are posed. + * + * This value is used in computing dimensionless numbers such as the + * Nusselt number indicating heat flux. + */ + double maximal_temperature (const std::set &fixed_boundary_ids) const override; + + /** + * Declare the parameters this class takes through input files. This + * class declares the inner and outer boundary temperatures. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The values of the various temperature variables on each of the + * 2*dim+2*(dim-1) boundaries of the box. + */ + double temperature_values[2*dim+2*(dim-1)]; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_traction/ascii_data.h.bak b/include/aspect/boundary_traction/ascii_data.h.bak new file mode 100644 index 00000000000..f6a3b095bd3 --- /dev/null +++ b/include/aspect/boundary_traction/ascii_data.h.bak @@ -0,0 +1,105 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_traction_ascii_data_h +#define _aspect_boundary_traction_ascii_data_h + +#include +#include +#include + +namespace aspect +{ + namespace BoundaryTraction + { + using namespace dealii; + + /** + * A class that implements prescribed traction boundary conditions determined + * from pressures given in an AsciiData input file. + * + * @ingroup BoundaryTractions + */ + template + class AsciiData : public Utilities::AsciiDataBoundary, public Interface + { + public: + /** + * Constructor. + */ + AsciiData (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataBoundary::initialize; + + /** + * Return the boundary traction as a function of position. The + * (outward) normal vector to the domain is also provided as + * a second argument. + */ + Tensor<1,dim> + boundary_traction (const types::boundary_id boundary_indicator, + const Point &position, + const Tensor<1,dim> &normal_vector) const override; + + /** + * A function that is called at the beginning of each time step to + * indicate what the model time is for which the boundary values will + * next be evaluated. For the current class, the function passes to + * the parsed function what the current time is. + */ + void + update () override; + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + std::set boundary_ids; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_traction/function.h.bak b/include/aspect/boundary_traction/function.h.bak new file mode 100644 index 00000000000..bcb2648bd54 --- /dev/null +++ b/include/aspect/boundary_traction/function.h.bak @@ -0,0 +1,112 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_traction_function_h +#define _aspect_boundary_traction_function_h + +#include +#include +#include + +#include + +namespace aspect +{ + namespace BoundaryTraction + { + using namespace dealii; + + /** + * A class that implements traction boundary conditions based on a + * functional description provided in the input file. + * + * @ingroup BoundaryTractions + */ + template + class Function : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + Function (); + + /** + * Return the boundary traction as a function of position. The + * (outward) normal vector to the domain is also provided as + * a second argument. + */ + Tensor<1,dim> + boundary_traction (const types::boundary_id boundary_indicator, + const Point &position, + const Tensor<1,dim> &normal_vector) const override; + + /** + * A function that is called at the beginning of each time step to + * indicate what the model time is for which the boundary values will + * next be evaluated. For the current class, the function passes to + * the parsed function what the current time is. + */ + void + update () override; + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A function object representing the components of the traction. + */ + Functions::ParsedFunction boundary_traction_function; + + /** + * The coordinate representation to evaluate the function. Possible + * choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + + /** + * Whether to specify traction in x, y, z components, or + * r, phi, theta components. + */ + bool use_spherical_unit_vectors; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_traction/initial_lithostatic_pressure.h.bak b/include/aspect/boundary_traction/initial_lithostatic_pressure.h.bak new file mode 100644 index 00000000000..e68df505956 --- /dev/null +++ b/include/aspect/boundary_traction/initial_lithostatic_pressure.h.bak @@ -0,0 +1,126 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_traction_initial_lithospheric_pressure_h +#define _aspect_boundary_traction_initial_lithospheric_pressure_h + +#include +#include + + +namespace aspect +{ + namespace BoundaryTraction + { + using namespace dealii; + + /** + * A class that implements traction boundary conditions by prescribing + * the lithostatic pressure as the normal traction component. + * + * @ingroup BoundaryTractions + */ + template + class InitialLithostaticPressure : public Interface, public SimulatorAccess + { + public: + + /** + * Initialization function. Because this function is called after + * initializing the SimulatorAccess, all of the necessary information + * is available to calculate the pressure profile based on the initial + * temperature and pressure conditions. + */ + void initialize () override; + + + /** + * Return the boundary traction as a function of position. The + * (outward) normal vector to the domain is also provided as + * a second argument. + */ + Tensor<1,dim> + boundary_traction (const types::boundary_id boundary_indicator, + const Point &position, + const Tensor<1,dim> &normal_vector) const override; + + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * The number of integration points. + */ + unsigned int n_points; + + /** + * Depth interval spacing between each two data points in the pressure profile. + */ + double delta_z; + + /* + * The user-specified point where to calculate the pressure profile. + * The vertical coordinate/radius is ignored. + */ + Point representative_point; + + /** + * The computed lithostatic pressure profile. + */ + std::vector pressure; + + /** + * Return the lithostatic pressure at a given point of the domain + * based on depth interpolation between computed pressure values. + */ + double interpolate_pressure (const Point &p) const; + + /** + * The id of the bottom boundary. + */ + types::boundary_id bottom_boundary_id; + + /** + * Whether or not to prescribe the + * largest pressure in the lithostatic pressure + * profile at the bottom boundary independent of + * actual depth. + */ + bool prescribe_constant_pressure_at_bottom_boundary; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_traction/interface.h.bak b/include/aspect/boundary_traction/interface.h.bak new file mode 100644 index 00000000000..cb6cf8c524b --- /dev/null +++ b/include/aspect/boundary_traction/interface.h.bak @@ -0,0 +1,286 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_traction_interface_h +#define _aspect_boundary_traction_interface_h + +#include +#include + +#include +#include + +namespace aspect +{ + /** + * A namespace in which we define everything that has to do with defining + * traction boundary conditions for the Stokes equations. + * + * @ingroup BoundaryTractions + */ + namespace BoundaryTraction + { + using namespace dealii; + + /** + * A base class for parameterizations of traction boundary conditions. + * + * @ingroup BoundaryTractions + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Return the traction that is to hold at a particular position on + * the boundary of the domain. + * + * @param boundary_indicator The boundary indicator of the part of the + * boundary of the domain on which the point is located at which we + * are requesting the traction. + * @param position The position of the point at which we ask for the + * traction. + * @param normal_vector The (outward) normal vector to the boundary + * of the domain. + * + * @return Boundary traction at position @p position. + */ + virtual + Tensor<1,dim> + boundary_traction (const types::boundary_id boundary_indicator, + const Point &position, + const Tensor<1,dim> &normal_vector) const = 0; + }; + + template + class Manager : public SimulatorAccess + { + public: + /** + * Destructor. Made virtual since this class has virtual member + * functions. + */ + ~Manager () override; + + /** + * A function that is called at the beginning of each time step and + * calls the corresponding functions of all created plugins. + * + * The point of this function is to allow complex boundary traction + * models to do an initialization step once at the beginning of each + * time step. An example would be a model that needs to call an + * external program to compute the traction change at a boundary. + */ + virtual + void + update (); + + /** + * A function that calls the boundary_traction functions of all the + * individual boundary traction objects and uses the stored operators + * to combine them. + */ + Tensor<1,dim> + boundary_traction (const types::boundary_id boundary_indicator, + const Point &position, + const Tensor<1,dim> &normal_vector) const; + + /** + * Return the names of all prescribed boundary traction models currently + * used in the computation as specified in the input file. The function + * returns a map between a boundary identifier and a pair. The + * first part of the pair is a string that represents the prescribed + * traction components on this boundary (e.g. y, xz, or xyz) and the + * second part is a vector of strings that represent the names of + * boundary traction plugins for this boundary. + * If there are no prescribed boundary traction plugins + * for a particular boundary, this boundary identifier will not appear + * in the map. + */ + const std::map>> & + get_active_boundary_traction_names () const; + + /** + * Return pointers to all boundary traction models + * currently used in the computation, as specified in the input file. + * The function returns a map between a boundary identifier and a vector + * of unique pointers that represent the names of prescribed traction + * boundary models for this boundary. If there are no prescribed + * boundary traction plugins for a particular boundary this boundary + * identifier will not appear in the map. + */ + const std::map>>> & + get_active_boundary_traction_conditions () const; + + /** + * Declare the parameters of all known boundary traction plugins, as + * well as the ones this class has itself. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * This determines which boundary traction objects will be created; + * then let these objects read their parameters as well. + */ + void + parse_parameters (ParameterHandler &prm); + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + + /** + * Exception. + */ + DeclException1 (ExcBoundaryTractionNameNotFound, + std::string, + << "Could not find entry <" + << arg1 + << "> among the names of registered boundary traction objects."); + + /** + * Register a traction boundary conditions model so that it can be + * selected from the parameter file. + * + * @param name A string that identifies the traction boundary conditions + * model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this traction boundary conditions + * model wants to read from input files. + * @param factory_function A pointer to a function that can create an + * object of this traction boundary conditions model. + * + * @ingroup BoundaryTractions + */ + static + void + register_boundary_traction (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + private: + /** + * A list of boundary traction objects that have been requested in the + * parameter file. + */ + std::map>>> boundary_traction_objects; + + /** + * Map from boundary id to a pair + * ("components", list of "traction boundary type"), + * where components is of the format "[x][y][z]" and the traction type is + * mapped to one of the plugins of traction boundary conditions (e.g. + * "function"). If the components string is empty, it is assumed the + * plugins are used for all components. + */ + std::map>> boundary_traction_indicators; + + }; + + /** + * A function that given the name of a model returns a pointer to an + * object that describes it. Ownership of the pointer is transferred to + * the caller. + * + * The model object returned is not yet initialized and has not + * read its runtime parameters yet. + * + * @ingroup BoundaryTractions + */ + template + std::unique_ptr> + create_boundary_traction (const std::string &name); + + /** + * Return a list of names of all implemented boundary traction models, + * separated by '|' so that it can be used in an object of type + * Patterns::Selection. + */ + template + std::string + get_names (); + + /** + * Declare the runtime parameters of the registered traction boundary + * conditions models. + * + * @ingroup BoundaryTractions + */ + template + void + declare_parameters (ParameterHandler &prm); + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + template + void + write_plugin_graph (std::ostream &output_stream); + + + + /** + * Given a class name, a name, and a description for the parameter file + * for a traction boundary conditions model, register it with the + * functions that can declare their parameters and create these objects. + * + * @ingroup BoundaryTractions + */ +#define ASPECT_REGISTER_BOUNDARY_TRACTION_MODEL(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_BOUNDARY_TRACTION_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::BoundaryTraction::Manager<2>::register_boundary_traction, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::BoundaryTraction::Manager<3>::register_boundary_traction, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/boundary_traction/zero_traction.h.bak b/include/aspect/boundary_traction/zero_traction.h.bak new file mode 100644 index 00000000000..d3aba4229d1 --- /dev/null +++ b/include/aspect/boundary_traction/zero_traction.h.bak @@ -0,0 +1,61 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_traction_zero_traction_h +#define _aspect_boundary_traction_zero_traction_h + +#include + +namespace aspect +{ + namespace BoundaryTraction + { + using namespace dealii; + + /** + * A class that implements zero traction boundary conditions. This + * is equivalent to an open boundary condition in domains where + * hydrostatic pressure is irrelevant. + * + * @ingroup BoundaryTractions + */ + template + class ZeroTraction : public Interface + { + public: + /** + * Return the boundary traction as a function of position. The + * (outward) normal vector to the domain is also provided as + * a second argument. + * + * For the current class, this function obviously simply returns a zero + * tensor. + */ + Tensor<1,dim> + boundary_traction (const types::boundary_id boundary_indicator, + const Point &position, + const Tensor<1,dim> &normal_vector) const override; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_velocity/ascii_data.h.bak b/include/aspect/boundary_velocity/ascii_data.h.bak new file mode 100644 index 00000000000..bc262ac86a4 --- /dev/null +++ b/include/aspect/boundary_velocity/ascii_data.h.bak @@ -0,0 +1,110 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_velocity_ascii_data_h +#define _aspect_boundary_velocity_ascii_data_h + +#include + +#include +#include + + +namespace aspect +{ + namespace BoundaryVelocity + { + using namespace dealii; + + /** + * A class that implements prescribed velocity boundary conditions + * determined from a AsciiData input file. + * + * @ingroup BoundaryVelocities + */ + template + class AsciiData : public Utilities::AsciiDataBoundary, public Interface + { + public: + /** + * Empty Constructor. + */ + AsciiData (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataBoundary::initialize; + + /** + * A function that is called at the beginning of each time step. For + * the current plugin, this function loads the next data files if + * necessary and outputs a warning if the end of the set of data files + * is reached. + */ + void + update () override; + + /** + * Return the boundary velocity as a function of position. For the + * current class, this function returns value from the text files. + */ + Tensor<1,dim> + boundary_velocity (const types::boundary_id boundary_indicator, + const Point &position) const override; + + // avoid -Woverloaded-virtual warning until the deprecated function + // is removed from the interface: + using Interface::boundary_velocity; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + + private: + std::set boundary_ids; + + /** + * Whether to specify velocity in x, y, z components, or + * r, phi, theta components. + */ + bool use_spherical_unit_vectors; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_velocity/function.h.bak b/include/aspect/boundary_velocity/function.h.bak new file mode 100644 index 00000000000..940840de66d --- /dev/null +++ b/include/aspect/boundary_velocity/function.h.bak @@ -0,0 +1,115 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_velocity_function_h +#define _aspect_boundary_velocity_function_h + +#include +#include +#include + +#include + +namespace aspect +{ + namespace BoundaryVelocity + { + using namespace dealii; + + /** + * A class that implements velocity boundary conditions based on a + * functional description provided in the input file. + * + * @ingroup BoundaryVelocities + */ + template + class Function : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + Function (); + + /** + * Return the boundary velocity as a function of position. For the + * current class, this function obviously simply returns a zero + * tensor. + */ + Tensor<1,dim> + boundary_velocity (const types::boundary_id boundary_indicator, + const Point &position) const override; + + // avoid -Woverloaded-virtual warning until the deprecated function + // is removed from the interface: + using Interface::boundary_velocity; + + /** + * A function that is called at the beginning of each time step to + * indicate what the model time is for which the boundary values will + * next be evaluated. For the current class, the function passes to + * the parsed function what the current time is. + */ + void + update () override; + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A function object representing the components of the velocity. + */ + Functions::ParsedFunction boundary_velocity_function; + + /** + * The coordinate representation to evaluate the function. Possible + * choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + + /** + * Whether to specify velocity in x, y, z components, or + * r, phi, theta components. + */ + bool use_spherical_unit_vectors; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_velocity/gplates.h.bak b/include/aspect/boundary_velocity/gplates.h.bak new file mode 100644 index 00000000000..7860576b75f --- /dev/null +++ b/include/aspect/boundary_velocity/gplates.h.bak @@ -0,0 +1,347 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_velocity_gplates_h +#define _aspect_boundary_velocity_gplates_h + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace BoundaryVelocity + { + using namespace dealii; + + namespace internal + { + /** + * GPlatesLookup handles all kinds of tasks around looking up a certain + * velocity boundary condition from a gplates .gpml file. + */ + template + class GPlatesLookup + { + public: + + /** + * Initialize all members and calculates any necessary rotation + * parameters for a 2D model. + */ + GPlatesLookup(const Tensor<1,2> &surface_point_one, + const Tensor<1,2> &surface_point_two); + + /** + * Outputs the GPlates module information at model start. + */ + std::string + screen_output(const Tensor<1,2> &surface_point_one, + const Tensor<1,2> &surface_point_two) const; + + /** + * Loads a gplates .gpml velocity file. Throws an exception if the + * file does not exist. + */ + void load_file(const std::string &filename, + const MPI_Comm comm); + + /** + * Returns the computed surface velocity in cartesian coordinates. + * Takes as input the position. Actual velocity interpolation is + * performed in spherical coordinates. + * + * @param position The current position to compute velocity + */ + Tensor<1,dim> surface_velocity(const Point &position) const; + + private: + /** + * Interpolation functions to access the velocities. + */ + std::array>, 2> velocities; + + /** + * Distances between adjacent point in the Lat/Long grid + */ + double delta_phi, delta_theta; + + /** + * The matrix, which describes the rotation by which a 2D model + * needs to be transformed to a plane that contains the origin and + * the two user prescribed points. Is not necessary and therefore + * not used for 3D models. + */ + Tensor<2,3> rotation_matrix; + + /** + * A function that returns the corresponding paraview angles for a + * rotation described by a rotation matrix. These differ from the + * usually used euler angles by assuming a rotation around the + * coordinate axes in the order y-x-z (instead of the often used + * z-x-z) + */ + std::array + angles_from_matrix (const Tensor<2,3> &rotation_matrix) const; + + /** + * A function that returns the corresponding rotation axis/angle for + * a rotation described by a rotation matrix. + */ + double + rotation_axis_from_matrix (Tensor<1,3> &rotation_axis, + const Tensor<2,3> &rotation_matrix) const; + + /** + * Convert a tensor of rank 1 and dimension in to rank 1 and + * dimension out. If $out < in$ the last elements will be discarded, + * if $out > in$ zeroes will be appended to fill the tensor. + */ + template + Tensor<1,out> convert_tensor (const Tensor<1,in> &old_tensor) const; + + /** + * Return the cartesian coordinates of a spherical surface position + * defined by theta (polar angle, not geographical latitude) and + * phi. + */ + Tensor<1,3> + cartesian_surface_coordinates(const Tensor<1,3> &sposition) const; + + /** + * This function looks up the north- and east-velocities at a given + * position and converts them to cartesian velocities. + */ + Tensor<1,dim> + cartesian_velocity_at_surface_point(const std::array &spherical_point) const; + + /** + * Returns cartesian velocities calculated from surface velocities + * and position in spherical coordinates + * + * @param s_velocities Surface velocities in spherical coordinates + * (theta, phi) + * @param s_position Position in spherical coordinates + * (radius,phi,theta) + */ + Tensor<1,3> sphere_to_cart_velocity(const Tensor<1,2> &s_velocities, + const std::array &s_position) const; + + /** + * Check whether the gpml file was created by GPlates1.4 or later. + * We need to know this, because the mesh has changed its longitude + * origin from 0 to -180 degrees and we need to correct for this. + */ + bool + gplates_1_4_or_higher(const boost::property_tree::ptree &pt) const; + }; + } + + /** + * A class that implements prescribed velocity boundary conditions + * determined from GPlates input files. The interpolation in time is + * performed between two objects of the GPlatesLookup class. + * + * @ingroup BoundaryVelocities + */ + template + class GPlates : public Interface, public SimulatorAccess + { + public: + /** + * Empty Constructor. + */ + GPlates (); + + /** + * Return the boundary velocity as a function of position. For the + * current class, this function returns value from gplates. + */ + Tensor<1,dim> + boundary_velocity (const types::boundary_id boundary_indicator, + const Point &position) const override; + + // avoid -Woverloaded-virtual warning until the deprecated function + // is removed from the interface: + using Interface::boundary_velocity; + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + /** + * A function that is called at the beginning of each time step. For + * the current plugin, this function loads the next velocity files if + * necessary and outputs a warning if the end of the set of velocity + * files is reached. + */ + void + update () override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A variable that stores the currently used data file of a series. It + * gets updated if necessary by update(). + */ + int current_file_number; + + /** + * Time from which on the data file with number 'First data file + * number' is used as boundary condition. Previous to this time, 0 is + * returned for every field. Depending on the setting of the global + * 'Use years in output instead of seconds' flag in the input file, + * this number is either interpreted as seconds or as years." + */ + double first_data_file_model_time; + + /** + * Number of the first data file to be loaded when the model time is + * larger than 'First data file model time'. + */ + int first_data_file_number; + + /** + * In some cases the boundary files are not numbered in increasing but + * in decreasing order (e.g. 'Ma BP'). If this flag is set to 'True' + * the plugin will first load the file with the number 'First data + * file number' and decrease the file number during the model run. + */ + bool decreasing_file_order; + + /** + * Time in model units (depends on other model inputs) between two + * velocity files. + */ + double data_file_time_step; + + /** + * Weight between velocity file n and n+1 while the current time is + * between the two values t(n) and t(n+1). + */ + double time_weight; + + /** + * State whether we have time_dependent boundary conditions. Switched + * off after finding no more velocity files to suppress attempts to read + * in new files. + */ + bool time_dependent; + + /** + * Directory in which the gplates velocity files are present. + */ + std::string data_directory; + + /** + * First part of filename of velocity files. The files have to have + * the pattern velocity_file_name.n.gpml where n is the number of the + * current timestep (starts from 0). + */ + std::string velocity_file_name; + + /** + * Scale the velocity boundary condition by a scalar factor. + */ + double velocity_scaling_factor; + + /** + * Two user defined points that prescribe the plane from which the 2D + * model takes the velocity boundary condition. One can think of this, + * as if the model is lying in this plane although no actual model + * coordinate is changed. The strings need to have the format "a,b" + * where a and b are doubles and define theta and phi on a sphere. + */ + std::string point1; + std::string point2; + + /** + * Parsed user input of point1 and point2 + */ + Tensor<1,2> pointone; + Tensor<1,2> pointtwo; + + /** + * Determines the depth of the lithosphere. The user might want to apply + * the GPlates velocities not only at the surface of the model, but also + * in the whole lithosphere. At every side boundary point with a depth + * smaller than this value (and thus being located in the lithosphere), + * the surface velocity will be described. + */ + double lithosphere_thickness; + + /** + * Pointer to an object that reads and processes data we get from + * gplates files. + */ + std::unique_ptr> lookup; + + /** + * Pointer to an object that reads and processes data we get from + * gplates files. This saves the previous data time step. + */ + std::unique_ptr> old_lookup; + + /** + * Handles the update of the velocity data in lookup. The input + * parameter makes sure that both velocity files (n and n+1) can be + * reloaded if the model time step is larger than the velocity file + * time step. + */ + void + update_data (const bool load_both_files); + + /** + * Handles settings and user notification in case the time-dependent + * part of the boundary condition is over. + */ + void + end_time_dependence (); + + /** + * Create a filename out of the name template. + */ + std::string + create_filename (const int timestep) const; + }; + } +} + + +#endif diff --git a/include/aspect/boundary_velocity/interface.h.bak b/include/aspect/boundary_velocity/interface.h.bak new file mode 100644 index 00000000000..e81c6e6cdfd --- /dev/null +++ b/include/aspect/boundary_velocity/interface.h.bak @@ -0,0 +1,349 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_velocity_interface_h +#define _aspect_boundary_velocity_interface_h + +#include +#include +#include +#include + +#include +#include + +#include +#include + + +namespace aspect +{ + /** + * A namespace in which we define everything that has to do with defining + * the velocity boundary conditions. + * + * @ingroup BoundaryVelocities + */ + namespace BoundaryVelocity + { + using namespace dealii; + + /** + * A base class for parameterizations of velocity boundary conditions. + * + * @ingroup BoundaryVelocities + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Return the velocity that is to hold at a particular position on + * the boundary of the domain. + * + * @param boundary_indicator The boundary indicator of the part of the + * boundary of the domain on which the point is located at which we + * are requesting the velocity. + * @param position The position of the point at which we ask for the + * velocity. + * + * @return Boundary velocity at position @p position. + */ + virtual + Tensor<1,dim> + boundary_velocity (const types::boundary_id boundary_indicator, + const Point &position) const = 0; + }; + + /** + * A class that manages all boundary velocity objects. + * + * @ingroup BoundaryVelocities + */ + template + class Manager : public SimulatorAccess + { + public: + /** + * Destructor. Made virtual since this class has virtual member + * functions. + */ + ~Manager () override; + + /** + * A function that is called at the beginning of each time step and + * calls the corresponding functions of all created plugins. + * + * The point of this function is to allow complex boundary velocity + * models to do an initialization step once at the beginning of each + * time step. An example would be a model that needs to call an + * external program to compute the velocity change at a boundary. + */ + virtual + void + update (); + + /** + * A function that calls the boundary_velocity functions of all the + * individual boundary velocity objects and uses the stored operators + * to combine them. + */ + Tensor<1,dim> + boundary_velocity (const types::boundary_id boundary_indicator, + const Point &position) const; + + /** + * A function that is used to register boundary velocity objects in such + * a way that the Manager can deal with all of them without having to + * know them by name. This allows the files in which individual + * plugins are implemented to register these plugins, rather than also + * having to modify the Manager class by adding the new boundary + * velocity plugin class. + * + * @param name A string that identifies the boundary velocity model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this boundary velocity model + * wants to read from input files. + * @param factory_function A pointer to a function that can create an + * object of this boundary velocity model. + */ + static + void + register_boundary_velocity (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + + /** + * Return the names of all prescribed boundary velocity models currently + * used in the computation as specified in the input file. The function + * returns a map between a boundary identifier and a pair. The + * first part of the pair is a string that represents the prescribed + * velocity components on this boundary (e.g. y, xz, or xyz) and the + * second part is a vector of strings that represent the names of + * boundary velocity plugins for this boundary. + * If there are no prescribed boundary velocity plugins + * for a particular boundary, this boundary identifier will not appear + * in the map. + */ + const std::map>> & + get_active_boundary_velocity_names () const; + + /** + * Return pointers to all boundary velocity models + * currently used in the computation, as specified in the input file. + * The function returns a map between a boundary identifier and a vector + * of unique pointers that represent the names of prescribed velocity + * boundary models for this boundary. If there are no prescribed + * boundary velocity plugins for a particular boundary this boundary + * identifier will not appear in the map. + */ + const std::map>>> & + get_active_boundary_velocity_conditions () const; + + /** + * Return a list of boundary ids on which the velocity is prescribed + * to be zero (no-slip). + */ + const std::set & + get_zero_boundary_velocity_indicators () const; + + /** + * Return a list of boundary ids on which the velocity is prescribed + * to be tangential (free-slip). + */ + const std::set & + get_tangential_boundary_velocity_indicators () const; + + /** + * Declare the parameters of all known boundary velocity plugins, as + * well as the ones this class has itself. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * This determines which boundary velocity objects will be created; + * then let these objects read their parameters as well. + */ + void + parse_parameters (ParameterHandler &prm); + + /** + * Go through the list of all boundary velocity models that have been selected + * in the input file (and are consequently currently active) and return + * true if one of them has the desired type specified by the template + * argument. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,BoundaryVelocityType>::value>> + bool + has_matching_boundary_velocity_model () const; + + /** + * Go through the list of all boundary velocity models that have been selected + * in the input file (and are consequently currently active) and see + * if one of them has the type specified by the template + * argument or can be cast to that type. If so, return a reference + * to it. If no boundary velocity model is active that matches the given type, + * throw an exception. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,BoundaryVelocityType>::value>> + const BoundaryVelocityType & + get_matching_boundary_velocity_model () const; + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + + /** + * Exception. + */ + DeclException1 (ExcBoundaryVelocityNameNotFound, + std::string, + << "Could not find entry <" + << arg1 + << "> among the names of registered boundary velocity objects."); + private: + /** + * A list of boundary velocity objects that have been requested in the + * parameter file. + */ + std::map>>> boundary_velocity_objects; + + /** + * Map from boundary id to a pair + * ("components", list of "velocity boundary type"), + * where components is of the format "[x][y][z]" and the velocity type is + * mapped to one of the plugins of velocity boundary conditions (e.g. + * "function"). If the components string is empty, it is assumed the + * plugins are used for all components. + */ + std::map>> boundary_velocity_indicators; + + /** + * A set of boundary indicators, on which velocities are prescribed to + * zero (no-slip). + */ + std::set zero_velocity_boundary_indicators; + + /** + * A set of boundary indicators, on which velocities are prescribed to + * be tangential (free-slip). + */ + std::set tangential_velocity_boundary_indicators; + }; + + + + template + template + inline + bool + Manager::has_matching_boundary_velocity_model () const + { + for (const auto &boundary : boundary_velocity_objects) + for (const auto &p : boundary.second) + if (Plugins::plugin_type_matches(*p)) + return true; + return false; + } + + + template + template + inline + const BoundaryVelocityType & + Manager::get_matching_boundary_velocity_model () const + { + AssertThrow(has_matching_boundary_velocity_model (), + ExcMessage("You asked BoundaryVelocity::Manager::get_boundary_velocity_model() for a " + "boundary velocity model of type <" + boost::core::demangle(typeid(BoundaryVelocityType).name()) + "> " + "that could not be found in the current model. Activate this " + "boundary velocity model in the input file.")); + + for (const auto &boundary : boundary_velocity_objects) + for (const auto &p : boundary) + if (Plugins::plugin_type_matches(*p)) + return Plugins::get_plugin_as_type(*p); + + // We will never get here, because we had the Assert above. Just to avoid warnings. + return Plugins::get_plugin_as_type(**(boundary_velocity_objects.begin())); + } + + + /** + * Return a string that consists of the names of boundary velocity models that can + * be selected. These names are separated by a vertical line '|' so + * that the string can be an input to the deal.II classes + * Patterns::Selection or Patterns::MultipleSelection. + */ + template + std::string + get_valid_model_names_pattern (); + + + /** + * Given a class name, a name, and a description for the parameter file + * for a boundary velocity model, register it with the functions that + * can declare their parameters and create these objects. + * + * @ingroup BoundaryVelocities + */ +#define ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(classname, name, description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::BoundaryVelocity::Manager<2>::register_boundary_velocity, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::BoundaryVelocity::Manager<3>::register_boundary_velocity, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/boundary_velocity/zero_velocity.h.bak b/include/aspect/boundary_velocity/zero_velocity.h.bak new file mode 100644 index 00000000000..03ddb3f6e86 --- /dev/null +++ b/include/aspect/boundary_velocity/zero_velocity.h.bak @@ -0,0 +1,59 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_boundary_velocity_zero_velocity_h +#define _aspect_boundary_velocity_zero_velocity_h + +#include + +namespace aspect +{ + namespace BoundaryVelocity + { + using namespace dealii; + + /** + * A class that implements zero velocity (stick) boundary conditions. + * + * @ingroup BoundaryVelocities + */ + template + class ZeroVelocity : public Interface + { + public: + /** + * Return the boundary velocity as a function of position. For the + * current class, this function obviously simply returns a zero + * tensor. + */ + Tensor<1,dim> + boundary_velocity (const types::boundary_id boundary_indicator, + const Point &position) const override; + + // avoid -Woverloaded-virtual warning until the deprecated function + // is removed from the interface: + using Interface::boundary_velocity; + }; + } +} + + +#endif diff --git a/include/aspect/citation_info.h.bak b/include/aspect/citation_info.h.bak new file mode 100644 index 00000000000..1514f29b101 --- /dev/null +++ b/include/aspect/citation_info.h.bak @@ -0,0 +1,62 @@ +/* + Copyright (C) 2017 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + +#ifndef _aspect_citation_info_h +#define _aspect_citation_info_h + +#include +#include + +/** + * A namespace to provide information to the user about stuff to cite. + */ +namespace CitationInfo +{ + /** + * Get the URL in the format "citing.html?(parameters)" that describes how to + * cite ASPECT based on the current model you are running. + */ + const std::string get_url_part (); + + /** + * Add the paper identified by the given id to the currently used list of + * papers. See citing.html for the list of ids. For specific features inside + * ASPECT that have associated publications, call this function if the + * feature is used in the current computation. For example, if the + * computation requires melt migration, call add("melt"). + */ + void add (const std::string &id); + + /** + * Print the info text containing the citation info into the given + * stream. + */ + template + void print_info_block (Stream &stream) + { + stream << "-----------------------------------------------------------------------------\n" + << "-- For information on how to cite ASPECT, see:\n" + << "-- https://aspect.geodynamics.org/" << get_url_part() << "\n" + << "-----------------------------------------------------------------------------" + << std::endl; + } +} + +#endif diff --git a/include/aspect/compat.h.bak b/include/aspect/compat.h.bak new file mode 100644 index 00000000000..3ff1642ae4c --- /dev/null +++ b/include/aspect/compat.h.bak @@ -0,0 +1,216 @@ +/* + Copyright (C) 2015 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_compat_h +#define _aspect_compat_h + +#include +// C++11 related includes. +#include +#include +#include + +namespace big_mpi +{ + + using dealii::Utilities::MPI::broadcast; + +} + +// deal.II 9.6 introduces the new MGTransferMF class as a replacement +// for MGTransferMatrixFree. Instead of putting an ifdef in every place, +// do this in one central location: +#if !DEAL_II_VERSION_GTE(9,6,0) +#include +namespace dealii +{ + template + using MGTransferMF = MGTransferMatrixFree; +} +#endif + + + +// deal.II versions up to 9.5 had a poorly designed interface of the +// SphericalManifold class that made it impossible for us to use. +// This file thus contains a copy of it. +#if !DEAL_II_VERSION_GTE(9,6,0) + +#include +#include + +namespace aspect +{ + using namespace dealii; + + /** + * The deal.II class SphericalManifold has a design flaw that made it + * impossible to derive from the class. This is fixed post-9.5, + * see https://github.com/dealii/dealii/pull/16242 and + * https://github.com/dealii/dealii/pull/16248, but we can't + * use deal.II 9.5 and earlier for this class. The current class + * here is therefore a copy of the fixed class. + */ + template + class SphericalManifold : public Manifold + { + public: + /** + * Constructor. + * + * @param[in] center The center of the coordinate system. Defaults to the + * origin. + */ + SphericalManifold(const Point center = Point()); + + /** + * Make a clone of this Manifold object. + */ + virtual std::unique_ptr> + clone() const override; + + /** + * Given any two points in space, first project them on the surface + * of a sphere with unit radius, then connect them with a geodesic + * and find the intermediate point, and finally rescale the final + * radius so that the resulting one is the convex combination of the + * starting radii. + */ + virtual Point + get_intermediate_point(const Point &p1, + const Point &p2, + const double w) const override; + + /** + * Compute the derivative of the get_intermediate_point() function + * with parameter w equal to zero. + */ + virtual Tensor<1, spacedim> + get_tangent_vector(const Point &x1, + const Point &x2) const override; + + /** + * @copydoc Manifold::normal_vector() + */ + virtual Tensor<1, spacedim> + normal_vector( + const typename Triangulation::face_iterator &face, + const Point &p) const override; + + /** + * Compute the normal vectors to the boundary at each vertex. + */ + virtual void + get_normals_at_vertices( + const typename Triangulation::face_iterator &face, + typename Manifold::FaceVertexNormals &face_vertex_normals) + const override; + + /** + * Compute a new set of points that interpolate between the given points @p + * surrounding_points. @p weights is a table with as many columns as @p + * surrounding_points.size(). The number of rows in @p weights must match + * the length of @p new_points. + * + * This function is optimized to perform on a collection + * of new points, by collecting operations that are not dependent on the + * weights outside of the loop over all new points. + * + * The implementation does not allow for @p surrounding_points and + * @p new_points to point to the same array, so make sure to pass different + * objects into the function. + */ + virtual void + get_new_points(const ArrayView> &surrounding_points, + const Table<2, double> &weights, + ArrayView> new_points) const override; + + /** + * Return a point on the spherical manifold which is intermediate + * with respect to the surrounding points. + */ + virtual Point + get_new_point(const ArrayView> &vertices, + const ArrayView &weights) const override; + + /** + * The center of the spherical coordinate system. + */ + const Point center; + + private: + /** + * Return a point on the spherical manifold which is intermediate + * with respect to the surrounding points. This function uses a linear + * average of the directions to find an estimated point. It returns a pair + * of radius and direction from the center point to the candidate point. + */ + std::pair> + guess_new_point(const ArrayView> &directions, + const ArrayView &distances, + const ArrayView &weights) const; + + /** + * This function provides an internal implementation of the get_new_points() + * interface. + * + * It computes a new set of points that interpolate between the given points + * @p + * surrounding_points. @p weights is an array view with as many entries as @p + * surrounding_points.size() times @p new_points.size(). + * + * This function is optimized to perform on a collection + * of new points, by collecting operations that are not dependent on the + * weights outside of the loop over all new points. + * + * The implementation does not allow for @p surrounding_points and + * @p new_points to point to the same array, so make sure to pass different + * objects into the function. + */ + void + do_get_new_points(const ArrayView> &surrounding_points, + const ArrayView &weights, + ArrayView> new_points) const; + + /** + * A manifold description to be used for get_new_point in 2d. + */ + const PolarManifold polar_manifold; + }; +} + +#else + +// For sufficiently new deal.II versions, we can use the deal.II class, but to +// avoid name clashes, we have to import the class into namespace aspect. Once +// we rely on these sufficiently new versions of deal.II, we can not only remove +// the code above, but also the following lines, and in all places where we +// reference 'aspect::SphericalManifold' simply use 'SphericalManifold' instead +// (which then refers to the deal.II class). + +#include +namespace aspect +{ + using dealii::SphericalManifold; +} + +#endif + +#endif diff --git a/include/aspect/coordinate_systems.h.bak b/include/aspect/coordinate_systems.h.bak new file mode 100644 index 00000000000..6e4b5748cff --- /dev/null +++ b/include/aspect/coordinate_systems.h.bak @@ -0,0 +1,52 @@ +/* + Copyright (C) 2018 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . + */ + +#ifndef _aspect_coordinate_systems_h +#define _aspect_coordinate_systems_h + +namespace aspect +{ + namespace Utilities + { + namespace Coordinates + { + /** + * This enum lists available coordinate systems that can be used for + * the function variables. Allowed values are 'cartesian', + * 'spherical', and 'depth'. 'spherical' coordinates follow: r, phi + * (2D) or r, phi, theta (3D); where r is radius, phi is longitude, + * and theta is the polar angle (colatitude). The 'depth' is a + * one-dimensional coordinate system in which only the distance + * below the 'top' surface (depth) as defined by each geometry model, + * is used. + */ + enum CoordinateSystem + { + depth, + cartesian, + spherical, + ellipsoidal, + invalid + }; + } + } +} + +#endif diff --git a/include/aspect/fe_variable_collection.h.bak b/include/aspect/fe_variable_collection.h.bak new file mode 100644 index 00000000000..f98de32db12 --- /dev/null +++ b/include/aspect/fe_variable_collection.h.bak @@ -0,0 +1,288 @@ +/* + Copyright (C) 2016 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_fe_variable_system_h +#define _aspect_fe_variable_system_h + +#include +#include +#include +#include + +namespace aspect +{ + using namespace dealii; + + /** + * A structure to describe everything necessary to define a single variable + * of the finite element system in isolation. It groups the FiniteElement with other + * information like a name and the block structure used in linear systems. A + * std::vector of these structs will be converted into an ordered collection of + * objects of type FEVariable represented by FEVariableCollection to form the + * finite element system. + * + * Blocks are used to extract or solve for certain variables separately or + * in block based preconditioners. As an example, in a Stokes problem one + * might want velocity and pressure in a single block (for use with a direct + * solver), or one block for all velocity components and a second block for + * the pressure (for a Schur complement-based preconditioner), or separate + * blocks for pressure and each velocity component. + */ + template + struct VariableDeclaration + { + /** + * Constructor. + * + * @param name A user-friendly and unique string representation of the variable. + * + * @param fe The FiniteElement class to use. Currently, this needs to be a scalar + * finite element class (with exactly one component). + * + * @param multiplicity Number of copies of the @p fe to create. + * + * @param n_blocks Number of blocks this variable represents inside the + * linear system. A value of 0 will add the next variable (in the std::vector + * that is used to construct the FEVariableCollection) to the current + * block, while 1 will put the next variable into a new block. A value + * that is equal to the number of components will create a block for each + * component. + */ + VariableDeclaration(const std::string &name, + const std::shared_ptr> &fe, + const unsigned int multiplicity, + const unsigned int n_blocks); + + /** + * Default constructor. + */ + VariableDeclaration(); + + /** + * Return the total number of components of this variable. + */ + unsigned int n_components() const; + + /** + * Name of the variable used in FEVariableCollection to identify it. + */ + std::string name; + + /** + * The FiniteElement space. + */ + std::shared_ptr> fe; + + /** + * The multiplicity used in FESystem: how many copies of @p fe are there? + */ + unsigned int multiplicity; + + /** + * Number of linear algebra blocks occupied by this variable. See + * constructor for details. + */ + unsigned int n_blocks; + }; + + /** + * Struct to represent a variable as part of a FEVariableCollection. Constructed + * from an instance of VariableDeclaration but contains additional + * information that can be queried. + */ + template + struct FEVariable: public VariableDeclaration + { + /** + * Initialize this variable as part of a FESystem with the given + * indices for @p component, @p block, and @p base. + */ + FEVariable(const VariableDeclaration &fe_variable, + const unsigned int component_index, + const unsigned int block_index, + const unsigned int base_index); + + /** + * The first component index of this variable within the + * FEVariableCollection. + */ + unsigned int first_component_index; + + /** + * The index of the block of the linear system this variable is + * placed in (within the FEVariableCollection). + */ + unsigned int block_index; + /** + * This index represents the how-manyth variable this is in the + * FEVariableCollection and consequently the FESystem, so the + * + */ + unsigned int base_index; + + /** + * The component mask of this variable. + */ + ComponentMask component_mask; + + /** + * Return a scalar FeValuesExtractor if this variable is scalar. + */ + const FEValuesExtractors::Scalar &extractor_scalar() const; + + /** + * Return a vector FeValuesExtractor if this variable is a vector. + */ + const FEValuesExtractors::Vector &extractor_vector() const; + + private: + /** + * Stores the object returned by extractor_scalar(). + */ + FEValuesExtractors::Scalar scalar_extractor; + + /** + * Stores the object returned by extractor_vector(). + */ + FEValuesExtractors::Vector vector_extractor; + }; + + + /** + * A class that represents a collection of variables (of type FEVariable) to + * form a Finite Element system. A dealii::FESystem can be constructed + * from it using get_fes() and get_multiplicities(). Other information + * contained in this class on top of FESystem are names, and the block + * structure for linear systems. + */ + template + class FEVariableCollection + { + public: + /** + * Construct an empty object. + */ + FEVariableCollection(); + + /** + * Construct object from a vector of variables (identical to calling + * initialize()). + */ + FEVariableCollection(const std::vector> &variable_definitions); + + /** + * Fill this object with the given list of @p variables. + */ + void initialize(const std::vector> &variable_definitions); + + /** + * Return the variable with name @p name. Throws an exception if this + * variable does not exist. If more than one variable with the same name + * exists, return the first one. Use variables_with_name() if you want + * to access all of them. + */ + const FEVariable &variable(const std::string &name) const; + + /** + * Return a vector of pointers of all variables with name @p name. + */ + std::vector*> variables_with_name(const std::string &name) const; + + /** + * Returns true if the variable with @p name exists in the list of + * variables. + */ + bool variable_exists(const std::string &name) const; + + /** + * Return the list of all variables. + */ + const std::vector> &get_variables() const; + + /** + * Return the total number of components in the system. + */ + unsigned int n_components() const; + + /** + * Return the total number of block of the system. + */ + unsigned int n_blocks() const; + + /** + * Return the vector of finite element spaces used for the construction + * of the FESystem. + */ + const std::vector *> &get_fes() const; + + /** + * Return the vector of multiplicities used for the construction of the + * FESystem. + */ + const std::vector &get_multiplicities() const; + + /** + * Return a variable that describes for each vector component which + * vector block it corresponds to. + */ + const std::vector &get_components_to_blocks() const; + + protected: + /** + * A std::vector that contains a collection of variables. + */ + std::vector> variables; + + /** + * Total number of components of all variables, returned by n_components(). + */ + unsigned int n_components_; + + /** + * Total number of blocks of all variables, returned by n_blocks(). + */ + unsigned int n_blocks_; + + /** + * Data to be used in the FESystem constructor. The get_fes() function + * returns a reference to this array. + * + * The pointers stored in this area are not owned by the current object, + * but are instead pointers to the finite elements owned by the elements + * of the `variables` array. As a consequence, we do not need to + * explicitly manage the deallocation of these pointers. + */ + std::vector *> fes; + + /** + * Data to be used in the FESystem constructor, returned by + * get_multiplicities(). + */ + std::vector multiplicities; + + /** + * Mapping from component to block, returned by get_components_to_blocks(). + */ + std::vector components_to_blocks; + }; + +} // namespace aspect + +#endif diff --git a/include/aspect/geometry_model/box.h.bak b/include/aspect/geometry_model/box.h.bak new file mode 100644 index 00000000000..de695292bf5 --- /dev/null +++ b/include/aspect/geometry_model/box.h.bak @@ -0,0 +1,255 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_geometry_model_box_h +#define _aspect_geometry_model_box_h + +#include +#include + + +namespace aspect +{ + namespace GeometryModel + { + using namespace dealii; + + /** + * A class that describes a box geometry of certain width, height, and + * depth (in 3d), and, possibly, topography. + */ + template + class Box : public Interface, public SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run and after + * the SimulatorAccess (if applicable) is initialized. + */ + void initialize () override; + + /** + * Add initial topography to the mesh. + */ + void topography (typename parallel::distributed::Triangulation &grid) const; + + /** + * Relocate the vertical coordinate of the given point based on + * the topography at the surface specified by the initial topography + * model. + */ + Point add_topography (const Point &x_y_z) const; + + /** + * Generate a coarse mesh for the geometry described by this class. + */ + void create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const override; + + /** + * Return a point that denotes the size of the box in each dimension + * of the domain. + */ + virtual + Point get_extents () const; + + /** + * Return an integer array that denotes the number of repetitions of + * the box's coarse mesh. + */ + const std::array & + get_repetitions () const; + + /** + * Return a point that denotes the lower left corner of the box + * domain. + */ + virtual + Point get_origin () const; + + /** + * Return the typical length scale one would expect of features in + * this geometry, assuming realistic parameters. + * + * We return 1/100th of the diameter of the box. + */ + double length_scale () const override; + + + /** + * Return the depth that corresponds to the given + * position. The documentation of the base class (see + * GeometryModel::Interface::depth()) describes in detail how + * "depth" is interpreted in general. + * + * Computing a depth requires a geometry model to define a + * "vertical" direction. The current class considers the + * $(0,1)^T$ vector in 2d (and the $(0,0,1)^T$ vector in 3d) + * as vertical and considers the "top" boundary as the + * surface. In almost all cases one will use a gravity model + * that also matches these definitions. + * + * Note that the depth is calculated with respect to the + * surface without initial topography. + */ + double depth(const Point &position) const override; + + /** + * Return the height of the given position relative to + * the initial box height. + */ + double height_above_reference_surface(const Point &position) const override; + + /** + * @copydoc Interface::representative_point() + */ + Point representative_point(const double depth) const override; + + /** + * @copydoc Interface::maximal_depth() + */ + double maximal_depth() const override; + + /** + * Return the set of boundary indicators that are used by this model. + * This information is used to determine what boundary indicators can + * be used in the input file. + * + * The box model uses boundary indicators zero through 2*dim-1, with + * the first two being the faces perpendicular to the x-axis, the next + * two perpendicular to the y-axis, etc. + */ + std::set + get_used_boundary_indicators () const override; + + /** + * Return a mapping from symbolic names of each part of the boundary + * to the corresponding boundary indicator. This allows users to + * specify *names*, not just *numbers* in their input files when + * describing which parts of the boundary have to satisfy which + * boundary conditions. + * + * This geometry returns the map {{"left"->0}, {"right"->1}, + * {"bottom"->2}, {"top"->3}} in 2d, and {{"left"->0}, + * {"right"->1}, {"front"->2}, {"back"->3}, {"bottom"->4}, + * {"top"->5}} in 3d. + */ + std::map + get_symbolic_boundary_names_map () const override; + + /** + * Return the set of periodic boundaries as described in the input + * file. + */ + std::set, unsigned int>> + get_periodic_boundary_pairs () const override; + + /** + * @copydoc Interface::adjust_positions_for_periodicity + * + * Apply a translation to all points outside of the domain + * to account for periodicity. + */ + void + adjust_positions_for_periodicity (Point &position, + const ArrayView> &connected_positions = {}, + const ArrayView> &connected_velocities = {}) const override; + + /** + * @copydoc Interface::has_curved_elements() + * + * A box has only straight boundaries and cells, so return false. + */ + bool + has_curved_elements() const override; + + /** + * Return whether the given point lies within the domain specified + * by the geometry. This function does not take into account + * initial or dynamic surface topography. + */ + bool + point_is_in_domain(const Point &point) const override; + + /** + * Returns what the natural coordinate system for this geometry model is, + * which for a box is Cartesian. + */ + aspect::Utilities::Coordinates::CoordinateSystem natural_coordinate_system() const override; + + /** + * Takes the Cartesian points (x,z or x,y,z) and returns standardized + * coordinates which are most 'natural' to the geometry model. For a box + * the results is unchanged and is (x,z) in 2d or (x,y,z) in 3d. + */ + std::array cartesian_to_natural_coordinates(const Point &position) const override; + + /** + * Undoes the action of cartesian_to_natural_coordinates, and turns the + * coordinate system which is most 'natural' to the geometry model into + * Cartesian coordinates. + */ + Point natural_to_cartesian_coordinates(const std::array &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A pointer to the initial topography model. + */ + InitialTopographyModel::Interface *topo_model; + + /** + * Extent of the box in x-, y-, and z-direction (in 3d). + */ + Point extents; + + /** + * Origin of the box in x, y, and z (in 3d) coordinates. + */ + Point box_origin; + + /** + * Flag whether the box is periodic in the x-, y-, and z-direction. + */ + std::array periodic; + + /** + * The number of cells in each coordinate direction. + */ + std::array repetitions; + }; + } +} + + +#endif diff --git a/include/aspect/geometry_model/chunk.h.bak b/include/aspect/geometry_model/chunk.h.bak new file mode 100644 index 00000000000..ed34f5801f3 --- /dev/null +++ b/include/aspect/geometry_model/chunk.h.bak @@ -0,0 +1,428 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_geometry_model_chunk_h +#define _aspect_geometry_model_chunk_h + +#include +#include +#include + +#include +#include +#include + +namespace aspect +{ + namespace GeometryModel + { + using namespace dealii; + + namespace internal + { + /** + * ChunkGeometry is a class that implements the interface of + * ChartManifold. The function push_forward takes a point + * in the reference (radius,lon,lat) domain and transforms + * it into real space (cartesian). The inverse function + * pull_back reverses this operation. + * The push_forward_gradient provides derivatives of the + * reference coordinates to the real space coordinates, + * which are used in computing normal vectors. + * The transformations can include topography added + * to the initially radially symmetric mesh. + */ + template + class ChunkGeometry : public ChartManifold + { + public: + /** + * Constructor + */ + ChunkGeometry(const InitialTopographyModel::Interface &topography, + const double min_longitude, + const double min_radius, + const double max_depth); + + /** + * Copy constructor + */ + ChunkGeometry(const ChunkGeometry &other) = default; + + /** + * This function receives a point in cartesian coordinates x, y and z, + * including initial prescribed topography and returns + * radius, longitude, latitude without topography. + */ + Point + pull_back(const Point &space_point) const override; + + /** + * This function receives a point in spherical coordinates + * radius, longitude, latitude and returns cartesian + * coordinates x, y and z, including any initially prescribed + * topography. + */ + Point + push_forward(const Point &chart_point) const override; + + /** + * This function provides the derivatives of the push_forward + * function to the spherical coordinates, which are needed + * in the computation of vectors tangential to the domain boundaries. + */ + DerivativeForm<1, dim, dim> + push_forward_gradient(const Point &chart_point) const override; + + /** + * This function receives a point in cartesian coordinates x, y and z, + * and returns radius, longitude, latitude. + */ + Point + pull_back_sphere(const Point &space_point) const; + + /** + * This function receives a point in spherical coordinates + * radius, longitude, latitude and returns cartesian + * coordinates x, y and z. + */ + Point + push_forward_sphere(const Point &chart_point) const; + + /** + * Return the (normalized) normal vector at the point @p p. + */ + virtual Tensor<1, dim> + normal_vector( + const typename Triangulation::face_iterator &face, + const Point &p) const override; + + /** + * This function computes the outer radius of the domain + * at the longitude (and latitude) of the given point + * (given in cartesian coordinates), i.e. the unperturbed + * outer radius + the topography. + */ + double + get_radius(const Point &space_point) const; + + /** + * Return a copy of this manifold. + */ + std::unique_ptr> + clone() const override; + + private: + /** + * A pointer to the topography model. + */ + const InitialTopographyModel::Interface *topo; + + /** + * The minimum longitude of the domain. + */ + double point1_lon; + + /** + * The inner radius of the domain. + */ + double inner_radius; + + /** + * The maximum depth not taking into account + * topography (outer radius minus inner radius). + */ + double max_depth; + + /** + * This function removes the initial topography from a + * given point in spherical coordinates R+topo, lon, lat. + * I.e. it returns R, lon, lat. + */ + virtual + Point + pull_back_topo(const Point &space_point) const; + + /** + * This function adds the initial topography to a + * given point in spherical coordinates R, lon, lat. + * I.e. it returns R+topo, lon, lat. + */ + virtual + Point + push_forward_topo(const Point &chart_point) const; + }; + } + + /** + * A geometry model class that describes a chunk of a spherical shell. + * In 2D, this class simulates a sector with inner and outer radius, and + * minimum and maximum longitude. Longitude increases anticlockwise + * from the positive x-axis, as per the mathematical convention of phi. + * In 3D, the class simulates a chunk of a sphere, bounded by arbitrary + * lines of longitude, latitude and radius. Boundary indicator names are + * west, east, south, north, inner and outer. + * + * The parameters that describe this geometry and that are read from the + * input file are the inner and outer radii of the shell, the minimum + * and maximum longitude, minimum and maximum longitude, and the + * number of cells initialized in each dimension. + * + * Initial topography can be added through a radial displacement of the + * mesh nodes. + */ + template + class Chunk : public Interface, public SimulatorAccess + { + public: + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run and after + * the SimulatorAccess (if applicable) is initialized. + * This function calls the initialize function of the manifold + * with a pointer to the initial topography model obtained + * from SimulatorAccess. + */ + void initialize () override; + + /** + * Generate a coarse mesh for the geometry described by this class. + */ + void create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const override; + + + /** + * Return the set of boundary indicators that are used by this model. + * This information is used to determine what boundary indicators can + * be used in the input file. + * + * The chunk model uses boundary indicators zero through 2*dim-1, with + * the first two being the faces perpendicular to the radius of the shell, + * the next two along lines of longitude and, in 3d, the next two + * along lines of latitude. + */ + std::set + get_used_boundary_indicators () const override; + + /** + * Return a mapping from symbolic names of each part of the boundary + * to the corresponding boundary indicator. This allows users to + * specify *names*, not just *numbers* in their input files when + * describing which parts of the boundary have to satisfy which + * boundary conditions. + * + * This geometry returns the map {{"bottom"->0}, {"top"->1}, + * {"west"->2}, {"east"->3}} in 2d, and {{"bottom"->0}, + * {"top"->1}, {"west"->2}, {"east"->3}, {"south"->4}, + * {"north"->5}} in 3d. + */ + std::map + get_symbolic_boundary_names_map () const override; + + + /** + * Return the typical length scale one would expect of features in + * this geometry, assuming realistic parameters. + * + * As described in the first ASPECT paper, a length scale of + * 10km = 1e4m works well for the pressure scaling for earth + * sized spherical shells. use a length scale that + * yields this value for the R0,R1 corresponding to earth + * but otherwise scales like (R1-R0) + */ + double length_scale () const override; + + /** + * Return the depth that corresponds to the given + * position. The documentation of the base class (see + * GeometryModel::Interface::depth()) describes in detail how + * "depth" is interpreted in general. + * + * Computing a depth requires a geometry model to define a + * "vertical" direction. The current class considers the + * radial vector away from the origin as vertical and + * considers the "top" boundary as the surface. In almost + * all cases one will use a gravity model that also matches + * these definitions. + */ + double depth(const Point &position) const override; + + /** + * Return the height of the given position relative to the outer + * radius. + */ + double height_above_reference_surface(const Point &position) const override; + + /** + * @copydoc Interface::representative_point() + */ + Point representative_point(const double depth) const override; + + /** + * Return the longitude at the western edge of the chunk measured in + * radians. + */ + virtual + double west_longitude() const; + + /** + * Return the longitude at the eastern edge of the chunk measured in + * radians. + */ + virtual + double east_longitude() const; + + /** + * Return the longitude range of the chunk measured in radians. + */ + virtual + double longitude_range() const; + + /** + * Return the latitude at the southern edge of the chunk measured in + * radians from the equator. + */ + virtual + double south_latitude() const; + + /** + * Return the latitude at the northern edge of the chunk measured in + * radians from the equator. + */ + virtual + double north_latitude() const; + + /** + * Return the latitude range of the chunk measured in radians + */ + virtual + double latitude_range() const; + + /** + * Return the maximum depth from the surface of the model measured in + * meters. + */ + double maximal_depth() const override; + + /** + * Return the inner radius of the chunk measured in meters. + */ + virtual + double inner_radius() const; + + /** + * Return the outer radius of the chunk measured in meters. + */ + virtual + double outer_radius() const; + + + /** + * @copydoc Interface::has_curved_elements() + * + * A chunk has curved boundaries and cells, so return true. + */ + bool + has_curved_elements() const override; + + /** + * Return whether the given point lies within the domain specified + * by the geometry. This function does not take into account + * initial or dynamic surface topography. + */ + bool + point_is_in_domain(const Point &point) const override; + + /** + * Returns what the natural coordinate system for this geometry model is, + * which for a chunk is Spherical. + */ + aspect::Utilities::Coordinates::CoordinateSystem natural_coordinate_system() const override; + + /** + * Takes the Cartesian points (x,z or x,y,z) and returns standardized + * coordinates which are most 'natural' to the geometry model. For a chunk + * this is (radius, longitude) in 2d and (radius, longitude, latitude) in 3d. + */ + std::array cartesian_to_natural_coordinates(const Point &position) const override; + + /** + * Undoes the action of cartesian_to_natural_coordinates, and turns the + * coordinate system which is most 'natural' to the geometry model into + * Cartesian coordinates. + */ + Point natural_to_cartesian_coordinates(const std::array &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Minimum longitude-depth or + * longitude-latitude-depth point + */ + Point point1; + + /** + * Maximum longitude-depth or + * longitude-latitude-depth point + */ + Point point2; + + /** + * The number of cells in each coordinate direction + */ + std::array repetitions; + + /** + * An object that describes the geometry. This pointer is + * initialized in the initialize() function, and serves as the manifold + * object that the triangulation is later given in create_coarse_mesh() + * where the triangulation clones it. + * + * The object is marked as 'const' to make it clear that it should not + * be modified once created. That is because the triangulation copies it, + * and modifying the current object will not have any impact on the + * manifold used by the triangulation. + */ + std::unique_ptr> manifold; + + /** + * Give a symbolic name to the manifold id to be used by this class. + */ + static const types::manifold_id my_manifold_id = 15; + }; + } +} + + +#endif diff --git a/include/aspect/geometry_model/ellipsoidal_chunk.h.bak b/include/aspect/geometry_model/ellipsoidal_chunk.h.bak new file mode 100644 index 00000000000..516162ddfad --- /dev/null +++ b/include/aspect/geometry_model/ellipsoidal_chunk.h.bak @@ -0,0 +1,346 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_geometry_model_ellipsoidal_chunk_h +#define _aspect_geometry_model_ellipsoidal_chunk_h + +#include +#include +#include +#include + + +namespace aspect +{ + namespace GeometryModel + { + using namespace dealii; + + namespace internal + { + /** + * A class which describes the manifold. + */ + template + class EllipsoidalChunkGeometry : public ChartManifold + { + public: + /** + * Constructor + */ + EllipsoidalChunkGeometry(const InitialTopographyModel::Interface &topography, + const double para_semi_major_axis_a, + const double para_eccentricity, + const double para_semi_minor_axis_b, + const double para_bottom_depth, + const std::vector> ¶_corners); + + /** + * Copy constructor + */ + EllipsoidalChunkGeometry(const EllipsoidalChunkGeometry &other) = default; + + /** + * The deal.ii pull back function in 3d. This function receives + * cartesian points x,y and z and returns spherical/ellipsoidal + * coordinates phi, theta and depth, also accounting for the + * topography. + */ + Point<3> + pull_back(const Point<3> &space_point) const override; + + /** + * The deal.ii pull back function in 2d. This function should + * not be used, until the TODO in the cc file has been fixed. + */ + virtual + Point<2> + pull_back(const Point<2> &space_point) const; + + /** + * The deal.ii push forward function in 3d. This function receives + * spherical/ellipsoidal coordinates phi, theta and depth and + * returns cartesian points x,y and z, also accounting for the + * topography. + */ + Point<3> + push_forward(const Point<3> &chart_point) const override; + + /** + * This function does the actual pull back from the ellipsoid. + * For the equation details, please see deal.ii step 53. + */ + Point<3> pull_back_ellipsoid (const Point<3> &x, const double semi_major_axis_a, const double eccentricity) const; + + /** + * This function does the actual push forward to the ellipsoid. + * For the equation details, please see deal.ii step 53. + */ + Point<3> push_forward_ellipsoid (const Point<3> &phi_theta_d, const double semi_major_axis_a, const double eccentricity) const; + + /** + * Return a copy of this manifold. + */ + std::unique_ptr> + clone() const override; + + private: + /** + * This function adds topography to the cartesian coordinates. + * For the equation details, please see deal.ii step 53. + */ + Point<3> push_forward_topography (const Point<3> &phi_theta_d_hat) const; + + /** + * This function removes topography from the cartesian coordinates. + * For the equation details, please see deal.ii step 53. + */ + Point<3> pull_back_topography (const Point<3> &phi_theta_d) const; + + /** + * A pointer to the topography model. + */ + const InitialTopographyModel::Interface *topography; + + const double semi_major_axis_a; + const double eccentricity; + const double semi_minor_axis_b; + const double bottom_depth; + const std::vector> corners; + }; + } + + /** + * A class that describes a geometry for an ellipsoid such as the WGS84 model of the earth. + * + * This geometry model implements a (3d) ellipsoidal chunk geometry where two of the axis have + * the same length. The ellipsoidal chunk can be a non-coordinate parallel part of the ellipsoid. + * + * @author This plugin is a joined effort of Menno Fraters, D. Sarah Stamps and Wolfgang Bangerth + */ + template + class EllipsoidalChunk : public Interface, public SimulatorAccess + { + public: + /** + * Initialize function + */ + void + initialize () override; + + + /** + * Generate a coarse mesh for the geometry described by this class. + */ + void + create_coarse_mesh(parallel::distributed::Triangulation &coarse_grid) const override; + + /** + * Return the typical length scale one would expect of features in this geometry, + * assuming realistic parameters. + */ + double + length_scale() const override; + + /** + * Return the depth that corresponds to the given + * position. The documentation of the base class (see + * GeometryModel::Interface::depth()) describes in detail how + * "depth" is interpreted in general. + * + * Computing a depth requires a geometry model to define a + * "vertical" direction. The current class considers the + * radial vector away from the origin as vertical and + * considers the "outer" boundary as the "surface". In almost + * all cases one will use a gravity model that also matches + * these definitions. + */ + double + depth(const Point &position) const override; + + /** + * Placeholder for a function returning the height of the given + * position relative to the reference model surface. + */ + double + height_above_reference_surface(const Point &position) const override; + + /** + * Returns a point in the center of the domain. + */ + Point + representative_point(const double depth) const override; + + /** + * Return whether the given point lies within the domain specified + * by the geometry. This function does not take into account + * initial or dynamic surface topography. + */ + bool + point_is_in_domain(const Point &point) const override; + + /** + * Returns the bottom depth which was used to create the geometry and + * which is defined by the depth parameter. + */ + double + maximal_depth() const override; + + /** + * Return the set of boundary indicators that are used by this model. This + * information is used to determine what boundary indicators can be used in + * the input file. + * + * The box model uses boundary indicators zero through 2*dim-1, with the first + * two being the faces perpendicular to the x-axis, the next two perpendicular + * to the y-axis, etc. + */ + std::set + get_used_boundary_indicators() const override; + + /** + * Set symbolic names for boundaries (mrtf) + */ + std::map + get_symbolic_boundary_names_map() const override; + + /** + * Returns what the natural coordinate system for this geometry model is, + * which for a Ellipsoidal chunk is Ellipsoidal. + */ + aspect::Utilities::Coordinates::CoordinateSystem natural_coordinate_system() const override; + + /** + * Takes the Cartesian points (x,z or x,y,z) and returns standardized + * coordinates which are most 'natural' to the geometry model. For a + * ellipsoidal chunk this is (radius, longitude) in 2d and (radius, + * longitude, latitude) in 3d. Note that internally the coordinates are + * stored in longitude, latitude, depth. + */ + std::array cartesian_to_natural_coordinates(const Point &position) const override; + + /** + * Undoes the action of cartesian_to_natural_coordinates, and turns the + * coordinate system which is most 'natural' to the geometry model into + * Cartesian coordinates. + */ + Point natural_to_cartesian_coordinates(const std::array &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters(ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter + * file. + */ + void + parse_parameters(ParameterHandler &prm) override; + + /** + * Calculate radius at current position. + */ + double + get_radius(const Point &position) const; + + /** + * Retrieve the semi minor axis b value. + */ + double + get_semi_minor_axis_b() const; + + /** + * Retrieve the semi major axis a value. + */ + double + get_semi_major_axis_a() const; + + + /** + * Retrieve the value of the eccentricity. + */ + double + get_eccentricity() const; + + + /** + * Retrieve the corners used to create the ellipsoid. This variable + * contains four vectors with each two elements. Each set of two + * elements represents a longitude and latitude value. The four + * vectors represent respectively the point in the North-East, + * North-West, South-West and South-East. + */ + const std::vector> & + get_corners() const; + + + /** + * Retrieve the manifold object. + */ + internal::EllipsoidalChunkGeometry + get_manifold() const; + + private: + // Declare variables for reading in coordinates of the region of interest. + std::vector> corners; + double semi_major_axis_a; + double eccentricity; + double semi_minor_axis_b; + double rot_para_to_para_angle; + double para_to_rect_angle; + double rotation_longitude; + double rotation_latitude; + double bottom_depth; + double westLongitude; + double eastLongitude; + double northLatitude; + double southLatitude; + // Declare variables for subdividing + unsigned int EW_subdiv; + unsigned int NS_subdiv; + unsigned int depth_subdiv; + + + + /** + * An object that describes the geometry. This pointer is + * initialized in the initialize() function, and serves as the manifold + * object that the triangulation is later given in create_coarse_mesh() + * where the triangulation clones it. + * + * The object is marked as 'const' to make it clear that it should not + * be modified once created. That is because the triangulation copies it, + * and modifying the current object will not have any impact on the + * manifold used by the triangulation. + */ + std::unique_ptr> manifold; + + void + set_boundary_ids(parallel::distributed::Triangulation &coarse_grid) const; + }; + } +} + + +#endif diff --git a/include/aspect/geometry_model/initial_topography_model/ascii_data.h.bak b/include/aspect/geometry_model/initial_topography_model/ascii_data.h.bak new file mode 100644 index 00000000000..8481e1c29e7 --- /dev/null +++ b/include/aspect/geometry_model/initial_topography_model/ascii_data.h.bak @@ -0,0 +1,103 @@ +/* + Copyright (C) 2016 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_geometry_model_initial_topography_model_ascii_data_h +#define _aspect_geometry_model_initial_topography_model_ascii_data_h + +#include +#include +#include + + +namespace aspect +{ + namespace InitialTopographyModel + { + using namespace dealii; + + /** + * A class that implements topography determined + * from an AsciiData input file. + * + * @ingroup InitialTopographyModel + */ + template + class AsciiData : public Utilities::AsciiDataBoundary, public Interface + { + public: + /** + * Empty Constructor. + */ + AsciiData (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Sets the boundary id of the surface boundary. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataBoundary::initialize; + + + /** + * Return the surface topography as a function of position along the surface. + * For the current class, this function returns a value from the text files. + * + * @copydoc aspect::InitialTopographyModel::Interface::value() + */ + double + value (const Point &surface_point) const override; + + /** + * Return the maximum value of the elevation. + */ + double max_topography () const override; + + /** + * Return the gradient of the surface topography for a given position + * along the surface. + */ + Tensor<1,dim-1> + vector_gradient(const Point &p) const; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + types::boundary_id surface_boundary_id; + }; + } +} + + +#endif diff --git a/include/aspect/geometry_model/initial_topography_model/function.h.bak b/include/aspect/geometry_model/initial_topography_model/function.h.bak new file mode 100644 index 00000000000..7b7421e0e00 --- /dev/null +++ b/include/aspect/geometry_model/initial_topography_model/function.h.bak @@ -0,0 +1,93 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_geometry_model_initial_topography_model_function_h +#define _aspect_geometry_model_initial_topography_model_function_h + +#include +#include +#include + +#include + +namespace aspect +{ + namespace InitialTopographyModel + { + using namespace dealii; + + /** + * A class that implements initial topography based + * on a user-defined function.. + * + * @ingroup InitialTopographyModels + */ + template + class Function : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + Function (); + + /** + * Return the value of the initial topography as a function + * of surface position. + */ + double + value (const Point &p) const override; + + /** + * Return the maximum value of the elevation. + */ + double max_topography () const override; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * The maximum value the topography can take. + */ + double max_topo; + + /** + * A function object representing the topography. + */ + Functions::ParsedFunction initial_topography_function; + + /** + * The coordinate representation to evaluate the function. Possible + * choices are cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + }; + } +} + + +#endif diff --git a/include/aspect/geometry_model/initial_topography_model/interface.h.bak b/include/aspect/geometry_model/initial_topography_model/interface.h.bak new file mode 100644 index 00000000000..f964b77f585 --- /dev/null +++ b/include/aspect/geometry_model/initial_topography_model/interface.h.bak @@ -0,0 +1,163 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_geometry_model_initial_topography_model_interface_h +#define _aspect_geometry_model_initial_topography_model_interface_h + +#include +#include +#include + +#include + + +namespace aspect +{ + /** + * A namespace for the definition of properties of the initial topography. + * This includes mainly the storage and retrieval of the initial topography. + * The retrieval is done through the value function, which requires a point + * of size dim-1, and it returns a double which represents the elevation. + * + * @ingroup InitialTopographyModels + */ + namespace InitialTopographyModel + { + using namespace dealii; + + /** + * Base class for classes that describe particular initial topographies + * for the domain. + * + * @ingroup InitialTopographyModels + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Return the value of the elevation at the given surface point. + * + * Note that different geometry models use different conventions for + * how they describe surface points. In general, the models use + * their own "natural" coordinate system. For example, box-type + * geometry models will generally provide points as x-y coordinates + * on the surface, whereas spherical-type geometry models will generally + * provide surface points in spherical coordinates. + */ + virtual + double value (const Point &surface_point) const = 0; + + /** + * Return the maximum value of the elevation. + */ + virtual + double max_topography () const = 0; + }; + + + + /** + * Register a initial topography model so that it can be selected from the parameter + * file. + * + * @param name A string that identifies the initial topography model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this initial topography model wants + * to read from input files. + * @param factory_function A pointer to a function that can create an + * object of this initial topography model. + * + * @ingroup InitialTopographyModels + */ + template + void + register_initial_topography_model (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * A function that given the name of a model returns a pointer to an + * object that describes it. Ownership of the pointer is transferred to + * the caller. + * + * The initial topography model will also be asked to read its runtime + * parameters already. + * + * @ingroup InitialTopographyModels + */ + template + std::unique_ptr> + create_initial_topography_model (ParameterHandler &prm); + + + /** + * Declare the runtime parameters of the registered initial topography + * models. + * + * @ingroup InitialTopographyModels + */ + template + void + declare_parameters (ParameterHandler &prm); + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + template + void + write_plugin_graph (std::ostream &output_stream); + + + /** + * Given a class name, a name, and a description for the parameter file + * for a initial topography model, register it with the functions that + * can declare their parameters and create these objects. + * + * @ingroup InitialTopographyModels + */ +#define ASPECT_REGISTER_INITIAL_TOPOGRAPHY_MODEL(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_INITIAL_TOPOGRAPHY_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::InitialTopographyModel::register_initial_topography_model<2>, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::InitialTopographyModel::register_initial_topography_model<3>, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/geometry_model/initial_topography_model/prm_polygon.h.bak b/include/aspect/geometry_model/initial_topography_model/prm_polygon.h.bak new file mode 100644 index 00000000000..51364d75e96 --- /dev/null +++ b/include/aspect/geometry_model/initial_topography_model/prm_polygon.h.bak @@ -0,0 +1,87 @@ +/* + Copyright (C) 2016 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_geometry_model_initial_topography_prm_polygon_h +#define _aspect_geometry_model_initial_topography_prm_polygon_h + +#include + + +namespace aspect +{ + namespace InitialTopographyModel + { + using namespace dealii; + + /** + * A class that describes an initial topography for the geometry model, + * by defining a set of polygons on the surface from the prm file. It + * sets the elevation in each polygon to a constant value. + */ + template + class PrmPolygon : public Interface + { + public: + /** + * Return the value of the topography for a point. + */ + double value (const Point &p) const override; + + /** + * Return the maximum value of the elevation. + */ + double max_topography () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The values of the topography are stored in a vector. + */ + std::vector topography_values; + + /** + * The maximum topography in this model + */ + double maximum_topography; + + /** + * The polygons and their points are stored in this vector. + */ + std::vector>> point_lists; + + }; + } +} + + +#endif diff --git a/include/aspect/geometry_model/initial_topography_model/zero_topography.h.bak b/include/aspect/geometry_model/initial_topography_model/zero_topography.h.bak new file mode 100644 index 00000000000..ce4fad60819 --- /dev/null +++ b/include/aspect/geometry_model/initial_topography_model/zero_topography.h.bak @@ -0,0 +1,60 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_geometry_model_initial_topography_model_zero_topography_h +#define _aspect_geometry_model_initial_topography_model_zero_topography_h + +#include + +namespace aspect +{ + namespace InitialTopographyModel + { + using namespace dealii; + + /** + * A class that implements zero initial topography. + * + * @ingroup InitialTopographyModels + */ + template + class ZeroTopography : public Interface + { + public: + /** + * Return the value of the initial topography as a function of position. + * + * For the current class, this function obviously simply returns a zero + * value. + */ + double + value (const Point &p) const override; + + /** + * Return the maximum value of the elevation. + */ + double max_topography () const override; + }; + } +} + + +#endif diff --git a/include/aspect/geometry_model/interface.h.bak b/include/aspect/geometry_model/interface.h.bak new file mode 100644 index 00000000000..a5ca7653044 --- /dev/null +++ b/include/aspect/geometry_model/interface.h.bak @@ -0,0 +1,447 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_geometry_model_interface_h +#define _aspect_geometry_model_interface_h + +#include +#include +#include +#include +#include +#include + +#include + + +namespace aspect +{ + /** + * A namespace for the definition of properties of the geometry. This + * primarily includes the definition of the shape of the domain (e.g. + * whether it is a full spherical shell, a quadrant/octant, a description of + * the geoid, etc. The classes and functions of this namespace also describe + * which kinds of boundary conditions hold on the different parts of the + * boundary of the geometry. + * + * @ingroup GeometryModels + */ + namespace GeometryModel + { + using namespace dealii; + + /** + * Base class for classes that describe particular geometries for the + * domain. These classes must also be able to create coarse meshes and + * describe what kinds of boundary conditions hold where. + * + * @ingroup GeometryModels + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Generate a coarse mesh for the geometry described by this class. + */ + virtual + void create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const = 0; + + /** + * Return the typical length scale one would expect of features in + * this geometry, assuming realistic parameters. + * + * The result of this function is used in computing the scaling factor + * for the pressure in the Stokes equation. There, the scaling factor + * is chosen as the ratio of the reference viscosity divided by the + * length scale. As an example, in the step-32 tutorial program we + * have determined that a suitable length scale for scaling is 10km, + * in a domain that is 12,000km across. This length scale suitably + * matches the order of magnitude for the diameter of plumes in the + * earth. + */ + virtual + double length_scale () const = 0; + + /** + * Return the depth that corresponds to the given position. The + * returned value is between 0 and maximal_depth(), where points + * with a zero depth correspond to the "surface" of the model. + * + * Computing a depth requires a geometry model to define a + * "vertical" direction. For example, the Box model considers + * the $(0,1)^T$ vector in 2d (and the $(0,0,1)^T$ vector in + * 3d) as vertical and considers the "top" boundary as the + * "surface". Similarly, the spherical shell takes the radial + * vector as "vertical" and the outer boundary as "surface". + * In most cases, how geometry models define "vertical" and + * "surface" will be intuitive and obvious. In almost all + * cases one will use a gravity model that also matches these + * definitions. + * + * @note Implementations of this function in derived classes can + * only compute the depth with regard to the reference + * configuration of the geometry, i.e., the geometry initially + * created. If you are using a dynamic topography in your models + * that changes in every time step, or if you apply initial + * topography to your model, then the actual depth + * of a point with regard to this dynamic topography will not + * match the value this function returns. This is so because + * computing the actual depth is difficult: In parallel computations, + * the processor on which you want to evaluate the depth of a point + * may know nothing about the displacement of the surface anywhere + * if it happens to store only interior cells. Furthermore, it is + * not even clear what "depth" one would compute in such situations: + * The distance to the closest surface point? The vertical distance + * to the surface point directly above? Or the length of the line + * from the given point to a surface point that is locally always + * parallel to the gravity vector? For all of these reasons, this + * function simply returns the geometric vertical depth of a point + * in the known and fixed reference geometry, to the reference + * surface that defines what zero depth is. + */ + virtual + double depth(const Point &position) const = 0; + + /** + * Return the height of the given position relative to the reference + * surface of the model. Positive returned value means that the point + * is above (i.e., farther from the center of the model) the reference + * surface, negative value means that the point is below the the + * reference surface. + * + * Same limitations as for the depth function, apply here. + */ + virtual + double height_above_reference_surface(const Point &position) const = 0; + + /** + * Converts a Cartesian Point into another coordinate system and returns it + * as a NaturalCoordinate. + */ + + Utilities::NaturalCoordinate + cartesian_to_other_coordinates(const Point &position, + const Utilities::Coordinates::CoordinateSystem &coordinate_system) const; + + /** + * Returns what the natural coordinate system for this geometry model is. + */ + virtual + aspect::Utilities::Coordinates::CoordinateSystem natural_coordinate_system() const = 0; + + /** + * Takes the Cartesian points (x,z or x,y,z) and returns standardized + * coordinates which are most 'natural' to the geometry model. For a box + * this will be (x,z) in 2d or (x,y,z) in 3d, and for a spheroid geometry + * model it will be (radius, longitude) in 2d and (radius, longitude, + * latitude) in 3d. + */ + virtual + std::array cartesian_to_natural_coordinates(const Point &position) const; + + /** + * Undoes the action of cartesian_to_natural_coordinates, and turns the + * coordinate system which is most 'natural' to the geometry model into + * Cartesian coordinates. + */ + virtual + Point natural_to_cartesian_coordinates(const std::array &position) const; + + /** + * Returns a representative point for a given depth. Such a point must + * lie inside the domain for sure (assuming the given depth is valid), + * but it is not important where exactly in the domain it is. A good + * choice would be on a middle axis, for example. + * + * The function is used, for example, in computing an initial + * adiabatic profile. For this, we need to be able to query the + * density as a function of (adiabatic) pressure and temperature. + * However, the functions returning the density from the material + * model also depend on location. Since we are interested only in + * computing a depth-dependent adiabatic profile without lateral + * variation, we need to be able to query the density at + * "representative points" at given depths, without caring too much + * where exactly that is -- but at points that we know for sure are + * inside the domain. + */ + virtual + Point representative_point(const double depth) const = 0; + + /** + * Returns the maximal depth of this geometry. For a definition of + * how "depth" is to be interpreted, see the documentation of the + * depth() member function. In particular, the maximal depth of a + * geometry model only represents the depth computed with regard + * to some reference configuration, ignoring any dynamic or initial + * topography. + */ + virtual + double maximal_depth() const = 0; + + + /** + * Return the set of boundary indicators that are used by this model. + * This information is used to determine what boundary indicators can + * be used in the input file. + */ + virtual + std::set + get_used_boundary_indicators () const = 0; + + /** + * Return a mapping from symbolic names of each part of the boundary + * to the corresponding boundary indicator. This allows users to + * specify *names*, not just *numbers* in their input files when + * describing which parts of the boundary have to satisfy which + * boundary conditions. + * + * An example would be that the "box" geometry returns a map of the + * form {{"left"->0}, {"right"->1}, {"bottom"->2}, + * {"top"->3}} in 2d. + * + * The default implementation of this function returns an empty map. + * This still allows the use of a geometry model that does not + * implement this function but forces the user to identify parts of + * the boundary by their boundary indicator number, rather than using + * a symbolic name. + * + * @note Names may contain spaces and numbers, but they may not + * contain special characters and they should not equal the text + * representation of numbers (e.g., a name "10" is ill-advised). + * + * @note Since in practice boundary indicators can be provided either + * via number or symbolic name, the mapping from something given in + * the input is not entirely trivial -- in particular, because a + * function also has to do some error checking that a given string in + * fact matches any known boundary indicator. To this end, use + * GeometryModel::translate_boundary_indicator() and + * GeometryModel::translate_boundary_indicators(). + * + * @return A map from symbolic names to boundary indicators. The map + * should provide a symbolic name for each used boundary indicator as + * returned by get_user_boundary_indicators(). In the end, however, a + * geometry model may define multiple symbolic names for the same + * boundary or not define any. + */ + virtual + std::map + get_symbolic_boundary_names_map () const; + + /** + * For a given name of a boundary component, translate it to its + * numeric value -- either by using one of the symbolic values in the + * mapping that derived classes provide through the + * get_symbolic_boundary_names_map() function, or by converting its + * string representation into a number. + * + * @param name A name or number (as string). Leading and trailing + * spaces are removed from this string. + * @return A boundary indicator number corresponding to the given + * name. If the name does not represent either a symbolic name or a + * number, this function will throw an exception of type std::string + * that explains the error. + */ + types::boundary_id + translate_symbolic_boundary_name_to_id (const std::string &name) const; + + /** + * For each one of the given names of boundary components, translate + * it to its numeric value -- either by using one of the symbolic + * values in the mapping that derived classes provide through the + * get_symbolic_boundary_names_map() function, or by converting its + * string representation into a number. + * + * @param names A list of names or numbers (as strings). Leading and + * trailing spaces are removed from the strings. + * @return A list of boundary indicator numbers corresponding to the + * given list of names. If one of the given names does not represent + * either a symbolic name or a number, this function will throw an + * exception of type std::string that explains the error. + */ + std::vector + translate_symbolic_boundary_names_to_ids (const std::vector &names) const; + + /** + * Given a boundary indicator, try and see whether this geometry model + * provides a symbolic name for it. If the geometry model does not + * provide a symbolic name, return the empty string. + * + * @param boundary_id The boundary indicator to be translated. + * @return A string representation for this boundary indicator, if one + * is available. + */ + std::string + translate_id_to_symbol_name (const types::boundary_id boundary_id) const; + + /** + * Returns a set of periodic boundary pairs. The elements of the set + * are a pair of boundary ids and a cartesian unit direction each. The + * base class returns an empty set, so this does nothing unless you + * specifically use a geometry model with periodic boundary conditions + */ + virtual + std::set, unsigned int>> + get_periodic_boundary_pairs () const; + + /** + * Adjust positions to be inside the domain considering periodic boundary conditions. + * + * This function checks if @p position is outside the domain and if it could + * have reasonably crossed a periodic boundary. If so, it will adjust the position + * as described by the periodic boundary (e.g. a translation in a box, or a rotation + * in a spherical shell). Afterwards, if it adjusted @p position, it will also adjust + * all locations given in @p connected_positions (if any where given) and all + * velocities given in @p connected_velocities in the same way. + * Adjusting both of these allows to adjust related temporary variables, + * e.g. the intermediate results of an ordinary differential equation solver + * that are used to compute differences/directions between points. The reason + * positions and velocities have to be treated separately is that some geometries + * have to adjust them differently across a periodic boundary, e.g. a box has + * to translate positions but not velocities, while a spherical shell has to + * translate positions (by rotation around the center) and rotate velocities. + * + * This function does not check that the position after the adjustment is inside the + * domain; to check this is the responsibility of the calling function. + * A common application of this function are particles that crossed a periodic boundary. + */ + virtual + void + adjust_positions_for_periodicity (Point &position, + const ArrayView> &connected_positions = {}, + const ArrayView> &connected_velocities = {}) const; + + /** + * If true, the geometry contains cells with boundaries that are not + * straight and have a deal.II boundary object attached to it. If the + * return value is @p false, certain operation can be optimized.The + * default implementation of this function will return @p true. + */ + virtual + bool + has_curved_elements() const; + + /** + * If true, the queried point (in Cartesian coordinates) + * lies in the domain specified by the geometry. + */ + virtual + bool + point_is_in_domain(const Point &p) const = 0; + + /** + * Collects periodic boundary constraints for the given geometry + * and @p dof_handler, which will be added to the existing @p constraints. + * The default implementation creates cartesian periodic boundary conditions + * for all periodic boundary indicators. + */ + virtual + void + make_periodicity_constraints(const DoFHandler &dof_handler, + AffineConstraints &constraints) const; + }; + + + + /** + * Register a geometry model so that it can be selected from the parameter + * file. + * + * @param name A string that identifies the geometry model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this geometry model wants to read + * from input files. + * @param factory_function A pointer to a function that can create an + * object of this geometry model. + * + * @ingroup GeometryModels + */ + template + void + register_geometry_model (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * A function that given the name of a model returns a pointer to an + * object that describes it. Ownership of the pointer is transferred to + * the caller. + * + * The geometry model will also be asked to read its runtime parameters + * already. + * + * @ingroup GeometryModels + */ + template + std::unique_ptr> + create_geometry_model (ParameterHandler &prm); + + /** + * Declare the runtime parameters of the registered geometry models. + * + * @ingroup GeometryModels + */ + template + void + declare_parameters (ParameterHandler &prm); + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + template + void + write_plugin_graph (std::ostream &output_stream); + + + + /** + * Given a class name, a name, and a description for the parameter file + * for a geometry model, register it with the functions that can declare + * their parameters and create these objects. + * + * @ingroup GeometryModels + */ +#define ASPECT_REGISTER_GEOMETRY_MODEL(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_GEOMETRY_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::GeometryModel::register_geometry_model<2>, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::GeometryModel::register_geometry_model<3>, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/geometry_model/sphere.h.bak b/include/aspect/geometry_model/sphere.h.bak new file mode 100644 index 00000000000..e3e51c74ed5 --- /dev/null +++ b/include/aspect/geometry_model/sphere.h.bak @@ -0,0 +1,164 @@ +/* + Copyright (C) 2014 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ +#ifndef _aspect_geometry_model_sphere_h +#define _aspect_geometry_model_sphere_h + +#include +#include + +namespace aspect +{ + namespace GeometryModel + { + using namespace dealii; + + template + class Sphere : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + Sphere() = default; + + /** + * Generate a coarse mesh for the geometry described by this class. + */ + void create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const override; + + /** + * Return the typical length scale one would expect of features in + * this geometry, assuming realistic parameters. + * + * As discussed in the step-32 tutorial program, an appropriate length + * scale for this geometry is 10km, so we return $10^4$ here. + */ + double length_scale () const override; + + /** + * Return the depth that corresponds to the given + * position. The documentation of the base class (see + * GeometryModel::Interface::depth()) describes in detail how + * "depth" is interpreted in general. + * + * Computing a depth requires a geometry model to define a + * "vertical" direction. The current class considers the + * radial vector away from the origin as vertical and + * considers the "outer" boundary as the "surface". In almost + * all cases one will use a gravity model that also matches + * these definitions. + */ + double depth(const Point &position) const override; + + /** + * Return the height of the given position relative to + * the radius of the sphere. + */ + double height_above_reference_surface(const Point &position) const override; + + /** + * @copydoc Interface::representative_point() + */ + Point representative_point(const double depth) const override; + + /** + * @copydoc Interface::maximal_depth() + */ + double maximal_depth() const override; + + /** + * Return the set of boundary indicators that are used by this model. + * This information is used to determine what boundary indicators can + * be used in the input file. + * + * The sphere model only has one boundary, with indicator zero. + */ + std::set + get_used_boundary_indicators () const override; + + /** + * Return symbolic names for all boundary components. Their names are + * described in the documentation of this plugin, at the bottom of the + * .cc file. + */ + std::map + get_symbolic_boundary_names_map () const override; + + /** + * @copydoc Interface::has_curved_elements() + * + * Return true because we have a curved boundary. + */ + bool + has_curved_elements() const override; + + /** + * Returns what the natural coordinate system for this geometry model is, + * which for a sphere is Spherical. + */ + aspect::Utilities::Coordinates::CoordinateSystem natural_coordinate_system() const override; + + /** + * Return whether the given point lies within the domain specified + * by the geometry. This function does not take into account + * initial or dynamic surface topography. + */ + bool + point_is_in_domain(const Point &point) const override; + + /** + * Takes the Cartesian points (x,z or x,y,z) and returns standardized + * coordinates which are most 'natural' to the geometry model. For a sphere + * this is (radius, longitude) in 2d and (radius, longitude, latitude) in 3d. + */ + std::array cartesian_to_natural_coordinates(const Point &position) const override; + + /** + * Undoes the action of cartesian_to_natural_coordinates, and turns the + * coordinate system which is most 'natural' to the geometry model into + * Cartesian coordinates. + */ + Point natural_to_cartesian_coordinates(const std::array &position) const override; + + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Return the radius of the sphere. + */ + double + radius () const; + + private: + /** + * Radius of the sphere + */ + double R; + }; + } +} + + +#endif diff --git a/include/aspect/geometry_model/spherical_shell.h.bak b/include/aspect/geometry_model/spherical_shell.h.bak new file mode 100644 index 00000000000..c2286088a31 --- /dev/null +++ b/include/aspect/geometry_model/spherical_shell.h.bak @@ -0,0 +1,454 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_geometry_model_spherical_shell_h +#define _aspect_geometry_model_spherical_shell_h + +#include +#include + +namespace aspect +{ + namespace GeometryModel + { + using namespace dealii; + + namespace internal + { + /** + * A description of a manifold that describes a spherical shell with overlaid + * topography. + */ + template + class SphericalManifoldWithTopography : public aspect::SphericalManifold + { + public: + /** + * Constructor. + */ + SphericalManifoldWithTopography(const InitialTopographyModel::Interface &topography, + const double inner_radius, + const double outer_radius); + + /** + * Copy constructor. + */ + SphericalManifoldWithTopography(const SphericalManifoldWithTopography &) = default; + + /** + * Make a clone of this Manifold object. + */ + virtual std::unique_ptr> + clone() const override; + + /** + * Given a point in the undeformed spherical geometry, push it forward to the + * corresponding point in the sphere with surface topography. + */ + Point + push_forward_from_sphere (const Point &p) const; + + /** + * Given a point in the deformed spherical geometry with topography, pull it + * back to the corresponding point in the undeformed sphere. + */ + Point + pull_back_to_sphere (const Point &p) const; + + /** + * Given any two points in space, first project them on the surface + * of a sphere with unit radius, then connect them with a geodesic + * and find the intermediate point, and finally rescale the final + * radius so that the resulting one is the convex combination of the + * starting radii. + */ + virtual Point + get_intermediate_point(const Point &p1, + const Point &p2, + const double w) const override; + + /** + * Compute the derivative of the get_intermediate_point() function + * with parameter w equal to zero. + */ + virtual Tensor<1, dim> + get_tangent_vector(const Point &x1, + const Point &x2) const override; + + /** + * @copydoc Manifold::normal_vector() + * + * We fudge here, but for a good reason. What the function is supposed + * to compute is the normal vector to the surface. This *should* be the + * normal to the surface with topography, but instead we return the + * normal to the undeformed surface -- i.e., the radial direction. This + * is, in particular, used to compute no-flux boundary conditions, + * for which we want to impose a boundary + * condition that allows for plate-like motion -- that is, we need + * to allow *horizontal motion*, even if that is not tangential to + * the surface along the slopes of mountains or ocean trenches. Using + * the radial direction, i.e., the normal vector to the undeformed surface + * (= a radial vector) allows for exactly this. + */ + virtual Tensor<1, dim> + normal_vector( + const typename Triangulation::face_iterator &face, + const Point &p) const override; + + /** + * Compute the normal vectors to the boundary at each vertex. + */ + virtual void + get_normals_at_vertices( + const typename Triangulation::face_iterator &face, + typename Manifold::FaceVertexNormals &face_vertex_normals) + const override; + + + /** + * Compute a new set of points that interpolate between the given points @p + * surrounding_points. @p weights is a table with as many columns as @p + * surrounding_points.size(). The number of rows in @p weights must match + * the length of @p new_points. + * + * This function is optimized to perform on a collection + * of new points, by collecting operations that are not dependent on the + * weights outside of the loop over all new points. + * + * The implementation does not allow for @p surrounding_points and + * @p new_points to point to the same array, so make sure to pass different + * objects into the function. + */ + virtual void + get_new_points(const ArrayView> &surrounding_points, + const Table<2, double> &weights, + ArrayView> new_points) const override; + + /** + * Return a point on the spherical manifold which is intermediate + * with respect to the surrounding points. + */ + virtual Point + get_new_point(const ArrayView> &vertices, + const ArrayView &weights) const override; + + private: + /** + * A pointer to the topography model. + */ + const InitialTopographyModel::Interface *topo; + + /** + * Inner and outer radii of the spherical shell. + */ + const double R0, R1; + + /** + * Return the topography of the surface directly above the point given + * by the coordinates stored in the argument. + */ + double topography_for_point (const Point &x_y_z) const; + }; + + } + + /** + * A class that describes the geometry as a spherical shell. To be more + * precise, at least in 2d this class can also simulate just a sector of + * the spherical shell geometry, in particular a half ring and a quarter + * ring. + * + * The parameters that describe this geometry and that are read from the + * input file are the inner and outer radii of the shell and the opening + * angle of the section of the shell we want to build. + */ + template + class SphericalShell : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + SphericalShell() = default; + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run and after + * the SimulatorAccess (if applicable) is initialized. + * This function calls the initialize function of the manifold + * with a pointer to the initial topography model obtained + * from SimulatorAccess. + */ + void initialize () override; + + /** + * Generate a coarse mesh for the geometry described by this class. + */ + void create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const override; + + /** + * Return the typical length scale one would expect of features in + * this geometry, assuming realistic parameters. + * + * As discussed in the step-32 tutorial program, an appropriate length + * scale for this geometry is 10km, so we return $10^4$ here. + */ + double length_scale () const override; + + /** + * Return the depth that corresponds to the given + * position. The documentation of the base class (see + * GeometryModel::Interface::depth()) describes in detail how + * "depth" is interpreted in general. + * + * Computing a depth requires a geometry model to define a + * "vertical" direction. The current class considers the + * radial vector away from the origin as vertical and + * considers the "outer" boundary as the "surface". In almost + * all cases one will use a gravity model that also matches + * these definitions. + */ + double depth(const Point &position) const override; + + /** + * Return the height of the given position relative to + * the outer radius of the shell. + */ + double height_above_reference_surface(const Point &position) const override; + + /** + * @copydoc Interface::representative_point() + */ + Point representative_point(const double depth) const override; + + /** + * @copydoc Interface::maximal_depth() + */ + double maximal_depth() const override; + + /** + * Return the set of boundary indicators that are used by this model. + * This information is used to determine what boundary indicators can + * be used in the input file. + * + * The spherical shell may be generated as per in the original code + * (with respect to the inner and outer radius, and an initial number + * of cells along circumference) or following a custom mesh scheme: + * list of radial values or number of slices. A surface mesh is first + * generated and refined as desired, before it is extruded radially. + * A list of radial values subdivides the spherical shell at specified + * radii. The number of slices subdivides the spherical shell into N + * slices of equal thickness. The custom spherical shell only works + * with an opening angle of 360 degrees. + * + * The spherical shell model uses boundary indicators zero and one, + * with zero corresponding to the inner surface and one corresponding + * to the outer surface. In 2d, if the geometry is only a slice of the + * shell, boundary indicators 2 and 3 indicate the left and right + * radial bounding lines. + */ + std::set + get_used_boundary_indicators () const override; + + /** + * Return symbolic names for all boundary components. Their names are + * described in the documentation of this plugin, at the bottom of the + * .cc file. + */ + std::map + get_symbolic_boundary_names_map () const override; + + /** + * Return the set of periodic boundaries as described in the input + * file. + */ + std::set, unsigned int>> + get_periodic_boundary_pairs () const override; + + /** + * @copydoc Interface::adjust_positions_for_periodicity + * + * Apply a rotation to all points outside of the domain + * to account for periodicity. + */ + void + adjust_positions_for_periodicity (Point &position, + const ArrayView> &connected_positions = {}, + const ArrayView> &connected_velocities = {}) const override; + + /** + * @copydoc Interface::has_curved_elements() + * + * Return true because we have a curved boundary. + */ + bool + has_curved_elements() const override; + + /** + * Return whether the given point lies within the domain specified + * by the geometry. This function does not take into account + * initial or dynamic surface topography. + */ + bool + point_is_in_domain(const Point &point) const override; + + /** + * Returns what the natural coordinate system for this geometry model is, + * which for a spherical shell is Spherical. + */ + aspect::Utilities::Coordinates::CoordinateSystem natural_coordinate_system() const override; + + /** + * Takes the Cartesian points (x,z or x,y,z) and returns standardized + * coordinates which are most 'natural' to the geometry model. For a spherical shell + * this is (radius, longitude) in 2d and (radius, longitude, latitude) in 3d. + */ + std::array cartesian_to_natural_coordinates(const Point &position) const override; + + /** + * Undoes the action of cartesian_to_natural_coordinates, and turns the + * coordinate system which is most 'natural' to the geometry model into + * Cartesian coordinates. + */ + Point natural_to_cartesian_coordinates(const std::array &position) const override; + + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Return the inner radius of the shell. + */ + double + inner_radius () const; + + /** + * Return the outer radius of the shell. + */ + double + outer_radius () const; + + /** + * Return the opening angle of the shell sector. + */ + double + opening_angle () const; + + /** + * Collects periodic boundaries constraints for the given geometry, + * which will be added to the existing @p constraints. + */ + void + make_periodicity_constraints(const DoFHandler &dof_handler, + AffineConstraints &constraints) const override; + + private: + /** + * Specify the radial subdivision of the spherical shell + * mesh. + */ + enum CustomMeshRadialSubdivision + { + none, + list, + slices + } custom_mesh; + + /** + * Initial surface refinement for the custom mesh cases. + */ + unsigned int initial_lateral_refinement; + + /** + * Initial surface refinement for the custom mesh cases. + */ + unsigned int n_slices; + + /** + * List of radial values for the list custom mesh. + */ + std::vector R_values_list; + + /** + * Inner and outer radii of the spherical shell. + */ + double R0, R1; + + /** + * Opening angle of the section of the shell that we simulate. + */ + double phi; + + /** + * Number of tangential mesh cells in the initial, coarse mesh. + */ + int n_cells_along_circumference; + + /** + * Set the manifold ids on all cells (also boundaries) before + * refinement to generate well shaped cells. + */ + void set_manifold_ids (parallel::distributed::Triangulation &triangulation) const; + + /** + * Flag whether the 2D quarter shell is periodic in phi. + */ + bool periodic; + + /** + * An object that describes the geometry. This pointer is + * initialized in the initialize() function, and serves as the manifold + * object that the triangulation is later given in create_coarse_mesh() + * where the triangulation clones it. + * + * The object is marked as 'const' to make it clear that it should not + * be modified once created. That is because the triangulation copies it, + * and modifying the current object will not have any impact on the + * manifold used by the triangulation. + */ + std::unique_ptr> manifold; + + /** + * Give a symbolic name to the manifold id to be used by this class. + */ + static const types::manifold_id my_manifold_id = 99; + }; + } +} + + +#endif diff --git a/include/aspect/geometry_model/two_merged_boxes.h.bak b/include/aspect/geometry_model/two_merged_boxes.h.bak new file mode 100644 index 00000000000..bfcc53789fd --- /dev/null +++ b/include/aspect/geometry_model/two_merged_boxes.h.bak @@ -0,0 +1,265 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_geometry_model_two_merged_boxes_h +#define _aspect_geometry_model_two_merged_boxes_h + +#include +#include + +namespace aspect +{ + namespace GeometryModel + { + using namespace dealii; + + /** + * A class that describes a box geometry of certain width, height, and + * depth (in 3d) and adds two (four in 3D) additional boundary indicators + * for the lithospheric part of the vertical boundaries. + */ + template + class TwoMergedBoxes : public Interface, public SimulatorAccess + { + public: + + /** + * Generate a coarse mesh for the geometry described by this class. + */ + void create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const override; + + /** + * Return a point that denotes the size of the box in each dimension + * of the domain. + */ + Point get_extents () const; + + /** + * Return a point that denotes the lower left corner of the box + * domain. + */ + Point get_origin () const; + + /** + * Return the typical length scale one would expect of features in + * this geometry, assuming realistic parameters. + * + * We return 1/100th of the X extent of the box. + */ + double length_scale () const override; + + /** + * Return the depth that corresponds to the given + * position. The documentation of the base class (see + * GeometryModel::Interface::depth()) describes in detail how + * "depth" is interpreted in general. + * + * Computing a depth requires a geometry model to define a + * "vertical" direction. The current class considers the + * $(0,1)^T$ vector in 2d (and the $(0,0,1)^T$ vector in 3d) + * as vertical and considers the "top" boundary as the + * "surface". In almost all cases one will use a gravity model + * that also matches these definitions. + */ + double depth(const Point &position) const override; + + /** + * Return the height of the given position relative to + * the initial box height. + */ + double height_above_reference_surface(const Point &position) const override; + + /** + * @copydoc Interface::representative_point() + */ + Point representative_point(const double depth) const override; + + /** + * @copydoc Interface::maximal_depth() + */ + double maximal_depth() const override; + + /** + * Return the set of boundary indicators that are used by this model. + * This information is used to determine what boundary indicators can + * be used in the input file. + * + * This box model uses boundary indicators zero through 2*dim+2*(dim-1)-1, with + * the first two being the faces perpendicular to the x-axis and the next + * two perpendicular to the y-axis. In 2D, the next two are perpendicular to + * the x-axis again. In 3D, two sets of two + * are added for the boundaries parallel to the z-axis. + */ + std::set + get_used_boundary_indicators () const override; + + /** + * Return a mapping from symbolic names of each part of the boundary + * to the corresponding boundary indicator. This allows users to + * specify *names*, not just *numbers* in their input files when + * describing which parts of the boundary have to satisfy which + * boundary conditions. + * + * This geometry returns the map {{"left"->0}, {"right"->1}, + * {"bottom"->2}, {"top"->3}, {"left lithosphere"->4}, + * {"right lithosphere"->5}} in 2d, and {{"left"->0}, + * {"right"->1}, {"front"->2}, {"back"->3}, {"bottom"->4}, + * {"top"->5}, {"left lithosphere"->6}, {"right lithosphere"->7}, + * {"front lithosphere"->8}, {"back lithosphere"->9}} in 3d. + */ + std::map + get_symbolic_boundary_names_map () const override; + + /** + * Return the set of periodic boundaries as described in the input + * file. + */ + std::set, unsigned int>> + get_periodic_boundary_pairs () const override; + + /** + * @copydoc Interface::adjust_positions_for_periodicity + * + * Apply a translation to all points outside of the domain + * to account for periodicity. + */ + void + adjust_positions_for_periodicity (Point &position, + const ArrayView> &connected_positions = {}, + const ArrayView> &connected_velocities = {}) const override; + + /** + * @copydoc Interface::has_curved_elements() + * + * A box has only straight boundaries and cells, so return false. + */ + bool + has_curved_elements() const override; + + /** + * Return whether the given point lies within the domain specified + * by the geometry. This function does not take into account + * initial or dynamic surface topography. + */ + bool + point_is_in_domain(const Point &point) const override; + + /** + * Returns what the natural coordinate system for this geometry model is, + * which for two merged boxes is Cartesian. + */ + aspect::Utilities::Coordinates::CoordinateSystem natural_coordinate_system() const override; + + /** + * Takes the Cartesian points (x,z or x,y,z) and returns standardized + * coordinates which are most 'natural' to the geometry model. For a box + * the results is unchanged and is (x,z) in 2d or (x,y,z) in 3d. + */ + std::array cartesian_to_natural_coordinates(const Point &position) const override; + + /** + * Undoes the action of cartesian_to_natural_coordinates, and turns the + * coordinate system which is most 'natural' to the geometry model into + * Cartesian coordinates. + */ + Point natural_to_cartesian_coordinates(const std::array &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Whether to make the grid by gluing together two boxes, or just + * use one chunk to make the grid. Using two grids glued together + * is a safer option, since it forces the boundary conditions + * to be always applied to the same depth, but one unified grid allows + * for a more flexible usage of the adaptive refinement. + */ + bool use_merged_grids; + + /** + * Extent of the whole model domain in x-, y-, and z-direction (in 3d). + */ + Point extents; + + /** + * Extent of the lower box in x-, y-, and z-direction (in 3d). + */ + Point lower_extents; + + /** + * Origin of the lower box in x, y, and z (in 3d) coordinates. + */ + Point lower_box_origin; + + /** + * Extent of the upper box in x-, y-, and z-direction (in 3d). + */ + Point upper_extents; + + /** + * Origin of the upper box in x, y, and z (in 3d) coordinates. + */ + Point upper_box_origin; + + /** + * Flag whether the whole domain is periodic in the x-, y-, and z-directions, + * the x- and y- (in 3d) direction in the lithosphere. + */ + bool periodic[dim+dim-1]; + + /** + * The number of cells in each coordinate direction for the lower box. + */ + std::array lower_repetitions; + + /** + * The number of cells in each coordinate direction for the upper box. + */ + std::array upper_repetitions; + + /** + * The height where the lithospheric part of the vertical boundary begins + * (so in positive z-direction). + */ + double height_lith; + + /** + * Bind boundary indicators to child cells after each mesh refinement round. + */ + void + set_boundary_indicators (parallel::distributed::Triangulation &triangulation) const; + }; + } +} + + +#endif diff --git a/include/aspect/geometry_model/two_merged_chunks.h.bak b/include/aspect/geometry_model/two_merged_chunks.h.bak new file mode 100644 index 00000000000..3c5eacd15cc --- /dev/null +++ b/include/aspect/geometry_model/two_merged_chunks.h.bak @@ -0,0 +1,325 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_geometry_model_two_merged_chunks_h +#define _aspect_geometry_model_two_merged_chunks_h + +#include +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace GeometryModel + { + using namespace dealii; + + + /** + * A geometry model class that describes a chunk of a spherical shell, + * but with two boundary indicators per side boundary. This allows + * for specifying two different types of boundary conditions on the + * side boundaries, for example prescribed plate motions along + * the edge of the lithosphere and an open boundary underneath. + * In 2D, this class simulates a sector with inner and outer radius, and + * minimum and maximum longitude. Longitude increases anticlockwise + * from the positive x-axis, as per the mathematical convention of phi. + * In 3D, the class simulates a chunk of a sphere, bounded by arbitrary + * lines of longitude, latitude and radius. Boundary indicator names are + * lowerwest, upperwest, lowereast, uppereast, lowersouth, uppersouth, + * lowernorth, uppernorth, bottom and top. + * + * The parameters that describe this geometry and that are read from the + * input file are the inner, outer and middle boundary radius of the shell, + * the minimum and maximum longitude, minimum and maximum longitude, and the + * number of cells initialized in each dimension. In the radial direction, + * this number should be specified for both the lower and the upper part of + * the chunk (with their boundary lying at the middle boundary radius). + * + * Initial topography can be added through a radial displacement of the + * mesh nodes. + */ + template + class TwoMergedChunks : public Interface, public SimulatorAccess + { + public: + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run and after + * the SimulatorAccess (if applicable) is initialized. + * This function calls the initialize function of the manifold + * with a pointer to the initial topography model obtained + * from SimulatorAccess. + */ + void initialize () override; + + /** + * Generate a coarse mesh for the geometry described by this class. + */ + void create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const override; + + /** + * Return the set of boundary indicators that are used by this model. + * This information is used to determine what boundary indicators can + * be used in the input file. + * + * The chunk model uses boundary indicators zero through 2*dim+2*(dim-1)-1, with + * the first two being the faces perpendicular to the radius of the shell, + * the next four along lines of longitude and, in 3d, the next four + * along lines of latitude. + */ + std::set + get_used_boundary_indicators () const override; + + /** + * Return a mapping from symbolic names of each part of the boundary + * to the corresponding boundary indicator. This allows users to + * specify *names*, not just *numbers* in their input files when + * describing which parts of the boundary have to satisfy which + * boundary conditions. + */ + std::map + get_symbolic_boundary_names_map () const override; + + /** + * Return the typical length scale one would expect of features in + * this geometry, assuming realistic parameters. + * + * As described in the first ASPECT paper, a length scale of + * 10km = 1e4m works well for the pressure scaling for earth + * sized spherical shells. use a length scale that + * yields this value for the R0,R1 corresponding to earth + * but otherwise scales like (R1-R0) + */ + double length_scale () const override; + + /** + * Return the depth that corresponds to the given + * position. The documentation of the base class (see + * GeometryModel::Interface::depth()) describes in detail how + * "depth" is interpreted in general. + * + * Computing a depth requires a geometry model to define a + * "vertical" direction. The current class considers the + * radial vector away from the origin as vertical and + * considers the "top" boundary as the surface. In almost + * all cases one will use a gravity model that also matches + * these definitions. + */ + double depth(const Point &position) const override; + + /** + * Return the height of the given position relative to the outer + * radius. + */ + double height_above_reference_surface(const Point &position) const override; + + /** + * @copydoc Interface::representative_point() + */ + Point representative_point(const double depth) const override; + + /** + * Return the longitude at the western edge of the chunk measured in + * radians. + */ + virtual + double west_longitude() const; + + /** + * Return the longitude at the eastern edge of the chunk measured in + * radians. + */ + virtual + double east_longitude() const; + + /** + * Return the longitude range of the chunk measured in radians. + */ + virtual + double longitude_range() const; + + /** + * Return the latitude at the southern edge of the chunk measured in + * radians from the equator. + */ + virtual + double south_latitude() const; + + /** + * Return the latitude at the northern edge of the chunk measured in + * radians from the equator. + */ + virtual + double north_latitude() const; + + /** + * Return the latitude range of the chunk measured in radians + */ + virtual + double latitude_range() const; + + /** + * Return the maximum depth from the surface of the model measured in + * meters. + */ + double maximal_depth() const override; + + /** + * Return the inner radius of the chunk measured in meters. + */ + virtual + double inner_radius() const; + + /** + * Return the outer radius of the chunk measured in meters. + */ + virtual + double outer_radius() const; + + + /** + * @copydoc Interface::has_curved_elements() + * + * A chunk has curved boundaries and cells, so return true. + */ + bool + has_curved_elements() const override; + + /** + * Return whether the given point lies within the domain specified + * by the geometry. This function does not take into account + * initial or dynamic surface topography. + */ + bool + point_is_in_domain(const Point &point) const override; + + /** + * Returns what the natural coordinate system for this geometry model is, + * which for a chunk is Spherical. + */ + aspect::Utilities::Coordinates::CoordinateSystem natural_coordinate_system() const override; + + /** + * Takes the Cartesian points (x,z or x,y,z) and returns standardized + * coordinates which are most 'natural' to the geometry model. For a chunk + * this is (radius, longitude) in 2d and (radius, longitude, latitude) in 3d. + */ + std::array cartesian_to_natural_coordinates(const Point &position) const override; + + /** + * Undoes the action of cartesian_to_natural_coordinates, and turns the + * coordinate system which is most 'natural' to the geometry model into + * Cartesian coordinates. + */ + Point natural_to_cartesian_coordinates(const std::array &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Whether to make the grid by gluing together two chunks, or just + * use one chunk to make the grid. Using two grids glued together + * is a safer option, since it forces the boundary conditions + * to be always applied to the same depth, but one unified grid allows + * for a more flexible usage of the adaptive refinement. + */ + bool use_merged_grids; + + /** + * Minimum longitude-depth (2D) or + * longitude-latitude-depth (3D) point + * of the entire merged chunk. + */ + Point point1; + + /** + * Maximum longitude-depth (2D) or + * longitude-latitude-depth (3D) point + * of the entire merged chunk. + */ + Point point2; + + /** + * Minimum longitude-depth (2D) or + * longitude-latitude-depth (3D) point + * for the upper chunk. + */ + Point point3; + + /** + * Maximum longitude-depth (2D) or + * longitude-latitude-depth (3D) point + * for the lower chunk. + */ + Point point4; + + /** + * The number of cells in each coordinate direction + * for the lower and upper chunk. + */ + std::array lower_repetitions; + std::array upper_repetitions; + + /** + * An object that describes the geometry. This pointer is + * initialized in the initialize() function, and serves as the manifold + * object that the triangulation is later given in create_coarse_mesh() + * where the triangulation clones it. + * + * The object is marked as 'const' to make it clear that it should not + * be modified once created. That is because the triangulation copies it, + * and modifying the current object will not have any impact on the + * manifold used by the triangulation. + */ + std::unique_ptr> manifold; + + /** + * Give a symbolic name to the manifold id to be used by this class. + */ + static const types::manifold_id my_manifold_id = 15; + + /** + * Bind boundary indicators to child cells after each mesh refinement round. + */ + void set_boundary_indicators (parallel::distributed::Triangulation &triangulation) const; + }; + } +} + + +#endif diff --git a/include/aspect/global.h.bak b/include/aspect/global.h.bak new file mode 100644 index 00000000000..c2de354a27a --- /dev/null +++ b/include/aspect/global.h.bak @@ -0,0 +1,312 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_global_h +#define _aspect_global_h + +#include + +#include + +DEAL_II_DISABLE_EXTRA_DIAGNOSTICS + +#include + +#include +#include + +DEAL_II_ENABLE_EXTRA_DIAGNOSTICS + + +#include + +namespace aspect +{ + /** + * The following are a set of global constants which may be used by ASPECT: + * (for sources of data and values used by ASPECT, see source/global.cc) + */ + namespace constants + { + /** + * Number of seconds in a year [s] + */ + constexpr double year_in_seconds = 60*60*24*365.2425; + + /** + * Zero degrees Celsius to Kelvin [K] + */ + constexpr double celsius_to_kelvin = 273.15; + + /** + * Convert angles in degree to radians. + */ + constexpr double degree_to_radians = dealii::numbers::PI / 180.; + + /** + * Convert angles in radians to degrees. + */ + constexpr double radians_to_degree = 180. / dealii::numbers::PI; + + /** + * Gas constant (also known as R) [J K^-1 mol^-1] + */ + constexpr double gas_constant = 8.3144621; + /** + * Avogadro's constant [mol^-1] + */ + constexpr double avogadro = 6.02214129e23; + /** + * Gravitational constant [m^3 kg^-1 s^-2] + * Value: 6.67430(15)E-11 (standard uncertainty in parenthesis) + * Source: 2018 CODATA Value: Newtonian constants of gravitation. + * The NIST Reference on Constants, Units, and Uncertainty. + * NIST. 20 May 2019. + */ + constexpr double big_g = 6.67430e-11; + + /** + * Constants for Earth: + */ + namespace earth + { + + /** + * Masses are taken from Yoder (1995) + */ + namespace masses + { + /** + * Planet mass [kg] + */ + constexpr double planet = 5.9736e24; + /** + * Mass of the whole core [kg] + */ + constexpr double core = 1.932e24; + /** + * Mass of the mantle [kg] + */ + constexpr double mantle = 4.043e24; + } + + /** + * Earth structure radii taken from the IASP91 model + */ + namespace iasp91_radii + { + /** + * Inner core radius [m], equivalent of 5150 km depth + */ + constexpr double inner_core = 1.2171e6; + /** + * Inner core radius [m], equivalent of 2889 km depth + */ + constexpr double core = 3.482e6; + /** + * Lower mantle radius [m], equivalent of 660 km depth + */ + constexpr double lower_mantle = 5.711e6; + /** + * Radius [m], equivalent of 5150 km depth + */ + constexpr double planet = 6.371e6; + } + + /** + * Gravity values taken from the PREM (Dziewonski and Anderson, 1981) + */ + namespace prem_gravity + { + /** + * Inner core boundary gravity [ms^-2] + */ + constexpr double icb = 4.4002; + /** + * Core-mantle boundary gravity [ms^-2] + */ + constexpr double cmb = 10.6823; + /** + * Upper-lower mantle boundary gravity [ms^-2] + */ + constexpr double ulmb = 10.0143; + /** + * Surface gravity [ms^-2] + */ + constexpr double surface = 9.8156; + } + + /** + * NIST "Standard gravity" (average gravitational acceleration at surface + * [ms^-2] + */ + constexpr double surface_gravity = 9.80665; + } + + /** + * Constants for Mars + */ + namespace mars + { + /** + * Mars structure radii + */ + namespace radii + { + /** + * Planetary radius from Seidermann et al., 2007 [m] + */ + constexpr double planet = 3.3895e6; + /** + * Core radius from Rivoldini et al., 2011 [m] + */ + constexpr double core = 1.794e6; + } + /** + * Surface gravity from Lodders et al., 1998 [ms^-2] + */ + constexpr double surface_gravity = 3.711; + } + } + + /** + * Number of seconds in a year [s] (deprecated) + */ + using constants::year_in_seconds; + + + /** + * A typedef that denotes the BOOST stream type for reading data during + * serialization. The type chosen here is a binary archive which we + * subsequently will have to un-compress. + */ + using iarchive = boost::archive::binary_iarchive; + + /** + * A typedef that denotes the BOOST stream type for writing data during + * serialization. The type chosen here is a binary archive which we compress + * before writing it into a file. + */ + using oarchive = boost::archive::binary_oarchive; + + /** + * A class we throw in exceptions in parallel jobs and that we can silently + * treat in main(). We do this, for example, in read_parameters() where each + * processor would otherwise throw the same exception and every processor + * would produce a tangle of output that is impenetrable in large parallel + * jobs. The same situation happens if a linear solver fails. Rather, we + * make processor 0 throw the real exception and every other processor + * converts the exception it wants to throw to an object of the current type + * -- which is caught in main() but doesn't produce any output (because + * processor 0 will already produce the output). + */ + class QuietException {}; + + + /** + * A namespace that contains typedefs for classes used in the linear algebra + * description. + */ + namespace LinearAlgebra + { + /** + * Typedef for the vector type used. + */ + using Vector = dealii::TrilinosWrappers::MPI::Vector; + + /** + * Typedef for the type used to describe vectors that consist of multiple + * blocks. + */ + using BlockVector = dealii::TrilinosWrappers::MPI::BlockVector; + + /** + * Typedef for the sparse matrix type used. + */ + using SparseMatrix = dealii::TrilinosWrappers::SparseMatrix; + + /** + * Typedef for the type used to describe sparse matrices that consist of + * multiple blocks. + */ + using BlockSparseMatrix = dealii::TrilinosWrappers::BlockSparseMatrix; + + /** + * Typedef for the base class for all preconditioners. + */ + using PreconditionBase = dealii::TrilinosWrappers::PreconditionBase; + + /** + * Typedef for the AMG preconditioner type used for the top left block of + * the Stokes matrix. + */ + using PreconditionAMG = dealii::TrilinosWrappers::PreconditionAMG; + + /** + * Typedef for the Incomplete Cholesky preconditioner used for other + * blocks of the system matrix. + */ + using PreconditionIC = dealii::TrilinosWrappers::PreconditionIC; + + /** + * Typedef for the Incomplete LU decomposition preconditioner used for + * other blocks of the system matrix. + */ + using PreconditionILU = dealii::TrilinosWrappers::PreconditionILU; + + /** + * Typedef for the Jacobi preconditioner used for free surface velocity + * projection. + */ + using PreconditionJacobi = dealii::TrilinosWrappers::PreconditionJacobi; + + /** + * Typedef for the block compressed sparsity pattern type. + */ + using BlockDynamicSparsityPattern = dealii::TrilinosWrappers::BlockSparsityPattern; + + /** + * Typedef for the compressed sparsity pattern type. + */ + using DynamicSparsityPattern = dealii::TrilinosWrappers::SparsityPattern; + } +} + + +/** + * Print a header into the given stream that will be written both to screen + * and to the log file and that provides basic information about what is + * running, with how many processes, and using which linear algebra library. + */ +template +void print_aspect_header(Stream &stream); + +/** + * A macro that is used in instantiating the ASPECT classes and functions for + * both 2d and 3d. Call this macro with the name of another macro that when + * called with a single integer argument instantiates the respective classes + * in the given space dimension. + */ +#define ASPECT_INSTANTIATE(INSTANTIATIONS) \ + INSTANTIATIONS(2) \ + INSTANTIATIONS(3) + +#endif diff --git a/include/aspect/gravity_model/ascii_data.h.bak b/include/aspect/gravity_model/ascii_data.h.bak new file mode 100644 index 00000000000..1c1d407bd6a --- /dev/null +++ b/include/aspect/gravity_model/ascii_data.h.bak @@ -0,0 +1,99 @@ +/* + Copyright (C) 2016 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_gravity_model_ascii_data_h +#define _aspect_gravity_model_ascii_data_h + +#include +#include +#include + +namespace aspect +{ + namespace GravityModel + { + using namespace dealii; + + /** + * A class that implements a gravity description based on + * an AsciiData input file. + * + * @ingroup GravityModels + */ + template + class AsciiData : public Utilities::AsciiDataProfile, public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + AsciiData (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataProfile::initialize; + + /** + * Return the gravity as a function of position. + */ + Tensor<1,dim> gravity_vector (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Object containing the data profile. + */ + std::unique_ptr> profile; + + /** + * The column index of the gravity column in the data file. + */ + unsigned int gravity_index; + }; + } +} + + +#endif diff --git a/include/aspect/gravity_model/function.h.bak b/include/aspect/gravity_model/function.h.bak new file mode 100644 index 00000000000..16119d1166f --- /dev/null +++ b/include/aspect/gravity_model/function.h.bak @@ -0,0 +1,100 @@ +/* + Copyright (C) 2014 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_gravity_model_function_h +#define _aspect_gravity_model_function_h + +#include +#include +#include + +#include + +namespace aspect +{ + namespace GravityModel + { + using namespace dealii; + + /** + * A class that implements gravity based on a functional description + * provided in the input file. + * + * @ingroup GravityModels + */ + template + class Function : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + Function (); + + /** + * A function that is called at the beginning of each time step to + * indicate what the model time is for which the gravity will + * next be evaluated. For the current class, the function passes to + * the parsed function what the current time is. + */ + void update () override; + + /** + * Return the gravity vector as a function of position. + */ + Tensor<1,dim> gravity_vector (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A function object representing the gravity. + */ + Functions::ParsedFunction function; + + /** + * The coordinate representation to evaluate the function. Possible + * choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + }; + } +} + + +#endif diff --git a/include/aspect/gravity_model/interface.h.bak b/include/aspect/gravity_model/interface.h.bak new file mode 100644 index 00000000000..a370ebb5e5f --- /dev/null +++ b/include/aspect/gravity_model/interface.h.bak @@ -0,0 +1,143 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_gravity_model_interface_h +#define _aspect_gravity_model_interface_h + +#include +#include +#include + +namespace aspect +{ + /** + * A namespace in which we define everything that has to do with modeling + * gravity. + * + * @ingroup GravityModels + */ + namespace GravityModel + { + using namespace dealii; + + /** + * A base class for parameterizations of gravity models. + * + * @ingroup GravityModels + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Return the gravity vector as a function of position. + */ + virtual Tensor<1,dim> gravity_vector (const Point &position) const = 0; + }; + + + + + /** + * Register a gravity model so that it can be selected from the parameter + * file. + * + * @param name A string that identifies the gravity model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this gravity model wants to read + * from input files. + * @param factory_function A pointer to a function that can create an + * object of this gravity model. + * + * @ingroup GravityModels + */ + template + void + register_gravity_model (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * A function that given the name of a model returns a pointer to an + * object that describes it. Ownership of the pointer is transferred to + * the caller. + * + * The model object returned is not yet initialized and has not read its + * runtime parameters yet. + * + * @ingroup GravityModels + */ + template + std::unique_ptr> + create_gravity_model (ParameterHandler &prm); + + + /** + * Declare the runtime parameters of the registered gravity models. + * + * @ingroup GravityModels + */ + template + void + declare_parameters (ParameterHandler &prm); + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + template + void + write_plugin_graph (std::ostream &output_stream); + + + /** + * Given a class name, a name, and a description for the parameter file + * for a gravity model, register it with the functions that can declare + * their parameters and create these objects. + * + * @ingroup GravityModels + */ +#define ASPECT_REGISTER_GRAVITY_MODEL(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_GRAVITY_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::GravityModel::register_gravity_model<2>, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::GravityModel::register_gravity_model<3>, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/gravity_model/radial.h.bak b/include/aspect/gravity_model/radial.h.bak new file mode 100644 index 00000000000..df05abe5ce9 --- /dev/null +++ b/include/aspect/gravity_model/radial.h.bak @@ -0,0 +1,143 @@ +/* + Copyright (C) 2014 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_gravity_model_radial_h +#define _aspect_gravity_model_radial_h + +#include +#include + +namespace aspect +{ + namespace GravityModel + { + using namespace dealii; + + /** + * A class that describes gravity as a radial vector of constant + * magnitude. The magnitude's value is read from the input file. + * + * @ingroup GravityModels + */ + template + class RadialConstant : public Interface, public SimulatorAccess + { + public: + /** + * Return the gravity vector as a function of position. + */ + Tensor<1,dim> gravity_vector (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Magnitude of the gravity vector. + */ + double magnitude; + }; + + + /** + * This model has been removed due to its misleading name. The available + * AsciiData gravity model (using default parameters) is much more + * earth-like, since it uses the gravity profile used in the construction + * of the Preliminary Reference Earth Model (PREM, Dziewonski and Anderson, + * 1981). + * + * This is the model used and discussed in the step-32 tutorial program of + * deal.II. + * + * @ingroup GravityModels + */ + template + class RadialEarthLike : public Interface, public SimulatorAccess + { + public: + /** + * Initialization. + */ + void initialize() override; + + /** + * Return the gravity vector as a function of position. + */ + Tensor<1,dim> gravity_vector (const Point &position) const override; + }; + + + /** + * A class that describes gravity as a radial vector of linearly + * changing magnitude with depth. + * + * @ingroup GravityModels + */ + template + class RadialLinear : public Interface, public SimulatorAccess + { + public: + /** + * Return the gravity vector as a function of position. + */ + Tensor<1,dim> gravity_vector (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Magnitude of the gravity vector at the surface, m/s^2 + */ + double magnitude_at_surface; + + /** + * Magnitude of the gravity vector at the bottom, m/s^2. + * 'Bottom' means at the maximum depth of the provided geometry, for + * a full sphere this means the center. + */ + double magnitude_at_bottom; + + }; + } +} + +#endif diff --git a/include/aspect/gravity_model/vertical.h.bak b/include/aspect/gravity_model/vertical.h.bak new file mode 100644 index 00000000000..95d834ad3be --- /dev/null +++ b/include/aspect/gravity_model/vertical.h.bak @@ -0,0 +1,72 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_gravity_model_vertical_h +#define _aspect_gravity_model_vertical_h + +#include +#include + +namespace aspect +{ + namespace GravityModel + { + using namespace dealii; + + /** + * A class that describes gravity as a vector of constant magnitude + * pointing vertically down. + * + * @ingroup GravityModels + */ + template + class Vertical : public Interface, public SimulatorAccess + { + public: + /** + * Return the gravity vector as a function of position. + */ + Tensor<1,dim> gravity_vector (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Magnitude of the gravity vector. + */ + double gravity_magnitude; + + }; + } +} + +#endif diff --git a/include/aspect/heating_model/adiabatic_heating.h.bak b/include/aspect/heating_model/adiabatic_heating.h.bak new file mode 100644 index 00000000000..bd8588b3a49 --- /dev/null +++ b/include/aspect/heating_model/adiabatic_heating.h.bak @@ -0,0 +1,104 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_heating_model_adiabatic_heating_h +#define _aspect_heating_model_adiabatic_heating_h + +#include +#include + +namespace aspect +{ + namespace HeatingModel + { + using namespace dealii; + + /** + * A class that implements a standard adiabatic heating rate. + * + * This adds the term from adiabatic compression heating + * $ \alpha T (\mathbf u \cdot \nabla p) $ + * where we use the definition of + * $ \alpha = - \frac{1}{\rho} \frac{\partial \rho}{\partial T} $ + * Note: this term is often simplified using the relationship + * $ \rho \mathbf g = - \nabla p $ + * to yield + * $ - \alpha \rho T (\mathbf u \cdot \mathbf g) $ + * + * The user can specify if the simplification should be used + * by setting the corresponding flag in the input file. + * Also see the Equations section in the manual. + * + * @ingroup HeatingModels + */ + template + class AdiabaticHeating : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Returns whether we compute a simplified adiabatic heating term by + * neglecting dynamic pressure effects. I.e. we use + * $ \alpha T (\mathbf u \cdot \nabla p) $ + * as adiabatic heating term if this function returns false, and + * $ - \alpha \rho T (\mathbf u \cdot \mathbf g) $ + * if it returns true. + */ + bool + use_simplified_adiabatic_heating() const; + + /** + * Compute the heating model outputs for this class. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @} + */ + + private: + bool simplified_adiabatic_heating; + }; + } +} + + +#endif diff --git a/include/aspect/heating_model/adiabatic_heating_of_melt.h.bak b/include/aspect/heating_model/adiabatic_heating_of_melt.h.bak new file mode 100644 index 00000000000..d992018020e --- /dev/null +++ b/include/aspect/heating_model/adiabatic_heating_of_melt.h.bak @@ -0,0 +1,108 @@ +/* + Copyright (C) 2015 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_heating_model_adiabatic_heating_of_melt_h +#define _aspect_heating_model_adiabatic_heating_of_melt_h + +#include +#include + +namespace aspect +{ + namespace HeatingModel + { + using namespace dealii; + + /** + * A class that implements a standard adiabatic heating rate + * for partially molten material. + * + * This adds the term from adiabatic compression heating + * $ \alpha T (-\phi \mathbf u_s \cdot \nabla p) + * + \alpha T (\phi \mathbf u_f \cdot \nabla p)$ + * where we use the definition of + * $ \alpha = - \frac{1}{\rho} \frac{\partial \rho}{\partial T} $ + * Note: this term is often simplified using the relationship + * $ \rho \mathbf g = - \nabla p $ + * to yield + * $ \alpha \rho_s T (\phi \mathbf u_s \cdot \mathbf g) + * - \alpha \rho_f T (\phi \mathbf u_f \cdot \mathbf g) $ + * + * The user can specify if the simplification should be used + * by setting the corresponding flag in the input file. + * Also see the Equations section in the manual. + * + * @ingroup HeatingModels + */ + template + class AdiabaticHeatingMelt : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Compute the heating model outputs for this class. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Allow the heating model to attach additional material model outputs. + */ + void + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const override; + + /** + * Allow the heating model to attach additional material model inputs it needs. + */ + void + create_additional_material_model_inputs(MaterialModel::MaterialModelInputs &inputs) const override; + + /** + * @} + */ + + private: + bool simplified_adiabatic_heating; + }; + } +} + + +#endif diff --git a/include/aspect/heating_model/compositional_heating.h.bak b/include/aspect/heating_model/compositional_heating.h.bak new file mode 100644 index 00000000000..5d1a8c6dde1 --- /dev/null +++ b/include/aspect/heating_model/compositional_heating.h.bak @@ -0,0 +1,94 @@ +/* + Copyright (C) 2017 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_heating_model_compositional_heating_h +#define _aspect_heating_model_compositional_heating_h + +#include +#include + +namespace aspect +{ + namespace HeatingModel + { + using namespace dealii; + + /** + * A class that implements a heating model where each compositional field + * is assigned a user-defined internal heating value. + * + * @ingroup HeatingModels + */ + template + class CompositionalHeating : public Interface, public SimulatorAccess + { + public: + /** + * Return the magnitude of heat production arising from values assigned + * to each compositional field. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Magnitude of heat production for each compositional field + */ + std::vector heating_values; + + /** + * A vector with as many entries as compositional fields. + * If the entry for a particular field is true the field is considered + * during the averaging of heat production rates, if not the field is + * ignored. This is useful if some compositional fields + * are used to track properties like finite strain that should not + * contribute to heat production. + */ + std::vector fields_used_in_heat_production_averaging; + + /** + * Similar to fields_used_in_heat_production_averaging, except it + * determines whether to include the background field in the heat + * production computation. + */ + bool use_background_field_for_heat_production_averaging; + }; + } +} + + +#endif diff --git a/include/aspect/heating_model/constant_heating.h.bak b/include/aspect/heating_model/constant_heating.h.bak new file mode 100644 index 00000000000..8eaa75402be --- /dev/null +++ b/include/aspect/heating_model/constant_heating.h.bak @@ -0,0 +1,79 @@ +/* + Copyright (C) 2014 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_heating_model_constant_heating_h +#define _aspect_heating_model_constant_heating_h + +#include + +namespace aspect +{ + namespace HeatingModel + { + using namespace dealii; + + /** + * A class that implements a constant radiogenic heating rate. + * + * @ingroup HeatingModels + */ + template + class ConstantHeating : public Interface + { + public: + /** + * Return the heating terms. For the current class, this + * function obviously simply returns a constant value. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @} + */ + + private: + double radiogenic_heating_rate; + }; + } +} + + +#endif diff --git a/include/aspect/heating_model/function.h.bak b/include/aspect/heating_model/function.h.bak new file mode 100644 index 00000000000..360677b3679 --- /dev/null +++ b/include/aspect/heating_model/function.h.bak @@ -0,0 +1,97 @@ +/* + Copyright (C) 2014 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_heating_model_function_h +#define _aspect_heating_model_function_h + +#include +#include + +#include + +namespace aspect +{ + namespace HeatingModel + { + using namespace dealii; + + /** + * A class that implements a heating model based on a functional + * description provided in the input file. + * + * @ingroup HeatingModels + */ + template + class Function : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + Function (); + + /** + * Return the specific heating rate as calculated by the function + * object. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + /** + * A function that is called at the beginning of each time step to + * allow the model to do whatever necessary. In this case the time of + * the function object is updated. + */ + void + update () override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A function object representing the components of the velocity. + */ + Functions::ParsedFunction heating_model_function; + + /** + * The coordinate representation to evaluate the function. Possible + * choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + }; + } +} + + +#endif diff --git a/include/aspect/heating_model/interface.h.bak b/include/aspect/heating_model/interface.h.bak new file mode 100644 index 00000000000..d40d83d0ec9 --- /dev/null +++ b/include/aspect/heating_model/interface.h.bak @@ -0,0 +1,384 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_heating_model_interface_h +#define _aspect_heating_model_interface_h + +#include +#include +#include +#include + +#include +#include + +#include +#include + + +namespace aspect +{ + template class SimulatorAccess; + /** + * A namespace in which we define everything that has to do with defining + * the heating model. + * + * @ingroup HeatingModels + */ + namespace HeatingModel + { + using namespace dealii; + + /** + * A data structure with the output field of the + * HeatingModel::Interface::evaluate() function. The vectors are the + * values at the different positions given by + * MaterialModelInputs::position. + */ + struct HeatingModelOutputs + { + /** + * Constructor. Initialize the various arrays of this structure with the + * given number of quadrature points and (finite element) components. + * + * @param n_points The number of quadrature points for which input + * quantities will be provided. + * @param n_comp The number of vector quantities (in the order in which + * the Introspection class reports them) for which input will be + * provided. + */ + HeatingModelOutputs (const unsigned int n_points, + const unsigned int n_comp); + + /** + * All source terms of the temperature equation that represent a + * continuous process leading to a rate of change in temperature + * at the given position. This includes shear heating, adiabatic + * heating, radiogenic heat production, or any other heating rates + * on the right hand side of the energy equation. + */ + std::vector heating_source_terms; + + /** + * The source terms of the temperature equation that represent + * fast changes in temperature (compared to the advection time + * scale), for example due to reactions, at the given position. + * On the advection time scale, these reactions might look like + * instantaneous changes in temperatures. This includes for example + * latent heat of melt. + * + * These reaction rates are only used in the operator_splitting nonlinear + * solver scheme, which allows it to solve reactions of compositional + * fields and temperature decoupled from the advection, and using a + * different time step size. + * In this case, they are used in addition to (and independent from) any + * heating_source_terms that a heating model defines, which are assembled + * as usual. For any other solver scheme, these values are ignored. + * + * In contrast to the heating source terms, these terms are actual changes + * in temperature (units K/s or K/yr) rather than changes in energy. + */ + std::vector rates_of_temperature_change; + + /** + * Left hand side contribution of latent heat; this is added to the + * $\rho C_p$ term on the left hand side of the energy equation. + */ + std::vector lhs_latent_heat_terms; + + /** + * Reset function. Resets all of the values in the heating model + * outputs to their uninitialized values (NaN for the source and latent + * heat terms, 0 for the rates of temperature change). + */ + void + reset (); + }; + + /** + * A base class for parameterizations of heating models. + * + * @ingroup HeatingModels + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Function to compute the heating terms in @p heating_model_outputs + * given the inputs in @p material_model_inputs and the outputs of the + * material model in @p material_model_outputs. + * All parts of the @p heating_model_outputs structure have to be + * filled, heating_source_terms with the value of the heating rate and + * lhs_latent_heat_terms with the part of the latent heat that depends + * on the temperature change (and thus ends up on the left hand side of + * the temperature equation) at each quadrature point as defined in + * @p material_model_inputs, setting them to zero if they are not to + * be used in the computation. + */ + virtual + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const = 0; + + /** + * Allow the heating model to attach additional material model outputs. + * The default implementation of this function does not add any + * outputs. Consequently, derived classes do not have to overload + * this function if they do not need any additional outputs. + */ + virtual + void + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const; + + /** + * Allow the heating model to attach additional material model inputs + * it needs. The default implementation of this function does not add any + * inputs. Consequently, derived classes do not have to overload + * this function if they do not need any additional inputs. + */ + virtual + void + create_additional_material_model_inputs(MaterialModel::MaterialModelInputs &inputs) const; + }; + + + /** + * A class that manages all objects that provide functionality to the + * heating models. + * + * @ingroup HeatingModels + */ + template + class Manager : public Plugins::ManagerBase>, public SimulatorAccess + { + public: + /** + * Returns true if the adiabatic heating plugin is found in the + * list of active heating models. + */ + bool + adiabatic_heating_enabled() const; + + /** + * Returns true if the shear heating plugin is found in the + * list of active heating models. + */ + bool + shear_heating_enabled() const; + + /** + * Declare the parameters of all known heating plugins, as + * well as of ones this class has itself. + */ + static + void + declare_parameters (ParameterHandler &prm); + + + /** + * Read the parameters this class declares from the parameter file. + * This determines which heating model objects will be created; then + * let these objects read their parameters as well. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * A function that calls the evaluate function of all the individual + * heating models and adds up the values of the individual heating + * model outputs. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const; + + /** + * Allow the heating model plugins to attach additional material model + * inputs and outputs by looping over all registered plugins and calling + * their respective member functions. + */ + virtual + void + create_additional_material_model_inputs_and_outputs(MaterialModel::MaterialModelInputs &material_model_inputs, + MaterialModel::MaterialModelOutputs &material_model_outputs) const; + + + /** + * A function that is used to register heating model objects in such + * a way that the Manager can deal with all of them without having to + * know them by name. This allows the files in which individual + * plugins are implemented to register these plugins, rather than also + * having to modify the Manager class by adding the new heating plugin + * class. + * + * @param name A string that identifies the heating model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this heating model wants to read + * from input files. + * @param factory_function A pointer to a function that can create an + * object of this heating model. + * + * @ingroup HeatingModels + */ + static + void + register_heating_model (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + + /** + * Return a list of names of all heating models currently used in the + * computation, as specified in the input file. + */ + const std::vector & + get_active_heating_model_names () const; + + /** + * Return a list of pointers to all heating models currently used in the + * computation, as specified in the input file. + */ + const std::list>> & + get_active_heating_models () const; + + /** + * Go through the list of all heating models that have been selected + * in the input file (and are consequently currently active) and return + * true if one of them has the desired type specified by the template + * argument. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,HeatingModelType>::value>> + bool + has_matching_heating_model () const; + + /** + * Go through the list of all heating models that have been selected + * in the input file (and are consequently currently active) and see + * if one of them has the type specified by the template + * argument or can be cast to that type. If so, return a reference + * to it. If no heating model is active that matches the given type, + * throw an exception. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,HeatingModelType>::value>> + const HeatingModelType & + get_matching_heating_model () const; + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + /** + * Exception. + */ + DeclException1 (ExcHeatingModelNameNotFound, + std::string, + << "Could not find entry <" + << arg1 + << "> among the names of registered heating model objects."); + private: + /** + * A list of names of heating model objects that have been requested + * in the parameter file. + */ + std::vector model_names; + }; + + + + template + template + inline + bool + Manager::has_matching_heating_model () const + { + return this->template has_matching_plugin_object(); + } + + + template + template + inline + const HeatingModelType & + Manager::get_matching_heating_model () const + { + return this->template get_matching_plugin_object(); + } + + + /** + * Return a string that consists of the names of heating models that can + * be selected. These names are separated by a vertical line '|' so + * that the string can be an input to the deal.II classes + * Patterns::Selection or Patterns::MultipleSelection. + */ + template + std::string + get_valid_model_names_pattern (); + + + /** + * Given a class name, a name, and a description for the parameter file + * for a heating model, register it with the + * aspect::HeatingModel::Manager class. + * + * @ingroup HeatingModels + */ +#define ASPECT_REGISTER_HEATING_MODEL(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_HEATING_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::HeatingModel::Manager<2>::register_heating_model, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::HeatingModel::Manager<3>::register_heating_model, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/heating_model/latent_heat.h.bak b/include/aspect/heating_model/latent_heat.h.bak new file mode 100644 index 00000000000..2761cccfae6 --- /dev/null +++ b/include/aspect/heating_model/latent_heat.h.bak @@ -0,0 +1,74 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_heating_model_latent_heat_h +#define _aspect_heating_model_latent_heat_h + +#include + +namespace aspect +{ + namespace HeatingModel + { + using namespace dealii; + + /** + * A class that implements a standard formulation of latent heat. + * This includes a left hand side and a right hand side term: + * + * The left hand side is + * $ -\rho T \frac{\partial S}{\partial T} \frac{D T}{D t}$ + * so that we can add + * $ -\rho T \frac{\partial S}{\partial T} $ + * to the $\rho C_p$ term. + * + * The right-hand side term from latent heating is + * $\frac{\partial S}{\partial p} T \rho (u \dot \nabla p)$. + * + * T, u, and p are the solutions from the previous time step or + * are extrapolated from there, depending on what is provided + * in the input arguments of this function. + * + * Formulation modified after Christensen, Ulrich R. & Yuen, + * David A.: Layered convection induced by phase transitions, + * Journal of Geophysical Research: Solid Earth (1985). + * + * Also see the Equations section in the manual. + * + * @ingroup HeatingModels + */ + template + class LatentHeat : public Interface + { + public: + /** + * Compute the heating model outputs for this class. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + }; + } +} + + +#endif diff --git a/include/aspect/heating_model/latent_heat_melt.h.bak b/include/aspect/heating_model/latent_heat_melt.h.bak new file mode 100644 index 00000000000..272771e2b82 --- /dev/null +++ b/include/aspect/heating_model/latent_heat_melt.h.bak @@ -0,0 +1,91 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_heating_model_latent_heat_melt_h +#define _aspect_heating_model_latent_heat_melt_h + +#include +#include + +namespace aspect +{ + namespace HeatingModel + { + using namespace dealii; + + /** + * A class that implements a standard formulation of latent heat + * of melting. This assumes that there is a compositional field + * called porosity, and it uses the reaction term of this field + * (the fraction of material that melted in the current time step) + * multiplied by a constant entropy change for melting 100% + * of the material as source term of the heating model. + * The left-hand side term is zero. + * + * @ingroup HeatingModels + */ + template + class LatentHeatMelt : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Compute the heating model outputs for this class. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @} + */ + + virtual + void + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const override; + + private: + // entropy change upon melting + double melting_entropy_change; + bool retrieve_entropy_change_from_material_model; + }; + } +} + + +#endif diff --git a/include/aspect/heating_model/radioactive_decay.h.bak b/include/aspect/heating_model/radioactive_decay.h.bak new file mode 100644 index 00000000000..d4bf222225a --- /dev/null +++ b/include/aspect/heating_model/radioactive_decay.h.bak @@ -0,0 +1,119 @@ +/* + Copyright (C) 2014 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_heating_model_radioactive_decay_h +#define _aspect_heating_model_radioactive_decay_h + +#include +#include + +#include + +namespace aspect +{ + namespace HeatingModel + { + using namespace dealii; + + /** + * A class that implements a heating model based on radioactive decay. + * + * @ingroup HeatingModels + */ + template + class RadioactiveDecay : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + RadioactiveDecay (); + + /** + * Return the specific heating rate as calculated by radioactive + * decay. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * Number of radio active heating elements. + */ + unsigned int n_radio_heating_elements; + + /** + * Store the half life of different elements. + */ + std::vector half_decay_times; + + /** + * Store the unit heating rate of different elements. + */ + std::vector radioactive_heating_rates; + + /** + * Store the initial concentration in the crust. + */ + std::vector radioactive_initial_concentrations_crust; + + /** + * Store the initial concentration in the mantle. + */ + std::vector radioactive_initial_concentrations_mantle; + + /** + * Whether crust defined by composition or depth + */ + bool is_crust_defined_by_composition; + + /** + * Depth of the crust. + */ + double crust_depth; + + /** + * Composition number of crust. + */ + unsigned int crust_composition_num; + }; + } +} + + +#endif diff --git a/include/aspect/heating_model/shear_heating.h.bak b/include/aspect/heating_model/shear_heating.h.bak new file mode 100644 index 00000000000..ee9cd7bf53c --- /dev/null +++ b/include/aspect/heating_model/shear_heating.h.bak @@ -0,0 +1,119 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_heating_model_shear_heating_h +#define _aspect_heating_model_shear_heating_h + +#include +#include +#include + +namespace aspect +{ + namespace HeatingModel + { + using namespace dealii; + + /** + * A class that implements a standard shear heating rate. + * + * Add the term + * $ 2 \eta \left( \varepsilon - \frac{1}{3} \text{tr} + * \varepsilon \mathbf 1 \right) : \left( \varepsilon - \frac{1}{3} + * \text{tr} \varepsilon \mathbf 1 \right) $ + * + * Also see the Equations section in the manual. + * + * @ingroup HeatingModels + */ + template + class ShearHeating : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Compute the heating model outputs for this class. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + /** + * Allow the heating model to attach additional material model outputs. + */ + void + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &material_model_outputs) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Parameters used for limiting the stress being used in the shear + * heating computation. To prevent shear heating from becoming + * unrealistically high, a Drucker-Prager yield criterion as given + * in the DruckerPrager rheology model can be used to define a + * maximum stress computed from the given cohesion and friction + * angle. + */ + bool limit_stress; + double cohesion; + double friction_angle; + MaterialModel::Rheology::DruckerPrager drucker_prager_plasticity; + }; + + + /** + * Additional output fields for the shear heating computation + * to be added to the MaterialModel::MaterialModelOutputs structure + * and filled in the MaterialModel::evaluate() function. + */ + template + class ShearHeatingOutputs : public MaterialModel::NamedAdditionalMaterialOutputs + { + public: + ShearHeatingOutputs(const unsigned int n_points); + + std::vector get_nth_output(const unsigned int idx) const override; + + /** + * The fraction of the deformation work that is released as shear heating + * rather than being converted into other forms of energy (such as, for + * example, surface energy of grains). If it is set to 1, all deformation + * work will go into shear heating. + */ + std::vector shear_heating_work_fractions; + }; + } +} + + +#endif diff --git a/include/aspect/heating_model/shear_heating_with_melt.h.bak b/include/aspect/heating_model/shear_heating_with_melt.h.bak new file mode 100644 index 00000000000..01e1847ae56 --- /dev/null +++ b/include/aspect/heating_model/shear_heating_with_melt.h.bak @@ -0,0 +1,78 @@ +/* + Copyright (C) 2015 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_heating_model_shear_heating_with_melt_h +#define _aspect_heating_model_shear_heating_with_melt_h + +#include +#include + +namespace aspect +{ + namespace HeatingModel + { + using namespace dealii; + + /** + * A class that implements a standard shear heating rate for dissipation + * heating of partially molten material. + * + * Add the term + * $ \xi \left( \nabla \cdot \mathbf u_s \right)^2 $, + * which corresponds to bulk (compression) heating, + * and the term + * $ \frac{\eta_f \phi^2}{k_{\phi}} \left( \mathbf u_f - \mathbf u_s \right)^2 $, + * which corresponds to heating due to melt segregation. + * Both terms are heating source terms, and the left-hand side term is zero. + * + * Also see the Equations section in the manual. + * + * @ingroup HeatingModels + */ + template + class ShearHeatingMelt : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Compute the heating model outputs for this class. + */ + void + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const override; + + /** + * Allow the heating model to attach additional material model outputs. + */ + void + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &) const override; + + /** + * Allow the heating model to attach additional material model inputs it needs. + */ + void + create_additional_material_model_inputs(MaterialModel::MaterialModelInputs &) const override; + }; + } +} + + +#endif diff --git a/include/aspect/initial_composition/adiabatic_density.h.bak b/include/aspect/initial_composition/adiabatic_density.h.bak new file mode 100644 index 00000000000..9229a7c753c --- /dev/null +++ b/include/aspect/initial_composition/adiabatic_density.h.bak @@ -0,0 +1,58 @@ +/* + Copyright (C) 2017 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_composition_adiabatic_density_h +#define _aspect_initial_composition_adiabatic_density_h + +#include +#include +#include + +namespace aspect +{ + namespace InitialComposition + { + using namespace dealii; + + /** + * A class that implements initial conditions for the compositional fields + * based on the adiabatic density profile. Note that only the field + * of the type 'density' will be filled, for all other fields + * this plugin returns 0.0. + * + * @ingroup InitialCompositionModels + */ + template + class AdiabaticDensity : public Interface, + public SimulatorAccess + { + public: + /** + * Return the initial composition as the adiabatic density at this + * point. + */ + double initial_composition (const Point &position, const unsigned int n_comp) const override; + }; + } +} + + +#endif diff --git a/include/aspect/initial_composition/ascii_data.h.bak b/include/aspect/initial_composition/ascii_data.h.bak new file mode 100644 index 00000000000..0a75b0af38d --- /dev/null +++ b/include/aspect/initial_composition/ascii_data.h.bak @@ -0,0 +1,90 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_composition_ascii_data_h +#define _aspect_initial_composition_ascii_data_h + +#include + +#include +#include + + +namespace aspect +{ + namespace InitialComposition + { + using namespace dealii; + + /** + * A class that implements the prescribed compositional fields determined + * from a AsciiData input file. + * + * @ingroup InitialCompositionModels + */ + template + class AsciiData : public Interface, public aspect::SimulatorAccess + { + public: + /** + * Empty Constructor. + */ + AsciiData (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + /** + * Return the initial composition as a function of position. For the + * current class, this function returns value from the text files. + */ + double + initial_composition (const Point &position, + const unsigned int n_comp) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The dataset that contains the initial composition. + */ + std::unique_ptr> ascii_data_initial; + }; + } +} + + +#endif diff --git a/include/aspect/initial_composition/ascii_data_layered.h.bak b/include/aspect/initial_composition/ascii_data_layered.h.bak new file mode 100644 index 00000000000..064e3cda15a --- /dev/null +++ b/include/aspect/initial_composition/ascii_data_layered.h.bak @@ -0,0 +1,87 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_composition_ascii_data_layered_h +#define _aspect_initial_composition_ascii_data_layered_h + +#include + +#include +#include + + +namespace aspect +{ + namespace InitialComposition + { + using namespace dealii; + + /** + * A class that implements prescribed compositional fields determined from + * AsciiData input files. Each file defines a layer boundary as a grid of points. + * + * @ingroup InitialCompositionModels + */ + template + class AsciiDataLayered : public Interface, public Utilities::AsciiDataLayered + { + public: + /** + * Empty Constructor. + */ + AsciiDataLayered (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataLayered::initialize; + + /** + * Return the initial composition as a function of position. For the + * current class, this function returns value from the text files. + */ + double + initial_composition (const Point &position, + const unsigned int n_comp) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + }; + } +} + + +#endif diff --git a/include/aspect/initial_composition/entropy_table_lookup.h.bak b/include/aspect/initial_composition/entropy_table_lookup.h.bak new file mode 100644 index 00000000000..fed4a58a985 --- /dev/null +++ b/include/aspect/initial_composition/entropy_table_lookup.h.bak @@ -0,0 +1,111 @@ +/* + Copyright (C) 2017 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_composition_entropy_table_lookup_h +#define _aspect_initial_composition_entropy_table_lookup_h + +#include +#include +#include +#include + +namespace aspect +{ + namespace InitialComposition + { + using namespace dealii; + + /** + * A class that implements initial conditions for the entropy field + * Note that this plugin only + * works if there is a compositional field called 'entropy'. + * All compositional fields except entropy are not changed by this plugin. + * + * @ingroup InitialCompositionModels + */ + template + class EntropyTableLookUp : public Interface, + public SimulatorAccess + { + public: + /** + * Initialize the plugin. + */ + void initialize () override; + + /** + * Return the initial composition as a function of position and number + * of compositional field. + */ + double initial_composition (const Point &position, + const unsigned int compositional_index) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Information about the location of data files. + */ + std::string data_directory; + std::string material_file_name; + + /** + * Index of the entropy in the compositional fields + */ + unsigned entropy_index; + + /** + * A shared pointer to the initial temperature object + * that ensures that the current object can continue + * to access the initial temperature object beyond the + * first time step. + */ + std::shared_ptr> initial_temperature_manager; + + /** + * A shared pointer to the initial composition object + * that ensures that the current object can continue + * to access the initial composition object beyond the + * first time step. + */ + std::shared_ptr> initial_composition_manager; + + /** + * Pointer to the StructuredDataLookup object that holds the material data. + */ + std::unique_ptr> material_lookup; + }; + } +} + + +#endif diff --git a/include/aspect/initial_composition/function.h.bak b/include/aspect/initial_composition/function.h.bak new file mode 100644 index 00000000000..15d0ffc7170 --- /dev/null +++ b/include/aspect/initial_composition/function.h.bak @@ -0,0 +1,89 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_composition_function_h +#define _aspect_initial_composition_function_h + +#include +#include +#include + +#include + +namespace aspect +{ + namespace InitialComposition + { + using namespace dealii; + + /** + * A class that implements initial conditions for the compositional fields + * based on a functional description provided in the input file. + * + * @ingroup InitialCompositionModels + */ + template + class Function : public Interface, + public SimulatorAccess + { + public: + /** + * Return the initial composition as a function of position and number + * of compositional field. + */ + double initial_composition (const Point &position, const unsigned int n_comp) const override; + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A function object representing the compositional fields. + */ + std::unique_ptr> function; + + /** + * The coordinate representation to evaluate the function. Possible + * choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + }; + } +} + + +#endif diff --git a/include/aspect/initial_composition/interface.h.bak b/include/aspect/initial_composition/interface.h.bak new file mode 100644 index 00000000000..96a1f5df87c --- /dev/null +++ b/include/aspect/initial_composition/interface.h.bak @@ -0,0 +1,280 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_composition_interface_h +#define _aspect_initial_composition_interface_h + +#include +#include +#include + +#include +#include + +#include +#include + + +namespace aspect +{ + template class SimulatorAccess; + + /** + * A namespace in which we define everything that has to do with defining + * the initial composition. + * + * @ingroup InitialCompositions + */ + namespace InitialComposition + { + using namespace dealii; + + /** + * A base class for parameterizations of initial conditions. + * + * @ingroup InitialCompositions + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Return the initial composition as a function of position. + */ + virtual + double initial_composition (const Point &position, const unsigned int n_comp) const = 0; + }; + + + + /** + * A class that manages all initial composition objects. + * + * @ingroup InitialCompositions + */ + template + class Manager : public Plugins::ManagerBase>, public SimulatorAccess + { + public: + /** + * Destructor. Made virtual since this class has virtual member + * functions. + */ + ~Manager () override; + + /** + * Update function. Called once at the beginning of a timestep to + * update all plugin objects. + */ + void update () override; + + /** + * Declare the parameters of all known initial composition plugins, as + * well as of ones this class has itself. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * This determines which initial composition objects will be created; + * then let these objects read their parameters as well. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * A function that calls the initial_composition functions of all + * individual initial composition objects for the composition given + * by @p n_comp, and adds up the values of the + * individual calls. + */ + double + initial_composition (const Point &position, + const unsigned int n_comp) const; + + /** + * A function that is used to register initial composition objects in + * such a way that the Manager can deal with all of them without having + * to know them by name. This allows the files in which individual + * plugins are implemented to register these plugins, rather than also + * having to modify the Manager class by adding the new initial + * composition plugin class. + * + * @param name A string that identifies the initial composition model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this initial composition model + * wants to read from input files. + * @param factory_function A pointer to a function that can create an + * object of this initial composition model. + */ + static + void + register_initial_composition (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + + /** + * Return a list of names of all initial composition models currently + * used in the computation, as specified in the input file. + */ + const std::vector & + get_active_initial_composition_names () const; + + /** + * Return a list of pointers to all initial composition models + * currently used in the computation, as specified in the input file. + */ + const std::list>> & + get_active_initial_composition_conditions () const; + + /** + * Go through the list of all initial composition models that have been selected + * in the input file (and are consequently currently active) and return + * true if one of them has the desired type specified by the template + * argument. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,InitialCompositionType>::value>> + bool + has_matching_initial_composition_model () const; + + /** + * Go through the list of all initial composition models that have been selected + * in the input file (and are consequently currently active) and see + * if one of them has the type specified by the template + * argument or can be cast to that type. If so, return a reference + * to it. If no initial composition model is active that matches the given type, + * throw an exception. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,InitialCompositionType>::value>> + const InitialCompositionType & + get_matching_initial_composition_model () const; + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + /** + * Exception. + */ + DeclException1 (ExcInitialCompositionNameNotFound, + std::string, + << "Could not find entry <" + << arg1 + << "> among the names of registered initial composition objects."); + private: + /** + * A list of names of initial composition objects that have been requested + * in the parameter file. + */ + std::vector model_names; + + /** + * A list of enums of initial composition operators that have been + * requested in the parameter file. Each entry is used to modify the + * initial compositional field with the values from the associated plugin + * in model_names. + */ + std::vector model_operators; + }; + + + + template + template + inline + bool + Manager::has_matching_initial_composition_model () const + { + return this->template has_matching_plugin_object(); + } + + + template + template + inline + const InitialCompositionType & + Manager::get_matching_initial_composition_model () const + { + return this->template get_matching_plugin_object(); + } + + + /** + * Return a string that consists of the names of initial composition models that can + * be selected. These names are separated by a vertical line '|' so + * that the string can be an input to the deal.II classes + * Patterns::Selection or Patterns::MultipleSelection. + * + * @ingroup InitialCompositions + */ + template + std::string + get_valid_model_names_pattern (); + + + + /** + * Given a class name, a name, and a description for the parameter file + * for a initial composition model, register it with the functions that can + * declare their parameters and create these objects. + * + * @ingroup InitialCompositions + */ +#define ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::InitialComposition::Manager<2>::register_initial_composition, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::InitialComposition::Manager<3>::register_initial_composition, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/initial_composition/porosity.h.bak b/include/aspect/initial_composition/porosity.h.bak new file mode 100644 index 00000000000..ea9b6709951 --- /dev/null +++ b/include/aspect/initial_composition/porosity.h.bak @@ -0,0 +1,84 @@ +/* + Copyright (C) 2017 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_composition_porosity_h +#define _aspect_initial_composition_porosity_h + +#include +#include +#include +#include + +namespace aspect +{ + namespace InitialComposition + { + using namespace dealii; + + /** + * A class that implements initial conditions for the porosity field + * by computing the equilibrium melt fraction for the given initial + * condition and reference pressure profile. Note that this plugin only + * works if there is a compositional field called 'porosity', and the + * used material model implements the 'MeltFractionModel' interface. + * All compositional fields except porosity are not changed by this plugin. + * + * @ingroup InitialCompositionModels + */ + template + class Porosity : public Interface, + public SimulatorAccess + { + public: + /** + * Initialize the plugin. + */ + void initialize () override; + + /** + * Return the initial composition as a function of position and number + * of compositional field. + */ + double initial_composition (const Point &position, + const unsigned int compositional_index) const override; + + private: + /** + * A shared pointer to the initial temperature object + * that ensures that the current object can continue + * to access the initial temperature object beyond the + * first time step. + */ + std::shared_ptr> initial_temperature_manager; + + /** + * A shared pointer to the initial composition object + * that ensures that the current object can continue + * to access the initial composition object beyond the + * first time step. + */ + std::shared_ptr> initial_composition_manager; + }; + } +} + + +#endif diff --git a/include/aspect/initial_composition/slab_model.h.bak b/include/aspect/initial_composition/slab_model.h.bak new file mode 100644 index 00000000000..6750c5f9055 --- /dev/null +++ b/include/aspect/initial_composition/slab_model.h.bak @@ -0,0 +1,109 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_composition_slab_model_h +#define _aspect_initial_composition_slab_model_h + +#include + +#include +#include + + +namespace aspect +{ + namespace InitialComposition + { + using namespace dealii; + + /** + * A class that implements subducted slab geometries as a compositional + * field determined from an input file. The file defines the depth to + * the top of the slab and the slab thickness. + * + * An example model that is included is Slab2 described in + * Hayes, G. P., Moore, G. L., Portner, D. E., Hearne, M., Flamme, H., Furtney, M., + * & Smoczyk, G. M. (2018). Slab2, a comprehensive subduction zone geometry model. + * Science, 362(6410), 58-61. + * + * @ingroup InitialCompositionModels + */ + template + class SlabModel : public Interface, public aspect::SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + /** + * Return the initial composition as a function of position. For the + * current class, this function returns 1.0 inside subducted slabs and 0.0 outside. + */ + double + initial_composition (const Point &position, + const unsigned int n_comp) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * A function that returns the slab_boundary object to allow access + * in other places. + */ + const Utilities::AsciiDataBoundary &get_slab_boundary() const; + + private: + /** + * An object of ascii data boundary to input subducted slab depths + * and thicknesses. + */ + Utilities::AsciiDataBoundary slab_boundary; + + /** + * Cache the surface boundary id to avoid unnecessary lookups. + */ + types::boundary_id surface_boundary_id; + + /** + * Cache the compositional field index that corresponds to + * the slab composition to avoid unnecessary lookups. + */ + unsigned int slab_index; + }; + } +} + + +#endif diff --git a/include/aspect/initial_composition/world_builder.h.bak b/include/aspect/initial_composition/world_builder.h.bak new file mode 100644 index 00000000000..144e18ff530 --- /dev/null +++ b/include/aspect/initial_composition/world_builder.h.bak @@ -0,0 +1,105 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_initial_composition_world_builder_h +#define _aspect_initial_composition_world_builder_h + +#include + +#ifdef ASPECT_WITH_WORLD_BUILDER + +#include +#include + +namespace WorldBuilder +{ + class World; +} + + +namespace aspect +{ + namespace InitialComposition + { + using namespace dealii; + + /** + * A class that implements initial conditions for the compositional fields + * based on a functional description provided in the input file through the + * World builder. + * + * @ingroup InitialCompositionModels + */ + template + class WorldBuilder : public Interface, + public SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run and after + * the SimulatorAccess (if applicable) is initialized. + */ + void + initialize () override; + + /** + * Return the initial composition as a function of position and number + * of compositional field. + */ + double initial_composition (const Point &position, const unsigned int n_comp) const override; + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A vector that specifies for each compositional field index if the world builder + * should be evaluated for this compositional field. + */ + std::vector relevant_compositions; + + /** + * A pointer to the WorldBuilder object. Keeping this pointer ensures + * that the object doesn't go away while we still need it. + */ + std::shared_ptr world_builder; + }; + } +} + +#endif +#endif diff --git a/include/aspect/initial_temperature/S40RTS_perturbation.h.bak b/include/aspect/initial_temperature/S40RTS_perturbation.h.bak new file mode 100644 index 00000000000..fa9bf8f7328 --- /dev/null +++ b/include/aspect/initial_temperature/S40RTS_perturbation.h.bak @@ -0,0 +1,233 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_S40RTS_perturbation_h +#define _aspect_initial_temperature_S40RTS_perturbation_h + +#include +#include + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + namespace internal + { + namespace S40RTS + { + class SphericalHarmonicsLookup + { + public: + SphericalHarmonicsLookup(const std::string &filename, + const MPI_Comm comm); + + /// Declare a function that returns the cosine coefficients + const std::vector & + cos_coeffs() const; + + /// Declare a function that returns the sine coefficients + const std::vector & + sin_coeffs() const; + + unsigned int maxdegree() const; + + private: + unsigned int order; + std::vector a_lm; + std::vector b_lm; + }; + + class SplineDepthsLookup + { + public: + SplineDepthsLookup(const std::string &filename, + const MPI_Comm comm); + + const std::vector & + spline_depths() const; + + private: + std::vector depths; + }; + } + } + + template + class PatchOnS40RTS; + + + /** + * A class that describes a perturbed initial temperature field for a + * spherical shell geometry model. The perturbation is based on the S20RTS + * / S40RTS global shear wave velocity model by Ritsema et al. + * http://www.earth.lsa.umich.edu/~jritsema/research.html + * + * @ingroup InitialTemperatures + */ + + template + class S40RTSPerturbation : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. Initialize variables. + */ + S40RTSPerturbation (); + + /** + * Initialization function. Loads the material data and sets up + * pointers. + */ + void + initialize () override; + + /** + * Return the Vs as a function of position. + */ + virtual + double get_Vs (const Point &position) const; + + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * An enum to describe which method should be chosen to scale vs to density. + */ + enum VsToDensityMethod + { + file, + constant + }; + + /** + * Currently chosen source for vs to density scaling. + */ + VsToDensityMethod vs_to_density_method; + + /** + * File directory and names + */ + std::string data_directory; + std::string spline_depth_file_name; + + /** + * This parameter allows setting the input file for the shear-wave + * perturbation. Options so far are S20RTS.sph and S40RTS.sph. For + * S40RTS there are different versions available that differ by the + * degree of damping in the seismic inversion. These models could be + * downloaded and used as well. + */ + std::string harmonics_coeffs_file_name; + + /** + * The parameters below describe the perturbation of shear wave + * velocity into a temperatures perturbation. The first parameter is + * constant so far but could be made depth dependent as constraint by + * e.g. Forte, A.M. & Woodward, R.L., 1997. Seismic-geodynamic + * constraints on three- dimensional structure, vertical flow, and + * heat transfer in the mantle, J. Geophys. Res. 102 (B8), + * 17,981-17,994. + * The last parameter is a depth down to which heterogeneities are + * zeroed out. + */ + double vs_to_density_constant; + double thermal_alpha; + double no_perturbation_depth; + + /** + * This parameter allows to remove the degree 0 component of the shear + * wave velocity perturbation, which guarantees that average + * temperature at a certain depth is the background temperature. + */ + bool zero_out_degree_0; + + /** + * This parameter allows to use a lower maximum degree when reading + * the spherical harmonic data file. + */ + bool lower_max_degree; + + /** + * The maximum degree the users specify, which is only valid when + * "lower_max_degree" is set to true. + */ + unsigned int specified_max_degree; + + /** + * This parameter gives the reference temperature, which will be + * perturbed. In the compressional case the background temperature + * will be the adiabat. + */ + double reference_temperature; + + /** + * Pointer to an object that reads and processes the spherical + * harmonics coefficients + */ + std::unique_ptr spherical_harmonics_lookup; + + /** + * Pointer to an object that reads and processes the depths for the + * spline knot points. + */ + std::unique_ptr spline_depths_lookup; + + /** + * Object containing the data profile. + */ + aspect::Utilities::AsciiDataProfile profile; + + /** + * The column index of the vs to density scaling in the data file + */ + unsigned int vs_to_density_index; + + /** + * Whether to use the thermal expansion coefficient from the material model + */ + bool use_material_model_thermal_alpha; + + template friend class PatchOnS40RTS; + }; + + } +} + +#endif diff --git a/include/aspect/initial_temperature/SAVANI_perturbation.h.bak b/include/aspect/initial_temperature/SAVANI_perturbation.h.bak new file mode 100644 index 00000000000..ec5c4a22905 --- /dev/null +++ b/include/aspect/initial_temperature/SAVANI_perturbation.h.bak @@ -0,0 +1,196 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_SAVANI_perturbation_h +#define _aspect_initial_temperature_SAVANI_perturbation_h + +#include +#include + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + namespace internal + { + namespace SAVANI + { + class SphericalHarmonicsLookup; + class SplineDepthsLookup; + } + } + + /** + * A class that describes a perturbed initial temperature field for a + * spherical shell geometry model. The perturbation is based on the SAVANI + * global shear wave velocity model by Auer et al. + * http://n.ethz.ch/~auerl/research.html + * + * @ingroup InitialTemperatures + */ + + template + class SAVANIPerturbation : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. Initialize variables. + */ + SAVANIPerturbation (); + + + /** + * Initialization function. Loads the material data and sets up + * pointers. + */ + void + initialize () override; + + /** + * Return the Vs as a function of position. + */ + //TODO + virtual + double get_Vs (const Point &position) const; + + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + + private: + + /** + * An enum to describe which method should be chosen to scale vs to density. + */ + enum VsToDensityMethod + { + file, + constant + }; + + /** + * Currently chosen source for vs to density scaling. + */ + VsToDensityMethod vs_to_density_method; + + /** + * File directory and names + */ + std::string data_directory; + std::string spline_depth_file_name; + + /** + * This parameter allows setting the input file for the SAVANI global + * shear-wave perturbation. + */ + std::string harmonics_coeffs_file_name; + + /** + * The parameters below describe the perturbation of shear wave + * velocity into a temperatures perturbation. The first parameter is + * constant so far but could be made depth dependent as constraint by + * e.g. Forte, A.M. & Woodward, R.L., 1997. Seismic-geodynamic + * constraints on three- dimensional structure, vertical flow, and + * heat transfer in the mantle, J. Geophys. Res. 102 (B8), + * 17,981-17,994. + * The last parameter is a depth down to which heterogeneities are + * zeroed out. + */ + double vs_to_density_constant; + double thermal_alpha; + double no_perturbation_depth; + + /** + * This parameter allows to remove the degree 0 component of the shear + * wave velocity perturbation, which guarantees that average + * temperature at a certain depth is the background temperature. + */ + bool zero_out_degree_0; + + /** + * This parameter allows to use a lower maximum degree when reading + * the spherical harmonic data file. + */ + bool lower_max_degree; + + /** + * The maximum degree the users specify, which is only valid when + * "lower_max_degree" is set to true. + */ + unsigned int specified_max_degree; + + /** + * This parameter gives the reference temperature, which will be + * perturbed. In the compressional case the background temperature + * will be the adiabat. + */ + double reference_temperature; + + /** + * Pointer to an object that reads and processes the spherical + * harmonics coefficients + */ + std::unique_ptr spherical_harmonics_lookup; + + /** + * Pointer to an object that reads and processes the depths for the + * spline knot points. + */ + std::unique_ptr spline_depths_lookup; + + /** + * Object containing the data profile. + */ + aspect::Utilities::AsciiDataProfile profile; + + /** + * The column index of the vs to density scaling in the data file + */ + unsigned int vs_to_density_index; + + /** + * Whether to use the thermal expansion coefficient from the material model + */ + bool use_material_model_thermal_alpha; + + }; + + } +} + +#endif diff --git a/include/aspect/initial_temperature/adiabatic.h.bak b/include/aspect/initial_temperature/adiabatic.h.bak new file mode 100644 index 00000000000..766ba7b786e --- /dev/null +++ b/include/aspect/initial_temperature/adiabatic.h.bak @@ -0,0 +1,187 @@ +/* + Copyright (C) 2012 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_adiabatic_h +#define _aspect_initial_temperature_adiabatic_h + +#include +#include +#include + +#include + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A namespace for selecting how to determine the age of a + * boundary layer. Current options are: + * + * 'constant': A constant age independent of position. + * 'ascii_data': Age is specified in an ascii data file. + * 'function': Age is specified as a function in the input file. + */ + namespace BoundaryLayerAgeModel + { + enum Kind + { + constant, + ascii_data, + function + }; + + /** + * Read the lithosphere age model from the parameter file, + * using the parameter name given in @p parameter_name, and return the + * enum that corresponds to this operation. + */ + BoundaryLayerAgeModel::Kind + parse (const std::string ¶meter_name, + const ParameterHandler &prm); + } + + /** + * A class that implements adiabatic initial conditions for the + * temperature field and, optional, upper and lower thermal boundary + * layers calculated using the half-space cooling model. The age of the + * boundary layers are input parameters. + * + * @ingroup InitialTemperatures + */ + template + class Adiabatic : public Interface, public Utilities::AsciiDataBoundary + { + public: + /** + * Constructor. + */ + Adiabatic (); + + void initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataBoundary::initialize; + + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The boundary identifier representing the 'surface' boundary as + * reported by the geometry model. + */ + types::boundary_id surface_boundary_id; + + /** + * Age of the upper thermal boundary layer at the surface of the + * model. If set to zero, no boundary layer will be present in the + * model. + */ + double age_top_boundary_layer; + + /* Age of the lower thermal boundary layer. */ + double age_bottom_boundary_layer; + + /** + * Radius (in m) of the initial temperature perturbation at the bottom + * of the model domain. + */ + double radius; + /** + * Amplitude (in K) of the initial temperature perturbation at the + * bottom of the model domain. + */ + double amplitude; + /* + * Position of the initial temperature perturbation (in the + * center or at the boundary of the model domain). + */ + std::string perturbation_position; + + /* + * Deviation from adiabaticity in a subadiabatic mantle + * temperature profile. 0 for an adiabatic temperature + * profile. + */ + double subadiabaticity; + + /** + * Age model to use for the top boundary layer. + */ + BoundaryLayerAgeModel::Kind top_boundary_layer_age_model; + + /* + * Whether to use the half space cooling model, or the plate cooling + * model + */ + std::string cooling_model; + + /* + * Depth to the base of the lithosphere for plate cooling model, in m + */ + double lithosphere_thickness; + + /** + * A function object representing the compositional fields that will + * be used as a reference profile for calculating the thermal + * diffusivity. The function depends only on depth. + */ + std::unique_ptr> function; + + /** + * A function object representing the age of the top boundary layer. + */ + Functions::ParsedFunction age_function; + + /** + * The coordinate representation to evaluate the function. Possible + * choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + + /** + * Compute the top boundary layer age at the given position. + */ + double top_boundary_layer_age(const Point &position) const; + }; + } +} + + +#endif diff --git a/include/aspect/initial_temperature/adiabatic_boundary.h.bak b/include/aspect/initial_temperature/adiabatic_boundary.h.bak new file mode 100644 index 00000000000..02c6b0c5669 --- /dev/null +++ b/include/aspect/initial_temperature/adiabatic_boundary.h.bak @@ -0,0 +1,89 @@ +/* + Copyright (C) 2016 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_initial_temperature_adiabatic_boundary_h +#define _aspect_initial_temperature_adiabatic_boundary_h + +#include +#include +#include + + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that computes an initial temperature field based + * on a user-defined adiabatic boundary. It discretizes the model domain into + * two regions separated by an isotherm boundary below which + * the temperature increases adiabatically. Above the + * user-defined isotherm boundary the temperature linearly + * increases from a surface temperature (273.15 K or 0 degree C) + * to the isotherm (1673.15 K or 1400 degree C). The user + * defines the location of the isotherm boundary with an ascii + * data file with the format defined in the ASPECT manual. + * + * This plugin is developed by Tahiry Rajaonarison, Emmanuel Njinju, and D. Sarah Stamps. + */ + template + class AdiabaticBoundary : public Interface, public Utilities::AsciiDataBoundary + { + public: + + /** + * Constructor. + */ + AdiabaticBoundary (); + + void initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataBoundary::initialize; + + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + + /** + * Declare the parameters that this class needs. + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters above from the parameter file. + */ + void parse_parameters (ParameterHandler &prm) override; + + private: + + double isotherm_temperature; + double surface_temperature; + double temperature_gradient; + types::boundary_id surface_boundary_id; + + }; + } +} +#endif diff --git a/include/aspect/initial_temperature/ascii_data.h.bak b/include/aspect/initial_temperature/ascii_data.h.bak new file mode 100644 index 00000000000..e568cfe53ed --- /dev/null +++ b/include/aspect/initial_temperature/ascii_data.h.bak @@ -0,0 +1,85 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_ascii_data_h +#define _aspect_initial_temperature_ascii_data_h + +#include +#include +#include + + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that implements a prescribed temperature field determined from + * a AsciiData input file. + * + * @ingroup InitialTemperatures + */ + template + class AsciiData : public Utilities::AsciiDataInitial, public Interface + { + public: + /** + * Empty Constructor. + */ + AsciiData (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataInitial::initialize; + + /** + * Return the boundary temperature as a function of position. For the + * current class, this function returns value from the text files. + */ + double + initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + }; + } +} + + +#endif diff --git a/include/aspect/initial_temperature/ascii_data_layered.h.bak b/include/aspect/initial_temperature/ascii_data_layered.h.bak new file mode 100644 index 00000000000..ccb5157ab13 --- /dev/null +++ b/include/aspect/initial_temperature/ascii_data_layered.h.bak @@ -0,0 +1,85 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_ascii_data_layered_h +#define _aspect_initial_temperature_ascii_data_layered_h + +#include +#include +#include + + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that implements an initial temperature field determined from + * AsciiData input files. Each file defines an isotherm as a grid of points. + * + * @ingroup InitialTemperatures + */ + template + class AsciiDataLayered : public Utilities::AsciiDataLayered, public Interface + { + public: + /** + * Empty Constructor. + */ + AsciiDataLayered (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataLayered::initialize; + + /** + * Return the initial temperature as a function of position. For the + * current class, this function returns value from the text files. + */ + double + initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + }; + } +} + + +#endif diff --git a/include/aspect/initial_temperature/ascii_profile.h.bak b/include/aspect/initial_temperature/ascii_profile.h.bak new file mode 100644 index 00000000000..337605de662 --- /dev/null +++ b/include/aspect/initial_temperature/ascii_profile.h.bak @@ -0,0 +1,90 @@ +/* + Copyright (C) 2016 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_ascii_profile_h +#define _aspect_initial_temperature_ascii_profile_h + +#include +#include +#include + +#include + + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that implements a prescribed temperature field determined from + * a AsciiDataProfile input file. + * + * @ingroup InitialTemperatures + */ + template + class AsciiProfile : public Utilities::AsciiDataProfile, public Interface, public SimulatorAccess + { + public: + /** + * Constructor. Initialize variables. + */ + AsciiProfile (); + + /** + * Initialization function. + */ + void initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataProfile::initialize; + + /** + * Return the temperature at a given point of the domain. + */ + double initial_temperature (const Point &p) const override; + + /** + * Declare the parameters for the input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * The column index of the temperature in the data file. + */ + unsigned int temperature_index; + }; + } +} + + +#endif diff --git a/include/aspect/initial_temperature/box.h.bak b/include/aspect/initial_temperature/box.h.bak new file mode 100644 index 00000000000..7f9462e17d6 --- /dev/null +++ b/include/aspect/initial_temperature/box.h.bak @@ -0,0 +1,122 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_box_h +#define _aspect_initial_temperature_box_h + +#include +#include + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that describes a perturbed initial temperature field for a box + * geometry. + * + * @ingroup InitialTemperatures + */ + template + class PerturbedBox : public Interface, public SimulatorAccess + { + public: + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + }; + + /** + * A class that describes an opposing poles initial temperature field for + * a box geometry. + * + * @ingroup InitialTemperatures + */ + template + class PolarBox : public Interface, public SimulatorAccess + { + public: + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + }; + + /** + * A field that describes a fractal initial temperature field + * + * @ingroup InitialTemperatures + */ + template + class MandelBox : public Interface, public SimulatorAccess + { + public: + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + }; + + /** + * A class that describes a shaped inclusion initial temperature field for + * a box geometry. + * + * @ingroup InitialTemperatures + */ + template + class InclusionShapeBox : public Interface, public SimulatorAccess + { + public: + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature(const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + std::string inclusion_shape; + std::string inclusion_gradient; + double radius; + double ambient_temperature; + double inclusion_temperature; + double center_x; + double center_y; + double center_z; + }; + } +} + +#endif diff --git a/include/aspect/initial_temperature/continental_geotherm.h.bak b/include/aspect/initial_temperature/continental_geotherm.h.bak new file mode 100644 index 00000000000..ef4af29d0b4 --- /dev/null +++ b/include/aspect/initial_temperature/continental_geotherm.h.bak @@ -0,0 +1,114 @@ +/* + Copyright (C) 2014 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + + +#ifndef _aspect_initial_temperature_continental_geotherm_h +#define _aspect_initial_temperature_continental_geotherm_h + +#include +#include + +namespace aspect +{ + namespace InitialTemperature + { + + /** + * + * @ingroup InitialTemperatures + */ + template + class ContinentalGeotherm : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + ContinentalGeotherm (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + /** + * Return the initial temperature as a function of depth, + * based on the solution of the steady-state heat conduction + * differential equation. + */ + double initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Surface temperature + */ + double T0; + + /** + * Value of the isotherm defining the + * Lithosphere-Asthenosphere boundary. + */ + double LAB_isotherm; + + /** + * Vector for the thicknesses of the compositional fields + * representing the layers 'upper_crust', 'lower_crust' and 'lithospheric_mantle'. + */ + std::vector thicknesses; + + /** + * Vector for the heat production rates of the different + * compositional fields, read from parameter file. + */ + std::vector heat_productivities; + + /** + * Vector for the thermal conductivities of the different + * compositional fields, read from parameter file. + */ + std::vector conductivities; + + /** + * Vector for the densities of the different compositional + * fields, read from parameter file. + */ + std::vector densities; + }; + } +} + + +#endif diff --git a/include/aspect/initial_temperature/function.h.bak b/include/aspect/initial_temperature/function.h.bak new file mode 100644 index 00000000000..65f9891f69b --- /dev/null +++ b/include/aspect/initial_temperature/function.h.bak @@ -0,0 +1,93 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_function_h +#define _aspect_initial_temperature_function_h + +#include +#include +#include + +#include + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that implements temperature initial conditions based on a + * functional description provided in the input file. + * + * @ingroup InitialTemperatures + */ + template + class Function : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + Function (); + + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A function object representing the temperature. + */ + Functions::ParsedFunction function; + + /** + * The coordinate representation to evaluate the function. Possible + * choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + + }; + } +} + + +#endif diff --git a/include/aspect/initial_temperature/harmonic_perturbation.h.bak b/include/aspect/initial_temperature/harmonic_perturbation.h.bak new file mode 100644 index 00000000000..ae58ff944c6 --- /dev/null +++ b/include/aspect/initial_temperature/harmonic_perturbation.h.bak @@ -0,0 +1,107 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_harmonic_perturbation_h +#define _aspect_initial_temperature_harmonic_perturbation_h + +#include +#include + + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that describes a perturbed initially constant temperature field + * for any geometry model or dimension in shape of a harmonic function. + * For 3D spherical shell models this is achieved by using spherical + * harmonics, in any other case sine function are scaled to fit the model + * geometry. + * + * @ingroup InitialTemperatures + */ + template + class HarmonicPerturbation : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + + private: + + /** + * The radial/depth wave number of the harmonic perturbation. All wave + * number variables are in fact twice the wave number in a + * mathematical sense. This allows the user to prescribe a single + * up-/downswing or half periods. + */ + int vertical_wave_number; + + /** + * The lateral wave number of the harmonic perturbation in the first + * dimension. This is the only lateral wave number in 2D and equals + * the degree of the spherical harmonics in a 3D spherical shell. + */ + int lateral_wave_number_1; + + /** + * The lateral wave number of the harmonic perturbation in the second + * dimension. This is not used in 2D and equals the order of the + * spherical harmonics in a 3D spherical shell. + */ + int lateral_wave_number_2; + + /** + * The maximal magnitude of the harmonic perturbation. + */ + double magnitude; + + /** + * The background temperature the harmonic perturbation is applied on + * in an incompressible material model. In case of a compressible + * material model the perturbation is applied on top of an adiabatic + * profile and this variable is not used at all. + */ + double reference_temperature; + }; + } +} + +#endif diff --git a/include/aspect/initial_temperature/interface.h.bak b/include/aspect/initial_temperature/interface.h.bak new file mode 100644 index 00000000000..9b726ab4f4d --- /dev/null +++ b/include/aspect/initial_temperature/interface.h.bak @@ -0,0 +1,277 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_interface_h +#define _aspect_initial_temperature_interface_h + +#include +#include +#include + +#include +#include + +#include +#include + + +namespace aspect +{ + template class SimulatorAccess; + + /** + * A namespace in which we define everything that has to do with defining + * the initial conditions. + * + * @ingroup InitialTemperatures + */ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A base class for parameterizations of initial conditions. + * + * @ingroup InitialTemperatures + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Return the initial temperature as a function of position. + */ + virtual + double initial_temperature (const Point &position) const = 0; + }; + + + /** + * A class that manages all initial condition objects. + * + * @ingroup InitialTemperatures + */ + template + class Manager : public Plugins::ManagerBase>, public SimulatorAccess + { + public: + /** + * Destructor. Made virtual since this class has virtual member + * functions. + */ + ~Manager () override; + + /** + * Update function. Called once at the beginning of a timestep to + * update all plugin objects. + */ + void + update() override; + + /** + * Declare the parameters of all known initial conditions plugins, as + * well as of ones this class has itself. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * This determines which initial conditions objects will be created; then + * let these objects read their parameters as well. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * A function that calls the initial_temperature functions of all the + * individual initial condition objects and adds up the values of the + * individual calls. + */ + double + initial_temperature (const Point &position) const; + + /** + * A function that is used to register initial temperature objects in such + * a way that the Manager can deal with all of them without having to + * know them by name. This allows the files in which individual + * plugins are implemented to register these plugins, rather than also + * having to modify the Manager class by adding the new initial + * temperature plugin class. + * + * @param name A string that identifies the initial temperature model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this initial temperature model + * wants to read from input files. + * @param factory_function A pointer to a function that can create an + * object of this initial temperature model. + */ + static + void + register_initial_temperature (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + + /** + * Return a list of names of all initial temperature models currently + * used in the computation, as specified in the input file. + */ + const std::vector & + get_active_initial_temperature_names () const; + + /** + * Return a list of pointers to all initial temperature models + * currently used in the computation, as specified in the input file. + */ + const std::list>> & + get_active_initial_temperature_conditions () const; + + /** + * Go through the list of all initial temperature models that have been selected + * in the input file (and are consequently currently active) and return + * true if one of them has the desired type specified by the template + * argument. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,InitialTemperatureType>::value>> + bool + has_matching_initial_temperature_model () const; + + /** + * Go through the list of all initial temperature models that have been selected + * in the input file (and are consequently currently active) and see + * if one of them has the type specified by the template + * argument or can be cast to that type. If so, return a reference + * to it. If no initial temperature model is active that matches the given type, + * throw an exception. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,InitialTemperatureType>::value>> + const InitialTemperatureType & + get_matching_initial_temperature_model () const; + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + /** + * Exception. + */ + DeclException1 (ExcInitialTemperatureNameNotFound, + std::string, + << "Could not find entry <" + << arg1 + << "> among the names of registered initial temperature objects."); + private: + /** + * A list of names of initial temperature objects that have been requested + * in the parameter file. + */ + std::vector model_names; + + /** + * A list of enums of initial temperature operators that have been + * requested in the parameter file. Each entry is used to modify the + * initial temperature field with the values from the associated plugin + * in model_names. + */ + std::vector model_operators; + }; + + + + template + template + inline + bool + Manager::has_matching_initial_temperature_model () const + { + return this->template has_matching_plugin_object(); + } + + + template + template + inline + const InitialTemperatureType & + Manager::get_matching_initial_temperature_model () const + { + return this->template get_matching_plugin_object(); + } + + + /** + * Return a string that consists of the names of initial temperature models that can + * be selected. These names are separated by a vertical line '|' so + * that the string can be an input to the deal.II classes + * Patterns::Selection or Patterns::MultipleSelection. + */ + template + std::string + get_valid_model_names_pattern (); + + + + /** + * Given a class name, a name, and a description for the parameter file + * for a initial conditions model, register it with the functions that can + * declare their parameters and create these objects. + * + * @ingroup InitialTemperatures + */ +#define ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::InitialTemperature::Manager<2>::register_initial_temperature, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::InitialTemperature::Manager<3>::register_initial_temperature, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/initial_temperature/lithosphere_mask.h.bak b/include/aspect/initial_temperature/lithosphere_mask.h.bak new file mode 100644 index 00000000000..db5442d0efa --- /dev/null +++ b/include/aspect/initial_temperature/lithosphere_mask.h.bak @@ -0,0 +1,168 @@ +/* + Copyright (C) 2019 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_lithosphere_mask_h +#define _aspect_initial_temperature_lithosphere_mask_h + +#include +#include +#include + + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + namespace LABDepth + { + template + class LABDepthLookup : public SimulatorAccess + { + public: + /** + * Empty Constructor. + */ + LABDepthLookup (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize (); + + /** + * Return LAB depth as a function of position (latitude and longitude). This + * function returns either a constant value or values from a text file, + * depending on the input parameters. Text files are read in + * two dimensions so the third column (depth) is treated as data. + */ + double + get_lab_depth (const Point &position) const; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm); + + private: + /** + * Reads in file containing input data. + */ + Utilities::StructuredDataLookup<2> lab_depths; + + /** + * Directory in which the LAB depth file is present. + */ + std::string data_directory; + + /** + * File name of the LAB depth file. + */ + std::string LAB_file_name; + + /** + * An enum to describe where the LAB depth is coming from. + */ + enum LABDepthSource + { + Value, + File + }; + + /** + * Currently chosen source for the LAB depth. + */ + LABDepthSource LAB_depth_source; + + /** + * This parameter gives the maximum depth of the lithosphere. The + * model returns nans below this depth. This parameter is only used if LAB + * depth source is set to 'Value'. + */ + double max_depth; + }; + } + + /** + * A class that implements a constant reference temperature + * above a specified depth and nans below the specified depth. + * + * @ingroup InitialTemperatures + */ + template + class LithosphereMask : public Interface, public SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + /** + * Return the initial temperature as a function of position. For the + * current class, this function uses the given lithosphere temperature + * above the lithosphere-asthenosphere boundary and nans below. + */ + double + initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * This parameter gives the initial temperature set within the lithosphere. + */ + double lithosphere_temperature; + + /** + * + */ + LABDepth::LABDepthLookup lab_depth_lookup; + }; + + } +} + +#endif diff --git a/include/aspect/initial_temperature/patch_on_S40RTS.h.bak b/include/aspect/initial_temperature/patch_on_S40RTS.h.bak new file mode 100644 index 00000000000..45b26fdf57d --- /dev/null +++ b/include/aspect/initial_temperature/patch_on_S40RTS.h.bak @@ -0,0 +1,122 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_patch_on_S40RTS_h +#define _aspect_initial_temperature_patch_on_S40RTS_h + +#include +#include +#include +#include + + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that implements a prescribed temperature field determined from + * an upper mantle Vs model (input as an ascii file) above a specified depth + * and S40RTS below the specified depth. + * + * @ingroup InitialTemperatures + */ + template + class PatchOnS40RTS : public Utilities::AsciiDataInitial, public Interface + { + public: + /** + * Empty Constructor. + */ + PatchOnS40RTS (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataInitial::initialize; + + /** + * Return Vs as a function of position. For the + * current class, this function returns value from the text files. + */ + double + ascii_grid_vs (const Point &position) const; + + /** + * This parameter gives the maximum depth of the Vs ascii grid. The + * model will read in Vs from S40RTS below this depth. + */ + double max_grid_depth; + + /** + * This parameter gives the range (above maximum grid depth) over which to smooth. + * Smoothing is done with a depth weighted combination of the values in the ascii grid and S40RTS + * at each point. + */ + double smoothing_length_scale; + + /** + * Return the initial temperature as a function of position. For the + * current class, this function calculates temperature from ascii grid Vs data + * above max_grid_depth and S40RTS Vs data below max_grid_depth. + */ + double + initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Declare a member variable of type S40RTSPerturbation that allows us to call + * functions from S40RTS_perturbation.cc. + */ + S40RTSPerturbation s40rts; + + /** + * This parameter is the depth down to which shear wave perturbations are + * zeroed out. + */ + double no_perturbation_depth_patch; + + }; + } +} + + +#endif diff --git a/include/aspect/initial_temperature/prescribed_temperature.h.bak b/include/aspect/initial_temperature/prescribed_temperature.h.bak new file mode 100644 index 00000000000..d117b3cf8a6 --- /dev/null +++ b/include/aspect/initial_temperature/prescribed_temperature.h.bak @@ -0,0 +1,73 @@ +/* + Copyright (C) 2012 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_prescribed_temperature_h +#define _aspect_initial_prescribed_temperature_h + +#include +#include + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class sets the initial temperature to the precribed temperature + * outputs computed by the material model. + * + * @ingroup InitialTemperatures + */ + template + class PrescribedTemperature : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run. + * + * This specific function makes sure that the objects that describe + * initial conditions remain available throughout the run of the + * program. + */ + void + initialize () override; + + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + + private: + /** + * A shared pointer to the initial composition object + * that ensures that the current object can continue + * to access the initial composition object beyond the + * first time step. + */ + std::shared_ptr> initial_composition; + }; + } +} + + +#endif diff --git a/include/aspect/initial_temperature/random_gaussian_perturbation.h.bak b/include/aspect/initial_temperature/random_gaussian_perturbation.h.bak new file mode 100644 index 00000000000..bbc9df3bfa6 --- /dev/null +++ b/include/aspect/initial_temperature/random_gaussian_perturbation.h.bak @@ -0,0 +1,99 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_random_gaussian_perturbation_h +#define _aspect_initial_temperature_random_gaussian_perturbation_h + +#include + + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that describes a perturbation to a zero temperature field + * by placing several Gaussians with a given magnitude and width at + * random locations throughout the model domain. + * + * @ingroup InitialTemperatures + */ + template + class RandomGaussianPerturbation : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * beginning of the program and computes the locations and + * magnitudes of all perturbations. + */ + void + initialize () override; + + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + + private: + + /** + * The number of the random Gaussian perturbations. + */ + unsigned int n_perturbations; + + /** + * The maximal magnitude of the random Gaussian perturbations. + */ + double max_magnitude; + + /** + * The width of the random Gaussian perturbations. + */ + double width; + + /** + * Vectors that store all (random) locations and magnitudes of + * the perturbations. + */ + std::vector> perturbation_centers; + std::vector perturbation_magnitudes; + }; + } +} + +#endif diff --git a/include/aspect/initial_temperature/spherical_shell.h.bak b/include/aspect/initial_temperature/spherical_shell.h.bak new file mode 100644 index 00000000000..8f620e24532 --- /dev/null +++ b/include/aspect/initial_temperature/spherical_shell.h.bak @@ -0,0 +1,147 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_initial_temperature_spherical_shell_h +#define _aspect_initial_temperature_spherical_shell_h + +#include +#include + + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that describes a perturbed initial temperature field for the + * spherical shell. + * + * @ingroup InitialTemperatures + */ + template + class SphericalHexagonalPerturbation : public Interface, public SimulatorAccess + { + public: + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The angular mode is the number of perturbations to apply to the + * spherical shell. Historically, this was permanently set to 6 (hence + * the class name SphericalHexagonalPerturbation) The default is 6 in + * order to provide backwards compatibility. + */ + unsigned int angular_mode; + + /** + * The rotation offset describes the number of degrees to rotate the + * perturbation counterclockwise. Setting the rotation offset to 0 + * will cause one of the perturbations to point north/up. Rotation + * offset is set to -45 degrees by default in order to provide + * backwards compatibility. + */ + double rotation_offset; + + /** + * Outer radius. + */ + double R1; + + }; + + + /** + * A class that describes a perturbed initial temperature field for the + * spherical shell. + * + * @ingroup InitialTemperatures + */ + template + class SphericalGaussianPerturbation : public Interface, public SimulatorAccess + { + public: + + /** + * Constructor. + */ + SphericalGaussianPerturbation(); + + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + double angle; + double depth; + double amplitude; + double sigma; + double sign; + unsigned int npoint; + + std::vector radial_position; + std::vector geotherm; + + /** + * Inner radius. + */ + double R0; + + /** + * Outer radius. + */ + double R1; + }; + } +} + +#endif diff --git a/include/aspect/initial_temperature/world_builder.h.bak b/include/aspect/initial_temperature/world_builder.h.bak new file mode 100644 index 00000000000..b275e2e5388 --- /dev/null +++ b/include/aspect/initial_temperature/world_builder.h.bak @@ -0,0 +1,84 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_initial_temperature_world_builder_h +#define _aspect_initial_temperature_world_builder_h + +#include + +#ifdef ASPECT_WITH_WORLD_BUILDER + +#include +#include + +namespace WorldBuilder +{ + class World; +} + + + +namespace aspect +{ + namespace InitialTemperature + { + using namespace dealii; + + /** + * A class that implements temperature initial conditions based on a + * functional description provided in the input file through the + * World builder. + * + * @ingroup InitialTemperatures + */ + template + class WorldBuilder : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + WorldBuilder (); + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run and after + * the SimulatorAccess (if applicable) is initialized. + */ + void + initialize () override; + + /** + * Return the initial temperature as a function of position. + */ + double initial_temperature (const Point &position) const override; + + private: + /** + * A pointer to the WorldBuilder object. Keeping this pointer ensures + * that the object doesn't go away while we still need it. + */ + std::shared_ptr world_builder; + }; + } +} + +#endif +#endif diff --git a/include/aspect/introspection.h.bak b/include/aspect/introspection.h.bak new file mode 100644 index 00000000000..9ce0167be3a --- /dev/null +++ b/include/aspect/introspection.h.bak @@ -0,0 +1,676 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_introspection_h +#define _aspect_introspection_h + +#include +#include +#include +#include +#include + +#include +#include + +#include + +namespace aspect +{ + using namespace dealii; + + /** + * Helper function to construct the default list of variables to use + * based on the given set of @p parameters. + */ + template + std::vector> + construct_default_variables (const Parameters ¶meters); + + + /** + * A data structure containing a description of each compositional field. + * At present, this structure only includes the field type + * (i.e., whether it is of type chemical composition, porosity, etc.). + */ + struct CompositionalFieldDescription + { + /** + * This enum lists available compositional field types. + */ + enum Type + { + chemical_composition = 0, + stress = 1, + strain = 2, + grain_size = 3, + porosity = 4, + density = 5, + entropy = 6, + generic = 7, + unspecified = 8 + } type; + + /** + * The number of different types defined in Type. + */ + constexpr static unsigned int n_types = 9; + + /** + * This function translates an input string into the + * available enum options for the type of compositional field. + */ + static + Type + parse_type(const std::string &input) + { + if (input == "chemical composition") + return CompositionalFieldDescription::chemical_composition; + else if (input == "stress") + return CompositionalFieldDescription::stress; + else if (input == "strain") + return CompositionalFieldDescription::strain; + else if (input == "grain size") + return CompositionalFieldDescription::grain_size; + else if (input == "porosity") + return CompositionalFieldDescription::porosity; + else if (input == "density") + return CompositionalFieldDescription::density; + else if (input == "entropy") + return CompositionalFieldDescription::entropy; + else if (input == "generic") + return CompositionalFieldDescription::generic; + else if (input == "unspecified") + return CompositionalFieldDescription::unspecified; + else + AssertThrow(false, ExcNotImplemented()); + + return CompositionalFieldDescription::Type(); + } + }; + + /** + * The introspection class provides information about the simulation as a + * whole. In particular, it provides symbolic names for things like the + * velocity, pressure and other variables, along with their corresponding + * vector and scalar FEValues extractors, component masks, etc. + * + * The purpose of this class is primarily to provide these symbolic names so + * that we do not have to use implicit knowledge about the ordering of + * variables (e.g., earlier versions of ASPECT had many places where we + * built a scalar FEValues extractor at component 'dim' since that is where + * we knew that the pressure lies in the finite element; this kind of + * implicit knowledge is no longer necessary with the Introspection class). + * The Introspection class is used both by the Simulator class itself, but + * is also exported to plugins via the SimulatorAccess class. + * + * @ingroup Simulator + */ + template + struct Introspection: public FEVariableCollection + { + public: + /** + * Constructor. + */ + Introspection (const std::vector> &variables, + const Parameters ¶meters); + + /** + * Destructor. + */ + ~Introspection (); + + + + /** + * @name Things that are independent of the current mesh + * @{ + */ + + /** + * The number of vector components used by the finite element + * description of this problem. It equals $d+2+n_c$ where $d$ is the + * dimension and equals the number of velocity components, and $n_c$ is + * the number of advected (compositional) fields. The remaining + * components are the scalar pressure and temperature fields. + */ + const unsigned int n_components; + + /** + * The number of compositional fields. + */ + const unsigned int n_compositional_fields; + + /** + * A variable that holds whether the temperature field should use a + * discontinuous discretization. + */ + const bool use_discontinuous_temperature_discretization; + + /** + * A variable that holds whether the composition field(s) should use a + * discontinuous discretization. + */ + const std::vector use_discontinuous_composition_discretization; + + /** + * A structure that enumerates the vector components of the finite + * element that correspond to each of the variables in this problem. + */ + struct ComponentIndices + { + unsigned int velocities[dim]; + unsigned int pressure; + unsigned int temperature; + std::vector compositional_fields; + }; + /** + * A variable that enumerates the vector components of the finite + * element that correspond to each of the variables in this problem. + */ + const ComponentIndices component_indices; + + /** + * The number of vector blocks. This equals $3+n_c$ where, in comparison + * to the n_components field, the velocity components form a single + * block. + */ + const unsigned int n_blocks; + + /** + * A structure that enumerates the vector blocks of the finite element + * that correspond to each of the variables in this problem. + */ + struct BlockIndices + { + unsigned int velocities; + unsigned int pressure; + unsigned int temperature; + std::vector compositional_fields; + + /** + * This variable contains the block for each compositional field + * where the matrix/sparsity pattern is copied from when we need to + * (temporarily) create a matrix. This way, we only need to store a + * single sparsity pattern and reuse it for all compositional fields + * (assuming they have an identical FiniteElement). + */ + std::vector compositional_field_sparsity_pattern; + }; + + /** + * A variable that enumerates the vector blocks of the finite element + * that correspond to each of the variables in this problem. + */ + const BlockIndices block_indices; + + /** + * A structure that contains FEValues extractors for every block of the + * finite element used in the overall description. + */ + struct Extractors + { + Extractors (const ComponentIndices &component_indices); + + const FEValuesExtractors::Vector velocities; + const FEValuesExtractors::Scalar pressure; + const FEValuesExtractors::Scalar temperature; + const std::vector compositional_fields; + }; + + /** + * A variable that contains extractors for every block of the finite + * element used in the overall description. + */ + const Extractors extractors; + + /** + * A structure that enumerates the base elements of the finite element + * that correspond to each of the variables in this problem. + * + * The indices here can be used to access the dealii::FiniteElement + * that describes the given variable. We support different finite + * elements for compositional fields, but we try to reuse the same + * element if possible. + */ + struct BaseElements + { + unsigned int velocities; + unsigned int pressure; + unsigned int temperature; + std::vector compositional_fields; + }; + + /** + * A variable that enumerates the base elements of the finite element + * that correspond to each of the variables in this problem. + */ + const BaseElements base_elements; + + /** + * A structure that contains the polynomial degree of the finite element + * that correspond to each of the variables in this problem. + * + * If there are compositional fields, they are all discretized with the + * same polynomial degree and, consequently, we only need a single integer. + */ + struct PolynomialDegree + { + unsigned int velocities; + unsigned int temperature; + unsigned int compositional_fields; + }; + + /** + * A variable that enumerates the polynomial degree of the finite element + * that correspond to each of the variables in this problem. + */ + const PolynomialDegree polynomial_degree; + + /** + * A structure that contains appropriate quadrature formulas for the + * finite elements that correspond to each of the variables in this problem, + * as well as for the complete system (the `system` variable). + * + * If there are compositional fields, they are all discretized with the + * same polynomial degree and, consequently, we only need a single formula. + * + * The quadrature formulas provided here are chosen such that the + * compute integrals with sufficient accuracy. For hypercube cells, + * this means in particular that they are of Gauss type with a + * number of Gauss points per coordinate direction that is one larger than + * the polynomial degree of the finite element per direction. For + * example, when using quadratic elements for the velocity, the + * corresponding quadrature formula will have three Gauss points per + * direction. If the mesh is based on triangles or tetrahedra, the + * quadrature formula is not of tensor-product Gauss type, but the + * corresponding analog for simplex cells. + */ + struct Quadratures + { + Quadrature velocities; + Quadrature pressure; + Quadrature temperature; + Quadrature compositional_fields; + Quadrature system; + }; + + /** + * A variable that enumerates the polynomial degree of the finite element + * that correspond to each of the variables in this problem. + */ + const Quadratures quadratures; + + /** + * A structure that contains appropriate face quadrature formulas for the + * finite elements that correspond to each of the variables in this problem, + * as well as for the complete system (the `system` variable). + * + * This structure corresponds to the Quadratures structure above, but for + * face integration. + */ + struct FaceQuadratures + { + Quadrature velocities; + Quadrature pressure; + Quadrature temperature; + Quadrature compositional_fields; + Quadrature system; + }; + + /** + * A variable that enumerates the polynomial degree of the finite element + * that correspond to each of the variables in this problem. + */ + const FaceQuadratures face_quadratures; + + /** + * A structure that contains component masks for each of the variables + * in this problem. Component masks are a deal.II concept, see the + * deal.II glossary. + */ + struct ComponentMasks + { + ComponentMasks (const FEVariableCollection &fevs, const Introspection::ComponentIndices &indices); + + ComponentMask velocities; + ComponentMask pressure; + ComponentMask temperature; + std::vector compositional_fields; + }; + + /** + * A variable that contains component masks for each of the variables in + * this problem. Component masks are a deal.II concept, see the deal.II + * glossary. + */ + const ComponentMasks component_masks; + + /** + * @} + */ + + /** + * @name Things that depend on the current mesh + * @{ + */ + /** + * A variable that describes how many of the degrees of freedom on the + * current mesh belong to each of the n_blocks blocks of the finite + * element. + */ + std::vector system_dofs_per_block; + + /** + * A structure that contains index sets describing which of the globally + * enumerated degrees of freedom are owned by or are relevant to the + * current processor in a parallel computation. + */ + struct IndexSets + { + /** + * An index set that indicates which (among all) degrees of freedom + * are relevant to the current processor. See the deal.II + * documentation for the definition of the term "locally relevant + * degrees of freedom". + */ + IndexSet system_relevant_set; + + /** + * A collection of index sets that for each of the vector blocks of + * this finite element represents the global indices of the degrees of + * freedom owned by this processor. The n_blocks elements of this + * array form a mutually exclusive decomposition of the index set + * containing all locally owned degrees of freedom. + */ + std::vector system_partitioning; + + /** + * A collection of index sets that for each of the vector blocks of + * this finite element represents the global indices of the degrees of + * freedom are relevant to this processor. The n_blocks elements of + * this array form a mutually exclusive decomposition of the index set + * containing all locally relevant degrees of freedom, i.e., of the + * system_relevant_set index set. + */ + std::vector system_relevant_partitioning; + + /** + * A collection of index sets for each vector block of the Stokes + * system (velocity and pressure). This variable contains the first + * two elements of system_partitioning. + */ + std::vector stokes_partitioning; + + /** + * Pressure unknowns that are locally owned. This IndexSet is needed + * if velocity and pressure end up in the same block and is used for + * pressure scaling and in make_pressure_rhs_compatible(). If melt + * transport is enabled, this field is unused and not filled. + */ + IndexSet locally_owned_pressure_dofs; + + /** + * Fluid and compaction pressure unknowns that are locally owned. Only + * valid if melt transport is enabled. + */ + IndexSet locally_owned_melt_pressure_dofs; + + /** + * Fluid pressure unknowns that are locally owned. Only valid if melt + * transport is enabled. + */ + IndexSet locally_owned_fluid_pressure_dofs; + }; + + /** + * A variable that contains index sets describing which of the globally + * enumerated degrees of freedom are owned by the current processor in a + * parallel computation. + */ + IndexSets index_sets; + + /** + * A variable that contains the field method for the temperature field + * and is used to determine how to solve it when solving a timestep. + */ + typename Parameters::AdvectionFieldMethod::Kind temperature_method; + + /** + * A vector that contains a field method for every compositional + * field and is used to determine how to solve a particular field when + * solving a timestep. + */ + std::vector::AdvectionFieldMethod::Kind> compositional_field_methods; + + /** + * @} + */ + + /** + * Return a vector that contains the base element indices of the deal.II FiniteElement + * that are used for compositional fields. Note that compositional fields can share the + * same base element, so this vector can (and usually will) be smaller than the number + * of compositional fields. The function get_compositional_field_indices_with_base_element() + * can be used to translate from base element index to all compositional field indices + * using the specified base element. + * If several fields are the finite element type (same degree and both continuous or both + * discontinuous), they share base elements. If you have no compositional fields, the + * vector returned has length 0. If all compositional fields have the same finite element + * space, the length is 1. + */ + const std::vector & + get_composition_base_element_indices() const; + + /** + * Return a vector with all compositional field indices that belong to a given + * base element index as returned by get_composition_base_element_indices(). + * The indices returned are therefore between 0 and n_compositional_fields-1. + * If you have a single compositional field, this function returns {0} when passing + * in base_element_index=0. + */ + const std::vector & + get_compositional_field_indices_with_base_element(const unsigned int base_element_index) const; + + /** + * A function that gets the name of a compositional field as an input + * parameter and returns its index. If the name is not found, an + * exception is thrown. + * + * @param name The name of compositional field (as specified in the + * input file) + */ + unsigned int + compositional_index_for_name (const std::string &name) const; + + /** + * A function that gets the index of a compositional field as an input + * parameter and returns its name. + * + * @param index The index of compositional field + */ + std::string + name_for_compositional_index (const unsigned int index) const; + + /** + * A function that returns the full list of compositional field names. + */ + const std::vector & + get_composition_names () const; + + /** + * A function that returns the full vector of compositional + * field descriptions. + */ + const std::vector & + get_composition_descriptions () const; + + /** + * A function that returns the names of + * compositional fields that correspond to chemical compositions. + * + * This function is shorthand for + * get_names_for_fields_of_type(CompositionalFieldDescription::chemical_composition). + */ + const std::vector & + chemical_composition_field_names () const; + + /** + * A function that returns the indices of + * compositional fields that correspond to chemical compositions. + * + * This function is shorthand for + * get_indices_for_fields_of_type(CompositionalFieldDescription::chemical_composition). + */ + const std::vector & + chemical_composition_field_indices () const; + + /** + * A function that returns the number of + * compositional fields that correspond to chemical compositions. + * + * This function is shorthand for + * get_number_of_fields_of_type(CompositionalFieldDescription::chemical_composition). + */ + unsigned int + n_chemical_composition_fields () const; + + /** + * A function that gets the type of a compositional field as an input + * parameter and returns if any compositional field of that type is + * used in this simulation. + * + * @param type The type of compositional field (as specified in the + * input file) + */ + bool + composition_type_exists (const CompositionalFieldDescription::Type &type) const; + + /** + * A function that gets the type of a compositional field as an input + * parameter and returns the index of the first compositional field of + * this type used in this simulation. If no such field is found, the + * function returns the number of compositional fields. + * + * @param type The type of compositional field (as specified in the + * input file) + */ + unsigned int + find_composition_type (const CompositionalFieldDescription::Type &type) const; + + /** + * A function that gets the name of a compositional field as an input + * parameter and returns if the compositional field is used in this + * simulation. + * + * @param name The name of compositional field (as specified in the + * input file) + */ + bool + compositional_name_exists (const std::string &name) const; + + /** + * Get the indices of the compositional fields which are of a + * particular type (chemical composition, porosity, etc.). + */ + const std::vector & + get_indices_for_fields_of_type (const CompositionalFieldDescription::Type &type) const; + + /** + * Get the names of the compositional fields which are of a + * particular type (chemical composition, porosity, etc.). + */ + const std::vector & + get_names_for_fields_of_type (const CompositionalFieldDescription::Type &type) const; + + /** + * Get the number of compositional fields which are of a + * particular type (chemical composition, porosity, etc.). + */ + unsigned int + get_number_of_fields_of_type (const CompositionalFieldDescription::Type &type) const; + + /** + * A function that gets a component index as an input + * parameter and returns if the component is one of the stokes system + * (i.e. if it is the pressure or one of the velocity components). + * + * @param component_index The component index to check. + */ + bool + is_stokes_component (const unsigned int component_index) const; + + /** + * A function that gets a component index as an input + * parameter and returns if the component is one of the + * compositional fields. + * + * @param component_index The component index to check. + */ + bool + is_composition_component (const unsigned int component_index) const; + + private: + /** + * A vector that stores the names of the compositional fields that will + * be used in the simulation. + */ + std::vector composition_names; + + /** + * A vector that stores descriptions of each compositional field, + * including its type (i.e. whether the compositional field corresponds + * to chemical composition, porosity etc.). + */ + std::vector composition_descriptions; + + /** + * A vector of vectors of composition names that stores the + * names of the compositional fields corresponding to each field type + * given in CompositionalFieldDescription. + */ + std::vector> composition_names_for_type; + + /** + * A vector of vectors of composition indices that stores the + * indices of the compositional fields corresponding to each field type + * given in CompositionalFieldDescription. + */ + std::vector> composition_indices_for_type; + + /** + * List of base element indices used by compositional fields. Cached + * result returned by get_composition_base_element_indices(). + */ + std::vector composition_base_element_indices; + + /** + * Map base_element_index to list of compositional field indices that use + * that base element. Cached result returned by + * get_compositional_field_indices_with_base_element(); + */ + std::map> compositional_field_indices_with_base_element; + }; +} + + +#endif diff --git a/include/aspect/lateral_averaging.h.bak b/include/aspect/lateral_averaging.h.bak new file mode 100644 index 00000000000..d18d38a9a6c --- /dev/null +++ b/include/aspect/lateral_averaging.h.bak @@ -0,0 +1,326 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_lateral_averaging_h +#define _aspect_lateral_averaging_h + +#include + +#include + +namespace aspect +{ + using namespace dealii; + + namespace internal + { + /** + * This is the base class for all the functors implemented. Each is + * used to compute one of the properties that will be laterally + * averaged. The point of the base class is to allow handing over + * a variable of type + * std::vector>> to the + * LateralAveraging::get_averages() function. + */ + template + class FunctorBase + { + public: + /** + * operator() will have @p in and @p out filled out if @p true. By default + * returns false. + */ + virtual + bool + need_material_properties() const; + + /** + * If this functor needs additional material model outputs create them + * in here. By default, this does nothing. + */ + virtual + void + create_additional_material_model_outputs (const unsigned int n_points, + MaterialModel::MaterialModelOutputs &outputs) const; + + /** + * Called once at the beginning of compute_lateral_averages() to setup + * internal data structures with the number of quadrature points. + */ + virtual + void + setup(const unsigned int q_points); + + /** + * This takes @p in material model inputs and @p out outputs (which are filled + * if need_material_properties() == true), an initialized FEValues + * object for a cell, and the current solution vector as inputs. + * Functions in derived classes should then evaluate the desired quantity + * and return the results in the output vector, which is q_points long. + */ + virtual + void + operator()(const MaterialModel::MaterialModelInputs &in, + const MaterialModel::MaterialModelOutputs &out, + const FEValues &fe_values, + const LinearAlgebra::BlockVector &solution, + std::vector &output) = 0; + + /** + * Provide an (empty) virtual destructor. + */ + virtual + ~FunctorBase(); + }; + } + + /** + * LateralAveraging is a class that performs various averaging operations + * on the solution. The functions of this class take a vector as an argument. + * The model is divided into depth slices where the number of slices is the + * length of the output vector. Each function averages a specific quantity + * (as specified by their name), and that quantity is averaged laterally + * for each depth slice. + * + * Plugins may access the LateralAveraging plugin through the SimulatorAccess + * function get_lateral_averaging(), and then query that for the desired + * averaged quantity. + * + * @ingroup Simulator + */ + template + class LateralAveraging : public SimulatorAccess + { + public: + /** + * @deprecated: This function is deprecated and only maintained for backward compatibility. + * Use the function compute_lateral_averages() with the same arguments instead. + */ + DEAL_II_DEPRECATED + std::vector> + get_averages(const unsigned int n_slices, + const std::vector &property_names) const; + + /** + * Return a depth profile of lateral averages of the selected + * @p property_names. This function is a convenience interface for + * the other functions of the same name and is more efficient for + * multiple properties than calling multiple of the single property functions + * sequentially. This version of the function creates @p n_slices + * equidistant depth slices to compute averages in. + * + * @param n_slices The number of equidistant depth slices + * to perform the averaging in. + * @param property_names Names of the available quantities to average. + * Check the implementation of this function for available names. + * @return The output vector of laterally averaged values. Each vector + * has the same size of @p n_slices, and there are + * as many vectors returned as names in @p property_names. + */ + std::vector> + compute_lateral_averages(const unsigned int n_slices, + const std::vector &property_names) const; + + /** + * Return a depth profile of lateral averages of the selected + * @p property_names. This function is a convenience interface for + * the other functions of the same name and is more efficient for + * multiple properties than calling multiple of the single property + * functions sequentially. This version of the function uses @p depth_bounds + * to determine the upper and lower boundary of each depth slice, + * and returns one averaged value per slice (= one less than the + * number of depth bounds). + * + * @param depth_bounds The boundaries of the depth slices to compute + * averages in. It is expected to be a vector of monotonically increasing + * depth values with consecutive entries representing the minimum and + * maximum depth of each depth slice. All depths smaller than + * entry 0 or larger than the last entry are ignored, and depths + * between entries 0 and 1 fall into depth slice 0, and so on. + * @param property_names Names of the available quantities to average. + * Check the implementation of this function for available names. + * @return The output vector of laterally averaged values. The length + * of each vector is one less than the number of @p depth_bounds, + * and there are as many vectors returned as names in @p property_names. + */ + std::vector> + compute_lateral_averages(const std::vector &depth_bounds, + const std::vector &property_names) const; + + /** + * Return a depth profile of lateral averages. This function is the + * low-level implementation for the other functions of the same name + * and is more efficient for multiple properties than calling multiple + * of the single property functions sequentially. This version of the + * function uses @p depth_bounds to determine the upper and lower + * boundary of each depth slice, and returns one averaged value per slice + * (= one less than the number of depth bounds). + * The vector of functors @p functors must contain one or more + * objects of classes that are derived from FunctorBase and are used to + * fill the values vectors. All of the other functions in this class use + * this low-level implementation for the actual computation. + * Using this function allows to provide user-defined functors to average + * properties not already implemented (e.g. to average additional + * material model outputs). + * + * @param depth_bounds The boundaries of the depth slices to compute + * averages in. It is expected to be a vector of monotonically increasing + * depth values with consecutive entries representing the minimum and + * maximum depth of each depth slice. All depths smaller than + * entry 0 or larger than the last entry are ignored, and depths + * between entries 0 and 1 fall into depth slice 0, and so on. + * @param functors Instances of a class derived from FunctorBase + * that are used to compute the averaged properties. + * @return The output vectors of depth averaged values. The + * function returns one vector of doubles per property and uses + * @p depth_bounds to determine the depth extents of each slice. + * Each returned vector has the same size (one entry less than + * the number of @p depth_bounds). + */ + std::vector> + compute_lateral_averages(const std::vector &depth_bounds, + std::vector>> &functors) const; + + /** + * Fill the argument with a set of lateral averages of the current + * temperature field. The function fills a vector that contains average + * field values over slices of the domain of same depth. + * + * @param values The output vector of laterally averaged values. The + * function takes the pre-existing size of this vector as the number of + * depth slices. + */ + void + get_temperature_averages(std::vector &values) const; + + /** + * Fill the argument with a set of lateral averages of the current + * compositional fields. + * + * @param composition_index The index of the compositional field whose + * matrix we want to assemble (0 <= composition_index < number of + * compositional fields in this problem). + * + * @param values The output vector of laterally averaged values. The + * function takes the pre-existing size of this vector as the number of + * depth slices. + */ + void + get_composition_averages(const unsigned int composition_index, + std::vector &values) const; + + /** + * Compute a lateral average of the current viscosity. + * + * @param values The output vector of laterally averaged values. The + * function takes the pre-existing size of this vector as the number of + * depth slices. + */ + void + get_viscosity_averages(std::vector &values) const; + + /** + * Compute a lateral average of the log10 of the current viscosity. + * + * @param values The output vector of laterally averaged values. The + * function takes the pre-existing size of this vector as the number of + * depth slices. + */ + void + get_log_viscosity_averages(std::vector &values) const; + + /** + * Compute a lateral average of the current velocity magnitude. + * + * @param values The output vector of laterally averaged values. The + * function takes the pre-existing size of this vector as the number of + * depth slices. + */ + void + get_velocity_magnitude_averages(std::vector &values) const; + + /** + * Compute a lateral average of the current sinking velocity. + * + * @param values The output vector of laterally averaged values. The + * function takes the pre-existing size of this vector as the number of + * depth slices. + */ + void + get_sinking_velocity_averages(std::vector &values) const; + + /** + * Compute a lateral average of the current rising velocity. + * + * @param values The output vector of laterally averaged values. The + * function takes the pre-existing size of this vector as the number of + * depth slices. + */ + void + get_rising_velocity_averages(std::vector &values) const; + + /** + * Compute a lateral average of the seismic shear wave speed: Vs. + * + * @param values The output vector of laterally averaged values. The + * function takes the pre-existing size of this vector as the number of + * depth slices. + */ + void + get_Vs_averages(std::vector &values) const; + + /** + * Compute a lateral average of the seismic pressure wave speed: Vp. + * + * @param values The output vector of laterally averaged values. The + * function takes the pre-existing size of this vector as the number of + * depth slices. + */ + void + get_Vp_averages(std::vector &values) const; + + /** + * Compute a lateral average of the vertical heat flux, with the sign + * convention of positive heat flux when it flows upwards. + * + * @param values The output vector of laterally averaged values. The + * function takes the pre-existing size of this vector as the number of + * depth slices. + */ + void + get_vertical_heat_flux_averages(std::vector &values) const; + + /** + * Compute a lateral average of the vertical mass flux. Note that + * while get_vertical_heat_flux_averages() computes the average + * vertical heat flux (positive or negative), this function computes + * the average of the total mass flux through a certain layer + * (both down- and upward motion counted positively). + * + * @param values The output vector of laterally averaged values. + */ + void + get_vertical_mass_flux_averages(std::vector &values) const; + }; +} + + +#endif diff --git a/include/aspect/material_model/ascii_reference_profile.h.bak b/include/aspect/material_model/ascii_reference_profile.h.bak new file mode 100644 index 00000000000..b04a689640c --- /dev/null +++ b/include/aspect/material_model/ascii_reference_profile.h.bak @@ -0,0 +1,167 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_model_ascii_reference_profile_h +#define _aspect_model_ascii_reference_profile_h + +#include +#include +#include +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that reads in a reference profile from an ascii file + * and computes properties based on this profile. + * + * The viscosity is computed as + * \f[ + * \eta(z,T) = \eta_r(z) \eta_0 \exp\left(-A \frac{T - T_\text{adi}}{T_\text{adi}}\right)." + * \f] + * + * @ingroup MaterialModels + */ + template + class AsciiReferenceProfile : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. Initialize variables. + */ + AsciiReferenceProfile (); + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run and after + * the SimulatorAccess (if applicable) is initialized. + */ + void + initialize () override; + + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + */ + bool is_compressible () const override; + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @} + */ + + /** + * Add the named outputs for seismic velocities. + */ + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + + private: + /** + * Use truncated anelastic approximation? + */ + bool tala; + + /** + * The reference viscosity + */ + double viscosity; + + /** + * The constant $A$ in the temperature dependence of viscosity + * $\exp\left(-A \frac{T - T_\text{adi}}{T_\text{adi}}\right).$ + */ + double thermal_viscosity_exponent; + + /** + * A list of constants that make up the piece-wise constant function + * $\eta_r(z)$, which determines the depth dependence of viscosity, + * and is multiplied with the reference viscosity and the + * temperature dependence to compute the viscosity $\eta(z,T)$. + */ + std::vector viscosity_prefactors; + + /** + * A list of depths that determine the locations of the jumps in + * the piece-wise constant function $\eta_r(z)$, which describes the + * depth dependence of viscosity. + */ + std::vector transition_depths; + + double thermal_conductivity; + + /** + * Object containing the data profile. + */ + aspect::Utilities::AsciiDataProfile profile; + + /** + * The column indices of the temperature, pressure, and density column + * in the data file. + */ + unsigned int density_index; + unsigned int thermal_expansivity_index; + unsigned int specific_heat_index; + unsigned int compressibility_index; + + /** + * The column indices of the seismic velocities and their temperature + * derivatives columns in the data file. + */ + unsigned int seismic_vp_index; + unsigned int seismic_vs_index; + unsigned int seismic_dvp_dT_index; + unsigned int seismic_dvs_dT_index; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/averaging.h.bak b/include/aspect/material_model/averaging.h.bak new file mode 100644 index 00000000000..d6d4431ff42 --- /dev/null +++ b/include/aspect/material_model/averaging.h.bak @@ -0,0 +1,168 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_averaging_h +#define _aspect_material_model_averaging_h + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * An enum to define what kind of averaging operations are implemented. + * These are: + * + * - No averaging, i.e., leave the values as they were provided by the + * material model. + * + * - Arithmetic averaging: Set the values of each output quantity at + * every quadrature point to \f[ \bar x = \frac 1Q \sum_{q=1}^Q x_q \f] + * where $x_q$ are the values at the $Q$ quadrature points. + * + * - Harmonic averaging: Set the values of each output quantity at every + * quadrature point to \f[ \bar x = \left(\frac 1Q \sum_{q=1}^Q + * \frac{1}{x_q}\right)^{-1} \f] where $x_q$ are the values at the $Q$ + * quadrature points. + * + * - Geometric averaging: Set the values of each output quantity at + * every quadrature point to \f[ \bar x = \left(\prod_{q=1}^Q + * x_q\right)^{1/Q} \f] where $x_q$ are the values at the $Q$ quadrature + * points. + * + * - Pick largest: Set the values of each output quantity at every + * quadrature point to \f[ \bar x = \max_{1\le q\le Q} x_q \f] where $x_q$ + * are the values at the $Q$ quadrature points. + * + * - Log average: Set the values of each output quantity at every + * quadrature point to \f[ \bar x = {10}^{\frac 1Q \sum_{q=1}^Q \log_{10} + * x_q} \f] where $x_q$ are the values at the $Q$ quadrature points. + * + * - NWD Arithmetic averaging: Set the values of each output quantity at + * every quadrature point to \f[ \bar x = \frac {\sum_{q=1}^Q W_q * x_q} + * {\sum_{q=1}^Q W_q} \f] where $x_q$ are the values and $w$ the weights + * at the $Q$ quadrature points. + * + * - NWD Harmonic averaging: Set the values of each output quantity at every + * quadrature point to \f[ \bar x = \frac{\sum_{q=1}^Q w_q }{ \sum_{q=1}^Q + * \frac{w_q}{x_q}} \f] where $x_q$ are the values and $w$ the weights at + * the $Q$ quadrature points. + * + * - NWD Geometric averaging: Set the values of each output quantity at + * every quadrature point to \f[ \bar x = \frac{ \sum_{q=1}^Q w_q x_q} + * {\sum_{q=1}^Q w_q} \f] where $x_q$ are the values and $w$ the weights + * at the $Q$ quadrature points. + */ + enum AveragingOperation + { + none, + arithmetic_average, + harmonic_average, + geometric_average, + pick_largest, + log_average, + nwd_arithmetic_average, + nwd_harmonic_average, + nwd_geometric_average + }; + + /** + * A material model that applies an average of the quadrature points in a cell to + * a ''base model'' chosen from any of the other available material models. + * @ingroup MaterialModels + */ + + template + class Averaging : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Function to compute the material properties in @p out given the + * inputs in @p in. + */ + void + evaluate (const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + /** + * Method to declare parameters related to depth-dependent model + */ + static void + declare_parameters (ParameterHandler &prm); + + /** + * Method to parse parameters related to depth-dependent model + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Method that indicates whether material is compressible. Depth dependent model is compressible + * if and only if base model is compressible. + */ + bool is_compressible () const override; + + + + private: + + /** + * Parse a string representing one of the options returned by + * get_averaging_operation_names(), and return the corresponding + * AveragingOperation value. + */ + AveragingOperation + parse_averaging_operation_name (const std::string &s); + + /** + * Given the averaging @p operation, a description of where the + * quadrature points are located on the given cell, and a mapping, + * perform this operation on all elements of the @p values structure. + */ + void + average (const AveragingOperation averaging_operation, + const std::vector> &position, + std::vector &values_out) const; + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + /** + * The bell shape limit variable stores the maximum extend of the bell + * shape for the Normalized Weighed Distance (NWD) averages. + */ + double bell_shape_limit; + /** + * The averaging operation variable stores the chosen averaging + * operation. + */ + AveragingOperation averaging_operation; + /** + * Pointer to the material model used as the base model + */ + std::unique_ptr> base_model; + }; + } +} + +#endif diff --git a/include/aspect/material_model/compositing.h.bak b/include/aspect/material_model/compositing.h.bak new file mode 100644 index 00000000000..8f9b30a7f1d --- /dev/null +++ b/include/aspect/material_model/compositing.h.bak @@ -0,0 +1,136 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_compositing_h +#define _aspect_material_model_compositing_h + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace Property + { + /** + * An enum to define what material properties are available. + */ + enum MaterialProperty + { + viscosity, + density, + thermal_expansion_coefficient, + specific_heat, + thermal_conductivity, + compressibility, + entropy_derivative_pressure, + entropy_derivative_temperature, + reaction_terms + }; + } + + /** + * A material model that selects properties from other + * (non-compositing) material models. + * + * @ingroup MaterialModels + */ + + template + class Compositing : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * @copydoc MaterialModel::Interface::initialize() + */ + void + initialize () override; + + /** + * @copydoc MaterialModel::Interface::evaluate() + */ + void + evaluate (const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + + /** + * If this material model can produce additional named outputs + * that are derived from NamedAdditionalOutputs, create them in here. + */ + void + create_additional_named_outputs (typename Interface::MaterialModelOutputs &outputs) const override; + + /** + * @copydoc MaterialModel::Interface::declare_parameters() + */ + static void + declare_parameters (ParameterHandler &prm); + + /** + * @copydoc MaterialModel::Interface::parse_parameters() + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @copydoc MaterialModel::Interface::is_compressible() + * + * Returns value from material model providing compressibility. + */ + bool is_compressible () const override; + + + + private: + /** + * Copy desired properties from material model outputs + * produced by another material model, + * + * @param model_index Internal index for pointer to the material model evaluated + * @param base_output Properties generated by the material model specified + * @param out MaterialModelOutputs to be used. + */ + void + copy_required_properties(const unsigned int model_index, + const typename Interface::MaterialModelOutputs &base_output, + typename Interface::MaterialModelOutputs &out) const; + + /** + * Map specifying which material model is responsible for a + * property. + */ + std::map model_property_map; + + /** + * Names of and pointers to the material models used for + * compositing. + */ + std::vector model_names; + std::vector>> models; + }; + } +} + +#endif diff --git a/include/aspect/material_model/composition_reaction.h.bak b/include/aspect/material_model/composition_reaction.h.bak new file mode 100644 index 00000000000..81a83dd7815 --- /dev/null +++ b/include/aspect/material_model/composition_reaction.h.bak @@ -0,0 +1,125 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_composition_reaction_h +#define _aspect_material_model_composition_reaction_h + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that consists of globally constant values for all + * material parameters except that the density decays linearly with the + * temperature. + * + * The model is considered incompressible, following the definition + * described in Interface::is_compressible. This is essentially the + * material model used in the step-32 tutorial program. + * + * @ingroup MaterialModels + */ + template + class CompositionReaction : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate material properties. + */ + void evaluate(const MaterialModelInputs &in, + MaterialModelOutputs &out) const override; + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @} + */ + + /** + * Create additional outputs + */ + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + + private: + double reference_T; + double eta; + double composition_viscosity_prefactor_1; + double composition_viscosity_prefactor_2; + double thermal_viscosity_exponent; + + /** + * The thermal conductivity. + */ + double k_value; + + EquationOfState::LinearizedIncompressible equation_of_state; + + /** + * Above this depth the compositional fields react: The first field + * gets converted to the second field. + */ + double reaction_depth; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/depth_dependent.h.bak b/include/aspect/material_model/depth_dependent.h.bak new file mode 100644 index 00000000000..0613ef53d9e --- /dev/null +++ b/include/aspect/material_model/depth_dependent.h.bak @@ -0,0 +1,151 @@ +/* + Copyright (C) 2014 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_depth_dependent_h +#define _aspect_material_model_depth_dependent_h + +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that applies a depth-dependent viscosity to a ''base model'' + * chosen from any of the other available material models. This depth-dependent + * material model allows the user to specify a depth-dependent reference viscosity + * either through a parsed function, lists of depth and viscosity values, or a file. + * The current implementation only allows for depth-dependence of viscosity - all + * other properties are derived from the base model. + * @ingroup MaterialModels + */ + template + class DepthDependent : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialize the base model at the beginning of the run. + */ + void initialize() override; + + /** + * Update the base model and viscosity function at the beginning of + * each timestep. + */ + void update() override; + + /** + * Method that indicates whether material is compressible. Depth dependent model is compressible + * if and only if base model is compressible. + */ + bool is_compressible () const override; + + /** + * Function to compute the material properties in @p out given the + * inputs in @p in. + */ + void + evaluate (const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + /** + * Method to declare parameters related to depth-dependent model + */ + static void + declare_parameters (ParameterHandler &prm); + + /** + * Method to parse parameters related to depth-dependent model + */ + void + parse_parameters (ParameterHandler &prm) override; + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + private: + /** + * An enum to describe where the depth dependency of the viscosity is coming from. + */ + enum ViscositySource + { + function, + file, + list, + none + }; + + /** + * The viscosity that will be used as a reference for computing the depth-dependent + * prefactor. + */ + double reference_viscosity; + + /** + * Currently chosen source for the viscosity. + */ + ViscositySource viscosity_source; + + /** + * Data structures to store depth and viscosity lookup tables as well as interpolating + * function to calculate viscosity for File Depth dependence method + */ + std::unique_ptr> viscosity_file_function; + + /** + * Function to calculate depth-dependent multiplicative prefactor to be applied + * to base model viscosity. + */ + double + calculate_depth_dependent_prefactor(const double &depth) const; + + /** + * Values of depth specified by the user if using the depth dependence method 'list' + */ + std::vector depth_values; + std::vector viscosity_values; + + /** + * Parsed function that specifies viscosity depth-dependence when using the 'function' + * method. + */ + Functions::ParsedFunction<1> viscosity_function; + + /** + * Pointer to the material model used as the base model + */ + std::unique_ptr> base_model; + + /** + * Pointer to the rheology model used for depth-dependence from an + * ascii file + */ + std::unique_ptr> depth_dependent_rheology; + }; + } +} + +#endif diff --git a/include/aspect/material_model/diffusion_dislocation.h.bak b/include/aspect/material_model/diffusion_dislocation.h.bak new file mode 100644 index 00000000000..61a420891ad --- /dev/null +++ b/include/aspect/material_model/diffusion_dislocation.h.bak @@ -0,0 +1,128 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_diffusion_dislocation_h +#define _aspect_material_model_diffusion_dislocation_h + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model based on a viscous rheology including diffusion and + * dislocation creep. + * + * The effective viscosity is defined as the harmonic mean of the two + * effective viscosity functions describing diffusion and dislocation creep: + * @f[ + * v_\text{eff} = \left( \frac{1}{v_\text{eff}^\text{diff}} + \frac{1}{v_\text{eff}^\text{dis}} \right)^{-1} + * @f] + * where + * @f[ + * v_\text{eff}^\text{diff} = A_\text{diff}^{-1} \exp\left(\frac{E_\text{diff} + PV_\text{diff}}{RT}\right), + * @f] + * and + * @f[ + * v_\text{eff}^\text{dis} = A_\text{dis}^{\frac{-1}{n_\text{dis}}} \dot{\varepsilon}^{\frac{1-n}{n}} + * \exp\left(\frac{E_\text{diff} + PV_\text{diff}}{n_\text{dis}RT}\right) + * @f] + * where $\dot{\varepsilon}$ is the second invariant of the strain rate tensor, + * $A_i$ are prefactors where $i$ corresponds to diffusion or dislocation creep, + * $E_i$ are the activation energies, $V_i$ are the activation volumes, + * $\rho_m$ is the mantle density, $R$ is the gas constant, + * $T$ is temperature, and $P$ is pressure. + * + * Several model parameters (reference densities, thermal expansivities + * and rheology parameters) can be defined per-compositional field. + * For each material parameter the user supplies a comma delimited list of + * length N+1, where N is the number of compositional fields. The + * additional field corresponds to the value for background mantle. They + * should be ordered ``background, composition1, composition2...'' + * + * If a list of values is given for the density and thermal expansivity, + * the volume weighted sum of the values of each of the compositional fields + * is used in their place, for example + * $\rho = \sum \left( \rho_i V_i \right)$ + * + * The individual output viscosities for each compositional field are + * also averaged. The user can choose from a range of options for this + * viscosity averaging. If only one value is given for any of these parameters, + * all compositions are assigned the same value. + * The first value in the list is the value assigned to "background mantle" + * (regions where the sum of the compositional fields is < 1.0). + * + * @ingroup MaterialModels + */ + template + class DiffusionDislocation : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the + * continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + * + * This material model is incompressible. + */ + bool is_compressible () const override; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Object for computing viscous creep viscosities. + */ + Rheology::DiffusionDislocation diffusion_dislocation; + + double reference_T; + + double thermal_diffusivity; + double heat_capacity; + + std::vector densities; + std::vector thermal_expansivities; + + MaterialUtilities::CompositionalAveragingOperation viscosity_averaging; + + }; + + } +} + +#endif diff --git a/include/aspect/material_model/drucker_prager.h.bak b/include/aspect/material_model/drucker_prager.h.bak new file mode 100644 index 00000000000..8cb0fe5581d --- /dev/null +++ b/include/aspect/material_model/drucker_prager.h.bak @@ -0,0 +1,170 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_drucker_prager_h +#define _aspect_material_model_drucker_prager_h + +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that consists of globally constant values for all + * material parameters except density and viscosity. + * + * The model is considered incompressible, following the definition + * described in Interface::is_compressible. + * + * The viscosity is computed according to the Drucker Prager frictional + * plasticity criterion based on a user-defined internal angle of friction $\phi$ + * and cohesion $C$. In 3D: + * $\sigma_y = \frac{6 C \cos(\phi)}{\sqrt{3} (3+\sin(\phi))} + + * \frac{6 P \sin(\phi)}{\sqrt{3} (3+\sin(\phi))}$, + * where $P$ is the pressure. + * See for example Zienkiewicz, O. C., Humpheson, C. and Lewis, R. W. (1975), + * Géotechnique 25, No. 4, 671-689. + * With this formulation we circumscribe instead of inscribe the Mohr Coulomb + * yield surface. + * In 2D the Drucker Prager yield surface is the same + * as the Mohr Coulomb surface: + * $\sigma_y = P \sin(\phi) + C \cos(\phi)$. + * Note that in 2D for $\phi=0$, these criteria + * revert to the von Mises criterion (no pressure dependence). + * See for example Thieulot, C. (2011), PEPI 188, 47-68. + * + * Note that we enforce the pressure to be positive in the computation of + * the yield strength by replacing it with + * a zero value whenever it is negative to prevent negative + * yield strengths and viscosities. + * We then use the computed yield strength to scale back the viscosity on + * to the yield surface using the Viscosity Rescaling Method described in + * Kachanov, L. M. (2004), Fundamentals of the Theory of Plasticity, + * Dover Publications, Inc. + * + * To avoid numerically unfavourably large (or even negative) viscosity ranges, + * we cut off the viscosity with a user-defined minimum and maximum viscosity: + * $\eta_eff = \frac{1}{\frac{1}{\eta_min + \eta}+\\ + * \frac{1}{\eta_max}}$. + * + * Note that this model uses the formulation that assumes an incompressible + * medium despite the fact that the density follows the law + * $\rho(T)=\rho_0(1-\beta(T-T_{\text{ref}}))$. + * + * + * @ingroup MaterialModels + */ + template + class DruckerPrager : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * @name Physical parameters used in the basic equations + * @{ + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + private: + + double reference_T; + double thermal_conductivities; + + EquationOfState::LinearizedIncompressible equation_of_state; + + /* + * Objects for computing plastic stresses, viscosities, and additional outputs + */ + Rheology::DruckerPrager drucker_prager_plasticity; + + /** + * The angle of internal friction + */ + double angle_of_internal_friction; + + /** + * The cohesion + */ + double cohesion; + + /** + * The applied viscosity bounds + */ + double minimum_viscosity; + double maximum_viscosity; + + /** + * The reference strain rate used as a first estimate + */ + double reference_strain_rate; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/entropy_model.h.bak b/include/aspect/material_model/entropy_model.h.bak new file mode 100644 index 00000000000..c245055e8b8 --- /dev/null +++ b/include/aspect/material_model/entropy_model.h.bak @@ -0,0 +1,187 @@ +/* + Copyright (C) 2016 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_entropy_model_h +#define _aspect_material_model_entropy_model_h + +#include + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + /** + * A material model that is designed to use pressure and entropy (rather + * than pressure and temperature) as independent variables. It will look up + * all material properties in a data table for a given pressure and + * entropy, and will additionally provide an additional output object of + * type PrescribedTemperatureOutputs filled with the temperature, and + * an additional output object of type PrescribedFieldOutput filled with + * the densities (necessary for the projected density approximation of + * the Stokes equation). + * @ingroup MaterialModels + */ + + template + class EntropyModel: public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. Loads the material data and sets up + * pointers. + */ + void + initialize () override; + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + */ + bool is_compressible () const override; + /** + * @} + */ + + /** + * Function to compute the material properties in @p out given the + * inputs in @p in. + */ + void + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + /** + * Creates additional output objects of + * type PrescribedTemperatureOutputs filled with the temperature + * (necessary for solving the entropy equation), and + * an additional output object of type PrescribedFieldOutput filled with + * the densities (necessary for the projected density approximation of + * the Stokes equation). Also creates SeismicAdditionalOutputs for + * postprocessing purposes. + */ + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + + private: + + double angle_of_internal_friction; + double cohesion; + + /** + * Minimum/Maximum viscosity and lateral viscosity variations. + */ + double min_eta; + double max_eta; + double max_lateral_eta_variation; + + /** + * The value for thermal conductivity. It can be a constant + * for the whole domain, or P-T dependent. + */ + double thermal_conductivity_value; + double thermal_conductivity (const double temperature, + const double pressure, + const Point &position) const; + + enum ConductivityFormulation + { + constant, + p_T_dependent + } conductivity_formulation; + + /** + * Parameters for the temperature- and pressure dependence of the + * thermal conductivity. + */ + std::vector conductivity_transition_depths; + std::vector reference_thermal_conductivities; + std::vector conductivity_pressure_dependencies; + std::vector conductivity_reference_temperatures; + std::vector conductivity_exponents; + std::vector saturation_scaling; + double maximum_conductivity; + + /** + * Information about the location of data files. + */ + std::string data_directory; + std::vector material_file_names; + std::string lateral_viscosity_file_name; + + /** + * List of pointers to the EntropyReader that reads in material data for + * given entropy and pressure. There is one pointer/object per lookup file. + */ + std::vector> entropy_reader; + + /** + * Pointer to an object that reads and processes data for the lateral + * temperature dependency of viscosity. + */ + std::unique_ptr lateral_viscosity_prefactor_lookup; + + /** + * Objects for computing plastic stresses, viscosities, and additional outputs + */ + Rheology::DruckerPrager drucker_prager_plasticity; + + /** + * Pointer to the rheology model used for depth-dependence from an + * ascii file + */ + std::unique_ptr> depth_dependent_rheology; + }; + } +} + +#endif diff --git a/include/aspect/material_model/equation_of_state/interface.h.bak b/include/aspect/material_model/equation_of_state/interface.h.bak new file mode 100644 index 00000000000..eee4c557502 --- /dev/null +++ b/include/aspect/material_model/equation_of_state/interface.h.bak @@ -0,0 +1,125 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_equation_of_state_interface_h +#define _aspect_material_model_equation_of_state_interface_h + +#include +#include +#include + + + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A data structure containing output fields that can be filled by the + * evaluate() function of an EquationOfState model. It contains those + * properties of the MaterialModelOutputs that are connected to the + * equation of state (or the thermodynamic properties). Output values + * are computed separately for each composition and phase. + * + * Accordingly, the vectors are the values for each compositional field + * and individual phase at one specific location. + */ + template + struct EquationOfStateOutputs + { + /** + * Constructor. Initialize the various arrays of this structure with the + * given number of compositions and phases. + * + * @param n_individual_compositions_and_phases The number of vector quantities + * for which input will be provided, and outputs should be filled. Note that this + * number does not have to be the number of compositions, it can be smaller (if + * some compositional fields do not represent volumetric compositions, but tracked + * quantities like strain) or larger (if there is a background field, or some + * compositions have several high-pressure phases). It is the responsibility + * of the material model and equation of state object to interpret the + * entries consistently. + */ + EquationOfStateOutputs (const unsigned int n_individual_compositions_and_phases); + + /** + * Density values for each composition and phase. + */ + std::vector densities; + + /** + * Thermal expansion coefficients for each composition and phase. It is defined + * as $\alpha = - \frac{1}{\rho} \frac{\partial\rho}{\partial T}$ + */ + std::vector thermal_expansion_coefficients; + + /** + * Specific heat for each composition and phase. + */ + std::vector specific_heat_capacities; + + /** + * Compressibility for each composition and phase. The compressibility is defined + * as $\kappa = \frac{1}{\rho} \frac{\partial\rho}{\partial p}$. + */ + std::vector compressibilities; + + /** + * The product of the change of entropy $\Delta S$ at a phase transition + * and the derivative of the phase function $X=X(p,T,\mathfrak c,\mathbf + * x)$ with regard to pressure for each composition and phase. + */ + std::vector entropy_derivative_pressure; + + /** + * The product of (minus) the change of entropy $-\Delta S$ at a phase + * transition and the derivative of the phase function + * $X=X(p,T,\mathfrak c,\mathbf x)$ with regard to temperature for + * each composition and phase. + */ + std::vector entropy_derivative_temperature; + }; + + + + /** + * This function takes the output of an equation of state @p eos_outputs_all_phases, + * which contains the data for all compositions and all of their phases at the + * current conditions and uses a PhaseFunction object @p phase_function to compute + * the effective value of equation of state properties for each individual composition. + * Essentially it computes which phase is stable at the current conditions + * (described in @p phase_in) and fills the equation of state output @p eos_outputs with + * the properties of these stable phases. + * @p eos_outputs now only contains as many entries as volumetric compositions (potentially + * plus one for the background field, if the input @p eos_outputs_all_phases contained + * one and the phase function contained one as well). + */ + template + void + phase_average_equation_of_state_outputs(const EquationOfStateOutputs &eos_outputs_all_phases, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition, + EquationOfStateOutputs &eos_outputs); + } +} + +#endif diff --git a/include/aspect/material_model/equation_of_state/linearized_incompressible.h.bak b/include/aspect/material_model/equation_of_state/linearized_incompressible.h.bak new file mode 100644 index 00000000000..5b1a4c0ffa7 --- /dev/null +++ b/include/aspect/material_model/equation_of_state/linearized_incompressible.h.bak @@ -0,0 +1,140 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_equation_of_state_linearized_incompressible_h +#define _aspect_material_model_equation_of_state_linearized_incompressible_h + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace EquationOfState + { + using namespace dealii; + + /** + * A simplified, incompressible equation of state where the density depends linearly + * on temperature and composition, using the equation + * $\rho(p,T,\mathfrak c) = \left(1-\alpha (T-T_0)\right)\rho_0 + \sum_i \Delta\rho_i \; \mathfrak c_i.$ " + * There is no pressure-dependence of the density, and all other material properties + * relating to the equation of state are assumed to be constant and identical for each + * composition. + */ + template + class LinearizedIncompressible + { + public: + /** + * A function that computes the output of the equation of state @p out + * for all compositions, given the inputs in @p in and an index @p q. + * More specifically, the inputs structure MaterialModelInputs contains + * a number of vectors, one for each input property, containing the + * material model inputs at a number of different locations. The equation + * of state model only evaluates one location (for each function call), + * and the index q determines which entry of each of these vectors of + * inputs is used. + * Using these inputs, the equation of state outputs are computed + * individually for each composition given in the inputs, and the outputs + * structure is filled with the equation of state outputs, which contain a + * number of vectors, one for each output property, with each vector + * containing the separate outputs for each composition. + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + const unsigned int q, + MaterialModel::EquationOfStateOutputs &out) const; + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const; + + /** + * Declare the parameters this class takes through input files. + * The optional parameter @p n_compositions determines the maximum + * number of compositions the equation of state is set up with, + * in other words, how many compositional fields influence the + * density. + */ + static + void + declare_parameters (ParameterHandler &prm, + const unsigned int n_compositions = 0); + + /** + * Read the parameters this class declares from the parameter file. + * The optional parameter @p n_compositions determines the maximum + * number of compositions the equation of state is set up with, + * and should have the same value as the parameter with the same + * name in the declare_parameters() function. + */ + void + parse_parameters (ParameterHandler &prm, + const unsigned int n_compositions = 0); + + + private: + /** + * The reference density $\rho_0$ used in the computation of the density. + */ + double reference_rho; + + /** + * The reference temperature $T_0$ used in the computation of the density. + */ + double reference_T; + + /** + * The constant thermal expansivity $\alpha$ used in the computation of the density. + */ + double thermal_alpha; + + /** + * The constant specific heat. + */ + double reference_specific_heat; + + /** + * The maximum number of compositions that densities will be computed for, and, + * accordingly, the maximum number of compositions the equation of state can be + * evaluated with. + */ + unsigned int maximum_number_of_compositions; + + /** + * The density difference $\Delta\rho_i$ between each composition $\mathfrak c_i$ + * and the background. + */ + std::vector compositional_delta_rhos; + }; + } + } +} + +#endif diff --git a/include/aspect/material_model/equation_of_state/multicomponent_compressible.h.bak b/include/aspect/material_model/equation_of_state/multicomponent_compressible.h.bak new file mode 100644 index 00000000000..33c54d2ec23 --- /dev/null +++ b/include/aspect/material_model/equation_of_state/multicomponent_compressible.h.bak @@ -0,0 +1,143 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_equation_of_state_multicomponent_compressible_h +#define _aspect_material_model_equation_of_state_multicomponent_compressible_h + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace EquationOfState + { + using namespace dealii; + + /** + * A compressible equation of state that is intended for use with multiple compositional + * fields. For each material property, the user supplies a comma delimited list of + * length N+1, where N is the number of compositional fields used in the computation. + * The first entry corresponds to the "background" (which is also why there are N+1 entries). + * + * If a single value is given, then all the compositional fields are given + * that value. Other lengths of lists are not allowed. The material parameters + * for each compositional field are calculated self-consistently, + * assuming a constant pressure derivative of the isothermal bulk modulus ($K_T'$) + * at the reference temperature (i.e. a Murnaghan equation of state), + * a constant ratio of the thermal expansivity ($\alpha$) and + * isothermal compressibility ($\beta_T$), and a constant isochoric + * specific heat $C_v$. This leads to the following expressions for the material + * properties of each material: + * + * $\rho(p,T) = \rho_0 f^{1/K_T'}$ + * $C_p(p,T) = C_v + (\alpha T \frac{\alpha}{\beta} f^{-1-(1/K_T')} / \rho_0)$ + * $\alpha(p, T) = \alpha_0/f$ + * $\beta_T(p, T) = \beta_0/f$ + * $f = (1 + (p - \frac{\alpha}{\beta}(T-T_0)) K_T' \beta)$. + * + * where $\rho$ is the density and $C_p$ is the isobaric heat capacity. + * $f$ is a scaling factor for $\alpha$ and $\beta_T$. + */ + template + class MulticomponentCompressible : public ::aspect::SimulatorAccess + { + public: + /** + * A function that computes the output of the equation of state @p out + * for all compositions, given the inputs in @p in and an index q that + * determines which entry of the vector of inputs is used. + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + const unsigned int q, + MaterialModel::EquationOfStateOutputs &out) const; + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + * This model is compressible. + */ + bool is_compressible () const; + + /** + * Declare the parameters this class takes through input files. + * The optional parameter @p n_compositions determines the maximum + * number of compositions the equation of state is set up with, + * in other words, how many compositional fields influence the + * density. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The optional parameter @p n_compositions determines the maximum + * number of compositions the equation of state is set up with, + * and should have the same value as the parameter with the same + * name in the declare_parameters() function. + */ + void + parse_parameters (ParameterHandler &prm); + + /** + * Vector for reference_densities, read from parameter file . + */ + std::vector reference_densities; + + private: + /** + * Vector for reference temperatures, read from parameter file . + */ + std::vector reference_temperatures; + + /** + * Vector for reference compressibilities, read from parameter file. + */ + std::vector reference_isothermal_compressibilities; + + /** + * Vector for isothermal bulk modulus pressure derivatives, read from parameter file. + */ + std::vector isothermal_bulk_modulus_pressure_derivatives; + + /** + * Vector for reference thermal expansivities, read from parameter file. + */ + std::vector reference_thermal_expansivities; + + /** + * Vector for isochoric specific heats, read from parameter file. + */ + std::vector isochoric_specific_heats; + + }; + } + } +} + +#endif diff --git a/include/aspect/material_model/equation_of_state/multicomponent_incompressible.h.bak b/include/aspect/material_model/equation_of_state/multicomponent_incompressible.h.bak new file mode 100644 index 00000000000..793c509b218 --- /dev/null +++ b/include/aspect/material_model/equation_of_state/multicomponent_incompressible.h.bak @@ -0,0 +1,127 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_equation_of_state_multicomponent_incompressible_h +#define _aspect_material_model_equation_of_state_multicomponent_incompressible_h + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace EquationOfState + { + using namespace dealii; + + /** + * An incompressible equation of state that is intended for use with multiple compositional + * fields and potentially phases. For each material property, the user supplies a comma + * delimited list of length N+P+1, where N is the number of compositional fields used in + * the computation, P is the total number of phase transitions. + * The first entry corresponds to the "background" (which is also why there are N+P+1 entries). + * + * If a single value is given, then all the compositional fields and phases are given + * that value. Other lengths of lists are not allowed. For a given + * compositional field and phase the material parameters are treated as constant, + * except density, which varies linearly with temperature according to the equation: + * + * $\rho(p,T,\mathfrak c) = \left(1-\alpha_i (T-T_0)\right) \rho_0(\mathfrak c_i).$ + * + * There is no pressure-dependence of the density. + */ + template + class MulticomponentIncompressible : public ::aspect::SimulatorAccess + { + public: + /** + * A function that computes the output of the equation of state @p out + * for all compositions and phases, given the inputs in @p in and an + * index input_index that determines which entry of the vector of inputs is used. + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + const unsigned int input_index, + MaterialModel::EquationOfStateOutputs &out) const; + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const; + + /** + * Declare the parameters this class takes through input files. + * The optional parameter @p default_thermal_expansion determines + * the default value of the thermal expansivity used in the + * equation of state. + */ + static + void + declare_parameters (ParameterHandler &prm, + const double default_thermal_expansion = 3.5e-5); + + /** + * Read the parameters this class declares from the parameter file. + * If @p expected_n_phases_per_composition points to a vector of + * unsigned integers this is considered the number of phases + * for each compositional field and will be checked against the parsed + * parameters. + */ + void + parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition = nullptr); + + private: + /** + * Vector of reference densities $\rho_0$ with one entry per composition and phase plus one + * for the background field. + */ + std::vector densities; + + /** + * The reference temperature $T_0$ used in the computation of the density. + * All components use the same reference temperature. + */ + double reference_T; + + /** + * Vector of thermal expansivities with one entry per composition and phase plus one + * for the background field. + */ + std::vector thermal_expansivities; + + /** + * Vector of specific heat capacities with one entry per composition and phase plus one + * for the background field. + */ + std::vector specific_heats; + }; + } + } +} + +#endif diff --git a/include/aspect/material_model/equation_of_state/thermodynamic_table_lookup.h.bak b/include/aspect/material_model/equation_of_state/thermodynamic_table_lookup.h.bak new file mode 100644 index 00000000000..2e798906904 --- /dev/null +++ b/include/aspect/material_model/equation_of_state/thermodynamic_table_lookup.h.bak @@ -0,0 +1,236 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_equation_of_state_thermodynamic_table_lookup_h +#define _aspect_material_model_equation_of_state_thermodynamic_table_lookup_h + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace EquationOfState + { + using namespace dealii; + + /** + * An equation of state class that reads thermodynamic properties + * from pressure-temperature tables in input files. These input files + * can be created using codes such as Perple_X or HeFESTo. + */ + template + class ThermodynamicTableLookup : public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. Loads the material data and sets up + * pointers. + */ + void + initialize (); + + /** + * Returns the number of lookups + */ + virtual unsigned int number_of_lookups() const; + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const; + + /** + * Function to compute the thermodynamic properties in @p out given the + * inputs in @p in over all evaluation points. + * This function also fills the mass_fraction and volume_fraction vectors. + */ + void + evaluate(const MaterialModel::MaterialModelInputs &in, + std::vector> &eos_outputs) const; + + /** + * Function to fill the seismic velocity and phase volume additional outputs + */ + void + fill_additional_outputs(const MaterialModel::MaterialModelInputs &in, + const std::vector> &volume_fractions, + MaterialModel::MaterialModelOutputs &out) const; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm); + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const; + + const MaterialModel::MaterialUtilities::Lookup::MaterialLookup & + get_material_lookup (unsigned int lookup_index) const; + + + private: + unsigned int n_material_lookups; + bool use_bilinear_interpolation; + bool latent_heat; + + /** + * Information about the location of data files. + */ + std::string data_directory; + std::vector material_file_names; + std::vector derivatives_file_names; + + /** + * The maximum number of substeps over the temperature pressure range + * to calculate the averaged enthalpy gradient over a cell + */ + unsigned int max_latent_heat_substeps; + + /** + * The format of the provided material files. Currently we support + * the Perple_X and HeFESTo data formats. + */ + enum formats + { + perplex, + hefesto + } material_file_format; + + /** + * List of pointers to objects that read and process data we get from + * material data files. There is one pointer/object per lookup file. + */ + std::vector> material_lookup; + + /** + * Vector of strings containing the names of the unique phases in all the material lookups. + */ + std::vector unique_phase_names; + + /** + * Vector of vector of unsigned ints which constitutes mappings + * between lookup phase name vectors and unique_phase_names. + * The element unique_phase_indices[i][j] contains the + * index of phase name j from lookup i as it is found in unique_phase_names. + */ + std::vector> unique_phase_indices; + + /** + * Vector of strings containing the names of the dominant phases in all the material lookups. + * In case the lookup table contains one string with the dominant phase rather than separate + * columns with volume fraction for each phase, this vector will be used instead of the + * unique_phase_names vector above. + */ + std::vector list_of_dominant_phases; + + /** + * Each lookup table reads in their own dominant phases and assigns indices based + * on all phases in that particular lookup. Since a model can have more than one + * lookup, it might have more phases than present in each lookup. We want to output + * unique/consistent indices for each phase, so we have to convert the indices of a phase + * in the individual lookup to the index in the global list of phases. This vector + * of vectors of unsigned int stores the global index for each lookup (so there are + * as many inner vectors as lookups, and each one stores the indices for an individual + * lookup, to be filled in the initialize function). + * + * In case the lookup table contains one string with the dominant phase rather than separate + * columns with volume fraction for each phase, this vector will be used instead of the + * unique_phase_indices vector above. + */ + std::vector> global_index_of_lookup_phase; + + /** + * Compute the specific heat and thermal expansivity using the pressure + * and temperature derivatives of the specific enthalpy. + * This evaluation incorporates the effects of latent heat production. + */ + void evaluate_thermal_enthalpy_derivatives(const MaterialModel::MaterialModelInputs &in, + std::vector> &eos_outputs) const; + + /** + * Returns the cell-wise averaged enthalpy derivatives for the evaluate + * function and postprocessors. The function returns two pairs, the + * first one represents the temperature derivative, the second one the + * pressure derivative. The first member of each pair is the derivative, + * the second one the number of vertex combinations the function could + * use to compute the derivative. The second member is useful to handle + * the case no suitable combination of vertices could be found (e.g. + * if the temperature and pressure on all vertices of the current + * cell is identical. + */ + std::array,2> + enthalpy_derivatives (const typename Interface::MaterialModelInputs &in) const; + + void fill_seismic_velocities (const MaterialModel::MaterialModelInputs &in, + const std::vector &composite_densities, + const std::vector> &volume_fractions, + SeismicAdditionalOutputs *seismic_out) const; + + /** + * This function uses the MaterialModelInputs &in to fill the output_values + * of the phase_volume_fractions_out output object with the volume + * fractions of each of the unique phases at each of the evaluation points. + * These volume fractions are obtained from the Perple_X- or HeFESTo-derived + * pressure-temperature lookup tables. + * The filled output_values object is a vector of vector; + * the outer vector is expected to have a size that equals the number + * of unique phases, the inner vector is expected to have a size that + * equals the number of evaluation points. + */ + void fill_phase_volume_fractions (const MaterialModel::MaterialModelInputs &in, + const std::vector> &volume_fractions, + NamedAdditionalMaterialOutputs *phase_volume_fractions_out) const; + + /** + * This function uses the MaterialModelInputs &in to fill the output_values + * of the dominant_phases_out output object with the index of the + * dominant phase at each of the evaluation points. + * The phases are obtained from the Perple_X- or HeFESTo-derived + * pressure-temperature lookup tables. + * The filled output_values object is a vector of vector; + * the outer vector is expected to have a size of 1, the inner vector is + * expected to have a size that equals the number of evaluation points. + */ + void fill_dominant_phases (const MaterialModel::MaterialModelInputs &in, + const std::vector> &volume_fractions, + PhaseOutputs &dominant_phases_out) const; + }; + } + } +} + +#endif diff --git a/include/aspect/material_model/grain_size.h.bak b/include/aspect/material_model/grain_size.h.bak new file mode 100644 index 00000000000..6aed6159ddc --- /dev/null +++ b/include/aspect/material_model/grain_size.h.bak @@ -0,0 +1,490 @@ +/* + Copyright (C) 2014 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_model_grain_size_h +#define _aspect_model_grain_size_h + +#include +#include +#include +#include + +#include +#include + +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * Additional output fields for the dislocation viscosity parameters + * to be added to the MaterialModel::MaterialModelOutputs structure + * and filled in the MaterialModel::GrainSize::evaluate() function. + */ + template + class DislocationViscosityOutputs : public NamedAdditionalMaterialOutputs + { + public: + DislocationViscosityOutputs(const unsigned int n_points); + + std::vector get_nth_output(const unsigned int idx) const override; + + /** + * Dislocation viscosities at the evaluation points passed to + * the instance of MaterialModel::Interface::evaluate() that fills + * the current object. + */ + std::vector dislocation_viscosities; + + /** + * Diffusion viscosities at the evaluation points passed to + * the instance of MaterialModel::Interface::evaluate() that fills + * the current object. + */ + std::vector diffusion_viscosities; + }; + + + + /** + * A material model that relies on compositional fields that stand for + * average grain sizes of a mineral phase and source terms for them that + * determine the grain size evolution in dependence of the strain rate, + * temperature, phase transitions, and the creep regime. + * This material model only works if a compositional field + * named 'grain_size' is present. In the diffusion + * creep regime, the viscosity depends on this grain size. We use the grain + * size evolution laws described in Behn et al., 2009. Implications of grain + * size evolution on the seismic structure of the oceanic upper mantle, Earth + * Planet. Sci. Letters, 282, 178–189. Other material parameters are either + * prescribed similar to the 'simple' material model, or read from data files + * that were generated by the Perplex or Hefesto software. The material model + * is described in more detail in Dannberg, J., Z. Eilon, U. Faul, + * R. Gassmöller, P. Moulik, and R. Myhill (2017), The importance of + * grain size to mantle dynamics and seismological observations, + * Geochem. Geophys. Geosyst., 18, 3034–3061, doi:10.1002/2017GC006944., + * which is the canonical reference for this material model. + * + * @ingroup MaterialModels + */ + template + class GrainSize : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. Loads the material data and sets up + * pointers. + */ + void + initialize () override; + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const override; + + void evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + /** + * @} + */ + + /** + * Returns the enthalpy as calculated by HeFESTo. + */ + double enthalpy (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + /** + * Returns the cell-wise averaged enthalpy derivatives for the evaluate + * function and postprocessors. The function returns two pairs, the + * first one represents the temperature derivative, the second one the + * pressure derivative. The first member of each pair is the derivative, + * the second one the number of vertex combinations the function could + * use to compute the derivative. The second member is useful to handle + * the case no suitable combination of vertices could be found (e.g. + * if the temperature and pressure on all vertices of the current + * cell is identical. + */ + std::array,2> + enthalpy_derivative (const typename Interface::MaterialModelInputs &in) const; + + protected: + double reference_rho; + double reference_T; + double eta; + double thermal_alpha; + double reference_specific_heat; + + /** + * The constant compressibility. + */ + double reference_compressibility; + + /** + * The thermal conductivity. + */ + double k_value; + + /** + * The index of the compositional field that represents the grain size. + */ + unsigned int grain_size_index; + + /** + * Parameters controlling the grain size evolution. + */ + std::vector grain_growth_activation_energy; + std::vector grain_growth_activation_volume; + std::vector grain_growth_rate_constant; + std::vector grain_growth_exponent; + double minimum_grain_size; + std::vector reciprocal_required_strain; + std::vector recrystallized_grain_size; + + /** + * Parameters controlling the dynamic grain recrystallization. + */ + std::vector grain_boundary_energy; + std::vector boundary_area_change_work_fraction; + std::vector geometric_constant; + + /** + * A struct that contains information about which + * formulation of grain size evolution should be used. + */ + struct Formulation + { + /** + * This enum lists available options that + * determine the equations being used for grain size evolution. + * + * We currently support three approaches: + * + * 'paleowattmeter': + * Austin, N. J., & Evans, B. (2007). Paleowattmeters: A scaling + * relation for dynamically recrystallized grain size. Geology, 354), 343-346.). + * + * 'paleopiezometer': + * Hall, C. E., Parmentier, E. M. (2003). Influence of grain size + * evolution on convective instability. Geochemistry, Geophysics, + * Geosystems, 4(3). + * + * 'pinned_grain_damage': + * Mulyukova, E., & Bercovici, D. (2018). Collapse of passive margins + * by lithospheric damage and plunging grain size. Earth and Planetary + * Science Letters, 484, 341-352. + */ + enum Kind + { + paleowattmeter, + paleopiezometer, + pinned_grain_damage + }; + + /** + * This function translates an input string into the + * available enum options. + */ + static + Kind + parse(const std::string &input) + { + if (input == "paleowattmeter") + return Formulation::paleowattmeter; + else if (input == "paleopiezometer") + return Formulation::paleopiezometer; + else if (input == "pinned grain damage") + return Formulation::pinned_grain_damage; + else + AssertThrow(false, ExcNotImplemented()); + + return Formulation::Kind(); + } + }; + + /** + * A variable that records the formulation of how to evolve grain size. + * See the type of this variable for a description of available options. + */ + typename Formulation::Kind grain_size_evolution_formulation; + + /** + * This function returns the fraction of shear heating energy partitioned + * into grain damage using the implementation by Mulyukova and Bercovici (2018) + * Collapse of passive margins by lithospheric damage + * and plunging grain size. Earth and Planetary Science Letters, 484, 341-352. + */ + double compute_partitioning_fraction (const double temperature) const; + + /** + * Parameters controlling the partitioning of energy + * into grain damage in the pinned state. + */ + double grain_size_reduction_work_fraction_exponent; + double minimum_grain_size_reduction_work_fraction; + double maximum_grain_size_reduction_work_fraction; + double temperature_minimum_partitioning_power; + double temperature_maximum_partitioning_power; + + /** + * Functions and parameters controlling conversion from interface roughness to grain size, + * used in pinned state formulation of grain damage. This conversion depends on the + * proportion of the two mineral phases. + * + * A detailed description of this approach can be found in Appendix H.1, in Equation (8) in + * the main manuscript, and in equation (F.28) of Bercovici, David, and Yanick Ricard (2012). + * Mechanisms for the generation of plate tectonics by two-phase grain-damage + * and pinning. Physics of the Earth and Planetary Interiors 202 (2012): 27-55. + */ + double phase_distribution; + + /** + * The factor used to convert roughness into the equivalent mean grain + * size for a given volume fraction of a mineral in the two-phase damage model. + */ + double roughness_to_grain_size; + + /** + * Parameters controlling the viscosity. + */ + double dislocation_viscosity_iteration_threshold; + unsigned int dislocation_viscosity_iteration_number; + std::vector dislocation_creep_exponent; + std::vector dislocation_activation_energy; + std::vector dislocation_activation_volume; + std::vector dislocation_creep_prefactor; + std::vector diffusion_creep_exponent; + std::vector diffusion_activation_energy; + std::vector diffusion_activation_volume; + std::vector diffusion_creep_prefactor; + std::vector diffusion_creep_grain_size_exponent; + + /** + * Because of the nonlinear nature of this material model many + * parameters need to be kept within bounds to ensure stability of the + * solution. These bounds can be adjusted as input parameters. + */ + double max_temperature_dependence_of_eta; + double min_eta; + double max_eta; + double min_specific_heat; + double max_specific_heat; + double min_thermal_expansivity; + double max_thermal_expansivity; + unsigned int max_latent_heat_substeps; + double min_grain_size; + + double diffusion_viscosity (const double temperature, + const double adiabatic_temperature, + const double adiabatic_pressure, + const double grain_size, + const double second_strain_rate_invariant, + const unsigned int phase_index) const; + + /** + * This function calculates the dislocation viscosity. For this purpose + * we need the dislocation component of the strain rate, which we can + * only compute by knowing the dislocation viscosity. Therefore, we + * iteratively solve for the dislocation viscosity and update the + * dislocation strain rate in each iteration using the new value + * obtained for the dislocation viscosity. The iteration is started + * with a dislocation viscosity calculated for the whole strain rate + * unless a guess for the viscosity is provided, which can reduce the + * number of iterations significantly. + */ + double dislocation_viscosity (const double temperature, + const double adiabatic_temperature, + const double adiabatic_pressure, + const SymmetricTensor<2,dim> &strain_rate, + const unsigned int phase_index, + const double diffusion_viscosity, + const double viscosity_guess = 0) const; + + double density (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + double compressibility (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + double specific_heat (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + double thermal_expansion_coefficient (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + /** + * Returns the p-wave velocity as calculated by HeFESTo. + */ + double seismic_Vp (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + /** + * Returns the s-wave velocity as calculated by HeFESTo. + */ + double seismic_Vs (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + /** + * Rate of grain size growth (Ostwald ripening) or reduction + * (due to dynamic recrystallization and phase transformations) + * in dependence on temperature, pressure, strain rate, mineral + * phase and creep regime. + * We use the grain size growth laws as for example described + * in Behn, M. D., Hirth, G., & Elsenbeck, J. R. (2009). Implications + * of grain size evolution on the seismic structure of the oceanic + * upper mantle. Earth and Planetary Science Letters, 282(1), 178-189. + * + * For the rate of grain size reduction due to dynamic crystallization + * there is the choice between the paleowattmeter (Austins and + * Evans, 2007) and the paleopiezometer (Hall and Parmentier, 2003) + * as described in the parameter use_paleowattmeter. + */ + std::vector> + grain_size_change (const typename Interface::MaterialModelInputs &in, + const std::vector &adiabatic_pressure, + const std::vector &phase_indices) const; + + /** + * Function that returns the phase for a given + * temperature, depth, pressure, and density gradient + * (which are all contained in the @p in argument). + * Because the function returns just the dominant + * phase, phase transitions are discrete in this + * material model (they have a zero width). + */ + unsigned int + get_phase_index (const MaterialUtilities::PhaseFunctionInputs &in) const; + + + /** + * Number of phase transitions for the one chemical composition used in this model. + */ + unsigned int n_phase_transitions; + + /** + * Object that handles phase transitions. + * Allows it to compute the phase function for each individual phase + * transition in the model, given the temperature, pressure, depth, + * and density gradient. + */ + MaterialUtilities::PhaseFunction phase_function; + + + /** + * The following variables are properties of the material files + * we read in. + */ + std::string datadirectory; + std::vector material_file_names; + std::vector derivatives_file_names; + unsigned int n_material_data; + bool use_table_properties; + bool use_enthalpy; + bool use_bilinear_interpolation; + + + /** + * The format of the provided material files. Currently we support + * the PERPLEX and HeFESTo data formats. + */ + enum formats + { + perplex, + hefesto + } material_file_format; + + /** + * List of pointers to objects that read and process data we get from + * material data files. There is one pointer/object per compositional + * field provided. + */ + std::vector> material_lookup; + + /** + * We cache the evaluators that are necessary to evaluate the temperature + * and pressure at the vertices of the current cell. + * By caching the evaluators, we can avoid recreating them + * every time we need them. + */ + mutable std::unique_ptr> temperature_evaluator; + mutable std::unique_ptr> pressure_evaluator; + + private: + /* + * Object for computing plastic stresses, viscosities, and additional outputs, + * as well as an object for the required input parameters. + */ + bool enable_drucker_prager_rheology; + bool use_adiabatic_pressure_for_yielding; + Rheology::DruckerPrager drucker_prager_plasticity; + Rheology::DruckerPragerParameters drucker_prager_parameters; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/interface.h.bak b/include/aspect/material_model/interface.h.bak new file mode 100644 index 00000000000..34b97c11bbd --- /dev/null +++ b/include/aspect/material_model/interface.h.bak @@ -0,0 +1,1534 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_interface_h +#define _aspect_material_model_interface_h + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + template + struct Introspection; + + + /** + * A namespace in which we define everything that has to do with modeling + * convecting material, including descriptions of material parameters such + * as viscosities, densities, etc. + * + * @ingroup MaterialModels + */ + namespace MaterialModel + { + using namespace dealii; + + /** + * A namespace whose enum members are used in querying the nonlinear + * dependence of physical parameters on other solution variables. + */ + namespace NonlinearDependence + { + /** + * + * An enum whose members are used in querying the nonlinear dependence + * of physical parameters on other solution variables. + * + * The values of this enum are used in the + * NonlinearDependence::model_dependence, queried by get_model_dependence() + * to see if a coefficient like the viscosity, depends on the + * temperature, pressure, strain rate, or compositional field value. + * Because the values of the enum are chosen so that they represent + * single bits in an integer, the result here is a number that can be + * represented in base-2 as 101 (the number 100=4 for the strain rate and + * 001=1 for the temperature). + * + * To query nonlinear dependence of a coefficient on any other variable, + * you can use + * @code + * material_model.get_model_dependence(); + * @endcode + * and compare the result to NonlinearDependence::Dependence::Variable. + */ + enum Dependence + { + uninitialized = 0, + + none = 1, + temperature = 2, + pressure = 4, + strain_rate = 8, + compositional_fields = 16, + + any_variable = temperature | pressure | strain_rate | compositional_fields + }; + + + /** + * Provide an operator that or's two Dependence variables. + */ + inline Dependence operator | (const Dependence d1, + const Dependence d2) + { + return Dependence(static_cast(d1) | static_cast(d2)); + } + + inline Dependence operator |= (Dependence &d1, + const Dependence d2) + { + d1 = (d1 | d2); + return d1; + } + + /** + * A structure that, for every output variable of a material model, + * describes which input variable it depends on. + */ + struct ModelDependence + { + /** + * A field that describes which input variable the viscosity + * of a material model depends on. + */ + Dependence viscosity; + + /** + * A field that describes which input variable the density + * of a material model depends on. + */ + Dependence density; + + /** + * A field that describes which input variable the compressibility + * of a material model depends on. + */ + Dependence compressibility; + + /** + * A field that describes which input variable the specific heat + * of a material model depends on. + */ + Dependence specific_heat; + + /** + * A field that describes which input variable the thermal conductivity + * of a material model depends on. + */ + Dependence thermal_conductivity; + + /** + * Default constructor. Sets all dependencies to invalid values in + * order to ensure that material models really correctly specify + * which input variables their output variables depend on. + */ + ModelDependence (); + }; + + /** + * Return whether the given argument @p dependence identifies a single + * variable (e.g., the pressure, the temperature, etc) or a combination + * of variables. Technically, this corresponds to the question of + * whether there is exactly one bit set in the argument. + * + * @return true if yes, false otherwise. + */ + bool + identifies_single_variable(const Dependence dependence); + } + + /** + * A namespace whose enum members are used in querying which material + * properties should be computed. + */ + namespace MaterialProperties + { + /** + * An enum whose members identify material model output + * properties. + * + * Because the values of the enum are chosen so that they represent + * single bits in an integer, the result here is a number that can be + * represented in base-2 as 110 (the number 100=4 for the density and + * 010=2 for the viscosity). + */ + enum Property + { + uninitialized = 0, + + none = 1, + viscosity = 2, + density = 4, + thermal_expansion_coefficient = 8, + specific_heat = 16, + thermal_conductivity = 32, + compressibility = 64, + entropy_derivative_pressure = 128, + entropy_derivative_temperature = 256, + reaction_terms = 512, + reaction_rates = 1024, + additional_outputs = 2048, + + equation_of_state_properties = density | + thermal_expansion_coefficient | + specific_heat | + compressibility | + entropy_derivative_pressure | + entropy_derivative_temperature, + all_properties = equation_of_state_properties | + viscosity | + thermal_conductivity | + reaction_terms | + reaction_rates | + additional_outputs + }; + + /** + * Provide an operator that or's two Property variables. This allows to + * combine more than one property in a single variable. + */ + inline Property operator | (const Property d1, + const Property d2) + { + return Property(static_cast(d1) | static_cast(d2)); + } + + inline Property operator |= (Property &d1, + const Property d2) + { + return (d1 | d2); + } + } + + + // Forward declaration: + template + class AdditionalMaterialInputs; + + /** + * A data structure with all inputs for the + * MaterialModel::Interface::evaluate() method. The vectors all have the + * same length and refer to different evaluation points (given in + * #position). + */ + template + class MaterialModelInputs + { + public: + /** + * Constructor. Initialize the various arrays of this structure with the + * given number of quadrature points and (finite element) components. + * + * @param n_points The number of quadrature points for which input + * quantities will be provided. + * @param n_comp The number of vector quantities (in the order in which + * the Introspection class reports them) for which input will be + * provided. + */ + MaterialModelInputs(const unsigned int n_points, + const unsigned int n_comp); + + /** + * Constructor. Initialize the arrays of the structure with the number + * of points in the `input_data` structure, and fills them appropriately. + * + * @param input_data The data used to populate the material model input quantities. + * @param introspection A reference to the simulator introspection object. + * @param compute_strain_rate If set to `true`, then the object that + * is currently created will also store the strain rates at all evaluation + * points. This is an expensive operation. If set to `false`, then the + * `strain_rate` array is going to be empty, and strain rates are not + * evaluated. As a consequence, strain rates are then also not + * available to functions that take this MaterialModelInputs + * object as input, for example to compute strain rate-dependent + * viscosities. + */ + MaterialModelInputs(const DataPostprocessorInputs::Vector &input_data, + const Introspection &introspection, + const bool compute_strain_rate = true); + + + /** + * Constructor. Initializes the various arrays of this + * structure with the FEValues and introspection objects and + * the solution_vector. This constructor calls the function + * reinit to populate the newly created arrays. + * + * @param fe_values An FEValuesBase object used to evaluate the finite elements. + * @param cell The currently active cell for the fe_values object. + * @param introspection A reference to the simulator introspection object. + * @param solution_vector The finite element vector from which to construct the inputs. + * @param compute_strain_rate If set to `true`, then the object that + * is currently created will also store the strain rates at all evaluation + * points. This is an expensive operation. If set to `false`, then the + * `strain_rate` array is going to be empty, and strain rates are not + * evaluated. As a consequence, strain rates are then also not + * available to functions that take this MaterialModelInputs + * object as input, for example to compute strain rate-dependent + * viscosities. + */ + MaterialModelInputs(const FEValuesBase &fe_values, + const typename DoFHandler::active_cell_iterator &cell, + const Introspection &introspection, + const LinearAlgebra::BlockVector &solution_vector, + const bool compute_strain_rate = true); + + /** + * Copy constructor. This constructor copies all data members of the + * source object except for the additional input data (of type + * AdditionalMaterialInputs) pointers, stored in the + * `source.additional_inputs` member variable. + * + * This is because these pointers can not be copied (they + * are unique to the @p source object). Since they can also not + * be recreated without the original code that created these objects + * in the first place, this constructor throws an exception if the + * @p source object had any additional input data objects + * associated with it. + */ + MaterialModelInputs (const MaterialModelInputs &source); + + /** + * Move constructor. This constructor simply moves all members. + */ + MaterialModelInputs (MaterialModelInputs &&) noexcept = default; + + /** + * Copy operator. Copying these objects is expensive and + * consequently prohibited + */ + MaterialModelInputs &operator= (const MaterialModelInputs &source) = delete; + + /** + * Move operator. + */ + MaterialModelInputs &operator= (MaterialModelInputs &&) = default; + + /** + * Function to re-initialize and populate the pre-existing arrays + * created by the constructor MaterialModelInputs. The arguments here + * have the same meaning as in the constructor of this class. + */ + void reinit(const FEValuesBase &fe_values, + const typename DoFHandler::active_cell_iterator &cell, + const Introspection &introspection, + const LinearAlgebra::BlockVector &solution_vector, + const bool compute_strain_rate = true); + + /** + * Function that returns the number of points at which + * the material model is to be evaluated. + */ + unsigned int n_evaluation_points() const; + + /** + * Function that returns if the caller requests an evaluation + * of the handed over @p property. This is optional, because calculating + * some properties can be more expensive than the other material + * model properties and not all are needed for all applications. + */ + bool requests_property(const MaterialProperties::Property &property) const; + + /** + * Vector with global positions where the material has to be evaluated + * in evaluate(). + */ + std::vector> position; + + /** + * Temperature values at the points given in the #position vector. + */ + std::vector temperature; + + /** + * Pressure values at the points given in the #position vector. + */ + std::vector pressure; + + /** + * Pressure gradients at the points given in the #position vector. + * This is important for the heating models. + */ + std::vector> pressure_gradient; + + /** + * Velocity values at the points given in the #position vector. + * This value is mostly important in the case of determining + * whether material crossed a certain region (e.g. a phase boundary). + * The timestep that is needed for this check can be requested from + * SimulatorAccess. + */ + std::vector> velocity; + + /** + * Values of the compositional fields at the points given in the + * #position vector: composition[i][c] is the compositional field c at + * point i. + */ + std::vector> composition; + + /** + * Strain rate at the points given in the #position vector. Only the + * viscosity may depend on these values. This std::vector can be set to + * size 0 if the viscosity is not needed. + * + * @note The strain rate is computed as $\varepsilon(\mathbf u)=\frac 12 + * (\nabla \mathbf u + \nabla \mathbf u^T)$, regardless of whether the + * model is compressible or not. This is relevant since in some other + * contexts, the strain rate in the compressible case is computed as + * $\varepsilon(\mathbf u)=\frac 12 (\nabla \mathbf u + \nabla \mathbf + * u^T) - \frac 13 \nabla \cdot \mathbf u \mathbf 1$. + */ + std::vector> strain_rate; + + /** + * Optional cell object that contains these quadrature + * points. This allows for evaluating properties at the cell vertices + * and interpolating to the quadrature points, or to query the cell for + * material ids, neighbors, or other information that is not available + * solely from the locations. Note that not all calling functions will + * set this cell iterator. In these cases it will be an invalid iterator + * constructed using the default constructor, so make sure that your + * material model either fails + * with a proper error message, or provides an alternative calculation for + * these cases. You can detect this with + * @code + * if (in.current_cell.state() == IteratorState::valid) + * @endcode + */ + typename DoFHandler::active_cell_iterator current_cell; + + /** + * A member variable that stores which properties the material model + * should compute. You can check specific properties using + * the requests_property function and usually do not need to access + * this variable directly. For documentation on the internal storage + * of this variable see the documentation for MaterialProperties::Property. + */ + MaterialProperties::Property requested_properties; + + /** + * Given an additional material model input class as explicitly specified + * template argument, returns a pointer to this additional material model + * input object if it is used in the current simulation. Ownership + * of the pointed-to object remains with the current object. + * + * If the input does not exist, i.e., if there is no additional input + * object of the specified type, then a null pointer is returned. + */ + template + AdditionalInputType *get_additional_input(); + + /** + * A version of the previous function that is used when the object + * being queried is `const`. + */ + template + const AdditionalInputType *get_additional_input() const; + + /** + * Vector of shared pointers to additional material model input + * objects that can be added to MaterialModelInputs. By default, + * no inputs are added. + */ + std::vector>> additional_inputs; + }; + + + // Forward declaration: + template + class AdditionalMaterialOutputs; + + + /** + * A data structure with the output field of the + * MaterialModel::Interface::evaluate() function. The vectors are the + * values at the different positions given by + * MaterialModelInputs::position. + */ + template + class MaterialModelOutputs + { + public: + /** + * Constructor. Initialize the various arrays of this structure with the + * given number of quadrature points and (finite element) components. + * + * @param n_points The number of quadrature points for which input + * quantities will be provided. + * @param n_comp The number of vector quantities (in the order in which + * the Introspection class reports them) for which input will be + * provided. + */ + MaterialModelOutputs (const unsigned int n_points, + const unsigned int n_comp); + + /** + * Copy constructor. This constructor copies all data members of the + * source object except for the additional output data (of type + * AdditionalMaterialOutputs) pointers, stored in the + * `source.additional_outputs` member variable. + * + * This is because these pointers can not be copied (they + * are unique to the @p source object). Since they can also not + * be recreated without the original code that created these objects + * in the first place, this constructor throws an exception if the + * @p source object had any additional output data objects + * associated with it. + */ + MaterialModelOutputs (const MaterialModelOutputs &source); + + /** + * Move constructor. This constructor simply moves all members. + */ + MaterialModelOutputs (MaterialModelOutputs &&) noexcept = default; + + /** + * Copy operator. Copying these objects is expensive, and consequently + * prohibited. + */ + MaterialModelOutputs &operator= (const MaterialModelOutputs &source) = delete; + + /** + * Move operator. + */ + MaterialModelOutputs &operator= (MaterialModelOutputs &&) noexcept = default; + + /** + * Function that returns the number of points at which + * the material model is to be evaluated. + */ + unsigned int n_evaluation_points() const; + + /** + * Viscosity $\eta$ values at the given positions. + */ + std::vector viscosities; + + /** + * Density values at the given positions. + */ + std::vector densities; + + /** + * Thermal expansion coefficients at the given positions. It is defined + * as $\alpha = - \frac{1}{\rho} \frac{\partial\rho}{\partial T}$ + */ + std::vector thermal_expansion_coefficients; + + /** + * Specific heat at the given positions. + */ + std::vector specific_heat; + + /** + * Thermal conductivity at the given positions. + */ + std::vector thermal_conductivities; + + /** + * Compressibility at the given positions. The compressibility is defined + * as $\kappa = \frac{1}{\rho} \frac{\partial\rho}{\partial p}$. + */ + std::vector compressibilities; + + /** + * The product of the change of entropy $\Delta S$ at a phase transition + * and the derivative of the phase function $X=X(p,T,\mathfrak c,\mathbf + * x)$ with regard to pressure at the given positions. + */ + std::vector entropy_derivative_pressure; + + /** + * The product of (minus) the change of entropy $-\Delta S$ at a phase + * transition and the derivative of the phase function + * $X=X(p,T,\mathfrak c,\mathbf x)$ with regard to temperature at the + * given positions. + */ + std::vector entropy_derivative_temperature; + + /** + * Change in composition due to chemical reactions at the given + * positions. The term reaction_terms[i][c] is the change in + * compositional field c at point i. + * + * The mental model behind prescribing actual changes in composition + * rather than reaction rates is that we assume that there is always an + * equilibrium between the compositional fields (because the time scale + * of reactions is normally much shorter than that of convection), so + * the quantity returned by this function is an actual change in the + * amount of material, which is added to or subtracted from the current + * value of the compositional field, and NOT a reaction rate. The idea + * is, that in dependence of temperature, pressure, position and the + * compositional fields themselves an equilibrium can be calculated, and + * the difference between the current value and the equilibrium can be + * added to the respective compositional field. + * + * For mass conservation it should ALWAYS be checked that what is + * subtracted from one field is added to another field (and the other + * way round) and that one never subtracts more than the actual value of + * a field (so it does not get negative). + * + * This function has a default implementation that sets the reaction + * term to zero (assuming no reactions). + * + * @note In cases where one has slow chemical reactions (or cases where + * compositional fields are used to track quantities different than + * actual compositions, for example accumulated strains in damage + * models), models are formulated as differential equations with right + * hand sides, not as instantaneous equations. In such cases, the + * reaction terms (i.e., the incremental additions to the previous + * state) are usually of the form reaction rate times time step size. To + * implement something like this, derive your material model from + * SimulatorAccess so you can query the time step used by the simulator + * in order to compute the reaction increment. + */ + std::vector> reaction_terms; + + /** + * Vector of shared pointers to additional material model output + * objects that can then be added to MaterialModelOutputs. By default, + * no outputs are added. + */ + std::vector>> additional_outputs; + + /** + * Given an additional material model output class as explicitly specified + * template argument, returns a pointer to this additional material model + * output object if it is used in the current simulation. + * The output can then be filled in the MaterialModels::Interface::evaluate() + * function. If the output does not exist, a null pointer is returned. + */ + template + AdditionalOutputType *get_additional_output(); + + /** + * Constant version of get_additional_output() returning a const pointer. + */ + template + const AdditionalOutputType *get_additional_output() const; + + /** + * Steal the additional outputs from @p other. The destination (@p + * this), is expected to currently have no additional outputs. + */ + void move_additional_outputs_from(MaterialModelOutputs &other); + }; + + + + /** + * A namespace in which we define how material model outputs should be + * averaged on each cell. + * + * Material models compute output quantities such as the viscosity, the + * density, etc, based on pressures, temperatures, composition, and + * location at every quadrature point. For some models, these values vary + * drastically from quadrature point to quadrature point, and this creates + * difficulties both for the stability of the discretization as well as + * for the linear solvers. Some of this can be ameliorated by averaging + * values on every cell, although this of course reduces the ideal + * convergence order. This namespace defines the means to achieve such + * averaging. + */ + namespace MaterialAveraging + { + /** + * An enum to define what kind of averaging operations are implemented. + * These are: + * + * - No averaging, i.e., leave the values as they were provided by the + * material model. + * + * - Arithmetic averaging: Set the values of each output quantity at + * every quadrature point to \f[ \bar x = \frac 1Q \sum_{q=1}^Q x_q \f] + * where $x_q$ are the values at the $Q$ quadrature points. + * + * - Harmonic averaging: Set the values of each output quantity at every + * quadrature point to \f[ \bar x = \left(\frac 1Q \sum_{q=1}^Q + * \frac{1}{x_q}\right)^{-1} \f] where $x_q$ are the values at the $Q$ + * quadrature points. + * + * - Geometric averaging: Set the values of each output quantity at + * every quadrature point to \f[ \bar x = \left(\prod_{q=1}^Q + * x_q\right)^{1/Q} \f] where $x_q$ are the values at the $Q$ quadrature + * points. + * + * - Pick largest: Set the values of each output quantity at every + * quadrature point to \f[ \bar x = \max_{1\le q\le Q} x_q \f] where + * $x_q$ are the values at the $Q$ quadrature points. + * + * - Project to $Q_1$: This operation takes the values at the quadrature + * points and computes the best bi- or trilinear approximation for them. + * In other words, it projects the values into the $Q_1$ finite element + * space. It then re-evaluate this projection at the quadrature points. + * + * - Log average: Set the values of each output quantity at every + * quadrature point to \f[ \bar x = {10}^{\frac 1Q \sum_{q=1}^Q \log_{10} x_q} \f] + * where $x_q$ are the values at the $Q$ quadrature points. + * + * - Harmonic average only viscosity, Geometric average only viscosity + * and project to Q1 only viscosity: Like harmonic averaging, geometric + * averaging and project to Q1, but only applied to the viscosity. + */ + enum AveragingOperation + { + none, + arithmetic_average, + harmonic_average, + geometric_average, + pick_largest, + project_to_Q1, + log_average, + harmonic_average_only_viscosity, + geometric_average_only_viscosity, + project_to_Q1_only_viscosity, + default_averaging + }; + + + /** + * Return a string that represents the various averaging options laid + * out above and that can be used in the declaration of an input + * parameter. The options are separated by "|" so that they can be used + * in a dealii::Patterns::Selection argument. + */ + std::string get_averaging_operation_names (); + + /** + * Parse a string representing one of the options returned by + * get_averaging_operation_names(), and return the corresponding + * AveragingOperation value. + */ + AveragingOperation parse_averaging_operation_name (const std::string &s); + + /** + * Given the averaging @p operation, a description of where the + * quadrature points are located on the given cell, and a mapping, + * perform this operation on all elements of the @p values structure. + */ + template + void average (const AveragingOperation operation, + const typename DoFHandler::active_cell_iterator &cell, + const Quadrature &quadrature_formula, + const Mapping &mapping, + const MaterialProperties::Property &requested_properties, + MaterialModelOutputs &values_out); + + /** + * Do the requested averaging operation for one array. The + * projection matrix argument is only used if the operation + * chosen is project_to_Q1 + */ + void average_property (const AveragingOperation operation, + const FullMatrix &projection_matrix, + const FullMatrix &expansion_matrix, + std::vector &values_out); + } + + + /** + * Some material and heating models need more than just the basic material + * model inputs defined in the MaterialModel::MaterialModelInputs + * class. These additions are either for more complicated physics + * than the basic flow model usually solved by ASPECT (for example + * to support the melt migration functionality), or other derived + * quantities. + * + * Rather than litter the MaterialModelInputs class with additional + * fields that are not universally used, we use a mechanism by + * which MaterialModelInputs can store a set of pointers to + * "additional" input objects that store information such as + * mentioned above. These pointers are all to objects whose types + * are derived from the current class. + * + * The format of the additional quantities defined in derived classes + * should be the same as for MaterialModel::MaterialModelInputs. + */ + template + class AdditionalMaterialInputs + { + public: + /** + * Destructor. This destructor is made `virtual` to ensure that + * derived classes can be accessed via a pointer-to-base-class. + */ + virtual ~AdditionalMaterialInputs() = default; + + /** + * Fill the additional inputs. Each additional input + * has to implement their own version of this function. + */ + virtual void + fill (const LinearAlgebra::BlockVector &solution, + const FEValuesBase &fe_values, + const Introspection &introspection) = 0; + }; + + + /** + * Some material models can compute more than just the basic material + * coefficients defined in the MaterialModel::MaterialModelOutputs + * class. These additions are either for more complicated physics + * than the basic flow model usually solved by ASPECT (for example + * to support the melt migration functionality), or other derived + * quantities that are not coefficients in any of the equations + * ASPECT solves but that may be of interest for visualization + * (for example seismic velocities). + * + * Rather than litter the MaterialModelOutputs class with additional + * fields that are not universally used, we use a mechanism by + * which MaterialModelOutputs can store a set of pointers to + * "additional" output objects that store information such as + * mentioned above. These pointers are all to objects whose types + * are derived from the current class. + * + * If an implementation of the MaterialModel::Interface::evaluate() + * in a class derived from MaterialModel::Interface encounters + * a MaterialModelOutputs object that has these pointers set + * (and if it recognizes the type of the object pointed to), + * it should fill this set of additional output quantities. + * + * The format of the additional quantities defined in derived classes + * should be the same as for MaterialModel::MaterialModelOutputs. + */ + template + class AdditionalMaterialOutputs + { + public: + /** + * Destructor. Made virtual to enable storing pointers to this + * base class. + */ + virtual ~AdditionalMaterialOutputs() = default; + + virtual void average (const MaterialAveraging::AveragingOperation /*operation*/, + const FullMatrix &/*projection_matrix*/, + const FullMatrix &/*expansion_matrix*/) + {} + }; + + + /** + * Some material models can compute things that are not used anywhere + * in the physics modules of ASPECT, but that may be of interest for + * visualization purposes. An example would be a material model that can + * compute seismic velocities -- these are irrelevant to the rest of + * ASPECT, but would be nice to have for postprocessing. + * + * This class is a base class for material models to provide this kind + * of information. It follows the scheme laid out by + * AdditionalMaterialModelOutputs but also provides an interface by which + * consumers of these objects (e.g., the + * Postprocess::Visualization::NamedAdditionalOutputs class) can query the + * names and values material models have put into these additional + * outputs. (Because every material model can decide by itself which -- + * if any -- additional outputs it produces, there are no standard + * names. Consequently, the material models have to describe what + * values and how many values they can produce.) + * + * This class is then this base class for additional named material model outputs + * to be added to the MaterialModel::MaterialModelOutputs structure. + */ + template + class NamedAdditionalMaterialOutputs : public AdditionalMaterialOutputs + { + public: + /** + * Base constructor. + * + * @param output_names A list of names for the additional output variables + * this object will store. The length of the list also indicates + * how many additional output variables objects of derived classes + * will store. + */ + NamedAdditionalMaterialOutputs(const std::vector &output_names); + + /** + * Constructor for case where outputs are stored for a number of points. + * + * @param output_names A list of names for the additional output variables + * this object will store. The length of the list also indicates + * how many additional output variables objects of derived classes + * will store. + * @param n_points The number of points for which to store each of the + * output variables. + */ + NamedAdditionalMaterialOutputs(const std::vector &output_names, + const unsigned int n_points); + + /** + * Destructor. + */ + ~NamedAdditionalMaterialOutputs() override; + + /** + * Return a reference to the vector of names of the additional + * outputs. + */ + const std::vector &get_names() const; + + /** + * Given an index as input argument, return a reference the to vector of + * values of the additional output with that index. + */ + virtual std::vector get_nth_output(const unsigned int idx) const; + + void average (const MaterialAveraging::AveragingOperation /*operation*/, + const FullMatrix &/*projection_matrix*/, + const FullMatrix &/*expansion_matrix*/) override + {} + + + /** + * Values for the outputs at a set of evaluation points + * output_values[i][j] is the value of output i at point j. + */ + std::vector> output_values; + + private: + const std::vector names; + }; + + + /** + * Additional output fields for the seismic velocities to be added to + * the MaterialModel::MaterialModelOutputs structure and filled in the + * MaterialModel::Interface::evaluate() function. + */ + template + class SeismicAdditionalOutputs : public NamedAdditionalMaterialOutputs + { + public: + SeismicAdditionalOutputs(const unsigned int n_points); + + std::vector get_nth_output(const unsigned int idx) const override; + + /** + * Seismic s-wave velocities at the evaluation points passed to + * the instance of MaterialModel::Interface::evaluate() that fills + * the current object. + */ + std::vector vs; + + /** + * Seismic p-wave velocities at the evaluation points passed to + * the instance of MaterialModel::Interface::evaluate() that fills + * the current object. + */ + std::vector vp; + }; + + + /** + * Additional output fields for reaction rates to be added to + * the MaterialModel::MaterialModelOutputs structure and filled in the + * MaterialModel::Interface::evaluate() function. + * + * These reaction rates are only used if the "operator splitting" solver scheme + * option is enabled, which decouples the reactions between compositional + * fields from the advection, so that different time step sizes can be used. + * In this case, the reaction rates are used in addition to (and independent + * from) any reaction_terms that a material model defines, which are assembled + * as usual. + * By default, the reaction rates are initialized with quiet_NaNs, and if + * "operator splitting" is not enabled, these values are not used, and they + * are expected to either remain at that value, or to not be created at all. + * + * In contrast to the reaction_terms, which are actual changes in composition + * rather than reaction rates, and assume equilibrium between the compositional + * fields, the reaction_rates defined here allow for reaction processes that + * happen on shorter time scales than the advection, and disequilibrium reactions. + */ + template + class ReactionRateOutputs : public NamedAdditionalMaterialOutputs + { + public: + ReactionRateOutputs (const unsigned int n_points, + const unsigned int n_comp); + + std::vector get_nth_output(const unsigned int idx) const override; + + /** + * Reaction rates for all compositional fields at the evaluation points + * that are passed to the instance of MaterialModel::Interface::evaluate() + * that fills the current object. + * reaction_rates[q][c] is the reaction rate at the evaluation point q + * for the compositional field with the index c. + */ + std::vector> reaction_rates; + }; + + + + /** + * Additional output fields for the phase with the largest fraction + * to be added to the MaterialModel::MaterialModelOutputs structure + * and filled in the MaterialModel::evaluate() function. + */ + template + class PhaseOutputs : public NamedAdditionalMaterialOutputs + { + public: + PhaseOutputs(const unsigned int n_points); + }; + + + + /** + * Additional output fields for prescribed field outputs to be added to + * the MaterialModel::MaterialModelOutputs structure and filled in the + * MaterialModel::Interface::evaluate() function. + * + * This structure is used if for one of the compositional fields employed + * by a simulation, the advection scheme "prescribed field" is selected. + * (See Parameters::AdvectionFieldMethod for more information.) + * Then, while updating the compositional field, a structure of this + * type is created, given to the material model, and the material model + * outputs will finally be interpolated onto the corresponding + * compositional field. + * + * @note This structure always has as many prescribed field + * outputs as there are compositional fields, even if not all of them + * are using the "prescribed field" method. It is the responsibility + * of the individual material models to fill the correct entries. + */ + template + class PrescribedFieldOutputs : public NamedAdditionalMaterialOutputs + { + public: + PrescribedFieldOutputs (const unsigned int n_points, + const unsigned int n_comp); + + std::vector get_nth_output(const unsigned int idx) const override; + + /** + * Prescribed field outputs for all compositional fields at the evaluation points + * that are passed to the instance of MaterialModel::Interface::evaluate() + * that fills the current object. + * prescribed_field_outputs[q][c] is the prescribed field output at the evaluation point q + * for the compositional field with the index c. + */ + std::vector> prescribed_field_outputs; + }; + + /** + * Additional output fields for prescribed temperature outputs to be added to + * the MaterialModel::MaterialModelOutputs structure and filled in the + * MaterialModel::Interface::evaluate() function. + * + * This structure is used if the temperature field is solved using the + * advection scheme "prescribed field". + * (See Parameters::AdvectionFieldMethod for more information.) + * Then, while updating the temperature field, a structure of this + * type is created, given to the material model, and the material model + * outputs will finally be interpolated onto the + * temperature field. + */ + template + class PrescribedTemperatureOutputs : public NamedAdditionalMaterialOutputs + { + public: + PrescribedTemperatureOutputs (const unsigned int n_points); + + std::vector get_nth_output(const unsigned int idx) const override; + + /** + * Prescribed field outputs for the temperature field at the evaluation points + * that are passed to the instance of MaterialModel::Interface::evaluate() + * that fills the current object. + * prescribed_temperature_outputs[q] is the prescribed field output at the evaluation point q + * for the temperature. + */ + std::vector prescribed_temperature_outputs; + }; + + /** + * A class for additional output fields to be added to the RHS of the + * Stokes system, which can be attached to the + * MaterialModel::MaterialModelOutputs structure and filled in the + * MaterialModel::Interface::evaluate() function. + */ + template + class AdditionalMaterialOutputsStokesRHS: public AdditionalMaterialOutputs + { + public: + AdditionalMaterialOutputsStokesRHS(const unsigned int n_points) + : rhs_u(n_points), rhs_p(n_points), rhs_melt_pc(n_points) + {} + + ~AdditionalMaterialOutputsStokesRHS() override + = default; + + void average (const MaterialAveraging::AveragingOperation /*operation*/, + const FullMatrix &/*projection_matrix*/, + const FullMatrix &/*expansion_matrix*/) override + { + // TODO: not implemented + } + + /** + * Force tensor on the right-hand side for the conservation of + * momentum equation (first part of the Stokes equation) in each + * quadrature point. + */ + std::vector> rhs_u; + + /** + * Force value for the conservation of mass equation (second Stokes + * equation) in each quadrature point. + */ + std::vector rhs_p; + + /** + * Force for the compaction pressure equation (when using melt + * transport) in each quadrature point. + */ + std::vector rhs_melt_pc; + }; + + + + /** + * An AdditionalOutput that allows prescribing a dilation applied to the + * Stokes solution. + * + * This is typically used in a MaterialModel to add dilation when plastic + * failure occurs as motivated by ChoiPeterson2015. If this output + * (denoted by R below) is present and enable_prescribed_dilation==true + * the following terms will be assembled: + * + * 1) $\int - (R,q)$ to the conservation of mass equation, creating + * $-(div u,q) = -(R,q)$. + * 2) $\int - 2.0 / 3.0 * eta * (R, div v)$ to the RHS of the momentum + * equation (if the model is incompressible), otherwise this term is + * already present on the left side. + */ + template + class PrescribedPlasticDilation : public NamedAdditionalMaterialOutputs + { + public: + /** + * Constructor + */ + explicit PrescribedPlasticDilation (const unsigned int n_points); + + /** + * Function for NamedAdditionalMaterialOutputs interface + */ + std::vector get_nth_output(const unsigned int idx) const override; + + /** + * A scalar value per evaluation point that specifies the prescribed dilation + * in that point. + */ + std::vector dilation; + }; + + + + /** + * A class for an elastic force term to be added to the RHS of the + * Stokes system, which can be attached to the + * MaterialModel::MaterialModelOutputs structure and filled in the + * MaterialModel::Interface::evaluate() function. + */ + template + class ElasticOutputs: public AdditionalMaterialOutputs + { + public: + ElasticOutputs(const unsigned int n_points) + : elastic_force(n_points, numbers::signaling_nan>()) + , viscoelastic_strain_rate(n_points, numbers::signaling_nan>()) + {} + + ~ElasticOutputs() override + = default; + + void average (const MaterialAveraging::AveragingOperation operation, + const FullMatrix &/*projection_matrix*/, + const FullMatrix &/*expansion_matrix*/) override + { + AssertThrow(operation == MaterialAveraging::AveragingOperation::none,ExcNotImplemented()); + return; + } + + /** + * Force tensor (elastic terms) on the right-hand side for the conservation of + * momentum equation (first part of the Stokes equation) in each + * quadrature point. + */ + std::vector> elastic_force; + + /** + * Strain rate tensor that includes the contribution of elastic shear, which is + * required by the Newton solver. + */ + std::vector> viscoelastic_strain_rate; + }; + + + + /** + * Additional output fields for the enthalpy change upon melting or + * freezing to be added to the MaterialModel::MaterialModelOutputs + * structure and filled in the MaterialModel::Interface::evaluate() + * function. + * These outputs are needed in heating models that compute the latent + * heat of melting/freezing based on the material properties in the + * material models (which is required for thermodynamically consistent + * models). + */ + template + class EnthalpyOutputs : public AdditionalMaterialOutputs + { + public: + EnthalpyOutputs(const unsigned int n_points) + : enthalpies_of_fusion(n_points, numbers::signaling_nan()) + {} + + virtual ~EnthalpyOutputs() + = default; + + void average (const MaterialAveraging::AveragingOperation operation, + const FullMatrix &/*projection_matrix*/, + const FullMatrix &/*expansion_matrix*/) override + { + AssertThrow(operation == MaterialAveraging::AveragingOperation::none,ExcNotImplemented()); + return; + } + + /** + * Enthalpies of fusion, describing the amount of heat required to + * melt/solidify the material. These values are used when computing + * latent heat effects. + */ + std::vector enthalpies_of_fusion; + }; + + + + /** + * A base class for parameterizations of material models. Classes derived + * from this class will need to implement functions that provide material + * parameters such as the viscosity, density, etc, typically as a function + * of position, temperature and pressure at that location. + * + * Implementing a material model requires you to override evaluate() and fill the output + * argument struct instead of implementing the functions viscosity(), + * density(), etc.. In this case, all other functions are being ignored. + * + * In all cases, model_dependence values, is_compressible() + * need to be implemented. + * + * @ingroup MaterialModels + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * A typedef to import the MaterialModelInputs name into the current + * class. This typedef primarily exists as a backward compatibility + * measure given that the referenced structure used to be a member of + * the current class. + */ + using MaterialModelInputs = MaterialModel::MaterialModelInputs; + + /** + * A typedef to import the MaterialModelOutputs name into the current + * class. This typedef primarily exists as a backward compatibility + * measure given that the referenced structure used to be a member of + * the current class. + */ + using MaterialModelOutputs = MaterialModel::MaterialModelOutputs; + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return a structure that describes how each of the model's + * output variables (such as viscosity, density, etc) depend + * on the input variables pressure, temperature, strain rate, + * and compositional fields. + */ + const NonlinearDependence::ModelDependence & + get_model_dependence () const; + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the + * continuity equation as $\nabla \cdot (\rho \mathbf u)=0$ + * (compressible Stokes) or as $\nabla \cdot \mathbf{u}=0$ + * (incompressible Stokes). + */ + virtual bool is_compressible () const = 0; + /** + * @} + */ + + /** + * Function to compute the material properties in @p out given the + * inputs in @p in. + */ + virtual + void evaluate (const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const = 0; + + /** + * If this material model can produce additional named outputs + * that are derived from NamedAdditionalOutputs, create them in here. + * By default, this does nothing. + */ + virtual + void + create_additional_named_outputs (MaterialModelOutputs &outputs) const; + + + /** + * Fill the additional material model inputs that have been attached + * by the individual heating or material models in the + * create_additional_material_model_inputs function. + * This is done by looping over all material model inputs that have + * been created and calling their respective member functions. + */ + virtual + void + fill_additional_material_model_inputs(MaterialModel::MaterialModelInputs &input, + const LinearAlgebra::BlockVector &solution, + const FEValuesBase &fe_values, + const Introspection &introspection) const; + + protected: + /** + * A structure that describes how each of the model's + * output variables (such as viscosity, density, etc) depend + * on the input variables pressure, temperature, strain rate, + * and compositional fields. + * + * The constructor of this class calls the default + * constructor of this member variable which in turn + * initializes the object to invalid values. Derived classes + * then need to fill it either in their constructor (if they + * already know the correct dependencies at that time) or + * at the end of their parse_parameter() functions where + * they know the correct material parameters they will + * use. + */ + NonlinearDependence::ModelDependence model_dependence; + }; + + /** + * Register a material model so that it can be selected from the parameter + * file. + * + * @param name A string that identifies the material model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this material model wants to read + * from input files. + * @param factory_function A pointer to a function that can create an + * object of this material model. + * + * @ingroup MaterialModels + */ + template + void + register_material_model (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * A function that given the name of a model returns a pointer to an + * object that describes it. Ownership of the pointer is transferred to + * the caller. + * + * The material model object returned is not yet initialized and has not + * read its runtime parameters yet. + * + * @ingroup MaterialModels + */ + template + std::unique_ptr> + create_material_model (const std::string &model_name); + + + /** + * A function that reads the name of a model from the parameter object + * and then returns a pointer to an + * object that describes this model. Ownership of the pointer is transferred to + * the caller. + * + * The material model object returned is not yet initialized and has not + * read its runtime parameters yet. + * + * @ingroup MaterialModels + */ + template + std::unique_ptr> + create_material_model (ParameterHandler &prm); + + + /** + * Return a string that consists of the names of material models that can + * be selected. These names are separated by a vertical line '|' so + * that the string can be an input to the deal.II classes + * Patterns::Selection or Patterns::MultipleSelection. + */ + template + std::string + get_valid_model_names_pattern (); + + + /** + * Declare the runtime parameters of the registered material models. + * + * @ingroup MaterialModels + */ + template + void + declare_parameters (ParameterHandler &prm); + + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + template + void + write_plugin_graph (std::ostream &output_stream); + + + +// --------------------- template function definitions ---------------------------------- + + template + template + AdditionalInputType *MaterialModelInputs::get_additional_input() + { + for (unsigned int i=0; i (additional_inputs[i].get()); + if (result) + return result; + } + return nullptr; + } + + + template + template + const AdditionalInputType *MaterialModelInputs::get_additional_input() const + { + for (unsigned int i=0; i (additional_inputs[i].get()); + if (result) + return result; + } + return nullptr; + } + + + template + template + AdditionalOutputType *MaterialModelOutputs::get_additional_output() + { + for (unsigned int i=0; i (additional_outputs[i].get()); + if (result) + return result; + } + return nullptr; + } + + + template + template + const AdditionalOutputType *MaterialModelOutputs::get_additional_output() const + { + for (unsigned int i=0; i (additional_outputs[i].get()); + if (result) + return result; + } + return nullptr; + } + + + template + void MaterialModelOutputs::move_additional_outputs_from(MaterialModelOutputs &other) + { + Assert(this->additional_outputs.empty(), ExcMessage("Destination of move needs to be empty!")); + this->additional_outputs = std::move(other.additional_outputs); + } + + + /** + * Given a class name, a name, and a description for the parameter file + * for a material model, register it with the functions that can declare + * their parameters and create these objects. + * + * @ingroup MaterialModels + */ +#define ASPECT_REGISTER_MATERIAL_MODEL(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_MATERIAL_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::MaterialModel::register_material_model<2>, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::MaterialModel::register_material_model<3>, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/material_model/latent_heat.h.bak b/include/aspect/material_model/latent_heat.h.bak new file mode 100644 index 00000000000..2646a5bc2e8 --- /dev/null +++ b/include/aspect/material_model/latent_heat.h.bak @@ -0,0 +1,127 @@ +/* + Copyright (C) 2013 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_latent_heat_h +#define _aspect_material_model_latent_heat_h + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that implements a standard approximation of the latent + * heat terms following Christensen \& Yuen, 1986. The change of entropy + * is calculated as $Delta S = \gamma \frac{\Delta\rho}{\rho^2}$ with the + * Clapeyron slope $\gamma$ and the density change $\Delta\rho$ of the + * phase transition being input parameters. This model employs an analytic + * phase function in the form $X=\frac{1}{2} \left( 1 + \tanh \left( \frac{\Delta + * p}{\Delta p_0} \right) \right)$ with $\Delta p = p - p_transition - + * \gamma \left( T - T_transition \right)$ and $\Delta p_0$ being the + * pressure difference over the width of the phase transition (specified + * as input parameter). + * + * @ingroup MaterialModels + */ + template + class LatentHeat : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + + /** + * Evaluate material properties. + */ + void evaluate(const MaterialModelInputs &in, + MaterialModelOutputs &out) const override; + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + private: + double reference_rho; + double reference_T; + double eta; + double composition_viscosity_prefactor; + double thermal_viscosity_exponent; + double thermal_alpha; + double reference_specific_heat; + double reference_compressibility; + double maximum_viscosity; + double minimum_viscosity; + + /** + * The thermal conductivity. + */ + double k_value; + + double compositional_delta_rho; + + // list of depth (or pressure), width and Clapeyron slopes + // for the different phase transitions + std::vector density_jumps; + std::vector transition_phases; + std::vector phase_prefactors; + + MaterialUtilities::PhaseFunction phase_function; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/latent_heat_melt.h.bak b/include/aspect/material_model/latent_heat_melt.h.bak new file mode 100644 index 00000000000..71770705bc7 --- /dev/null +++ b/include/aspect/material_model/latent_heat_melt.h.bak @@ -0,0 +1,205 @@ +/* + Copyright (C) 2013 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_latent_heat_melt_h +#define _aspect_material_model_latent_heat_melt_h + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that implements latent heat of melting for two + * materials: peridotite and pyroxenite. The density and thermal + * expansivity depend on the melt fraction. + * + * @ingroup MaterialModels + */ + template + class LatentHeatMelt : public MaterialModel::Interface, + public MaterialModel::MeltFractionModel, + public ::aspect::SimulatorAccess + { + public: + /** + * @name Physical parameters used in the basic equations + * @{ + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + + void melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const override; + + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + private: + double reference_rho; + double reference_T; + double eta; + double composition_viscosity_prefactor; + double thermal_viscosity_exponent; + double thermal_alpha; + double melt_thermal_alpha; + double reference_specific_heat; + double reference_compressibility; + + /** + * The thermal conductivity. + */ + double k_value; + + double compositional_delta_rho; + + /** + * Parameters for anhydrous melting of peridotite after Katz, 2003 + */ + + // for the solidus temperature + double A1; // °C + double A2; // °C/Pa + double A3; // °C/(Pa^2) + + // for the lherzolite liquidus temperature + double B1; // °C + double B2; // °C/Pa + double B3; // °C/(Pa^2) + + // for the liquidus temperature + double C1; // °C + double C2; // °C/Pa + double C3; // °C/(Pa^2) + + // for the reaction coefficient of pyroxene + double r1; // cpx/melt + double r2; // cpx/melt/GPa + double M_cpx; // mass fraction of pyroxene + + // melt fraction exponent + double beta; + + // entropy change upon melting + double peridotite_melting_entropy_change; + + /** + * Parameters for melting of pyroxenite after Sobolev et al., 2011 + */ + + // for the melting temperature + double D1; // °C + double D2; // °C/Pa + double D3; // °C/(Pa^2) + // for the melt-fraction dependence of productivity + double E1; + double E2; + + // for the maximum melt fraction of pyroxenite + double F_px_max; + + // the relative density of molten material (compared to solid) + double relative_melt_density; + + double pyroxenite_melting_entropy_change; + + /** + * Percentage of material that is molten. Melting model after Katz, + * 2003 (for peridotite) and Sobolev et al., 2011 (for pyroxenite) + */ + virtual + double + melt_fraction (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + virtual + double + peridotite_melt_fraction (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + virtual + double + pyroxenite_melt_fraction (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const; + + double + entropy_derivative ( const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position, + const NonlinearDependence::Dependence dependence) const; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/melt_boukare.h.bak b/include/aspect/material_model/melt_boukare.h.bak new file mode 100644 index 00000000000..145fad241fb --- /dev/null +++ b/include/aspect/material_model/melt_boukare.h.bak @@ -0,0 +1,355 @@ +/* + Copyright (C) 2015 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_melt_boukare_h +#define _aspect_material_model_melt_boukare_h + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * Additional output fields for the melt boukare material model. + */ + template + class BoukareOutputs : public NamedAdditionalMaterialOutputs + { + public: + BoukareOutputs(const unsigned int n_points); + + std::vector get_nth_output(const unsigned int idx) const override; + + /** + * Bulk composition of the material. + */ + std::vector bulk_composition; + std::vector molar_volatiles_in_melt; + }; + + /** + * A material model that implements a simplified version of the melting + * model of Boukare et al. (https://doi.org/10.1002/2015JB011929) for the + * lowermost mantle. The model parameterizes the composition (which includes + * the components MgO, FeO and SiO2) as a mixture between two endmembers + * (one iron-bearing and one magnesium-bearing). The equation of state + * considers three phases: bridgmanite, ferropericlase, and melt (each with + * their individual compositions). + * More details can be found in Dannberg, J., Myhill, R., Gassmöller, R., + * & Cottaar, S. (2021). The morphology, evolution and seismic visibility + * of partial melt at the core–mantle boundary: implications for ULVZs. + * Geophysical Journal International, 227(2), 1028-1059. + * + * @ingroup MaterialModels + */ + template + class MeltBoukare : public MaterialModel::MeltInterface, + public MaterialModel::MeltFractionModel, + public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. Computes endmember properties. + */ + void + initialize () override; + + /** + * Return whether the model is compressible or not. In this model, + * both the melt and solid are compressible. + */ + bool is_compressible () const override; + + void evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + + /** + * Compute the equilibrium melt fractions for the given input conditions. + * @p in and @p melt_fractions need to have the same size. + * + * @param in Object that contains the current conditions. + * @param melt_fractions Vector of doubles that is filled with the + * equilibrium melt fraction for each given input conditions. + */ + void melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const override; + + /** + * @name Reference quantities + * @{ + */ + double reference_darcy_coefficient () const override; + + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @} + */ + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + + private: + // Thermodynamic parameters of the endmember components in the equation of state, + // needed to compute their material properties. + std::vector endmember_names; + std::vector molar_masses; + std::vector number_of_atoms; + std::vector reference_volumes; + std::vector reference_thermal_expansivities; + std::vector reference_bulk_moduli; + std::vector bulk_modulus_pressure_derivatives; + std::vector bulk_modulus_second_pressure_derivatives; + std::vector Einstein_temperatures; + std::vector reference_enthalpies; + std::vector reference_entropies; + std::vector reference_specific_heats; + std::vector specific_heat_linear_coefficients; + std::vector specific_heat_second_coefficients; + std::vector specific_heat_third_coefficients; + + std::vector tait_parameters_a; + std::vector tait_parameters_b; + std::vector tait_parameters_c; + + // Reference conditions for computing the material properties in the equation of state. + double reference_temperature; + double reference_pressure; + + // Rheological properties. + double eta_0; + double xi_0; + double eta_f; + double thermal_viscosity_exponent; + double thermal_bulk_viscosity_exponent; + double alpha_phi; + + // Transport properties that are not computed from the equation of state. + double thermal_conductivity; + double reference_permeability; + + // Parameters controlling melting and solidification of melt. + bool include_melting_and_freezing; + double melting_time_scale; + + // Parameters defining the molar composition of the two endmember compositions we use + // in the melting model. + const double molar_MgO_in_Mg_mantle_endmember = 0.581; + const double molar_SiO2_in_Mg_mantle_endmember = 0.419; + const double molar_FeO_in_Fe_mantle_endmember = 0.908; + const double molar_SiO2_in_Fe_mantle_endmember = 0.092; + + // Parameters describing the melting properties of the two endmembers of the melting model. + const double melting_reference_pressure = 120.e9; + + // reference melting temperature for Fe and Mg mantle endmember at the reference pressure + double Fe_mantle_melting_temperature; + double Mg_mantle_melting_temperature; + + // molar entropy change of melting in J/mol K + const double Fe_mantle_melting_entropy = 33.77; + const double Mg_mantle_melting_entropy = 34.33; + + // molar volume change of melting of solid Fe and Mg mantle endmember in m3/mol + const double Fe_mantle_melting_volume = 1.51e-07; + const double Mg_mantle_melting_volume = 9.29e-08; + + // Number of moles of atoms mixing on pseudosite in mantle lattice (empirical model fitting the full Boukare model). + double Fe_number_of_moles; + double Mg_number_of_moles; + + // Indices for the endmembers in the equation of state. + unsigned int febdg_idx; + unsigned int mgbdg_idx; + unsigned int wus_idx; + unsigned int per_idx; + unsigned int femelt_idx; + unsigned int mgmelt_idx; + + + // Parameter describing if an endmember in the equation of state is solid or molten. + struct EndmemberState + { + enum Kind + { + solid, + melt + }; + }; + + std::vector endmember_states; + + + // Material properties of the different endmembers of the equation of state. + struct EndmemberProperties + { + /** + * Constructor. Initialize the various arrays of this structure with the + * given number of endmembers. + */ + EndmemberProperties(const unsigned int n_endmembers); + + std::vector volumes; + std::vector gibbs_energies; + std::vector entropies; + std::vector thermal_expansivities; + std::vector bulk_moduli; + std::vector heat_capacities; + }; + + + /** + * Fill the endmember properties at a single point. + */ + virtual + void + fill_endmember_properties (const typename Interface::MaterialModelInputs &in, + const unsigned int q, + EndmemberProperties &properties) const; + + + /** + * Calculate the Einstein thermal energy of an endmember component. + */ + virtual + double + endmember_thermal_energy (const double temperature, + const unsigned int endmember_index) const; + + + /** + * Calculate the heat capacity of an endmember component. + */ + virtual + double + endmember_molar_heat_capacity (const double temperature, + const unsigned int endmember_index) const; + + /** + * Calculate the thermal pressure of an endmember component. + */ + virtual + double + endmember_thermal_pressure (const double temperature, + const unsigned int endmember_index) const; + + /** + * Calculate the thermal addition to the standard state enthalpy of an endmember component + * at the reference pressure. + */ + virtual + double + endmember_enthalpy_thermal_addition (const double temperature, + const unsigned int endmember_index) const; + + /** + * Calculate the thermal addition to the standard state enttropy of an endmember component + * at the reference pressure. + */ + virtual + double + endmember_entropy_thermal_addition (const double temperature, + const unsigned int endmember_index) const; + + + /** + * Convert from the mole fraction of iron in the solid and melt to the mole fraction of iron + * and magnesium in each of the two solid phases, bridgmanite and ferropericlase, and the melt + * phase. In addition, compute the molar fraction of bridgmanite in the solid. + */ + virtual + void + convert_composition_to_fraction_of_endmembers (const double temperature, + const double molar_Fe_in_solid, + const double molar_Fe_in_melt, + const std::vector &endmember_gibbs_energies, + std::vector &endmember_mole_fractions_per_phase, + double &molar_bridgmanite_in_solid) const; + + + /** + * Compute the molar fraction of melt from the volume fraction of melt (the porosity). + * This requires knowing the densities of both solid and melt, which can be computed + * from the fractions and material properties of the component endmembers. + */ + virtual + double + compute_melt_molar_fraction (const double porosity, + const double bridgmanite_molar_fraction_in_solid, + EndmemberProperties &properties, + const std::vector &endmember_mole_fractions_per_phase) const; + + + /** + * Make sure that when the property @p value is updated by adding @p change_of_value, + * the new value is between zero and one. Otherwise, throw an error message. + */ + virtual + double + assert_update_is_within_0_and_1 (const double value, + const double change_of_value) const; + + + /** + * Compute the equilibrium melt fraction for a given @p temperature, @p pressure, + * and @p bulk_composition and the corresponding composition of melt and solid. The + * melting model is based on Phipps Morgan, Jason. "Thermodynamics of pressure release + * melting of a veined plum pudding mantle." Geochemistry, Geophysics, Geosystems 2.4 + * (2001), and additionally includes volatiles. + */ + virtual + double + melt_fraction (const double temperature, + const double pressure, + const double bulk_composition, + double &molar_volatiles_in_melt, + double &solid_composition, + double &melt_composition) const; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/melt_global.h.bak b/include/aspect/material_model/melt_global.h.bak new file mode 100644 index 00000000000..cc2da5af596 --- /dev/null +++ b/include/aspect/material_model/melt_global.h.bak @@ -0,0 +1,149 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_melt_global_h +#define _aspect_material_model_melt_global_h + +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that implements a simple formulation of the + * material parameters required for the modeling of melt transport + * in a global model, including a source term for the porosity according + * a simplified linear melting model. + * + * The model is considered incompressible, following the definition + * described in Interface::is_compressible. + * + * @ingroup MaterialModels + */ + template + class MeltGlobal : public MaterialModel::MeltInterface, + public MaterialModel::MeltFractionModel, + public ::aspect::SimulatorAccess + { + public: + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const override; + + void evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + + /** + * Compute the equilibrium melt fractions for the given input conditions. + * @p in and @p melt_fractions need to have the same size. + * + * @param in Object that contains the current conditions. + * @param melt_fractions Vector of doubles that is filled with the + * equilibrium melt fraction for each given input conditions. + */ + void melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const override; + + /** + * @name Reference quantities + * @{ + */ + double reference_darcy_coefficient () const override; + + + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + + private: + double reference_rho_s; + double reference_rho_f; + double reference_T; + double eta_0; + double xi_0; + double eta_f; + double thermal_viscosity_exponent; + double thermal_bulk_viscosity_exponent; + double thermal_expansivity; + double reference_specific_heat; + double thermal_conductivity; + double reference_permeability; + double alpha_phi; + double depletion_density_change; + double depletion_solidus_change; + double pressure_solidus_change; + double surface_solidus; + double compressibility; + double melt_compressibility; + bool include_melting_and_freezing; + double melting_time_scale; + double alpha_depletion; + double delta_eta_depletion_max; + + // entropy change upon melting + double peridotite_melting_entropy_change; + + virtual + double + melt_fraction (const double temperature, + const double pressure, + const double depletion) const; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/melt_simple.h.bak b/include/aspect/material_model/melt_simple.h.bak new file mode 100644 index 00000000000..0d30c32c9ee --- /dev/null +++ b/include/aspect/material_model/melt_simple.h.bak @@ -0,0 +1,144 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_melt_simple_h +#define _aspect_material_model_melt_simple_h + +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that implements a simple formulation of the + * material parameters required for the modeling of melt transport, + * including a source term for the porosity according to the melting + * model for dry peridotite of Katz, 2003. This also includes a + * computation of the latent heat of melting (if the latent heat + * heating model is active). + * + * Most of the material properties are constant, except for the shear, + * compaction and melt viscosities and the permeability, which depend on + * the porosity; and the solid and melt densities, which depend on + * temperature and pressure. + * + * The model is compressible (following the definition described in + * Interface::is_compressible) only if this is specified in the input file, + * and contains compressibility for both solid and melt. + * + * @ingroup MaterialModels + */ + template + class MeltSimple : public MaterialModel::MeltInterface, + public MaterialModel::MeltFractionModel, + public ::aspect::SimulatorAccess + { + public: + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const override; + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run and after + * the SimulatorAccess (if applicable) is initialized. + */ + void + initialize () override; + + void evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + + void melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const override; + + /** + * @name Reference quantities + * @{ + */ + double reference_darcy_coefficient () const override; + + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @} + */ + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + + private: + bool model_is_compressible; + double thermal_expansivity; + double eta_0; + double reference_specific_heat; + double thermal_conductivity; + double compressibility; + double thermal_viscosity_exponent; + double reference_T; + double depletion_density_change; + double reference_rho_solid; + + + + /* + * Object for computing the melt parameters + */ + ReactionModel::Katz2003MantleMelting katz2003_model; + + }; + + } +} + +#endif diff --git a/include/aspect/material_model/modified_tait.h.bak b/include/aspect/material_model/modified_tait.h.bak new file mode 100644 index 00000000000..c889f06370b --- /dev/null +++ b/include/aspect/material_model/modified_tait.h.bak @@ -0,0 +1,166 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_modified_tait_h +#define _aspect_material_model_modified_tait_h + +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A compressible material model that implements the thermal modified Tait + * equation of state as written in the paper of Holland and Powell, 2011 + * "An improved and extended internally consistent thermodynamic dataset + * for phases of petrological interest, involving a new equation of state + * for solids". + * + * Constant values are used for the thermal conductivity and viscosity. + * + * @ingroup MaterialModels + */ + template + class ModifiedTait : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + + public: + /** + * Evaluate material properties. + */ + void evaluate(const MaterialModelInputs &in, + MaterialModelOutputs &out) const override; + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + * This model is compressible. + */ + bool is_compressible () const override; + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @} + */ + + private: + /** + * The Tait parameters + */ + double tait_a, tait_b, tait_c; + + /** + * The reference pressure + */ + double reference_pressure; + + /** + * The reference temperature + */ + double reference_temperature; + + /** + * The reference density + */ + double reference_rho; + + /** + * The reference isothermal bulk modulus + */ + double reference_isothermal_bulk_modulus; + + /** + * The reference K' + * (first pressure derivative of the isothermal bulk modulus) + */ + double reference_Kprime; + + /** + * The reference K'' + * (second pressure derivative of the isothermal bulk modulus) + */ + double Kdprime_0; + + /** + * The reference thermal expansivity + */ + double reference_thermal_expansivity; + + /** + * The Einstein temperature + */ + double einstein_temperature; + + /** + * Parsed function that specifies the specific heat at P0 when using the Function + * method. + */ + Functions::ParsedFunction<1> reference_heat_capacity_function; + + /** + * The constant viscosity + */ + double eta; + + /** + * The constant thermal conductivity. + */ + double k_value; + + }; + + } +} + +#endif diff --git a/include/aspect/material_model/multicomponent.h.bak b/include/aspect/material_model/multicomponent.h.bak new file mode 100644 index 00000000000..49524bf31e1 --- /dev/null +++ b/include/aspect/material_model/multicomponent.h.bak @@ -0,0 +1,139 @@ +/* + Copyright (C) 2014 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_multicomponent_h +#define _aspect_material_model_multicomponent_h + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * An incompressible material model which is intended for use with multiple + * compositional fields. Each compositional field is meant to be a single + * rock type, where the value of the field at a point is interpreted to be + * a volume fraction of that rock type. If the sum of the compositional field + * volume fractions is less than one, then the remainder of the volume is + * assumed to be ``background mantle''. If the sum of the compositional + * field volume fractions is greater than one, then they are renormalized + * to sum to one and there is no background mantle. + * + * For each material parameter the user supplies a comma delimited list of + * length N+1, where N is the number of compositional fields. The + * additional field corresponds to the value for background mantle. They + * should be ordered ``background, composition1, composition2...'' + * + * If a single value is given, then all the compositional fields are given + * that value. Other lengths of lists are not allowed. For a given + * compositional field the material parameters are treated as constant, + * except density, which varies linearly with temperature according to the + * thermal expansivity. + * + * When more than one field is present at a point, they are averaged + * arithmetically. An exception is viscosity, which may be averaged + * arithmetically, harmonically, geometrically, or by selecting the + * viscosity of the composition with the greatest volume fraction. + * + * @ingroup MaterialModels + */ + template + class Multicomponent : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + + /** + * Function to compute the material properties in @p out given the + * inputs in @p in. + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * This model is not compressible, so this returns false. + */ + bool is_compressible () const override; + + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @} + */ + + private: + /** + * Reference temperature for thermal expansion. All components use + * the same reference_T. + */ + double reference_T; + + /** + * Enumeration for selecting which viscosity averaging scheme to use. + */ + MaterialUtilities::CompositionalAveragingOperation viscosity_averaging; + + /** + * Vector for field viscosities, read from parameter file. + */ + std::vector viscosities; + + /** + * Vector for field thermal conductivities, read from parameter file. + */ + std::vector thermal_conductivities; + + EquationOfState::MulticomponentIncompressible equation_of_state; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/multicomponent_compressible.h.bak b/include/aspect/material_model/multicomponent_compressible.h.bak new file mode 100644 index 00000000000..9198a5ea8b4 --- /dev/null +++ b/include/aspect/material_model/multicomponent_compressible.h.bak @@ -0,0 +1,133 @@ +/* + Copyright (C) 2014 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_multicomponent_compressible_h +#define _aspect_material_model_multicomponent_compressible_h + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model which is intended for use with multiple compositional + * fields. Each compositional field is meant to be a single rock type, + * where the value of the field at a point is interpreted to be the + * mass fraction of that rock type. If the sum of the compositional field + * mass fractions is less than one, then the remainder of the mass is + * assumed to be ``background mantle''. If the sum of the compositional + * field mass fractions is greater than one, then they are renormalized + * to sum to one and there is no background mantle. + * + * For each material parameter the user supplies a comma delimited list of + * length N+1, where N is the number of compositional fields. The + * additional field corresponds to the value for background mantle. They + * should be ordered ``background, composition1, composition2...'' + * + * If a single value is given, then all the compositional fields are given + * that value. Other lengths of lists are not allowed. The material + * parameters for each compositional field are derived from the + * multicomponent compressible equation of state, and are pressure and + * temperature dependent. + * + * When more than one field is present at a point, they are either averaged + * self-consistently (for equation of state properties) or arithmetically + * (for thermal conductivity). For the special case of viscosity, the user + * may select from a variety of averaging schemes: + * arithmetic, harmonic, geometric, or by selecting the + * viscosity of the composition with the greatest volume fraction. + * + * @ingroup MaterialModels + */ + template + class MulticomponentCompressible : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + + /** + * Function to compute the material properties in @p out given the + * inputs in @p in. + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * This model is compressible, so this returns true. + */ + bool is_compressible () const override; + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + private: + /** + * Enumeration for selecting which viscosity averaging scheme to use. + */ + MaterialUtilities::CompositionalAveragingOperation viscosity_averaging; + + /** + * Vector for field viscosities, read from parameter file. + */ + std::vector viscosities; + + /** + * Vector for field thermal conductivities, read from parameter file. + */ + std::vector thermal_conductivities; + + EquationOfState::MulticomponentCompressible equation_of_state; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/nondimensional.h.bak b/include/aspect/material_model/nondimensional.h.bak new file mode 100644 index 00000000000..3dcf1482c19 --- /dev/null +++ b/include/aspect/material_model/nondimensional.h.bak @@ -0,0 +1,132 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_material_model_nondimensional_h +#define _aspect_material_model_nondimensional_h + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model for incompressible (using the Boussinesq approximation) + * and compressible computations (with ALA or TALA) for a nondimensionalized + * problem. The viscosity is (optionally) depth and temperature dependent. + * + * @ingroup MaterialModels + */ + template + class Nondimensional : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + + /** + * Initialize. + */ + void initialize () override; + + /** + * Evaluate the material model. + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. + */ + bool is_compressible () const override; + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + private: + /** + * Use truncated anelastic approximation? + */ + bool tala; + + /** + * Are we using ALA/TALA or BA? (determined by the choice of Di) + */ + bool compressible; + + /** + * Parameter describing the temperature prefactor of viscosity. + */ + double exponential_viscosity_temperature_prefactor; + + /** + * Parameter describing the depth prefactor of viscosity. + */ + double exponential_viscosity_depth_prefactor; + + /** + * The surface density. + */ + double reference_rho; + + /** + * The nondimensional numbers (Dissipation number, + * Rayleigh number, Grueneisen parameter). + */ + double Di, Ra, gamma; + + /** + * The constant specific heat + */ + double reference_specific_heat; + + }; + + } +} + +#endif diff --git a/include/aspect/material_model/perplex_lookup.h.bak b/include/aspect/material_model/perplex_lookup.h.bak new file mode 100644 index 00000000000..5054a36f822 --- /dev/null +++ b/include/aspect/material_model/perplex_lookup.h.bak @@ -0,0 +1,113 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_perplex_lookup_h +#define _aspect_material_model_perplex_lookup_h + +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that calls the thermodynamic software PerpleX + * in order to evaluate material properties at a given point, namely + * the density, heat capacity, thermal expansivity and compressibility. + * The viscosity and thermal conductivity are globally constant. + * + * The usual PerpleX input files are required in the working directory: + * an endmember dataset file, solution model dataset file and + * option file. The path to a PerpleX input file must be given by + * the user in the ASPECT parameter file; this file may be in any + * directory. PerpleX output files will be written to the same + * directory. + * + * Compositional fields are used to define the bulk composition at + * each point. These compositional fields correspond to the + * components as given in the PerpleX input file. The order of + * components is preserved. + * + * This model requires PerpleX. A script to download and setup the + * required files can be found in contrib/perplex. If the default + * installation directory is not changed, cmake will automatically + * find the required files during creation of the ASPECT build files. + * See ./contrib/perplex/README.md + * + * WARNING: This model is extremely slow because there are many + * redundant calls to evaluate the material properties; + * it serves only as a proof of concept. + * + * @ingroup MaterialModels + */ + template + class PerpleXLookup : public Interface + { + public: + /** + * Initialization function. Loads the material data and sets up + * pointers. + */ + void + initialize () override; + + bool is_compressible () const override; + + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + + private: + std::string perplex_file_name; + double eta; + double k_value; + double min_temperature; + double max_temperature; + double min_pressure; + double max_pressure; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/prescribed_viscosity.h.bak b/include/aspect/material_model/prescribed_viscosity.h.bak new file mode 100644 index 00000000000..321949d3b9b --- /dev/null +++ b/include/aspect/material_model/prescribed_viscosity.h.bak @@ -0,0 +1,110 @@ +/* + Copyright (C) 2014 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_prescribed_viscosity_h +#define _aspect_material_model_prescribed_viscosity_h + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that applies a viscosity to a ''base model'' chosen from any of + * the other available material models. This prescribed viscosity material model + * allows the user to specify a function which describes where the viscosity should be + * prescribed and a second function which describes the viscosity in that region. + * This material model requires a base model which prescribes the viscosity and the + * other material parameters in the rest of the model. + * @ingroup MaterialModels + */ + template + class PrescribedViscosity : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialize the base model at the beginning of the run. + */ + void initialize() override; + + /** + * Update the base model and viscosity function at the beginning of + * each timestep. + */ + void update() override; + + /** + * Compute the material properties by evaluating the base model and + * then overwrite the viscosity according to the viscosity function + * in the locations set by the indicator function. + */ + void + evaluate (const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + + /** + * Method to declare parameters related to prescribed viscosity model + */ + static void + declare_parameters (ParameterHandler &prm); + + /** + * Method to parse parameters related to prescribed viscosity model + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Method that indicates whether material is compressible. Prescribed viscosity model is compressible + * if and only if base model is compressible. + */ + bool is_compressible () const override; + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + private: + + /** + * Parsed function that specifies where the viscosity is prescribed. + */ + Functions::ParsedFunction prescribed_viscosity_indicator_function; + + /** + * Parsed function that specifies what the viscosity is set to in the + * prescribed regions. + */ + Functions::ParsedFunction prescribed_viscosity_function; + + /** + * Pointer to the material model used as the base model + */ + std::unique_ptr> base_model; + }; + } +} + +#endif diff --git a/include/aspect/material_model/reaction_model/katz2003_mantle_melting.h.bak b/include/aspect/material_model/reaction_model/katz2003_mantle_melting.h.bak new file mode 100644 index 00000000000..b5bf2bd066c --- /dev/null +++ b/include/aspect/material_model/reaction_model/katz2003_mantle_melting.h.bak @@ -0,0 +1,168 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_reaction_melt_katz2003_mantle_melting_h +#define _aspect_material_reaction_melt_katz2003_mantle_melting_h + +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace ReactionModel + { + + /** + * A melt model that calculates melt fraction and entropy change + * according to the melting model for dry peridotite of Katz, 2003. + * This also includes a computation of the latent heat of melting (if the latent heat + * heating model is active). + * + * These functions can be used in the calculation of melting and melt transport + * in the melt_simple material model and can be extended to other material models + * + * @ingroup ReactionModel + */ + template + class Katz2003MantleMelting : public ::aspect::SimulatorAccess + { + public: + // constructor + Katz2003MantleMelting(); + + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm); + + + /** + * Percentage of material that is molten for a given @p temperature and + * @p pressure (assuming equilibrium conditions). Melting model after Katz, + * 2003, for dry peridotite. + */ + double + melt_fraction (const double temperature, + const double pressure) const; + + /** + * Compute the change in entropy due to melting for a given @p temperature + * and @p pressure, and under the assumption that a fraction + * @p maximum_melt_fraction of the material has already been molten + * previously. The entropy change is computed with respect to temperature + * or pressure, depending on @p dependence. + * This is needed to calculate the latent heat of melt. + */ + double + entropy_change (const double temperature, + const double pressure, + const double maximum_melt_fraction, + const NonlinearDependence::Dependence dependence) const; + + + /** + * Compute all the reaction rate variables needed for a reactive transport model based on the + * Katz 2003 formulation. Takes the material model inputs @p in to compute the material model outputs @p out. + * This function mainly fills the reaction_rate_out object but populates out.reaction_terms, + * out.entropy_derivative_pressure and entropy_derivative_temperature + */ + void calculate_reaction_rate_outputs(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const; + + /** + * Compute all the fluid variables needed for a reactive transport model based on the + * Katz 2003 formulation. This function fills melt outputs, the out object should already contain + * outputs for the solid and this function uses the inputs @p in and the solid outputs @p out + * to fill MeltOutputs. Solid outputs such as out.Thermal_expansion_coefficients are expected + * to have already been computed when this function is called. Solid viscosities are also modified + * in the out object here because the presence of melt weakens the material. + */ + void calculate_fluid_outputs(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out, + const double reference_T) const; + + + double reference_darcy_coefficient () const; + + private: + /** + * Parameters for anhydrous melting of peridotite after Katz, 2003 + */ + + double reference_rho_fluid; + double xi_0; + double viscosity_fluid; + double thermal_bulk_viscosity_exponent; + double alpha_phi; + double extraction_depth; + double melt_compressibility; + double melt_bulk_modulus_derivative; + double depletion_solidus_change; + bool fractional_melting; + double freezing_rate; + double melting_time_scale; + double reference_permeability; + + // for the solidus temperature + double A1; // °C + double A2; // °C/Pa + double A3; // °C/(Pa^2) + + // for the lherzolite liquidus temperature + double B1; // °C + double B2; // °C/Pa + double B3; // °C/(Pa^2) + + // for the liquidus temperature + double C1; // °C + double C2; // °C/Pa + double C3; // °C/(Pa^2) + + // for the reaction coefficient of pyroxene + double r1; // cpx/melt + double r2; // cpx/melt/GPa + double M_cpx; // mass fraction of pyroxene + + // melt fraction exponent + double beta; + + // entropy change upon melting + double peridotite_melting_entropy_change; + }; + } + + } +} + +#endif diff --git a/include/aspect/material_model/reactive_fluid_transport.h.bak b/include/aspect/material_model/reactive_fluid_transport.h.bak new file mode 100644 index 00000000000..245f2e0eb2c --- /dev/null +++ b/include/aspect/material_model/reactive_fluid_transport.h.bak @@ -0,0 +1,262 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_reactive_fluid_transport_h +#define _aspect_material_model_reactive_fluid_transport_h + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + /** + * A material model that simulates both fluid-rock interactions + * and the advection of fluids. It is designed to be composited with another material + * model that computes the solid material properties. + * @ingroup MaterialModels + */ + + template + class ReactiveFluidTransport : public MaterialModel::MeltInterface, public MaterialModel::MeltFractionModel, public ::aspect::SimulatorAccess + { + public: + /** + * @copydoc MaterialModel::Interface::is_compressible() + * + * Returns value from material model providing compressibility. + */ + bool is_compressible () const override; + + /** + * @name Reference quantities + * @{ + */ + virtual double reference_darcy_coefficient () const override; + + + /** + * Compute the maximum allowed bound water content at the input + * pressure and temperature conditions. This is used to determine + * how free water interacts with the solid phase. + * @param in Object that contains the current conditions. + * @param q unsigned int from 0-3 indexing which rock phase the equilbrium + * bound water content is being calculated for + */ + std::vector tian_equilibrium_bound_water_content(const MaterialModel::MaterialModelInputs &in, + unsigned int q) const; + + /** + * Compute the free fluid fraction that can be present in the material based on the + * fluid content of the material and the fluid solubility for the given input conditions. + * @p in and @p melt_fractions need to have the same size. + * + * @param in Object that contains the current conditions. + * @param melt_fractions Vector of doubles that is filled with the + * allowable free fluid fraction for each given input conditions. + */ + virtual void melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const override; + + /** + * Initialize the base model at the beginning of the model run + * @copydoc MaterialModel::Interface::initialize() + */ + void + initialize () override; + + /** + * Update the base model at the beginning of each timestep. + */ + void update() override; + + /** + * @copydoc MaterialModel::Interface::evaluate() + */ + void + evaluate (const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + + /** + * @copydoc MaterialModel::Interface::declare_parameters() + */ + static void + declare_parameters (ParameterHandler &prm); + + /** + * @copydoc MaterialModel::Interface::parse_parameters() + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * If this material model can produce additional named outputs + * that are derived from NamedAdditionalOutputs, create them in here. + */ + virtual + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + private: + + /** + * Pointer to the material model used as the base model + */ + std::unique_ptr> base_model; + + // Variables that describe the properties of the fluid, i.e. its density, + // viscosity, and compressibility. + // Properties of the solid are defined in the base model. + double reference_rho_f; + double eta_f; + double fluid_compressibility; + + // Material properties governing the transport of the fluid with respect + // to the solid, i.e., the bulk viscosity (relative to the shear viscosity), + // the permeability, and how much the solid viscosity changes in the presence + // of fluids. + double shear_to_bulk_viscosity_ratio; + double min_compaction_visc; + double max_compaction_visc; + double reference_permeability; + double alpha_phi; + double reference_T; + + // Time scale for fluid release and absorption. + double fluid_reaction_time_scale; + + // The maximum water content for each of the 4 rock types in the tian approximation + // method. These are important for keeping the polynomial bounded within reasonable + // values. + double tian_max_peridotite_water; + double tian_max_gabbro_water; + double tian_max_MORB_water; + double tian_max_sediment_water; + + // The following coefficients are taken from a publication from Tian et al., 2019, and can be found + // in Table 3 (Gabbro), Table B1 (MORB), Table B2 (Sediments) and Table B3 (peridotite). + // LR refers to the effective enthalpy change for devolatilization reactions, + // csat is the saturated mass fraction of water in the solid, and Td is the + // onset temperature of devolatilization for water. + std::vector LR_peridotite_poly_coeffs {-19.0609, 168.983, -630.032, 1281.84, -1543.14, 1111.88, -459.142, 95.4143, 1.97246}; + std::vector csat_peridotite_poly_coeffs {0.00115628, 2.42179}; + std::vector Td_peridotite_poly_coeffs {-15.4627, 94.9716, 636.603}; + + std::vector LR_gabbro_poly_coeffs {-1.81745, 7.67198, -10.8507, 5.09329, 8.14519}; + std::vector csat_gabbro_poly_coeffs {-0.0176673, 0.0893044, 1.52732}; + std::vector Td_gabbro_poly_coeffs {-1.72277, 20.5898, 637.517}; + + std::vector LR_MORB_poly_coeffs {-1.78177, 7.50871, -10.4840, 5.19725, 7.96365}; + std::vector csat_MORB_poly_coeffs {0.0102725, -0.115390, 0.324452, 1.41588}; + std::vector Td_MORB_poly_coeffs {-3.81280, 22.7809, 638.049}; + + std::vector LR_sediment_poly_coeffs {-2.03283, 10.8186, -21.2119, 18.3351, -6.48711, 8.32459}; + std::vector csat_sediment_poly_coeffs {-0.150662, 0.301807, 1.01867}; + std::vector Td_sediment_poly_coeffs {2.83277, -24.7593, 85.9090, 524.898}; + + // The polynomials breakdown above certain pressures, 10 GPa for peridotite, 26 GPa for gabbro, 16 GPa for MORB, + // and 50 GPa for sediment. These cutoff pressures were determined by extending the pressure range in Tian et al. (2019) + // and observing where the maximum allowed water contents jump towards infinite values. + const std::vector pressure_cutoffs {10, 26, 16, 50}; + + std::vector> devolatilization_enthalpy_changes {LR_peridotite_poly_coeffs, LR_gabbro_poly_coeffs, \ + LR_MORB_poly_coeffs, LR_sediment_poly_coeffs + }; + + std::vector> water_mass_fractions {csat_peridotite_poly_coeffs, csat_gabbro_poly_coeffs, \ + csat_MORB_poly_coeffs, csat_sediment_poly_coeffs + }; + + std::vector> devolatilization_onset_temperatures {Td_peridotite_poly_coeffs, Td_gabbro_poly_coeffs, \ + Td_MORB_poly_coeffs, Td_sediment_poly_coeffs + }; + + /* + * Object for computing Katz 2003 melt parameters + */ + ReactionModel::Katz2003MantleMelting katz2003_model; + + /** + * Enumeration for selecting which type of scheme to use for + * reactions between fluids and solids. The available + * reaction models are described below. + * + * The no reaction model does not include any reactions + * between the solid and fluid phases. As a result, + * there is no exchange between the bound fluid and porosity + * compositional fields. However, the values of each field + * may vary through the model evolution through advection + * from their initial configurations. + * + * The zero solubility model describes a scenario where the + * solid cannot accommodate any fluid (i.e., zero solubility). + * The fluid volume fraction in equilibrium with the solid + * at any point (stored in the melt_fractions vector) is + * equal to the sum of the bound fluid content and porosity, + * with the latter determined by the assigned initial + * porosity, fluid boundary conditions, and fluid + * transport through the model. Significantly, this reaction + * model is thus assuming that the bound water fraction is a + * volume fraction (i.e., since porosity is always a volume + * fraction). This latter assumption also requires the selected + * base model to be incompressible, as otherwise the advection + * equation would only be valid for mass and not volume + * fractions. + * + * The tian approximation model implements parametrized phase + * diagrams from Tian et al., 2019 G3, https://doi.org/10.1029/2019GC008488 + * and calculates the fluid-solid reactions for four different rock types: + * sediments, MORB, gabbro and peridotite. This is achieved by calculating the + * maximum allowed bound water content for each composition at the current + * Pressure-Temperature conditions, and releasing bound water as free water if: + * (maximum bound water content < current bound water content) + * or incorporating free water (if present) into the solid phase as bound water: + * maximum bound water content > current bound water content + * This model requires that 4 compositional fields named after the 4 different rock + * types exist in the input file. + * + * The Katz2003 model implements anhydrous the mantle melting model from + * Katz et. al., 2003 G3, doi:10.1029/2002GC000433. + */ + enum ReactionScheme + { + no_reaction, + zero_solubility, + tian_approximation, + katz2003 + } + fluid_solid_reaction_scheme; + }; + } +} + +#endif diff --git a/include/aspect/material_model/replace_lithosphere_viscosity.h.bak b/include/aspect/material_model/replace_lithosphere_viscosity.h.bak new file mode 100644 index 00000000000..e7ac2fd94b6 --- /dev/null +++ b/include/aspect/material_model/replace_lithosphere_viscosity.h.bak @@ -0,0 +1,102 @@ +/* + Copyright (C) 2014 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_replace_lithosphere_viscosity_h +#define _aspect_material_model_replace_lithosphere_viscosity_h + +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that applies a given constant viscosity in the lithosphere. + * Viscosity below this is taken from a ''base model'' chosen from any of the + * other available material models. The 'replace lithosphere viscosity' + * material model allows the user to specify the depth of the lithosphere-asthenosphere + * boundary either as one value or as a file. All other properties are derived + * from the base model. + * @ingroup MaterialModels + */ + template + class ReplaceLithosphereViscosity : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + + /** + * Initialize the base model at the beginning of the run. + */ + void initialize() override; + + /** + * Function to compute the material properties in @p out given the + * inputs in @p in. + */ + void + evaluate (const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const override; + + /** + * Method to declare parameters related to replace lithosphere viscosity model + */ + static void + declare_parameters (ParameterHandler &prm); + + /** + * Method to parse parameters related to replace lithosphere viscosity model + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Method that indicates whether material is compressible. Replace lithosphere viscosity model is compressible + * if and only if base model is compressible. + */ + bool is_compressible () const override; + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + private: + + /** + * This parameter gives the viscosity set within the lithosphere. + */ + double lithosphere_viscosity; + + + /** + * Pointer to the material model used as the base model + */ + std::unique_ptr> base_model; + + + InitialTemperature::LABDepth::LABDepthLookup lab_depth_lookup; + }; + } +} + +#endif diff --git a/include/aspect/material_model/rheology/ascii_depth_profile.h.bak b/include/aspect/material_model/rheology/ascii_depth_profile.h.bak new file mode 100644 index 00000000000..1655724499e --- /dev/null +++ b/include/aspect/material_model/rheology/ascii_depth_profile.h.bak @@ -0,0 +1,96 @@ +/* + Copyright (C) 2020 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_material_model_rheology_ascii_depth_profile_h +#define _aspect_material_model_rheology_ascii_depth_profile_h + +#include +#include +#include + +#include + + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace Rheology + { + + /** + * A class that implements a prescribed viscosity with depth determined from + * an AsciiDataProfile input file. + * + * @ingroup Rheology + */ + template + class AsciiDepthProfile : public Utilities::AsciiDataProfile , public SimulatorAccess + { + public: + /** + * Constructor. Initialize variables. + */ + AsciiDepthProfile (); + + /** + * Initialization function. + */ + void initialize (); + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataProfile::initialize; + + /** + * Return the viscosity at a given point of the domain. + */ + double compute_viscosity (const double depth) const; + + /** + * Declare the parameters for the input files. + */ + static + void + declare_parameters (ParameterHandler &prm, + const std::string &subsection_name = "Ascii data model"); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm, + const std::string &subsection_name = "Ascii data model"); + + private: + + /** + * The column index of the viscosity in the data file. + */ + unsigned int viscosity_index; + }; + } + } +} + + +#endif diff --git a/include/aspect/material_model/rheology/composite_visco_plastic.h.bak b/include/aspect/material_model/rheology/composite_visco_plastic.h.bak new file mode 100644 index 00000000000..265660e8c27 --- /dev/null +++ b/include/aspect/material_model/rheology/composite_visco_plastic.h.bak @@ -0,0 +1,147 @@ +/* + Copyright (C) 2020 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_composite_visco_plastic_h +#define _aspect_material_model_rheology_composite_visco_plastic_h + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace Rheology + { + + template + class CompositeViscoPlastic : public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + CompositeViscoPlastic(); + + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * If @p expected_n_phases_per_composition points to a vector of + * unsigned integers this is considered the number of phases + * for each compositional field and will be checked against the parsed + * parameters. + */ + void + parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition = nullptr); + + /** + * Compute the viscosity based on the composite viscous creep law. + * If @p n_phase_transitions_per_composition points to a vector of + * unsigned integers this is considered the number of phase transitions + * for each compositional field and viscosity will be first computed on + * each phase and then averaged for each compositional field. + */ + double + compute_viscosity (const double pressure, + const double temperature, + const std::vector &volume_fractions, + const SymmetricTensor<2,dim> &strain_rate, + std::vector &partial_strain_rates, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phase_transitions_per_composition = std::vector()) const; + + /** + * Compute the compositional field viscosity + * based on the composite viscous creep law. + * If @p n_phase_transitions_per_composition points to a vector of + * unsigned integers this is considered the number of phase transitions + * for each compositional field and viscosity will be first computed on + * each phase and then averaged for each compositional field. + */ + double + compute_composition_viscosity (const double pressure, + const double temperature, + const unsigned int composition, + const SymmetricTensor<2,dim> &strain_rate, + std::vector &partial_strain_rates, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phase_transitions_per_composition = std::vector()) const; + + /** + * Compute the strain rate and first stress derivative + * as a function of stress based on the composite viscous creep law. + */ + std::pair + compute_strain_rate_and_derivative (const double creep_stress, + const double pressure, + const double temperature, + const DiffusionCreepParameters diffusion_creep_parameters, + const DislocationCreepParameters dislocation_creep_parameters, + const PeierlsCreepParameters peierls_creep_parameters, + const DruckerPragerParameters drucker_prager_parameters) const; + + private: + + /** + * Whether to use different deformation mechanisms + */ + bool use_diffusion_creep; + bool use_dislocation_creep; + bool use_peierls_creep; + bool use_drucker_prager; + + /** + * Pointers to objects for computing deformation mechanism + * strain rates and effective viscosities. + */ + std::unique_ptr> diffusion_creep; + std::unique_ptr> dislocation_creep; + std::unique_ptr> peierls_creep; + std::unique_ptr> drucker_prager; + + DruckerPragerParameters drucker_prager_parameters; + + unsigned int number_of_compositions; + double minimum_viscosity; + double maximum_viscosity; + + double min_strain_rate; + double strain_rate_residual_threshold; + unsigned int stress_max_iteration_number; + }; + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/compositional_viscosity_prefactors.h.bak b/include/aspect/material_model/rheology/compositional_viscosity_prefactors.h.bak new file mode 100644 index 00000000000..970084c4a2e --- /dev/null +++ b/include/aspect/material_model/rheology/compositional_viscosity_prefactors.h.bak @@ -0,0 +1,122 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_compositional_viscosity_prefactors_h +#define _aspect_material_model_rheology_compositional_viscosity_prefactors_h + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace Rheology + { + /** + * A class that handles multiplication of viscosity for a given compositional + * field. The multiplication factors for each composition (viscosity + * prefactors) are also declared, parsed, and in some cases calculated in this class. + */ + template + class CompositionalViscosityPrefactors : public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + CompositionalViscosityPrefactors(); + + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm); + + // The flow laws that can be + // currently modified. + enum ModifiedFlowLaws + { + diffusion, + dislocation + } modified_flow_laws; + + /** + * Compute the viscosity. + */ + double + compute_viscosity (const MaterialModel::MaterialModelInputs &in, + const double base_viscosity, + const unsigned int composition_index, + const unsigned int q, + const ModifiedFlowLaws &modified_flow_laws) const; + + private: + /** + * The viscosity prefactors or terms used to calculate the viscosity + * prefactors, which are read in from the input file by the + * parse_parameters() function. Users can choose between different schemes. + * none: no viscosity change + * hk04_olivine_hydration: calculate the viscosity change due to hydrogen + * incorporation into olivine using Hirth & Kohlstaedt 2004 10.1029/138GM06. + * This method requires a composition called 'bound_fluid' which tracks the wt% + * water in the solid, which is used to compute an atomic ratio of H/Si ppm + * assuming 90 mol% forsterite and 10 mol% fayalite, and finally calculates + * a water fugacity. + * The prefactor for a given compositional field is multiplied with a + * base_viscosity value provided by the material model, which is then returned + * to the material model. + */ + enum ViscosityPrefactorScheme + { + none, + hk04_olivine_hydration, + } viscosity_prefactor_scheme; + + // Initialize variables for the water fugacity calculation, from HK04 + std::vector diffusion_water_fugacity_exponents; + std::vector dislocation_water_fugacity_exponents; + std::vector minimum_mass_fraction_water_for_dry_creep; + + // From Hirth & Kohlstaedt 2004, equation 6 + const double A_H2O = 2.6e-5; // 1/Pa + const double activation_energy_H2O = 40e3; // J/mol/K + const double activation_volume_H2O = 10e-6; // m^3/mol + + // We calculate the molar mass of olivine using the molar mass of fayalite (0.20379 kg/mol) + // and the molar mass of forsterite (0.140693 kg/mol), and a mole fraction of 90% forsterite + // in olivine. + const double molar_mass_olivine = 0.1470027; // kg/mol + const double molar_mass_H2O = 0.01801528; // kg/mol + }; + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/constant_viscosity.h.bak b/include/aspect/material_model/rheology/constant_viscosity.h.bak new file mode 100644 index 00000000000..987209b35c1 --- /dev/null +++ b/include/aspect/material_model/rheology/constant_viscosity.h.bak @@ -0,0 +1,73 @@ +/* + Copyright (C) 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_constant_viscosity_h +#define _aspect_material_model_rheology_constant_viscosity_h + +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace Rheology + { + class ConstantViscosity + { + public: + /** + * Constructor. Initializes viscosity to NaN. + */ + ConstantViscosity(); + + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm, + const double default_viscosity = 1e21); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm); + + /** + * Compute the viscosity, in this case just a constant. + */ + double + compute_viscosity () const; + + private: + /** + * The constant viscosity that defines this rheology. It + * is read from the input file by the parse_parameters() + * function. + */ + double viscosity; + }; + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/constant_viscosity_prefactors.h.bak b/include/aspect/material_model/rheology/constant_viscosity_prefactors.h.bak new file mode 100644 index 00000000000..1ecc37aad36 --- /dev/null +++ b/include/aspect/material_model/rheology/constant_viscosity_prefactors.h.bak @@ -0,0 +1,85 @@ +/* + Copyright (C) 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_constant_viscosity_prefactors_h +#define _aspect_material_model_rheology_constant_viscosity_prefactors_h + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace Rheology + { + /** + * A class that handles multiplication of viscosity for a given compositional + * field. The multiplication factors for each composition (constant viscosity + * prefactors) are also declared and parsed in this class. + */ + template + class ConstantViscosityPrefactors : public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + ConstantViscosityPrefactors(); + + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm); + + /** + * Compute the viscosity. + */ + double + compute_viscosity (const double base_viscosity, + const unsigned int composition_index) const; + + private: + /** + * The constant viscosity prefactors, which are read in + * from the input file by the parse_parameters() function. + * The total number of prefactors will be equal to one + * plus the number of compositional fields. The prefactor + * for a given compositional field is multiplied with a + * base_viscosity value provided by the material model, which + * is then returned to the material model. + */ + std::vector constant_viscosity_prefactors; + }; + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/diffusion_creep.h.bak b/include/aspect/material_model/rheology/diffusion_creep.h.bak new file mode 100644 index 00000000000..5146a371806 --- /dev/null +++ b/include/aspect/material_model/rheology/diffusion_creep.h.bak @@ -0,0 +1,167 @@ +/* + Copyright (C) 2019 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_diffusion_creep_h +#define _aspect_material_model_rheology_diffusion_creep_h + +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace Rheology + { + /** + * Data structure for diffusion creep parameters. + */ + struct DiffusionCreepParameters + { + /** + * The diffusion creep prefactor, activation energy, activation volume + * and grain size exponent. + */ + double prefactor; + double activation_energy; + double activation_volume; + double stress_exponent; + double grain_size_exponent; + + /** + * Constructor. Initializes all values to NaN. + */ + DiffusionCreepParameters(); + }; + + template + class DiffusionCreep : public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + DiffusionCreep(); + + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * If @p expected_n_phases_per_composition points to a vector of + * unsigned integers this is considered the number of phases + * for each compositional field and will be checked against the parsed + * parameters. + */ + void + parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition = nullptr); + + + /** + * Compute the creep parameters for the diffusion creep law. + * If @p n_phase_transitions_per_composition points to a vector of + * unsigned integers this is considered the number of phase transitions + * for each compositional field and viscosity will be first computed on + * each phase and then averaged for each compositional field. + */ + const DiffusionCreepParameters + compute_creep_parameters (const unsigned int composition, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phase_transitions_per_composition = std::vector()) const; + + /** + * Compute the viscosity based on the diffusion creep law. + * If @p n_phase_transitions_per_composition points to a vector of + * unsigned integers this is considered the number of phase transitions + * for each compositional field and viscosity will be first computed on + * each phase and then averaged for each compositional field. + */ + double + compute_viscosity (const double pressure, + const double temperature, + const unsigned int composition, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phase_transitions_per_composition = std::vector()) const; + + /** + * Compute the strain rate and first stress derivative as a function + * of stress based on the diffusion creep law. + */ + std::pair + compute_strain_rate_and_derivative (const double stress, + const double pressure, + const double temperature, + const DiffusionCreepParameters creep_parameters) const; + + /** + * Compute the logarithm of strain rate and first derivative with respect to + * the logarithm of the stress based on the diffusion creep law. + */ + std::pair + compute_log_strain_rate_and_derivative (const double log_stress, + const double pressure, + const double temperature, + const DiffusionCreepParameters creep_parameters) const; + + private: + + /** + * List of diffusion creep prefactors A. + */ + std::vector prefactors_diffusion; + + /** + * List of diffusion creep stress exponents n (usually = 1). + */ + std::vector stress_exponents_diffusion; + + /** + * List of diffusion creep grain size exponents m. + */ + std::vector grain_size_exponents_diffusion; + + /** + * List of diffusion creep activation energies E. + */ + std::vector activation_energies_diffusion; + + /** + * List of diffusion creep activation volumes V. + */ + std::vector activation_volumes_diffusion; + + /** + * Diffusion creep grain size d. + */ + double grain_size; + }; + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/diffusion_dislocation.h.bak b/include/aspect/material_model/rheology/diffusion_dislocation.h.bak new file mode 100644 index 00000000000..49315dda652 --- /dev/null +++ b/include/aspect/material_model/rheology/diffusion_dislocation.h.bak @@ -0,0 +1,139 @@ +/* + Copyright (C) 2011 - 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_diffusion_dislocation_h +#define _aspect_material_model_rheology_diffusion_dislocation_h + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace Rheology + { + /** + * A viscous rheology including diffusion and dislocation creep. + * + * The effective viscosity is defined as the harmonic mean of the two + * effective viscosity functions describing diffusion and dislocation creep: + * @f[ + * v_\text{eff} = \left( \frac{1}{v_\text{eff}^\text{diff}} + \frac{1}{v_\text{eff}^\text{dis}} \right)^{-1} + * @f] + * where + * @f[ + * v_\text{eff}^\text{diff} = A_\text{diff}^{-1} \exp\left(\frac{E_\text{diff} + PV_\text{diff}}{RT}\right), + * @f] + * and + * @f[ + * v_\text{eff}^\text{dis} = A_\text{dis}^{\frac{-1}{n_\text{dis}}} \dot{\varepsilon}^{\frac{1-n}{n}} + * \exp\left(\frac{E_\text{diff} + PV_\text{diff}}{n_\text{dis}RT}\right) + * @f] + * where $\dot{\varepsilon}$ is the second invariant of the strain rate tensor, + * $A_i$ are prefactors where $i$ corresponds to diffusion or dislocation creep, + * $E_i$ are the activation energies, $V_i$ are the activation volumes, + * $\rho_m$ is the mantle density, $R$ is the gas constant, + * $T$ is temperature, and $P$ is pressure. + * + * Rheological parameters can be defined per-compositional field. + * For each material parameter the user supplies a comma delimited list of + * length N+1, where N is the number of compositional fields. The + * additional field corresponds to the value for background mantle. They + * should be ordered ``background, composition1, composition2...'' + * + * The individual output viscosities for each compositional field are + * averaged. The user can choose from a range of options for this + * viscosity averaging. If only one value is given for any of these parameters, + * all compositions are assigned the same value. + * The first value in the list is the value assigned to "background mantle" + * (regions where the sum of the compositional fields is < 1.0). + */ + template + class DiffusionDislocation : public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + DiffusionDislocation(); + + /** + * Calculate the viscosities for each compositional field + * assuming that each composition experiences the same strain rate. + */ + std::vector + calculate_isostrain_viscosities ( const double pressure, + const double temperature, + const SymmetricTensor<2,dim> &strain_rate) const; + + /** + * Compute the viscosity based on the composite viscous creep law, + * averaging over all compositional fields according to their + * volume fractions. + */ + double + compute_viscosity (const double pressure, + const double temperature, + const std::vector &volume_fractions, + const SymmetricTensor<2,dim> &strain_rate) const; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm); + + private: + /** + * Objects for computing viscous creep viscosities. + */ + Rheology::DiffusionCreep diffusion_creep; + Rheology::DislocationCreep dislocation_creep; + + /** + * Defining a minimum strain rate stabilizes the viscosity calculation, + * which involves a division by the strain rate. Units: 1/s. + */ + double min_strain_rate; + double minimum_viscosity; + double maximum_viscosity; + + double log_strain_rate_residual_threshold; + unsigned int stress_max_iteration_number; + + double grain_size; + unsigned int n_chemical_composition_fields; + + MaterialUtilities::CompositionalAveragingOperation viscosity_averaging; + + }; + + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/dislocation_creep.h.bak b/include/aspect/material_model/rheology/dislocation_creep.h.bak new file mode 100644 index 00000000000..a655183450a --- /dev/null +++ b/include/aspect/material_model/rheology/dislocation_creep.h.bak @@ -0,0 +1,155 @@ +/* + Copyright (C) 2019 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_dislocation_creep_h +#define _aspect_material_model_rheology_dislocation_creep_h + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace Rheology + { + /** + * Data structure for dislocation creep parameters. + */ + struct DislocationCreepParameters + { + /** + * The dislocation creep prefactor, activation energy, activation volume + * and stress exponent. + */ + double prefactor; + double activation_energy; + double activation_volume; + double stress_exponent; + + /** + * Constructor. Initializes all values to NaN. + */ + DislocationCreepParameters(); + }; + + template + class DislocationCreep : public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + DislocationCreep(); + + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * If @p expected_n_phases_per_composition points to a vector of + * unsigned integers this is considered the number of phases + * for each compositional field and will be checked against the parsed + * parameters. + */ + void + parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition = nullptr); + + /** + * Compute the creep parameters for the dislocation creep law. + * If @p n_phase_transitions_per_composition points to a vector of + * unsigned integers this is considered the number of phase transitions + * for each compositional field and viscosity will be first computed on + * each phase and then averaged for each compositional field. + */ + const DislocationCreepParameters + compute_creep_parameters (const unsigned int composition, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phase_transitions_per_composition = std::vector()) const; + + /** + * Compute the viscosity based on the dislocation creep law. + * If @p n_phase_transitions_per_composition points to a vector of + * unsigned integers this is considered the number of phase transitions + * for each compositional field and viscosity will be first computed on + * each phase and then averaged for each compositional field. + */ + double + compute_viscosity (const double strain_rate, + const double pressure, + const double temperature, + const unsigned int composition, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phase_transitions_per_composition = std::vector()) const; + + /** + * Compute the strain rate and first stress derivative + * as a function of stress based on the dislocation creep law. + */ + std::pair + compute_strain_rate_and_derivative (const double stress, + const double pressure, + const double temperature, + const DislocationCreepParameters creep_parameters) const; + + /** + * Compute the logarithm of strain rate and first derivative with respect to + * the logarithm of the stress based on the dislocation creep law. + */ + std::pair + compute_log_strain_rate_and_derivative (const double log_stress, + const double pressure, + const double temperature, + const DislocationCreepParameters creep_parameters) const; + + private: + + /** + * List of dislocation creep prefactors A. + */ + std::vector prefactors_dislocation; + + /** + * List of dislocation creep stress exponents n. + */ + std::vector stress_exponents_dislocation; + + /** + * List of dislocation creep activation energies E. + */ + std::vector activation_energies_dislocation; + + /** + * List of dislocation creep activation volumes V. + */ + std::vector activation_volumes_dislocation; + + }; + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/drucker_prager.h.bak b/include/aspect/material_model/rheology/drucker_prager.h.bak new file mode 100644 index 00000000000..d787f070357 --- /dev/null +++ b/include/aspect/material_model/rheology/drucker_prager.h.bak @@ -0,0 +1,161 @@ +/* + Copyright (C) 2019 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_drucker_prager_h +#define _aspect_material_model_rheology_drucker_prager_h + +#include +#include + +#include +#include +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace Rheology + { + /** + * A data structure with all input file parameters relevant to + * Drucker-Prager plasticity. + */ + struct DruckerPragerParameters + { + /** + * Internal friction angle (phi) for the current composition and phase + */ + double angle_internal_friction; + + /** + * Cohesion for the current composition and phase + */ + double cohesion; + + /** + * Limit maximum yield stress from drucker prager yield criterion. + */ + double max_yield_stress; + + /** + * Constructor. Initializes all values to NaN. + */ + DruckerPragerParameters(); + }; + + template + class DruckerPrager : public ::aspect::SimulatorAccess + { + public: + DruckerPrager(); + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * If @p expected_n_phases_per_composition points to a vector of + * unsigned integers, this is considered the number of phases + * for each compositional field (plus possibly a background field) + * and this number will be checked against the parsed parameters. + * + * @param [in] prm The ParameterHandler to read from. + * @param expected_n_phases_per_composition Optional list of number of phases. + */ + void + parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition = nullptr); + + /** + * Compute the parameters for the Drucker Prager plasticity. + * If @p n_phase_transitions_per_composition points to a vector of + * unsigned integers this is considered the number of phase transitions + * for each compositional field and viscosity will be first computed on + * each phase and then averaged for each compositional field. + */ + const DruckerPragerParameters + compute_drucker_prager_parameters (const unsigned int composition, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phase_transitions_per_composition = std::vector()) const; + + /** + * Compute the plastic yield stress based on the Drucker Prager yield criterion. + */ + double + compute_yield_stress (const double cohesion, + const double angle_internal_friction, + const double pressure, + const double max_yield_stress) const; + + /** + * Compute the apparent viscosity using the yield stress and effective strain rate. + * If the non_yielding_viscosity is not infinite + * (i.e., if there are other rheological elements accommodating strain), the returned + * value is the effective composite viscosity, not the pure "plastic" viscosity. + */ + double + compute_viscosity (const double cohesion, + const double angle_internal_friction, + const double pressure, + const double effective_strain_rate, + const double max_yield_stress, + const double non_yielding_viscosity = std::numeric_limits::infinity()) const; + + /** + * Compute the strain rate and first stress derivative + * as a function of stress based on the damped Drucker-Prager flow law. + */ + std::pair + compute_strain_rate_and_derivative (const double stress, + const double pressure, + const DruckerPragerParameters p) const; + + /** + * Compute the derivative of the plastic viscosity with respect to pressure. + */ + double + compute_derivative (const double angle_internal_friction, + const double effective_strain_rate) const; + + private: + + std::vector angles_internal_friction; + std::vector cohesions; + double max_yield_stress; + + /** + * Whether to add a plastic damper in the computation + * of the drucker prager plastic viscosity. + */ + bool use_plastic_damper; + + /** + * Viscosity of a damper used to stabilize plasticity + */ + double damper_viscosity; + }; + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/elasticity.h.bak b/include/aspect/material_model/rheology/elasticity.h.bak new file mode 100644 index 00000000000..f3f3698c8f6 --- /dev/null +++ b/include/aspect/material_model/rheology/elasticity.h.bak @@ -0,0 +1,197 @@ +/* + Copyright (C) 2019 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_elasticity_h +#define _aspect_material_model_rheology_elasticity_h + +#include +#include +#include + +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * Additional output fields for the elastic shear modulus to be added to + * the MaterialModel::MaterialModelOutputs structure and filled in the + * MaterialModel::Interface::evaluate() function. + */ + template + class ElasticAdditionalOutputs : public NamedAdditionalMaterialOutputs + { + public: + explicit ElasticAdditionalOutputs(const unsigned int n_points); + + std::vector get_nth_output(const unsigned int idx) const override; + + /** + * Elastic shear moduli at the evaluation points passed to + * the instance of MaterialModel::Interface::evaluate() that fills + * the current object. + */ + std::vector elastic_shear_moduli; + }; + + + + namespace Rheology + { + template + class Elasticity : public ::aspect::SimulatorAccess + { + public: + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm); + + /** + * Create the additional material model outputs object that contains the + * elastic shear moduli. + */ + void + create_elastic_outputs (MaterialModel::MaterialModelOutputs &out) const; + + /** + * Given the stress of the previous time step in the material model inputs @p in, + * the elastic shear moduli @p average_elastic_shear_moduli a each point, + * and the (viscous) viscosities given in the material model outputs object @p out, + * fill an additional material model outputs objects with the elastic force terms. + */ + void + fill_elastic_outputs (const MaterialModel::MaterialModelInputs &in, + const std::vector &average_elastic_shear_moduli, + MaterialModel::MaterialModelOutputs &out) const; + + /** + * Given the stress of the previous time step in the material model inputs @p in, + * the elastic shear moduli @p average_elastic_shear_moduli a each point, + * and the (viscous) viscosities given in the material model outputs object @p out, + * compute an update to the elastic stresses and use it to fill the reaction terms + * material model output property. + */ + void + fill_reaction_outputs (const MaterialModel::MaterialModelInputs &in, + const std::vector &average_elastic_shear_moduli, + MaterialModel::MaterialModelOutputs &out) const; + + /** + * Return the values of the elastic shear moduli for each composition used in the + * rheology model. + */ + const std::vector & + get_elastic_shear_moduli () const; + + /** + * Calculates the effective elastic viscosity (this is the equivalent viscosity of + * a material which was unstressed at the end of the previous timestep). + */ + double + calculate_elastic_viscosity (const double shear_modulus) const; + + /** + * Given the (viscous or visco-plastic) viscosity and the shear modulus, compute the viscoelastic + * viscosity (eqn 28 in Moresi et al., 2003, J. Comp. Phys.). + */ + double + calculate_viscoelastic_viscosity (const double viscosity, + const double shear_modulus) const; + + /** + * Calculate the effective deviatoric strain rate tensor, + * which equals the true deviatoric strain rate plus + * a fictional strain rate which would arise from stored elastic stresses. + * In ASPECT, this additional strain rate is + * supported by a fictional body force. + * This formulation allows the use of an isotropic effective viscosity + * by ensuring that the resulting strain rate tensor is equal to the + * total current stress tensor multiplied by a scalar. + */ + SymmetricTensor<2,dim> + calculate_viscoelastic_strain_rate (const SymmetricTensor<2,dim> &strain_rate, + const SymmetricTensor<2,dim> &stored_stress, + const double shear_modulus) const; + + /** + * Compute the elastic time step. + */ + double + elastic_timestep () const; + + private: + /** + * Viscosity of a damper used to stabilize elasticity. + * A value of 0 Pas is equivalent to not using a damper. + */ + double elastic_damper_viscosity; + + /** + * Vector for field elastic shear moduli, read from parameter file. + */ + std::vector elastic_shear_moduli; + + /** + * Bool indicating whether to use a fixed material time scale in the + * viscoelastic rheology for all time steps (if true) or to use the + * actual (variable) advection time step of the model (if false). Read + * from parameter file. + */ + bool use_fixed_elastic_time_step; + + /** + * Double for fixed elastic time step value, read from parameter file + */ + double fixed_elastic_time_step; + + /** + * A stabilization factor for the elastic stresses that influences how + * fast elastic stresses adjust to deformation. 1.0 is equivalent to no + * stabilization, and infinity is equivalent to not applying elastic + * stresses at all. The factor is multiplied with the computational + * time step to create a time scale. + */ + double stabilization_time_scale_factor; + + /** + * We cache the evaluator that is necessary to evaluate the old velocity + * gradients. They are required to compute the elastic stresses, but + * are not provided by the material model. + * By caching the evaluator, we can avoid recreating it every time we + * need it. + */ + mutable std::unique_ptr> evaluator; + }; + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/frank_kamenetskii.h.bak b/include/aspect/material_model/rheology/frank_kamenetskii.h.bak new file mode 100644 index 00000000000..a63e3c9d53b --- /dev/null +++ b/include/aspect/material_model/rheology/frank_kamenetskii.h.bak @@ -0,0 +1,98 @@ +/* + Copyright (C) 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_frank_kamenetskii_h +#define _aspect_material_model_rheology_frank_kamenetskii_h + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace Rheology + { + /** + * A class that computes a Frank-Kamenetskii viscosity approximation + * of the form: + * viscosity = A * exp(E * 0.5 * (1.0-(T/ref_T)) + F * (P-ref_P)/(rho*g*h)) + * A: prefactor of viscosity, E: adjusted viscosity ratio, + * ref_T: reference temperature, T: temperature. F: prefactor of pressure, + * ref_P: reference pressure, rho: density, g: gravity, h, model depth + * + * Refer to Noack and Breuer, 2013, GJI. doi: 10.1093/gji/ggt248 Eq. 2.10 for reference. + */ + + template + class FrankKamenetskii : public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + FrankKamenetskii(); + + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm); + + /** + * Compute the viscosity based on the Frank-Kamenetskii approximation. + */ + double + compute_viscosity (const double temperature, + const unsigned int composition, + const double pressure = std::numeric_limits::infinity(), + const double density = std::numeric_limits::infinity(), + const double gravity = std::numeric_limits::infinity()) const; + + private: + /** + * List of Frank-Kamenetskii viscosity ratios (E). + */ + std::vector viscosity_ratios_frank_kamenetskii; + + /** + * List of Frank-Kamenetskii prefactors (A). + */ + std::vector prefactors_frank_kamenetskii; + + /** + * List of Frank-Kamenetskii pressure prefactors (F). + */ + std::vector pressure_prefactors_frank_kamenetskii; + }; + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/friction_models.h.bak b/include/aspect/material_model/rheology/friction_models.h.bak new file mode 100644 index 00000000000..fb23ef023a4 --- /dev/null +++ b/include/aspect/material_model/rheology/friction_models.h.bak @@ -0,0 +1,135 @@ +/* + Copyright (C) 2019 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_friction_models_h +#define _aspect_material_model_rheology_friction_models_h + +#include +#include +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + namespace Rheology + { + /** + * Enumeration for selecting which type of friction dependence to use. + * + * For the type 'static friction', the user-supplied internal angle of friction is used. + * + * For the type 'dynamic friction', the friction angle is rate dependent following + * Equation 13 from \\cite{van_dinther_seismic_2013}. + */ + enum FrictionMechanism + { + static_friction, + dynamic_friction, + function + }; + + template + class FrictionModels : public ::aspect::SimulatorAccess + { + public: + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm); + + /** + * A function that computes the new friction angle when it is not independent. + * Given a volume fraction with the index and a vector of all compositional + * fields, it returns the newly calculated friction angle. + */ + double + compute_friction_angle(const double current_edot_ii, + const unsigned int volume_fraction_index, + const double static_friction_angle, + const Point &position) const; + + /** + * A function that returns the selected type of friction dependence. + */ + FrictionMechanism + get_friction_mechanism () const; + + private: + /** + * Select the mechanism to be used for the friction dependence. + * Possible options: static friction | dynamic friction | function + */ + FrictionMechanism friction_mechanism; + + /** + * Dynamic friction input parameters + */ + + /** + * Dynamic angles of internal friction that are used at high strain rates. + */ + std::vector dynamic_angles_of_internal_friction; + + /** + * The characteristic strain rate value at which the angle of friction is taken as + * the mean of the dynamic and the static angle of friction. When the effective + * strain rate in a cell is very high the dynamic angle of friction is taken, when + * it is very low the static angle of internal friction is chosen. + */ + double dynamic_characteristic_strain_rate; + + /** + * An exponential factor in the equation for the calculation of the friction angle + * to make the transition between static and dynamic friction angle more smooth or + * more step-like. + */ + double dynamic_friction_smoothness_exponent; + + /** + * Parsed functions that specify the friction angle which must be + * given in the input file using the function method. + */ + std::unique_ptr> friction_function; + + /** + * The coordinate representation to evaluate the function for the friction angle. + * Possible choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system_friction_function; + }; + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/peierls_creep.h.bak b/include/aspect/material_model/rheology/peierls_creep.h.bak new file mode 100644 index 00000000000..a63f863ebaf --- /dev/null +++ b/include/aspect/material_model/rheology/peierls_creep.h.bak @@ -0,0 +1,275 @@ +/* + Copyright (C) 2020 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_peierls_creep_h +#define _aspect_material_model_rheology_peierls_creep_h + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace Rheology + { + /** + * Data structure for Peierls creep parameters. + */ + struct PeierlsCreepParameters + { + /** + * The Peierls creep prefactor, stress exponent, activation energy, + * activation volume, Peierls stress, glide parameters p and q + * and fitting parameter, + */ + double prefactor; + double stress_exponent; + double activation_energy; + double activation_volume; + double peierls_stress; + double glide_parameter_p; + double glide_parameter_q; + double fitting_parameter; + double stress_cutoff; + + /** + * Constructor. Initializes all values to NaN. + */ + PeierlsCreepParameters(); + }; + + /** + * Peierls creep is a low temperature, high stress viscous deformation mechanism. + * Crystal deformation occurs through dislocation glide, which requires high stresses. + * It is considered an important deformation mechanism in the lithosphere and subducting + * slabs (Kumamoto et al., 2017, Science Advances). The approximate form of the Peierls + * flow law used here is based on a derivation from Kameyama et al., 1999, Earth and + * Planetary Science Letters. + */ + template + class PeierlsCreep : public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + PeierlsCreep(); + + /** + * Compute the creep parameters for the Peierls creep law. + */ + const PeierlsCreepParameters + compute_creep_parameters (const unsigned int composition, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phases_per_composition = std::vector()) const; + + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + * If @p expected_n_phases_per_composition points to a vector of + * unsigned integers this is considered the number of phases + * for each compositional field and will be checked against the parsed + * parameters. + */ + void + parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition = nullptr); + + /** + * Compute the viscosity based on the approximate Peierls creep flow law. + * If @p n_phase_transitions_per_composition points to a vector of + * unsigned integers this is considered the number of phase transitions + * for each compositional field and viscosity will be first computed on + * each phase and then averaged for each compositional field. + */ + double + compute_approximate_viscosity (const double strain_rate, + const double pressure, + const double temperature, + const unsigned int composition, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phase_transitions_per_composition = std::vector()) const; + + /** + * Compute the viscosity based on the exact Peierls creep flow law. + * If @p n_phase_transitions_per_composition points to a vector of + * unsigned integers this is considered the number of phase transitions + * for each compositional field and viscosity will be first computed on + * each phase and then averaged for each compositional field. + */ + double + compute_exact_viscosity (const double strain_rate, + const double pressure, + const double temperature, + const unsigned int composition, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phase_transitions_per_composition = std::vector()) const; + + /** + * Compute the viscosity based on the selected Peierls creep flow law. + * This function uses either the compute_approximate_viscosity + * or the compute_exact_viscosity function. + * If @p n_phase_transitions_per_composition points to a vector of + * unsigned integers this is considered the number of phase transitions + * for each compositional field and viscosity will be first computed on + * each phase and then averaged for each compositional field. + */ + double + compute_viscosity (const double strain_rate, + const double pressure, + const double temperature, + const unsigned int composition, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phase_transitions_per_composition = std::vector()) const; + + /** + * Compute the strain rate and first stress derivative + * as a function of stress based on the approximate Peierls creep law. + */ + std::pair + compute_approximate_strain_rate_and_derivative (const double stress, + const double pressure, + const double temperature, + const PeierlsCreepParameters creep_parameters) const; + + /** + * Compute the strain rate and first stress derivative + * as a function of stress based on the exact Peierls creep law. + */ + std::pair + compute_exact_strain_rate_and_derivative (const double stress, + const double pressure, + const double temperature, + const PeierlsCreepParameters creep_parameters) const; + + /** + * Compute the natural logarithm of the strain rate norm and its first + * derivative with respect to the natural logarithm of the stress norm + * based on the exact Peierls creep law. + */ + std::pair + compute_exact_log_strain_rate_and_derivative (const double log_stress, + const double pressure, + const double temperature, + const PeierlsCreepParameters creep_parameters) const; + + /** + * Compute the strain rate and first stress derivative + * as a function of stress based on the selected Peierls creep law. + * This function uses either the + * compute_approximate_strain_rate_and_derivative + * or the compute_exact_strain_rate_and_derivative function. + */ + std::pair + compute_strain_rate_and_derivative (const double stress, + const double pressure, + const double temperature, + const PeierlsCreepParameters creep_parameters) const; + + private: + /** + * Enumeration for selecting which type of Peierls creep flow law to use. + * The options are currently "exact" (which requires a Newton-Raphson iteration + * in compute_viscosity) and "viscosity_approximation", which + * uses a simplified expression where the strain rate has a power law dependence + * on the stress (so that the equation can be directly inverted for viscosity). + * This approximation requires specifying one fitting parameter (gamma) to + * obtain the best fit in the expected stress range for a given problem + * (gamma = stress / peierls_stress). The derivation for this approximation + * (derived by Magali Billen) can be found at: + * https://ucdavis.app.box.com/s/cl5mwhkjeabol4otrdukfcdwfvg9me4w/file/705438695737. + */ + enum PeierlsCreepScheme + { + viscosity_approximation, + exact + } peierls_creep_flow_law; + + /** + * List of Peierls creep prefactors (A). + */ + std::vector prefactors; + + /** + * List of Peierls creep stress exponents (n). + */ + std::vector stress_exponents; + + /** + * List of Peierls creep activation energies (E). + */ + std::vector activation_energies; + + /** + * List of Peierls creep activation volumes (V). + */ + std::vector activation_volumes; + + /** + * List of Peierls stresses (sigma_p). + */ + std::vector peierls_stresses; + + /** + * List of Peierls fitting parameters (gamma). + */ + std::vector fitting_parameters; + + /** + * List of the first Peierls parameter related + * to dislocation glide (p). + */ + std::vector glide_parameters_p; + + /** + * List of the second Peierls parameter related + * to dislocation glide (q). + */ + std::vector glide_parameters_q; + + std::vector stress_cutoffs; + + /** + * A parameter determines whether a strict cutoff + * on the stress is applied to the Peierls creep + */ + bool apply_strict_cutoff; + + /** + * Parameters governing the iteration for the exact + * Peierls viscosity. + */ + double strain_rate_residual_threshold; + unsigned int stress_max_iteration_number; + + }; + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/strain_dependent.h.bak b/include/aspect/material_model/rheology/strain_dependent.h.bak new file mode 100644 index 00000000000..3e23c658077 --- /dev/null +++ b/include/aspect/material_model/rheology/strain_dependent.h.bak @@ -0,0 +1,274 @@ +/* + Copyright (C) 2019 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_strain_dependent_h +#define _aspect_material_model_rheology_strain_dependent_h + +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace Rheology + { + /** + * Enumeration for selecting which type of weakening mechanism to use. + * For none, no strain weakening occurs. + * Otherwise, the material can be weakened based on the second + * invariant of the full finite strain tensor, the total accumulated + * strain, or the plastic strain and viscous strain can be tracked + * separately and used only for the corresponding (plastic or viscous) + * part of the viscosity computation. + */ + enum WeakeningMechanism + { + none, + finite_strain_tensor, + total_strain, + plastic_weakening_with_plastic_strain_only, + plastic_weakening_with_total_strain_only, + plastic_weakening_with_plastic_strain_and_viscous_weakening_with_viscous_strain, + viscous_weakening_with_viscous_strain_only + }; + + /** + * Enumeration for selecting which type of healing mechanism to use. + * For the case no healing, no strain healing occurs. + * Otherwise, the strain is healed (reduced) as a function of temperature, + * a user defined healing time scale and additional parameters. + * Future models could consider strain healing formulations that are a function + * of time, deformation rate, or other parameters. + */ + enum HealingMechanism + { + no_healing, + temperature_dependent + }; + + template + class StrainDependent : public ::aspect::SimulatorAccess + { + public: + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm); + + /** + * A function that computes by how much the rheologic parameters change + * if strain weakening is applied. Given a vector @p composition of all + * fields, it returns reduction factors for the cohesion, friction angle + * and the prefactor of the viscous flow law(s) for the compositional + * field with index @p j. The reason all fields are passed is that + * the weakening factors can depend on the values of fields that track + * different measures of previously applied strain. + */ + std::array + compute_strain_weakening_factors(const std::vector &composition, + const unsigned int j) const; + + /** + * @deprecated: Deprecated version of the function of the same + * name described above. + */ + DEAL_II_DEPRECATED + std::array + compute_strain_weakening_factors(const unsigned int j, + const std::vector &composition) const; + + /** + * A function that alters the viscous weakening factor based on the + * temperature field. + */ + std::array + apply_temperature_dependence_to_strain_weakening_factors(const std::array &weakening_factors, + const double temperature, + const unsigned int j) const; + + /** + * A function that computes the strain healing (reduction in accumulated strain) + */ + double + calculate_strain_healing (const MaterialModel::MaterialModelInputs &in, + const unsigned int j) const; + + /** + * A function that computes by how much the cohesion and internal friction + * angle for a given compositional field are weakened under the influence + * of a given strain. + */ + std::pair + calculate_plastic_weakening (const double strain_ii, + const unsigned int j) const; + + /** + * A function that computes by how much the diffusion and dislocation + * prefactors for a given compositional field are weakened under the + * influence of a given strain. + */ + double + calculate_viscous_weakening (const double strain_ii, + const unsigned int j) const; + + /** + * Whether to use the temperature-activated viscous strain weakening. + */ + bool use_temperature_activated_strain_softening; + + /** + * A function that fills the reaction terms for the finite strain tensor in + * MaterialModelOutputs object that is handed over. It assumes the first + * component of the finite strain tensor is named 's11' and all other + * components follow this compositional field. + */ + void compute_finite_strain_reaction_terms (const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const; + /** + * A function that fills the reaction terms for the finite strain invariant(s) in + * MaterialModelOutputs object that is handed over. + */ + void fill_reaction_outputs (const MaterialModel::MaterialModelInputs &in, + const int i, + const double min_strain_rate, + const bool plastic_yielding, + MaterialModel::MaterialModelOutputs &out) const; + + /** + * A function that returns a ComponentMask, which indicates that components + * associated with strain should be excluded during the volume fraction computation. + */ + ComponentMask get_strain_composition_mask() const; + + /** + * A function that returns the selected type of strain weakening mechanism. + */ + WeakeningMechanism + get_weakening_mechanism () const; + + /** + * A function that returns the selected type of strain healing mechanism. + */ + HealingMechanism + get_healing_mechanism () const; + + private: + + WeakeningMechanism weakening_mechanism; + + HealingMechanism healing_mechanism; + + /** + * The start of the strain interval (plastic or total strain) + * within which cohesion and angle of friction should be weakened. + */ + std::vector start_plastic_strain_weakening_intervals; + + /** + * The end of the strain interval (plastic or total strain) + * within which cohesion and angle of friction should be weakened. + */ + std::vector end_plastic_strain_weakening_intervals; + + /** + * The factor specifying the amount of weakening of the + * cohesion over the prescribed strain interval (plastic or total strain). + */ + std::vector cohesion_strain_weakening_factors; + + /** + * The factor specifying the amount of weakening of the + * internal friction angles over the prescribed strain interval + * (plastic or total strain). + */ + std::vector friction_strain_weakening_factors; + + /** + * The start of the strain interval (viscous or total strain) + * within which cohesion and angle of friction should be weakened. + */ + std::vector start_viscous_strain_weakening_intervals; + + /** + * The end of the strain interval (viscous or total strain) + * within which cohesion and angle of friction should be weakened. + */ + std::vector end_viscous_strain_weakening_intervals; + + /** + * The factor specifying the amount of weakening over + * the prescribed strain interval (viscous or total strain). + */ + std::vector viscous_strain_weakening_factors; + + /** + * The four temperatures that parameterize the temperature-activated strain softening. + * These can be different for each compositional field. + * ------ -------- 1 + * \ / + * \ / + * \______/ _ _ _ _ _ viscous_weakening_factor[2] + * + * ----------------------------> T + * T0 T1 T2 T3 + */ + std::vector viscous_strain_weakening_T0; + std::vector viscous_strain_weakening_T1; + std::vector viscous_strain_weakening_T2; + std::vector viscous_strain_weakening_T3; + + /** + * The healing rate used in the temperature dependent strain healing model. + */ + double strain_healing_temperature_dependent_recovery_rate; + + /** + * A prefactor of viscosity used in the strain healing calculation. + */ + double strain_healing_temperature_dependent_prefactor; + + /** + * We cache the evaluators that are necessary to evaluate the velocity + * gradients and compositions. + * By caching the evaluator, we can avoid recreating them + * every time we need it. + */ + mutable std::unique_ptr> evaluator; + mutable std::vector>> composition_evaluators; + }; + } + } +} +#endif diff --git a/include/aspect/material_model/rheology/visco_plastic.h.bak b/include/aspect/material_model/rheology/visco_plastic.h.bak new file mode 100644 index 00000000000..e4f6b171102 --- /dev/null +++ b/include/aspect/material_model/rheology/visco_plastic.h.bak @@ -0,0 +1,339 @@ +/* + Copyright (C) 2020 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_rheology_visco_plastic_h +#define _aspect_material_model_rheology_visco_plastic_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * Additional output fields for the plastic parameters weakened (or hardened) + * by strain to be added to the MaterialModel::MaterialModelOutputs structure + * and filled in the MaterialModel::Interface::evaluate() function. + */ + template + class PlasticAdditionalOutputs : public NamedAdditionalMaterialOutputs + { + public: + PlasticAdditionalOutputs(const unsigned int n_points); + + std::vector get_nth_output(const unsigned int idx) const override; + + /** + * Cohesions at the evaluation points passed to + * the instance of MaterialModel::Interface::evaluate() that fills + * the current object. + */ + std::vector cohesions; + + /** + * Internal angles of friction at the evaluation points passed to + * the instance of MaterialModel::Interface::evaluate() that fills + * the current object. + */ + std::vector friction_angles; + + /** + * The plastic yield stress. + */ + std::vector yield_stresses; + + /** + * The area where the viscous stress exceeds the plastic yield stress, + * and viscosity is rescaled back to the yield envelope. + */ + std::vector yielding; + + }; + + /** + * A data structure with the output of calculate_isostrain_viscosities. + */ + struct IsostrainViscosities + { + /** + * The composition viscosity. + */ + std::vector composition_viscosities; + + /** + * The composition yielding. + */ + std::vector composition_yielding; + + /** + * The current friction angle. + */ + std::vector current_friction_angles; + + /** + * The current cohesion. + */ + std::vector current_cohesions; + }; + + namespace Rheology + { + + template + class ViscoPlastic : public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + ViscoPlastic(); + + /** + * This function calculates viscosities assuming that all the compositional fields + * experience the same strain rate (isostrain). + * If @p n_phase_transitions_per_composition points to a vector of + * unsigned integers this is considered the number of phase transitions + * for each compositional field and viscosity will be first computed on + * each phase and then averaged for each compositional field. + */ + IsostrainViscosities + calculate_isostrain_viscosities ( const MaterialModel::MaterialModelInputs &in, + const unsigned int i, + const std::vector &volume_fractions, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phase_transitions_per_composition = + std::vector()) const; + + /** + * A function that fills the viscosity derivatives in the + * MaterialModelOutputs object that is handed over, if they exist. + * Does nothing otherwise. + * If @p n_phase_transitions_per_composition points to a vector of + * unsigned integers this is considered the number of phase transitions + * for each compositional field and viscosity will be first computed on + * each phase and then averaged for each compositional field. + */ + void compute_viscosity_derivatives(const unsigned int point_index, + const std::vector &volume_fractions, + const std::vector &composition_viscosities, + const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out, + const std::vector &phase_function_values = std::vector(), + const std::vector &n_phase_transitions_per_composition = + std::vector()) const; + + /** + * A function that returns a ComponentMask that represents all compositional + * fields that should be considered 'volumetric', that is representing a + * physical proportion of the material, e.g. volume fraction of peridotite + * (as opposed to non-volumetric quantities like the amount of finite-strain). + */ + ComponentMask get_volumetric_composition_mask() const; + + /** + * Declare the parameters this function takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * If @p expected_n_phases_per_composition points to a vector of + * unsigned integers this is considered the number of phases + * for each compositional field and will be checked against the parsed + * parameters. + */ + void + parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition = nullptr); + + /** + * Create the additional material model outputs object that contains the + * plastic outputs. + */ + void + create_plastic_outputs (MaterialModel::MaterialModelOutputs &out) const; + + /** + * A function that fills the plastic additional output in the + * MaterialModelOutputs object that is handed over, if it exists. + * Does nothing otherwise. + */ + void fill_plastic_outputs(const unsigned int point_index, + const std::vector &volume_fractions, + const bool plastic_yielding, + const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out, + const IsostrainViscosities &isostrain_viscosities) const; + + /** + * Minimum strain rate used to stabilize the strain rate dependent rheology. + */ + double min_strain_rate; + + /** + * Enumeration for selecting which viscosity averaging scheme to use. + */ + MaterialUtilities::CompositionalAveragingOperation viscosity_averaging; + + /** + * Object for computing the strain dependence of the rheology model. + */ + Rheology::StrainDependent strain_rheology; + + /** + * Object for computing the friction dependence of the rheology model. + */ + Rheology::FrictionModels friction_models; + + /** + * Object for computing viscoelastic viscosities and stresses. + */ + Rheology::Elasticity elastic_rheology; + + + private: + + /** + * Reference strain rate for the first non-linear iteration + * in the first time step. + */ + double ref_strain_rate; + + /** + * Minimum and maximum viscosities used to improve the + * stability of the rheology model. + * These parameters contain one value per composition and phase (potentially the same value). + */ + std::vector minimum_viscosity; + std::vector maximum_viscosity; + + /** + * Enumeration for selecting which type of viscous flow law to use. + * Select between diffusion, dislocation, frank_kamenetskii or composite. + */ + enum ViscosityScheme + { + diffusion, + dislocation, + frank_kamenetskii, + composite + } viscous_flow_law; + + /** + * Enumeration for selecting which type of yield mechanism to use. + * Select between Drucker Prager and stress limiter. + */ + enum YieldScheme + { + stress_limiter, + drucker_prager + } yield_mechanism; + + /** + * Whether to allow negative pressures to be used in the computation + * of plastic yield stresses and viscosities. If false, the minimum + * pressure in the plasticity formulation will be set to zero. + */ + bool allow_negative_pressures_in_plasticity; + + /** + * Whether to use the adiabatic pressure instead of the full pressure (default) + * when calculating creep (diffusion, dislocation, and peierls) viscosity. + * This may be helpful in models where the full pressure has an unusually + * large negative value arising from large negative dynamic pressure, + * resulting in solver convergence issue and in some cases a viscosity + * of zero. + */ + bool use_adiabatic_pressure_in_creep; + + /** + * List of exponents controlling the behavior of the stress limiter + * yielding mechanism. + */ + std::vector exponents_stress_limiter; + + /** + * Temperature gradient added to temperature used in the flow law. + */ + double adiabatic_temperature_gradient_for_viscosity; + + /** + * Objects for computing viscous creep viscosities. + */ + Rheology::DiffusionCreep diffusion_creep; + Rheology::DislocationCreep dislocation_creep; + std::unique_ptr> frank_kamenetskii_rheology; + + /** + * Whether to include Peierls creep in the constitutive formulation. + */ + bool use_peierls_creep; + + /** + * Object for computing Peierls creep viscosities. + */ + std::unique_ptr> peierls_creep; + + /** + * Object for computing the viscosity multiplied by a constant prefactor. + * This multiplication step is done just prior to calculating the effective + * viscoelastic viscosity or plastic viscosity. + */ + Rheology::ConstantViscosityPrefactors constant_viscosity_prefactors; + + /** + * Object for computing the viscosity multiplied by a given prefactor term. + */ + Rheology::CompositionalViscosityPrefactors compositional_viscosity_prefactors; + + /* + * Object for computing plastic stresses, viscosities, and additional outputs + */ + Rheology::DruckerPrager drucker_prager_plasticity; + + /* + * Input parameters for the drucker prager plasticity. + */ + Rheology::DruckerPragerParameters drucker_prager_parameters; + + }; + } + } +} +#endif diff --git a/include/aspect/material_model/simple.h.bak b/include/aspect/material_model/simple.h.bak new file mode 100644 index 00000000000..e266b0d0302 --- /dev/null +++ b/include/aspect/material_model/simple.h.bak @@ -0,0 +1,109 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_simple_h +#define _aspect_material_model_simple_h + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that consists of globally constant values for all + * material parameters except density and viscosity. + * + * The model is considered incompressible, following the definition + * described in Interface::is_compressible. This is essentially the + * material model used in the step-32 tutorial program. + * + * @ingroup MaterialModels + */ + template + class Simple : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @} + */ + + private: + double reference_T; + double eta; + double composition_viscosity_prefactor; + double thermal_viscosity_exponent; + double maximum_thermal_prefactor; + double minimum_thermal_prefactor; + + /** + * The thermal conductivity. + */ + double k_value; + + EquationOfState::LinearizedIncompressible equation_of_state; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/simple_compressible.h.bak b/include/aspect/material_model/simple_compressible.h.bak new file mode 100644 index 00000000000..1658b3b147c --- /dev/null +++ b/include/aspect/material_model/simple_compressible.h.bak @@ -0,0 +1,137 @@ +/* + Copyright (C) 2014 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_simple_compressible_h +#define _aspect_material_model_simple_compressible_h + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that consists of globally constant values for the + * viscosity, thermal conductivity, thermal expansivity + * and compressibility. The density decays linearly with the + * temperature and increases exponentially with pressure. + * + * The formulation for the density assumes that the compressibility + * provided by the user is the adiabatic compressibility ($\beta_S$). + * The thermal expansivity and isentropic compressibility implied by + * the pressure and temperature dependence are equal to the + * user-defined constant values only along the reference isentrope, and + * there is also an implicit pressure dependence to the heat capacity + * $C_p$ via Maxwell's relations. + * + * The model is considered incompressible or compressible, depending on + * the compressibility. + * + * @ingroup MaterialModels + */ + template + class SimpleCompressible : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate material properties. + */ + void evaluate(const MaterialModelInputs &in, + MaterialModelOutputs &out) const override; + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @} + */ + + private: + /** + * The reference density + */ + double reference_rho; + + /** + * The constant thermal expansivity + */ + double thermal_alpha; + + /** + * The constant specific heat + */ + double reference_specific_heat; + + /** + * The constant compressibility. + */ + double reference_compressibility; + + /** + * The constant thermal conductivity. + */ + double k_value; + + /** + * The constant rheology model. + */ + Rheology::ConstantViscosity constant_rheology; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/simpler.h.bak b/include/aspect/material_model/simpler.h.bak new file mode 100644 index 00000000000..f2f89c8aa02 --- /dev/null +++ b/include/aspect/material_model/simpler.h.bak @@ -0,0 +1,86 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_simpler_h +#define _aspect_material_model_simpler_h + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model that consists of globally constant values for all + * material parameters except the density, which depends linearly on the + * temperature. The model is considered incompressible. + * + * This material model implements what the "Simple" model was originally + * intended to do, before it got too complicated. + * + * @ingroup MaterialModels + */ + template + class Simpler : public Interface + { + public: + + bool is_compressible () const override; + + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @} + */ + + private: + double k_value; + + Rheology::ConstantViscosity constant_rheology; + EquationOfState::LinearizedIncompressible equation_of_state; + }; + + } +} + +#endif diff --git a/include/aspect/material_model/steinberger.h.bak b/include/aspect/material_model/steinberger.h.bak new file mode 100644 index 00000000000..f57aa7747be --- /dev/null +++ b/include/aspect/material_model/steinberger.h.bak @@ -0,0 +1,335 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_steinberger_h +#define _aspect_material_model_steinberger_h + +#include +#include + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + namespace internal + { + /** + * A class that reads in a text file that contains the + * temperature-dependency of viscosity for a set of equidistant depth + * layers. See + * the data/material-model/steinberger directory for an example data + * file. + * The class can return the value for a given depth. + */ + class LateralViscosityLookup + { + public: + /** + * Read in a file. + */ + LateralViscosityLookup(const std::string &filename, + const MPI_Comm comm); + + /** + * Returns a temperature-dependency for a given depth. + */ + double lateral_viscosity(double depth) const; + + /** + * Number of depth slices of the read file. + */ + int get_nslices() const; + private: + /** + * Stored values + */ + std::vector values; + + /** + * Stored bounds an depths. + */ + double min_depth; + double delta_depth; + double max_depth; + }; + + /** + * A class that reads in a text file that contains the + * viscosity for a set of equidistant depth layers. See + * the data/material-model/steinberger directory for an example data + * file. + * The class can return the value for a given depth. + */ + class RadialViscosityLookup + { + public: + /** + * Constructor. Reads in the given file. + */ + RadialViscosityLookup(const std::string &filename, + const MPI_Comm comm); + + /** + * Return the viscosity for a given depth. + */ + double radial_viscosity(double depth) const; + + private: + /** + * Stored data values. + */ + std::vector values; + + /** + * Depth bounds for the read in values. + */ + double min_depth; + double delta_depth; + double max_depth; + }; + } + + /** + * A variable viscosity material model that reads the essential values of + * coefficients from tables in input files. + * + * The viscosity of this model is based on the paper + * Steinberger & Calderwood 2006: "Models of large-scale viscous flow in the + * Earth's mantle with constraints from mineral physics and surface + * observations". The thermal conductivity is constant and the other + * parameters are provided via lookup tables from the software PERPLEX. + * + * @ingroup MaterialModels + */ + template + class Steinberger: public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. Loads the material data and sets up + * pointers. + */ + void + initialize () override; + + /** + * Called at the beginning of each time step and allows the material + * model to update internal data structures. + */ + void update() override; + + /** + * @name Physical parameters used in the basic equations + * @{ + */ + virtual double viscosity (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const SymmetricTensor<2,dim> &strain_rate, + const Point &position) const; + /** + * @} + */ + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + */ + bool is_compressible () const override; + /** + * @} + */ + + /** + * Function to compute the material properties in @p out given the + * inputs in @p in. + */ + void + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + + private: + /** + * Compute the pressure- and temperature-dependent thermal + * conductivity either as a constant value, or based on the + * equation given in Stackhouse et al., 2015: First-principles + * calculations of the lattice thermal conductivity of the + * lower mantle, or based on the equation given in Tosi et al., + * 2013: Mantle dynamics with pressure- and temperature-dependent + * thermal expansivity and conductivity. + */ + double thermal_conductivity (const double temperature, + const double pressure, + const Point &position) const; + + /** + * Whether the compositional fields representing mass fractions + * should be normalized to one when computing their fractions + * (if false), or whether there is an additional composition + * (the background field) that is not represented by a + * compositional field, and makes up the remaining fraction of + * material if the compositional fields add up to less than one + * at any given location (if true). + */ + bool has_background_field; + + /** + * Pointer to a composition mask, which is meant to be filled with + * one entry per compositional field that determines if this + * field is considered to represent a mass fractions (if the entry + * is set to true) or not (if set to false). This is needed for + * averaging of material properties. + */ + std::unique_ptr composition_mask; + + /** + * The thermodynamic lookup equation of state. + */ + EquationOfState::ThermodynamicTableLookup equation_of_state; + + /** + * Boolean describing whether to use the lateral average temperature + * for computing the viscosity, rather than the temperature + * on the reference adiabat. + */ + bool use_lateral_average_temperature; + + /** + * The value of the thermal conductivity if a constant thermal + * conductivity is used for the whole domain. + */ + double thermal_conductivity_value; + + /** + * Enumeration for selecting which type of conductivity law to use. + */ + enum ConductivityFormulation + { + constant, + p_T_dependent + } conductivity_formulation; + + /** + * Parameters for the temperature- and pressure dependence of the + * thermal conductivity. + */ + std::vector conductivity_transition_depths; + std::vector reference_thermal_conductivities; + std::vector conductivity_pressure_dependencies; + std::vector conductivity_reference_temperatures; + std::vector conductivity_exponents; + std::vector saturation_scaling; + double maximum_conductivity; + + /** + * Compositional prefactors with which to multiply the reference viscosity. + * Volume fractions are used to weight the prefactors according to the + * assigned viscosity averaging scheme. + */ + std::vector viscosity_prefactors; + MaterialUtilities::CompositionalAveragingOperation viscosity_averaging_scheme; + + /** + * Information about lateral temperature averages. + */ + std::vector average_temperature; + unsigned int n_lateral_slices; + + /** + * Minimum and maximum allowed viscosity, as well as the maximum allowed + * viscosity variation compared to the average radial viscosity. + */ + double min_eta; + double max_eta; + double max_lateral_eta_variation; + + /** + * Information about the location of data files. + */ + std::string data_directory; + std::string radial_viscosity_file_name; + std::string lateral_viscosity_file_name; + + /** + * Pointer to an object that reads and processes data for the lateral + * temperature dependency of viscosity. + */ + std::unique_ptr lateral_viscosity_lookup; + + /** + * Pointer to an object that reads and processes data for the radial + * viscosity profile. + */ + std::unique_ptr radial_viscosity_lookup; + + /** + * A function that fills the prescribed additional outputs in the + * MaterialModelOutputs object that is handed over, if it exists, + * in this case, densities for the projected density approximation. + * Does nothing otherwise. + */ + void fill_prescribed_outputs (const unsigned int i, + const std::vector &volume_fractions, + const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const; + + }; + } +} + +#endif diff --git a/include/aspect/material_model/utilities.h.bak b/include/aspect/material_model/utilities.h.bak new file mode 100644 index 00000000000..c65828f7b19 --- /dev/null +++ b/include/aspect/material_model/utilities.h.bak @@ -0,0 +1,680 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_utilities_h +#define _aspect_material_model_utilities_h + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + template class SimulatorAccess; + namespace Utilities + { + using namespace dealii; + using namespace dealii::Utilities; + + template + class StructuredDataLookup; + } + namespace MaterialModel + { + using namespace dealii; + + template class MaterialModelOutputs; + template struct EquationOfStateOutputs; + + /** + * A namespace in which we define utility functions that + * might be used in many different places in the material + * model to prevent code duplication. + */ + namespace MaterialUtilities + { + namespace Lookup + { + /** + * A base class that can be used to look up material data from an external + * data source (e.g. a table in a file). The class consists of data members + * and functions to access this data, but it does not contain the functions + * to read this data, which has to be implemented in a derived class. + */ + class MaterialLookup + { + public: + + double + specific_heat(const double temperature, + const double pressure) const; + + double + density(const double temperature, + const double pressure) const; + + double + thermal_expansivity(const double temperature, + const double pressure) const; + + double + seismic_Vp(const double temperature, + const double pressure) const; + + double + seismic_Vs(const double temperature, + const double pressure) const; + + double + enthalpy(const double temperature, + const double pressure) const; + + /** + * Computes the derivative of enthalpy for temperature, using the + * resolution of the read-in table to compute a finite-difference + * approximation of the derivative. + */ + double + dHdT (const double temperature, + const double pressure) const; + + /** + * Computes the derivative of enthalpy for pressure, using the + * resolution of the read-in table to compute a finite-difference + * approximation of the derivative. + */ + double + dHdp (const double temperature, + const double pressure) const; + + /** + * Compute the enthalpy derivatives for temperature and pressure + * given a set of temperature and pressure points, which will be + * used as support points for the finite difference scheme. This + * is useful to not 'miss' phase transitions that are not resolved in + * the dHdT and dHdp functions. The third argument represents + * the number of substeps taken to compute this average. A number + * larger than one means the temperature-pressure range that is spanned + * by the first two input arguments is separated into @p n_substeps + * equally spaced pressure-temperature steps, the derivatives are + * computed for each substep and then averaged. + */ + std::array,2> + enthalpy_derivatives(const std::vector &temperatures, + const std::vector &pressures, + const unsigned int n_substeps = 1) const; + + double + dRhodp (const double temperature, + const double pressure) const; + + /** + * Returns the index that indicates the phase with the largest volume + * fraction at a given temperature and pressure. + */ + unsigned int + dominant_phase (const double temperature, + const double pressure) const; + + /** + * Returns whether a lookup has a column that indicates which is the + * phase with the largest volume fraction is this material. + */ + bool + has_dominant_phase() const; + + /** + * Returns a vector of all the column names in the lookup file + * that start with the character string vol_fraction_ + */ + std::vector + phase_volume_column_names() const; + + /** + * Returns the volume fraction of the phase_idth phase + * at a given temperature and pressure. + */ + double + phase_volume_fraction(const int phase_id, + const double temperature, + const double pressure) const; + + /** + * Returns the size of the data tables in pressure (first entry) + * and temperature (second entry) dimensions. + */ + std::array + get_pT_steps() const; + + + /** + * Get the list of names of all of the dominant phases + * in a given lookup table as given by the phase column. + * The names of the phases are stored in the order they + * first appear in the table. + */ + const std::vector & + get_dominant_phase_names() const; + + protected: + /** + * Access that data value of the property that is stored in table + * @p values at pressure @p pressure and temperature @p temperature. + * @p interpol controls whether to perform linear interpolation + * between the closest data points, or simply use the closest point + * value. + */ + double + value (const double temperature, + const double pressure, + const Table<2, double> &values, + const bool interpol) const; + + /** + * Access that data value of the property that is stored in table + * @p values at pressure @p pressure and temperature @p temperature + * using the closest point value. + */ + unsigned int + value (const double temperature, + const double pressure, + const Table<2, unsigned int> &values) const; + + /** + * Find the position in a data table given a temperature. + */ + double get_nT(const double temperature) const; + + /** + * Find the position in a data table given a pressure. + */ + double get_np(const double pressure) const; + + dealii::Table<2,double> density_values; + dealii::Table<2,double> thermal_expansivity_values; + dealii::Table<2,double> specific_heat_values; + dealii::Table<2,double> vp_values; + dealii::Table<2,double> vs_values; + dealii::Table<2,double> enthalpy_values; + dealii::Table<2,unsigned int> dominant_phase_indices; + + /** + * The vector of column names corresponding to each phase, + * and a vector of tables containing the volume fractions of + * each phase at a given temperature and pressure. + * The ordering of both vectors is the same. + */ + std::vector phase_column_names; + std::vector> phase_volume_fractions; + + double delta_press; + double min_press; + double max_press; + double delta_temp; + double min_temp; + double max_temp; + unsigned int n_temperature; + unsigned int n_pressure; + unsigned int n_phases; + unsigned int n_columns; + bool interpolation; + bool has_dominant_phase_column; + std::vector dominant_phase_names; + }; + + /** + * An implementation of the above base class that reads in files created + * by the HeFESTo software. + */ + class HeFESToReader : public MaterialLookup + { + public: + HeFESToReader(const std::string &material_filename, + const std::string &derivatives_filename, + const bool interpol, + const MPI_Comm comm); + }; + + /** + * An implementation of the above base class that reads in files created + * by the Perplex software. + */ + class PerplexReader : public MaterialLookup + { + public: + PerplexReader(const std::string &filename, + const bool interpol, + const MPI_Comm comm); + }; + + /** + * This class reads in an entropy-pressure material table and looks up material + * properties for the given entropy and pressure. + */ + class EntropyReader + { + public: + + /** + * Read the table. + */ + void + initialize(const MPI_Comm comm, + const std::string &data_directory, + const std::string &material_file_name); + + /** + * Returns the specific heat for a given entropy and pressure. + */ + double + specific_heat(const double entropy, + const double pressure) const; + + /** + * Returns the density for a given entropy and pressure. + */ + double + density(const double entropy, + const double pressure) const; + + /** + * Returns the thermal_expansivity for a given entropy and pressure. + */ + double + thermal_expansivity(const double entropy, + const double pressure) const; + + /** + * Returns the temperature for a given entropy and pressure. + */ + double + temperature(const double entropy, + const double pressure) const; + + /** + * Returns the seismic p wave velocity for a given entropy and pressure. + */ + double + seismic_vp(const double entropy, + const double pressure) const; + + /** + * Returns the seismic s wave velocity for a given entropy and pressure. + */ + double + seismic_vs(const double entropy, + const double pressure) const; + + /** + * Returns density gradient for a given entropy and pressure. + */ + Tensor<1, 2> + density_gradient(const double entropy, + const double pressure) const; + + private: + /** + * The StructuredDataLookup object that stores the material data. + */ + std::unique_ptr> material_lookup; + }; + } + + /** + * For multicomponent material models: Given a vector of compositional + * field values of length N, of which M indices correspond to mass or + * volume fractions, this function returns a vector of fractions + * of length M+1, corresponding to the fraction of a ``background + * material'' as the first entry, and fractions for each of the input + * fields as the following entries. The returned vector will sum to one. + * If the sum of the compositional_fields is greater than + * one, we assume that there is no background field (i.e., that field value + * is zero). Otherwise, the difference between the sum of the compositional + * fields and 1.0 is assumed to be the amount of the background field. + * This function makes no assumptions about the units of the + * compositional field values; for example, they could correspond to + * mass or volume fractions. + */ + std::vector + compute_only_composition_fractions(const std::vector &compositional_fields, + const std::vector &indices_to_use); + + /** + * For multicomponent material models: Given a vector of compositional + * field values of length N, this function returns a vector of fractions + * of length N+1, corresponding to the fraction of a ``background + * material'' as the first entry, and fractions for each of the input + * fields as the following entries. The returned vector will sum to one. + * If the sum of the compositional_fields is greater than + * one, we assume that there is no background field (i.e., that field value + * is zero). Otherwise, the difference between the sum of the compositional + * fields and 1.0 is assumed to be the amount of the background field. + * Optionally, one can input a component mask that determines which of the + * compositional fields to use during the computation (e.g. because + * some fields contain unrelated quantities (like strain, + * porosity, or trace elements). By default, all fields are included. + * This function makes no assumptions about the units of the + * compositional field values; for example, they could correspond to + * mass or volume fractions. + */ + std::vector + compute_composition_fractions(const std::vector &compositional_fields, + const ComponentMask &field_mask = ComponentMask()); + + /** + * See compute_composition_fractions() for the documentation of this function. + * @deprecated: This function is deprecated. Please use compute_composition_fractions() instead. + */ + DEAL_II_DEPRECATED + std::vector + compute_volume_fractions(const std::vector &compositional_fields, + const ComponentMask &field_mask = ComponentMask()); + + /** + * Given a vector of component masses, + * and another of the corresponding densities, calculate the volumes + * of each component. If return_as_fraction is true, the returned vector + * will sum to one. If the input vectors have a length of one, the + * returned volume fraction is one. + */ + std::vector + compute_volumes_from_masses(const std::vector &masses, + const std::vector &densities, + const bool return_as_fraction); + + /** + * For multicomponent material models: + * Enumeration for selecting which averaging scheme to use when + * averaging the properties of different compositional fields. + * Select between harmonic, arithmetic, geometric, and + * maximum_composition. The max composition scheme simply uses the + * viscosity of whichever field has the highest volume fraction. + */ + enum CompositionalAveragingOperation + { + harmonic, + arithmetic, + geometric, + maximum_composition + }; + + + + /** + * Read the compositional averaging operation from the parameter file, + * using the parameter name given in @p parameter_name, and return the + * enum that corresponds to this operation. + */ + CompositionalAveragingOperation + parse_compositional_averaging_operation (const std::string ¶meter_name, + const ParameterHandler &prm); + + + + /** + * For multicomponent material models: + * Material models compute output quantities such as the viscosity, the + * density, etc. For some models, these values depend strongly on the + * composition, and more than one compositional field might have nonzero + * values at a given quadrature point. This means that properties have to + * be averaged based on the fractions of each compositional field present. + * This function performs this type of averaging. The averaging is based + * on the choice in @p average_type. Averaging is conducted over the + * compositional fields given in @p volume_fractions. This means that + * @p volume_fractions and @p parameter_values have to have the same size, + * which would typically be the number of compositional fields used in the + * simulation (with the potential addition of a background field, in case + * the composition does not add up to 1). However, one might not want to + * average over all fields, as in some cases compositional fields do not + * represent a rock type, but other tracked quantities like the finite + * strain, so the implementation is independent of the number of entries in + * @p volume_fractions. + */ + double average_value (const std::vector &volume_fractions, + const std::vector ¶meter_values, + const CompositionalAveragingOperation &average_type); + + + + /** + * This function computes averages of multicomponent thermodynamic properties + * that are stored in a vector of EquationOfStateOutputs. + * Each @p eos_outputs contains the thermodynamic properties for + * all materials at a given evaluation point. + * The averaged properties are: + * density, isothermal compressibility, thermal_expansivity, + * the specific entropy derivatives with respect to pressure and temperature + * and the specific heat capacity. The first three of these properties + * are averaged by volume fraction, and the second three + * (the specific properties) are averaged by mass fraction. + * These averages are used to fill the corresponding attributes of + * a MaterialModelOutputs object. + */ + template + void + fill_averaged_equation_of_state_outputs(const EquationOfStateOutputs &eos_outputs, + const std::vector &mass_fractions, + const std::vector &volume_fractions, + const unsigned int i, + MaterialModelOutputs &out); + + + + /** + * Utilities for material models with multiple phases + */ + namespace PhaseUtilities + { + /** + * Enumeration for selecting which averaging scheme to use when + * averaging the properties of different phases. + * Select between arithmetic and logarithmic. + */ + enum PhaseAveragingOperation + { + arithmetic, + logarithmic + }; + } + + /** + * Material models compute output quantities such as the viscosity, the + * density, etc. For some models, these values may depend on the phase in + * addition to the composition, and more than one phase field might have + * nonzero values at a given quadrature point. This means that properties + * for each composition have to be averaged based on the fractions of each + * phase field present. This function performs this type of averaging. + * The averaging is based on the choice in @p operation. Averaging is conducted + * over the phase functions given in @p phase_function_values, with + * @p parameter_values containing values of all individual phases. Unlike the average_value + * function defined for compositions, averaging in this function is calculated based + * on phase functions and the change of variables on the trajectory of phase boundaries. + * Thus on a single phase boundary, values of variables change gradually from one phase + * to the other. The values of the phase function used to average the properties varies + * between 0 and 1. + */ + double phase_average_value (const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition, + const std::vector ¶meter_values, + const unsigned int composition_index, + const PhaseUtilities::PhaseAveragingOperation operation = PhaseUtilities::arithmetic); + + + + /** + * A data structure with all inputs for the + * PhaseFunction::phase_function_value() and + * PhaseFunction::phase_function_derivative() method. + */ + template + struct PhaseFunctionInputs + { + /** + * Constructor. Initializes the various variables of this + * structure with the input values. + */ + PhaseFunctionInputs(const double temperature, + const double pressure, + const double depth, + const double pressure_depth_derivative, + const unsigned int phase_index); + + double temperature; + double pressure; + double depth; + double pressure_depth_derivative; + + /** + * This parameter determines which phase function of all the stored + * functions to compute. Phase functions are numbered consecutively, + * starting at 0 and the interpretation of their output is up to the + * calling side. For example the first phase function could be used to + * indicate a viscosity jump in the first compositional field, + * while the second function indicates a density jump in all + * compositions. None of this is known to the PhaseFunction object, + * which only has information that there are two phase functions + * and what their properties are. + */ + unsigned int phase_index; + }; + + /** + * A class that bundles functionality to compute the values and + * derivatives of phase functions. The class can handle arbitrary + * numbers of phase transitions, but the calling side has to determine + * how to use the return values of this object (e.g. in terms of + * density or viscosity). + */ + template + class PhaseFunction: public ::aspect::SimulatorAccess + { + public: + /** + * Percentage of material that has already undergone the phase + * transition to the higher-pressure material (this is done + * individually for each transition and summed up in the end) + */ + double compute_value (const PhaseFunctionInputs &in) const; + + /** + * Return the derivative of the phase function with respect to + * pressure. + */ + double compute_derivative (const PhaseFunctionInputs &in) const; + + /** + * Return the total number of phase transitions. + */ + unsigned int n_phase_transitions () const; + + /** + * Return the total number of phases. + */ + unsigned int n_phases () const; + + /** + * Return the Clapeyron slope (dp/dT of the transition) for + * phase transition number @p phase_index. + */ + double get_transition_slope (const unsigned int phase_index) const; + + /** + * Return the depth for phase transition number @p phase_index. + */ + double get_transition_depth (const unsigned int phase_index) const; + + /** + * Return how many phase transitions there are for each composition. + */ + const std::vector & + n_phase_transitions_for_each_composition () const; + + /** + * Return how many phases there are for each composition. + */ + const std::vector & + n_phases_for_each_composition () const; + + /** + * Declare the parameters this class takes through input files. + * Note that this class does not declare its own subsection, + * i.e. the parameters will be declared in the subsection that + * was active before calling this function. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * Note that this class does not declare its own subsection, + * i.e. the parameters will be parsed from the subsection that + * was active before calling this function. + */ + void + parse_parameters (ParameterHandler &prm); + + + private: + /** + * List of depth (or pressure), width, Clapeyron slopes and + * limits of temperature for the different phase transitions + */ + std::vector transition_depths; + std::vector transition_pressures; + std::vector transition_temperatures; + std::vector transition_widths; + std::vector transition_pressure_widths; + std::vector transition_slopes; + std::vector transition_temperature_upper_limits; + std::vector transition_temperature_lower_limits; + + /** + * Whether to define the phase transitions based on depth, or pressure. + * Based on this parameter, either transition_depths and transition_width, + * or transition_pressures and transition_pressure_widths determine the + * depth of the phase transition. + */ + bool use_depth_instead_of_pressure; + + /** + * A vector that stores how many phase transitions there are for each compositional field. + */ + std::unique_ptr> n_phase_transitions_per_composition; + + /** + * A vector that stores how many phases there are for each compositional field. + */ + std::vector n_phases_per_composition; + + /** + * Total number of phases over all compositional fields + */ + unsigned int n_phases_total; + }; + } + } +} + + +#endif diff --git a/include/aspect/material_model/visco_plastic.h.bak b/include/aspect/material_model/visco_plastic.h.bak new file mode 100644 index 00000000000..9ba9bf9fa67 --- /dev/null +++ b/include/aspect/material_model/visco_plastic.h.bak @@ -0,0 +1,283 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_material_model_visco_plastic_h +#define _aspect_material_model_visco_plastic_h + +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * A material model combining viscous and plastic deformation, with + * the option to also include viscoelastic deformation. + * + * Viscous deformation is defined by a viscous flow law describing + * dislocation and diffusion creep: + * $ v = \frac{1}{2} A^{-\frac{1}{n}} d^{\frac{m}{n}} + * \dot{\varepsilon}_{ii}^{\frac{1-n}{n}} + * \exp\left(\frac{E + PV}{nRT}\right) $ + * where + * where $A$ is the prefactor, $n$ is the stress exponent, + * $\dot{\varepsilon}_{ii}$ is the square root of the deviatoric + * strain rate tensor second invariant, $d$ is grain size, + * $m$ is the grain size exponent, $E$ is activation energy, + * $V$ is activation volume, $P$ is pressure, $R$ is the gas + * exponent and $T$ is temperature. + * + * One may select to use the diffusion ($v_{diff}$; $n=1$, $m!=0$), + * dislocation ($v_{disl}$, $n>1$, $m=0$) or composite + * $\frac{v_{diff}v_{disl}}{v_{diff}+v_{disl}}$ equation form. + * + * Viscous stress is limited by plastic deformation, which follows + * a Drucker Prager yield criterion: + * $\sigma_y = C\cos(\phi) + P\sin(\phi)$ (2D) + * or in 3D + * $\sigma_y = \frac{6C\cos(\phi) + 2P\sin(\phi)}{\sqrt{3}(3+\sin(\phi))}$ + * where + * $\sigma_y$ is the yield stress, $C$ is cohesion, $phi$ is the angle + * of internal friction and $P$ is pressure. + * If the viscous stress ($2v{\varepsilon}_{ii})$) exceeds the yield + * stress ($\sigma_{y}$), the viscosity is rescaled back to the yield + * surface: $v_{y}=\sigma_{y}/(2{\varepsilon}_{ii})$ + * + * When included, the viscoelastic rheology takes into account the elastic shear + * strength (e.g., shear modulus), while the tensile and volumetric + * strength (e.g., Young's and bulk modulus) are not considered. The model + * is incompressible and allows specifying an arbitrary number of + * compositional fields, where each field represents a different rock type + * or component of the viscoelastic stress tensor. The symmetric stress tensor in + * 2D and 3D, respectively, contains 3 or 6 components. The compositional fields + * representing these components must be named and listed in a very specific + * format, which is designed to minimize mislabeling stress tensor components + * as distinct 'compositional rock types' (or vice versa). For 2D models, + * the first three compositional fields must be labeled ve_stress_xx, ve_stress_yy + * and ve_stress_xy. In 3D, the first six compositional fields must be labeled + * ve_stress_xx, ve_stress_yy, ve_stress_zz, ve_stress_xy, ve_stress_xz, ve_stress_yz. + * + * Combining this viscoelasticity implementation with non-linear viscous flow + * and plasticity produces a constitutive relationship commonly referred to + * as partial elastoviscoplastic (e.g., pEVP) in the geodynamics community. + * While extensively discussed and applied within the geodynamics literature, + * notable references include: + * Moresi et al. (2003), J. Comp. Phys., v. 184, p. 476-497. + * Gerya and Yuen (2007), Phys. Earth. Planet. Inter., v. 163, p. 83-105. + * Gerya (2010), Introduction to Numerical Geodynamic Modeling. + * Kaus (2010), Tectonophysics, v. 484, p. 36-47. + * Choi et al. (2013), J. Geophys. Res., v. 118, p. 2429-2444. + * Keller et al. (2013), Geophys. J. Int., v. 195, p. 1406-1442. + * + * The overview below directly follows Moresi et al. (2003) eqns. 23-32. + * However, an important distinction between this material model and + * the studies above is the use of compositional fields, rather than + * particles, to track individual components of the viscoelastic stress + * tensor. The material model will be updated when an option to track + * and calculate viscoelastic stresses with particles is implemented. + * Moresi et al. (2003) begins (eqn. 23) by writing the deviatoric + * rate of deformation ($\hat{D}$) as the sum of elastic + * ($\hat{D_{e}}$) and viscous ($\hat{D_{v}}$) components: + * $\hat{D} = \hat{D_{e}} + \hat{D_{v}}$. + * These terms further decompose into + * $\hat{D_{v}} = \frac{\tau}{2\eta}$ and + * $\hat{D_{e}} = \frac{\overset{\triangledown}{\tau}}{2\mu}$, where + * $\tau$ is the viscous deviatoric stress, $\eta$ is the shear viscosity, + * $\mu$ is the shear modulus and $\overset{\triangledown}{\tau}$ is the + * Jaumann corotational stress rate. If plasticity is included the + * deviatoric rate of deformation may be written as: + * $\hat{D} = \hat{D_{e}} + \hat{D_{v}} + \hat{D_{p}}$, where $\hat{D_{p}}$ + * is the plastic component. As defined in the second paragraph, $\hat{D_{p}}$ + * decomposes to $\frac{\tau_{y}}{2\eta_{y}}$, where $\tau_{y}$ is the yield + * stress and $\eta_{y}$ is the viscosity rescaled to the yield surface. + * + * Above, the Jaumann corotational stress rate (eqn. 24) from the elastic + * component contains the time derivative of the deviatoric stress ($\dot{\tau}$) + * and terms that account for material spin (e.g., rotation) due to advection: + * $\overset{\triangledown}{\tau} = \dot{\tau} + {\tau}W -W\tau$. + * Above, $W$ is the material spin tensor (eqn. 25): + * $W_{ij} = \frac{1}{2} \left (\frac{\partial V_{i}}{\partial x_{j}} - + * \frac{\partial V_{j}}{\partial x_{i}} \right )$. + * + * The Jaumann stress-rate can also be approximated using terms from the time + * at the previous time step ($t$) and current time step ($t + \Delta t^{e}$): + * $\smash[t]{\overset{\triangledown}{\tau}}^{t + \Delta t^{e}} \approx + * \frac{\tau^{t + \Delta t^{e} - \tau^{t}}}{\Delta t^{e}} - + * W^{t}\tau^{t} + \tau^{t}W^{t}$. + * In this material model, the size of the time step above ($\Delta t^{e}$) + * can be specified as the numerical time step size or an independent fixed time + * step. If the latter case is selected, the user has an option to apply a + * stress averaging scheme to account for the differences between the numerical + * and fixed elastic time step (eqn. 32). If one selects to use a fixed elastic time + * step throughout the model run, an equal numerical and elastic time step can be + * achieved by using CFL and maximum time step values that restrict the numerical + * time step to the fixed elastic time step. + * + * The formulation above allows rewriting the total rate of deformation (eqn. 29) as + * $\tau^{t + \Delta t^{e}} = \eta_{eff} \left ( + * 2\hat{D}^{t + \triangle t^{e}} + \frac{\tau^{t}}{\mu \Delta t^{e}} + + * \frac{W^{t}\tau^{t} - \tau^{t}W^{t}}{\mu} \right )$. + * + * The effective viscosity (eqn. 28) is a function of the viscosity ($\eta$), + * elastic time step size ($\Delta t^{e}$) and shear relaxation time + * ($ \alpha = \frac{\eta}{\mu} $): + * $\eta_{eff} = \eta \frac{\Delta t^{e}}{\Delta t^{e} + \alpha}$ + * The magnitude of the shear modulus thus controls how much the effective + * viscosity is reduced relative to the initial viscosity. + * + * Elastic effects are introduced into the governing Stokes equations through + * an elastic force term (eqn. 30) using stresses from the previous time step: + * $F^{e,t} = -\frac{\eta_{eff}}{\mu \Delta t^{e}} \tau^{t}$. + * This force term is added onto the right-hand side force vector in the + * system of equations. + * + * Several model parameters (reference densities, thermal expansivities + * thermal diffusivities, heat capacities and rheology parameters) can + * be defined per-compositional field. + * For each material parameter the user supplies a comma delimited list of + * length N+1, where N is the number of compositional fields. The + * additional field corresponds to the value for background material. They + * should be ordered ``background, composition1, composition2...'' + * + * If a list of values is given for the density, thermal expansivity, + * thermal diffusivity and heat capacity, the volume weighted sum of the + * values of each of the compositional fields is used in their place, + * for example $\rho = \sum \left( \rho_i V_i \right)$ + * + * The individual output viscosities for each compositional field are + * also averaged. The user can choose from a range of options for this + * viscosity averaging. If only one value is given for any of these parameters, + * all compositions are assigned the same value. + * The first value in the list is the value assigned to "background material" + * (regions where the sum of the compositional fields is < 1.0). + * + * @ingroup MaterialModels + */ + template + class ViscoPlastic : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * Return whether the model is compressible or not. Incompressibility + * does not necessarily imply that the density is constant; rather, it + * may still depend on temperature or pressure. In the current + * context, compressibility means whether we should solve the continuity + * equation as $\nabla \cdot (\rho \mathbf u)=0$ (compressible Stokes) + * or as $\nabla \cdot \mathbf{u}=0$ (incompressible Stokes). + * + * This material model is incompressible. + */ + bool is_compressible () const override; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + double get_min_strain_rate() const; + + /** + * A function that returns whether the material is plastically yielding at + * the given pressure, temperature, composition, and strain rate. + * + * @deprecated: Use the other function with this name instead, which allows + * to pass in more general input variables. + */ + DEAL_II_DEPRECATED + bool + is_yielding (const double pressure, + const double temperature, + const std::vector &composition, + const SymmetricTensor<2,dim> &strain_rate) const; + + /** + * A function that returns whether the material is plastically + * yielding at the given input variables (pressure, temperature, + * composition, strain rate, and so on). + */ + bool + is_yielding (const MaterialModelInputs &in) const; + + private: + + /** + * Pointer to the object used to compute the rheological properties. + * In this case, the rheology in question is visco(elasto)plastic. The + * object contains functions for parameter declaration and parsing, + * and further functions that calculate viscosity and viscosity + * derivatives. It also contains functions that create and fill + * additional material model outputs, specifically plastic outputs. + * The rheology itself is a composite rheology, and so the object + * contains further objects and/or pointers to objects that provide + * functions and parameters for all subordinate rheologies. + */ + std::unique_ptr> rheology; + + std::vector thermal_diffusivities; + + /** + * Whether to use user-defined thermal conductivities instead of thermal diffusivities. + */ + bool define_conductivities; + + std::vector thermal_conductivities; + + /** + * Number of phase transitions for each chemical composition (including the background field). + */ + std::vector n_phase_transitions_for_each_chemical_composition; + + /** + * Total number of phases. + */ + unsigned int n_phases; + + /** + * Object for computing the equation of state. + */ + EquationOfState::MulticomponentIncompressible equation_of_state; + + /** + * Object that handles phase transitions. + */ + MaterialUtilities::PhaseFunction phase_function; + + }; + + } +} + +#endif diff --git a/include/aspect/material_model/viscoelastic.h.bak b/include/aspect/material_model/viscoelastic.h.bak new file mode 100644 index 00000000000..7003201e0e7 --- /dev/null +++ b/include/aspect/material_model/viscoelastic.h.bak @@ -0,0 +1,220 @@ +/* + Copyright (C) 2014 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + +#ifndef _aspect_material_model_viscoelastic_h +#define _aspect_material_model_viscoelastic_h + +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + using namespace dealii; + + /** + * An implementation of a simple linear viscoelastic rheology that only + * includes the deviatoric components of elasticity. Specifically, the + * viscoelastic rheology only takes into account the elastic shear + * strength (e.g., shear modulus), while the tensile and volumetric + * strength (e.g., Young's and bulk modulus) are not considered. The model + * is incompressible and allows specifying an arbitrary number of + * compositional fields, where each field represents a different rock type + * or component of the viscoelastic stress tensor. The stress tensor in 2D + * and 3D, respectively, contains 3 or 6 components. The compositional fields + * representing these components must be named and listed in a very specific + * format, which is designed to minimize mislabeling stress tensor components + * as distinct 'compositional rock types' (or vice versa). For 2D models, + * the first three compositional fields must be labeled ve_stress_xx, ve_stress_yy + * and ve_stress_xy. In 3D, the first six compositional fields must be labeled + * ve_stress_xx, ve_stress_yy, ve_stress_zz, ve_stress_xy, ve_stress_xz, ve_stress_yz. + * + * Expanding the model to include non-linear viscous flow (e.g., + * diffusion/dislocation creep) and plasticity would produce a constitutive + * relationship commonly referred to as partial elastoviscoplastic + * (e.g., pEVP) in the geodynamics community. While extensively discussed + * and applied within the geodynamics literature, notable references include: + * Moresi et al. (2003), J. Comp. Phys., v. 184, p. 476-497. + * Gerya and Yuen (2007), Phys. Earth. Planet. Inter., v. 163, p. 83-105. + * Gerya (2010), Introduction to Numerical Geodynamic Modeling. + * Kaus (2010), Tectonophysics, v. 484, p. 36-47. + * Choi et al. (2013), J. Geophys. Res., v. 118, p. 2429-2444. + * Keller et al. (2013), Geophys. J. Int., v. 195, p. 1406-1442. + * + * The overview below directly follows Moresi et al. (2003) eqns. 23-32. + * However, an important distinction between this material model and + * the studies above is the use of compositional fields, rather than + * particles, to track individual components of the viscoelastic stress + * tensor. The material model will be updated when an option to track + * and calculate viscoelastic stresses with particles is implemented. + * + * Moresi et al. (2003) begins (eqn. 23) by writing the deviatoric + * rate of deformation ($\hat{D}$) as the sum of elastic + * ($\hat{D_{e}}$) and viscous ($\hat{D_{v}}$) components: + * $\hat{D} = \hat{D_{e}} + \hat{D_{v}}$. + * These terms further decompose into + * $\hat{D_{v}} = \frac{\tau}{2\eta}$ and + * $\hat{D_{e}} = \frac{\overset{\nabla}{\tau}}{2\mu}$, where + * $\tau$ is the viscous deviatoric stress, $\eta$ is the shear viscosity, + * $\mu$ is the shear modulus and $\overset{\nabla}{\tau}$ is the + * Jaumann corotational stress rate. This later term (eqn. 24) contains the + * time derivative of the deviatoric stress ($\dot{\tau}$) and terms that + * account for material spin (e.g., rotation) due to advection: + * $\overset{\nabla}{\tau} = \dot{\tau} + {\tau}W -W\tau$. + * Above, $W$ is the material spin tensor (eqn. 25): + * $W_{ij} = \frac{1}{2} \left (\frac{\partial V_{i}}{\partial x_{j}} - + * \frac{\partial V_{j}}{\partial x_{i}} \right )$. + * + * The Jaumann stress-rate can also be approximated using terms from the time + * at the previous time step ($t$) and current time step ($t + \Delta t^{e}$): + * $\smash[t]{\overset{\nabla}{\tau}}^{t + \Delta t^{e}} \approx + * \frac{\tau^{t + \Delta t^{e} - \tau^{t}}}{\Delta t^{e}} - + * W^{t}\tau^{t} + \tau^{t}W^{t}$. + * In this material model, the size of the time step above ($\Delta t^{e}$) + * can be specified as the numerical time step size or an independent fixed time + * step. If the latter case is a selected, the user has an option to apply a + * stress averaging scheme to account for the differences between the numerical + * and fixed elastic time step (eqn. 32). If one selects to use a fixed elastic time + * step throughout the model run, this can still be achieved by using CFL and + * maximum time step values that restrict the numerical time step to a specific time. + * + * The formulation above allows rewriting the total rate of deformation (eqn. 29) as + * $\tau^{t + \Delta t^{e}} = \eta_{eff} \left ( + * 2\hat{D}^{t + \triangle t^{e}} + \frac{\tau^{t}}{\mu \Delta t^{e}} + + * \frac{W^{t}\tau^{t} - \tau^{t}W^{t}}{\mu} \right )$. + * + * The effective viscosity (eqn. 28) is a function of the viscosity ($\eta$), + * elastic time step size ($\Delta t^{e}$) and shear relaxation time + * ($ \alpha = \frac{\eta}{\mu} $): + * $\eta_{eff} = \eta \frac{\Delta t^{e}}{\Delta t^{e} + \alpha}$ + * The magnitude of the shear modulus thus controls how much the effective + * viscosity is reduced relative to the initial viscosity. + * + * Elastic effects are introduced into the governing stokes equations through + * an elastic force term (eqn. 30) using stresses from the previous time step: + * $F^{e,t} = -\frac{\eta_{eff}}{\mu \Delta t^{e}} \tau^{t}$. + * This force term is added onto the right-hand side force vector in the + * system of equations. + * + * The value of each compositional field representing distinct + * rock types at a point is interpreted to be a volume fraction of that + * rock type. If the sum of the compositional field volume fractions is + * less than one, then the remainder of the volume is assumed to be + * 'background material'. + * + * Several model parameters (densities, elastic shear moduli, + * thermal expansivities, thermal conductivies, specific heats) can + * be defined per-compositional field. For each material parameter the + * user supplies a comma delimited list of length N+1, where N is the + * number of compositional fields. The additional field corresponds to + * the value for background material. They should be ordered + * ``background, composition1, composition2...''. However, the first 3 (2D) + * or 6 (3D) composition fields correspond to components of the elastic + * stress tensor and their material values will not contribute to the volume + * fractions. If a single value is given, then all the compositional fields + * are given that value. Other lengths of lists are not allowed. For a given + * compositional field the material parameters are treated as constant, + * except density, which varies linearly with temperature according to the + * thermal expansivity. + * + * When more than one compositional field is present at a point, they are + * averaged arithmetically. An exception is viscosity, which may be averaged + * arithmetically, harmonically, geometrically, or by selecting the + * viscosity of the composition with the greatest volume fraction. + * + * @ingroup MaterialModels + */ + template + class Viscoelastic : public MaterialModel::Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Function to compute the material properties in @p out given the + * inputs in @p in. + */ + void evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const override; + + /** + * @name Qualitative properties one can ask a material model + * @{ + */ + + /** + * This model is not compressible, so this returns false. + */ + bool is_compressible () const override; + /** + * @} + */ + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + void + create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const override; + + + private: + /** + * Enumeration for selecting which viscosity averaging scheme to use. + */ + MaterialUtilities::CompositionalAveragingOperation viscosity_averaging; + + EquationOfState::MulticomponentIncompressible equation_of_state; + + /** + * Vector for field viscosities, read from parameter file. + */ + std::vector viscosities; + + /** + * Vector for field thermal conductivities, read from parameter file. + */ + std::vector thermal_conductivities; + + Rheology::Elasticity elastic_rheology; + }; + + } +} + +#endif diff --git a/include/aspect/melt.h.bak b/include/aspect/melt.h.bak new file mode 100644 index 00000000000..9db3a27b005 --- /dev/null +++ b/include/aspect/melt.h.bak @@ -0,0 +1,571 @@ +/* + Copyright (C) 2016 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#ifndef _aspect_melt_h +#define _aspect_melt_h + +#include +#include +#include +#include +#include + +namespace aspect +{ + using namespace dealii; + + namespace MaterialModel + { + /** + * The MeltInputs provide the compaction pressures and + * melt (fluid) velocities, so that they can be used as + * additional inputs in heating or material models. + */ + template + class MeltInputs : public AdditionalMaterialInputs + { + public: + /** + * Constructor. When the MeltInputs are created, + * all properties are initialized with signalingNaNs. + * This means that individual heating or material models + * can all attach the plugins they need, and in a later + * step they will all be filled together (using the fill + * function). + */ + MeltInputs (const unsigned int n_points); + + /** + * Compaction pressure values $p_c$ at the given positions. + */ + std::vector compaction_pressures; + + /** + * An approximation for the fluid (melt) velocities + * at the given positions. + */ + std::vector> fluid_velocities; + + /** + * Fill the compaction pressures and fluid velocities. + */ + void fill (const LinearAlgebra::BlockVector &solution, + const FEValuesBase &fe_values, + const Introspection &introspection) override; + }; + + template + class MeltOutputs : public AdditionalMaterialOutputs + { + public: + MeltOutputs (const unsigned int n_points, + const unsigned int /*n_comp*/) + { + compaction_viscosities.resize(n_points); + fluid_viscosities.resize(n_points); + permeabilities.resize(n_points); + fluid_densities.resize(n_points); + fluid_density_gradients.resize(n_points, Tensor<1,dim>()); + } + + /** + * Compaction viscosity values $\xi$ at the given positions. + * This parameter describes the resistance of the solid matrix + * in a two-phase simulation to dilation and compaction. + */ + std::vector compaction_viscosities; + + /** + * Fluid (melt) viscosity values $\eta_f$ at the given positions. + */ + std::vector fluid_viscosities; + + /** + * Permeability values $k$ at the given positions. + */ + std::vector permeabilities; + + /** + * Fluid (melt) density values $\rho_f$ at the given positions. + */ + std::vector fluid_densities; + + /** + * An approximation for the fluid (melt) density gradients + * $\nabla \rho_f$ at the given positions. These values are + * required for compressible models to describe volume changes + * of melt in dependence of pressure, temperature etc. + */ + std::vector> fluid_density_gradients; + + /** + * Do the requested averaging operation for the melt outputs. + * The projection matrix argument is only used if the operation + * chosen is project_to_Q1. + */ + void average (const MaterialAveraging::AveragingOperation operation, + const FullMatrix &projection_matrix, + const FullMatrix &expansion_matrix) override; + }; + + /** + * Base class for material models that implement a melt fraction function. + * This is used to compute some statistics about the melt fraction. + * + * This class is used as a "mix-in" class: Concrete material models will + * be derived from MaterialModel::Interface (and consequently have to + * implement the `virtual` functions of that class) *and also* from the + * current class (and consequently have to implement the `virtual` function + * of the current class). The inheritance from MaterialModel::Interface is + * typically via the MaterialModel::MeltInterface intermediate class. + */ + template + class MeltFractionModel + { + public: + /** + * Destructor. Does nothing but is virtual so that derived classes + * destructors are also virtual. + */ + virtual ~MeltFractionModel () = default; + + /** + * Compute the equilibrium melt fractions for the given input conditions. + * @p in and @p melt_fractions need to have the same size. + * + * @param in Object that contains the current conditions. + * @param melt_fractions Vector of doubles that is filled with the + * equilibrium melt fraction for each given input conditions. + */ + virtual void melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const = 0; + + /** + * Return whether an object provided as argument is of a class that is + * derived from the current MeltFractionModel class. (Many of these models + * will be derived from MaterialModel::Interface and *also* be derived + * from MeltFractionModel; only the latter derivation is of interest to + * this function. + */ + template + static + bool is_melt_fraction_model (const ModelType &model_object); + + /** + * Return a reference to the MeltFractionModel base class of + * the object. This function will throw an exception unless + * is_melt_fraction_model() returns `true` for the given argument. + */ + template + static + const MeltFractionModel & + as_melt_fraction_model (const ModelType &model_object); + }; + + + + template + template + inline + bool + MeltFractionModel::is_melt_fraction_model (const ModelType &model_object) + { + return (dynamic_cast*>(&model_object) + != nullptr); + } + + + template + template + inline + const MeltFractionModel & + MeltFractionModel::as_melt_fraction_model (const ModelType &model_object) + { + Assert (is_melt_fraction_model(model_object) == true, + ExcMessage ("This function can only be called for model objects " + "whose types are derived from MeltFractionModel.")); + + return dynamic_cast&>(model_object); + } + + + + /** + * Base class for material models to be used with melt transport enabled. + */ + template + class MeltInterface: public MaterialModel::Interface + { + public: + /** + * Reference value for the Darcy coefficient, which is defined as + * permeability divided by fluid viscosity. Units: m^2/Pa/s. + */ + virtual double reference_darcy_coefficient () const = 0; + + /** + * Returns the cell-averaged and cut-off value of p_c_scale, + * the factor we use to rescale the compaction pressure and to + * decide if a cell is a melt cell. + * The last input argument @p consider_is_melt_cell determines if + * this computation takes into account if a cell is a "melt cell". + * Melt cells are cells where we solve the melt transport equations, + * as indicated by the entries stored in the is_melt_cell vector of + * the melt handler. In case @p consider_is_melt_cell is set to true, + * this function returns a value of zero if the cell is not a melt cell. + * If @p consider_is_melt_cell is set to false the computation + * disregards the information about which cells are melt cells, + * and computes p_c_scale from the cell-averaged Darcy coefficient + * for all cells. This is needed for example when we want to update + * the is_melt_cell vector and need to find out which cells should be + * marked as melt cells. + */ + double p_c_scale (const MaterialModel::MaterialModelInputs &inputs, + const MaterialModel::MaterialModelOutputs &outputs, + const MeltHandler &melt_handler, + const bool consider_is_melt_cell) const; + }; + + + } + + + + namespace Assemblers + { + /** + * A base class for the definition of assemblers that implement the linear + * system terms for the *melt* migration compressible or incompressible + * equations. + */ + template + class MeltInterface : public aspect::Assemblers::Interface, + public SimulatorAccess + { + public: + /** + * Attach melt outputs. Since most melt assemblers require the + * melt material model properties they are created in this base class + * already. + */ + void + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const override; + }; + + /** + * Compute the integrals for the preconditioner for the Stokes system in + * the case of melt migration on a single cell. + */ + template + class MeltStokesPreconditioner : public MeltInterface + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * Compute the integrals for the Stokes matrix and right hand side in + * the case of melt migration on a single cell. + */ + template + class MeltStokesSystem : public MeltInterface + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + + /** + * Compute the boundary integrals for the Stokes right hand side in + * the case of melt migration on a single cell. These boundary terms + * are used to describe Neumann boundary conditions for the fluid pressure. + */ + template + class MeltStokesSystemBoundary : public MeltInterface + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * Compute the integrals for the Advection system matrix and right hand side in + * the case of melt migration on a single cell. + */ + template + class MeltAdvectionSystem : public MeltInterface, public Assemblers::AdvectionStabilizationInterface + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + + /** + * Compute the residual of the advection system on a single cell in + * the case of melt migration. + */ + std::vector + compute_residual(internal::Assembly::Scratch::ScratchBase &scratch_base) const override; + }; + + /** + * Integrate the local fluid pressure shape functions on a single cell + * for models with melt migration, so that they can later be used to do + * the pressure right-hand side compatibility modification. + */ + template + class MeltPressureRHSCompatibilityModification : public MeltInterface + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * Assemble traction boundary condition terms for models with melt. + */ + template + class MeltBoundaryTraction : public MeltInterface + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + } + + + namespace Melt + { + template + struct Parameters + { + /** + * Declare additional parameters that are needed in models with + * melt transport. + */ + static void declare_parameters (ParameterHandler &prm); + + /** + * Parse additional parameters that are needed in models with + * melt transport. + * + * This has to be called before edit_finite_element_variables, + * so that the finite elements that are used for the additional melt + * variables can be specified in the input file and are parsed before + * the introspection object is created. + */ + void parse_parameters (ParameterHandler &prm); + + /** + * The factor by how much the Darcy coefficient K_D in a cell can be smaller than + * the reference Darcy coefficient for this cell still to be considered a melt cell + * (for which the melt transport equations are solved). If the Darcy coefficient + * is smaller than the product of this value and the reference Dracy coefficient, + * the cell is not considered a melt cell and the Stokes system without melt + * transport is solved instead. In practice, this means that all terms in the + * assembly related to the migration of melt are set to zero, and the compaction + * pressure degrees of freedom are constrained to be zero. + */ + double melt_scaling_factor_threshold; + + /** + * Whether to use a porosity weighted average of the melt and solid velocity + * to advect heat in the temperature equation or not. If this is set to true, + * additional terms are assembled on the left-hand side of the temperature + * advection equation in models with melt migration. + * If this is set to false, only the solid velocity is used (as in models + * without melt migration). + */ + bool heat_advection_by_melt; + + /** + * Whether to use a discontinuous element for the compaction pressure or not. + */ + bool use_discontinuous_p_c; + + /** + * Whether to cell-wise average the material properties that are used to + * compute the melt velocity or not. Note that the melt velocity is computed + * as the sum of the solid velocity and the phase separation flux (difference + * between melt and solid velocity). If this parameter is set to true, + * material properties in the computation of the phase separation flux will + * be averaged cell-wise. + */ + bool average_melt_velocity; + }; + } + + + /** + * Class that contains all runtime parameters and other helper functions + * related to melt transport. A global instance can be retrieved with + * SimulatorAccess::get_melt_handler(), but keep in mind that it only + * exists if parameters.include_melt_transport is true. + */ + template + class MeltHandler: public SimulatorAccess + { + public: + MeltHandler(ParameterHandler &prm); + + /** + * Create an additional material model output object that contains + * the additional output variables needed in simulation with melt transport, + * and attaches a pointer to it to the corresponding vector in the + * MaterialModel::MaterialModelOutputs structure. + */ + static void create_material_model_outputs(MaterialModel::MaterialModelOutputs &output); + + /** + * Add the additional variables we need in simulations with melt + * migration to the list of variables, which will be used later + * to set up the introspection object. + */ + void edit_finite_element_variables(const Parameters ¶meters, + std::vector> &variables); + + /** + * Determine, based on the run-time parameters of the current simulation, + * which functions need to be called in order to assemble linear systems, + * matrices, and right hand side vectors. + */ + void set_assemblers (Assemblers::Manager &assemblers) const; + + + /** + * Initialize function. This is mainly to check that the melt transport + * parameters chosen in the input file are consistent with the rest of + * the options. We can not do this in the parse_parameters function, + * as we do not have simulator access at that point. + */ + void initialize() const; + + /** + * Setup SimulatorAccess for the plugins related to melt transport. + */ + void initialize_simulator (const Simulator &simulator_object) override; + + /** + * Compute fluid velocity and solid pressure in this ghosted solution vector. + * The fluid velocity is computed by solving a mass matrix problem, and the + * solid pressure is computed algebraically. + * + * @param system_matrix The system matrix with an already set up sparsity + * pattern that will be used by this function to compute the melt variables. + * @param solution The existing solution vector that contains the values + * for porosity, compaction pressure, fluid pressure and solid velocity + * obtained by solving the Stokes and advection system, and that will be + * updated with the computed values for fluid velocity and solid pressure. + * @param system_rhs The right-hand side vector that will be used by + * this function to compute the melt variables. + */ + void compute_melt_variables(LinearAlgebra::BlockSparseMatrix &system_matrix, + LinearAlgebra::BlockVector &solution, + LinearAlgebra::BlockVector &system_rhs); + + /** + * Return whether this object refers to the porosity field. + */ + bool is_porosity (const typename Simulator::AdvectionField &advection_field) const; + + /** + * Apply free surface stabilization to a cell of the system matrix when melt + * transport is used in the computation. Called during assembly of the system matrix. + */ + void apply_free_surface_stabilization_with_melt (const double free_surface_theta, + const typename DoFHandler::active_cell_iterator &cell, + internal::Assembly::Scratch::StokesSystem &scratch, + internal::Assembly::CopyData::StokesSystem &data) const; + + /** + * Constrain the compaction pressure to zero in all cells that are not + * "melt cells" (cells where the porosity is above a given threshold). + * This reverts the system of equations we solve back to the Stokes + * system without melt transport for these cells. + */ + void add_current_constraints(AffineConstraints &constraints); + + /** + * Returns the entry of the private variable is_melt_cell_vector for the + * cell given in the input, describing if we have melt transport in this + * cell or not. + */ + bool is_melt_cell(const typename DoFHandler::active_cell_iterator &cell) const; + + /** + * Given the Darcy coefficient @p K_D as computed by the material model, + * limit the coefficient to a minimum value (computed as the K_D + * variation threshold given in the input file times the reference Darcy + * coefficient) in melt cells and return this value. If @p is_melt_cell + * is false, return zero. + */ + double limited_darcy_coefficient(const double K_D, + const bool is_melt_cell) const; + + /** + * Return a pointer to the boundary fluid pressure. + */ + const BoundaryFluidPressure::Interface & + get_boundary_fluid_pressure () const; + + /** + * The object that stores the run-time parameters that control the how the + * melt transport equations are solved. + */ + Melt::Parameters melt_parameters; + + private: + /** + * Store a pointer to the fluid pressure boundary plugin, so that the + * initialization can be done together with the other objects related to melt + * transport. + */ + const std::unique_ptr> boundary_fluid_pressure; + + /** + * is_melt_cell_vector[cell->active_cell_index()] says whether we want to + * solve the melt transport equations (as opposed to the Stokes equations without + * melt) in this cell or not. The value is set to true or false based on the + * porosity in the cell (only cells where the porosity is above a threshold are + * considered melt cells). + */ + std::vector is_melt_cell_vector; + + /** + * Constraint object. We need to save the current constraints at the + * start of every time step so that we can add the melt constraints, + * which depend on the solution of the porosity field, later after + * we have computed this solution. + */ + AffineConstraints current_constraints; + + }; + +} + +#endif diff --git a/include/aspect/mesh_deformation/ascii_data.h.bak b/include/aspect/mesh_deformation/ascii_data.h.bak new file mode 100644 index 00000000000..2b49c54566d --- /dev/null +++ b/include/aspect/mesh_deformation/ascii_data.h.bak @@ -0,0 +1,96 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_deformation_ascii_data_h +#define _aspect_mesh_deformation_ascii_data_h + +#include +#include +#include + + +namespace aspect +{ + namespace MeshDeformation + { + using namespace dealii; + + /** + * A class that implements initial topography determined + * from an AsciiData input file. + * + * @ingroup InitialTopographyModel + */ + template + class AsciiData : public Utilities::AsciiDataBoundary, public Interface + { + public: + /** + * Empty Constructor. + */ + AsciiData (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Sets the boundary id of the surface boundary. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataBoundary::initialize; + + /** + * Return the surface topography as a function of position along the surface. + * For the current class, this function returns a value from the text files. + * + * @copydoc aspect::InitialTopographyModel::Interface::value() + */ + Tensor<1,dim> + compute_initial_deformation_on_boundary(const types::boundary_id boundary_indicator, + const Point &position) const override; + + /** + * Returns whether or not the plugin requires surface stabilization + */ + bool needs_surface_stabilization () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + types::boundary_id surface_boundary_id; + }; + } +} + + +#endif diff --git a/include/aspect/mesh_deformation/diffusion.h.bak b/include/aspect/mesh_deformation/diffusion.h.bak new file mode 100644 index 00000000000..4459211f10c --- /dev/null +++ b/include/aspect/mesh_deformation/diffusion.h.bak @@ -0,0 +1,138 @@ +/* + Copyright (C) 2020 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_deformation_diffusion_h +#define _aspect_mesh_deformation_diffusion_h + +#include +#include +#include + + +namespace aspect +{ + using namespace dealii; + + + namespace MeshDeformation + { + /** + * A plugin that computes the deformation of surface + * vertices according to the solution of a dim-1 diffusion + * problem. + */ + template + class Diffusion : public Interface, public SimulatorAccess + { + public: + Diffusion(); + + /** + * Initialize function, which sets the start time and + * start timestep of diffusion. + */ + void initialize() override; + + /** + * The update function sets the current time and determines + * whether diffusion should be applied in this timestep. + */ + void update() override; + + + + /** + * A function that creates constraints for the velocity of certain mesh + * vertices (e.g. the surface vertices) for a specific boundary. + * The calling class will respect + * these constraints when computing the new vertex positions. + */ + void + compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, + AffineConstraints &mesh_velocity_constraints, + const std::set &boundary_id) const override; + + /** + * Returns whether or not the plugin requires surface stabilization + */ + bool needs_surface_stabilization () const override; + + /** + * Declare parameters for the diffusion of the surface. + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * Parse parameters for the diffusion of the surface. + */ + void parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Compute the surface velocity from a difference + * in surface height given by the solution of + * the hillslope diffusion problem. + */ + void diffuse_boundary (const DoFHandler &free_surface_dof_handler, + const IndexSet &mesh_locally_owned, + const IndexSet &mesh_locally_relevant, + LinearAlgebra::Vector &output, + const std::set &boundary_id) const; + + /** + * Check that the size of the next time step is not larger than the conduction + * timestep based on the mesh size and the diffusivity on each cell along the + * surface. The computed time step has to satisfy the CFL + * number chosen in the input parameter file on each cell of the mesh. + */ + void check_diffusion_time_step (const DoFHandler &mesh_deformation_dof_handler, + const std::set &boundary_ids) const; + + /** + * The hillslope transport coefficient or diffusivity [m2/s] + * used in the hillslope diffusion of the deformed + * surface. + */ + double diffusivity; + + /** + * Maximum number of steps between the application of diffusion. + */ + unsigned int timesteps_between_diffusion; + + /** + * Whether or not in the current timestep, diffusion + * should be applied. + */ + bool apply_diffusion; + + /** + * Boundaries along which the mesh is allowed to move tangentially + * despite of the Stokes velocity boundary conditions. + */ + std::set additional_tangential_mesh_boundary_indicators; + }; + } +} + + +#endif diff --git a/include/aspect/mesh_deformation/fastscape.h.bak b/include/aspect/mesh_deformation/fastscape.h.bak new file mode 100644 index 00000000000..f087d987365 --- /dev/null +++ b/include/aspect/mesh_deformation/fastscape.h.bak @@ -0,0 +1,597 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_mesh_deformation_fastscape_h +#define _aspect_mesh_deformation_fastscape_h + +#include + +#ifdef ASPECT_WITH_FASTSCAPE + +#include + +namespace aspect +{ + using namespace dealii; + + namespace MeshDeformation + { + /** + * A plugin that utilizes the landscape evolution code FastScape + * to deform the ASPECT boundary through advection, uplift, + * hillslope diffusion, sediment deposition, marine diffusion, + * and the stream power law, which describes river incision. + * + */ + template + class FastScape : public Interface, public SimulatorAccess + { + public: + /** + * Initialize variables for FastScape. + */ + virtual void initialize () override; + + /** + * Destructor for FastScape. + */ + ~FastScape() override; + + /** + * A function that creates constraints for the velocity of certain mesh + * vertices (e.g. the surface vertices) for a specific boundary. + * The calling class will respect + * these constraints when computing the new vertex positions. + */ + virtual + void + compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, + AffineConstraints &mesh_velocity_constraints, + const std::set &boundary_id) const override; + + /** + * Returns whether or not the plugin requires surface stabilization + */ + bool needs_surface_stabilization () const override; + + /** + * Declare parameters for the FastScape plugin. + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * Parse parameters for the FastScape plugin. + */ + void parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Function used to set the FastScape ghost nodes. FastScape boundaries are + * not uplifted or periodic for advection and diffusion. By using a layer + * of extra nodes in the FastScape model, we can avoid seeing FastScape boundary + * effects within ASPECT. Similarly, we can use these nodes to have fully + * periodic boundaries, where we check the flow direction and update the FastScape + * ghost nodes, and the nodes one layer inward (boundary nodes in ASPECT) to match + * the parameters on the other side (vx, vy, vz, h). This is done every ASPECT timestep + * before running FastScape. + */ + void set_ghost_nodes(std::vector &elevation, + std::vector &velocity_x, + std::vector &velocity_y, + std::vector &velocity_z, + const double &fastscape_timestep_in_years, + const bool init) const; + + /** + * Function to determine whether the current index is a ghost node + */ + bool is_ghost_node(const unsigned int &index, + const bool &exclude_boundaries) const; + + /** + * Function to fill the Fastscape arrays (height and velocities) with the data received from ASPECT in the correct index order. + */ + void fill_fastscape_arrays(std::vector &elevation, + std::vector &bedrock_transport_coefficient_array, + std::vector &bedrock_river_incision_rate_array, + std::vector &velocity_x, + std::vector &velocity_y, + std::vector &velocity_z, + std::vector> &temporary_variables) const; + + /** + * Function to get the ASPECT topography and velocities at the surface, and an index for transferring these to FastScape. + */ + std::vector> get_aspect_values() const; + + /** + * Function to initialize or restart FastScape + */ + void initialize_fastscape(std::vector &elevation, + std::vector &basement, + std::vector &bedrock_transport_coefficient_array, + std::vector &bedrock_river_incision_rate_array, + std::vector &silt_fraction) const; + + /** + * Execute FastScape + */ + void execute_fastscape(std::vector &elevation, + std::vector &extra_vtk_field, + std::vector &velocity_x, + std::vector &velocity_y, + std::vector &velocity_z, + const double &fastscape_timestep_in_years, + const unsigned int &fastscape_iterations) const; + + /** + * Function to apply orographic (mountain related, e.g., wind or elevation) + * controls to the FastScape model. + */ + void apply_orographic_controls(const std::vector &elevation, + std::vector &bedrock_river_incision_rate_array, + std::vector &bedrock_transport_coefficient_array) const; + + /** + * Fill velocity data table to be interpolated back onto the ASPECT mesh. + */ + Table fill_data_table(std::vector &values, + TableIndices &size_idx, + const unsigned int &fastscape_nx, + const unsigned int &fastscape_ny) const; + + /** + * Read data from file for restarting. + */ + void read_restart_files(std::vector &elevation, + std::vector &basement, + std::vector &silt_fraction) const; + + /** + * Save data to file for restarting. + */ + void save_restart_files(const std::vector &elevation, + std::vector &basement, + std::vector &silt_fraction) const; + + /** + * Suggestion for the number of FastScape steps to run for every ASPECT timestep, + * where the FastScape timestep is determined by ASPECT_timestep_length divided by + * this parameter. + */ + unsigned int fastscape_steps_per_aspect_step; + + /** + * Maximum timestep allowed for FastScape, if the suggested timestep exceeds this + * limit it is repeatedly divided by 2 until the final timestep is smaller than this parameter. + */ + double maximum_fastscape_timestep; + + /** + * Check whether FastScape needs to be restarted. This is used as + * a mutable bool because we determine whether the model is being resumed in + * initialize(), and then after reinitializing FastScape we change it to false + * so it does not initialize FastScape again in future timesteps. + * TODO: There is probably a better way to do this, and restarts should be rolled into + * the general ASPECT restart. + */ + mutable bool restart; + + /** + * FastScape cell size in X. + */ + double fastscape_dx; + + /** + * FastScape cell size in Y. + */ + double fastscape_dy; + + /** + * FastScape X extent (ASPECT X extent + 2*dx for ghost nodes). + */ + double fastscape_x_extent; + + /** + * Fastscape Y extent (ASPECT Y extent + 2*dy for ghost nodes). + */ + double fastscape_y_extent; + + /** + * User set FastScape Y extent for a 2D ASPECT model. + */ + double fastscape_y_extent_2d; + + /** + * Number of x points in FastScape array. + */ + unsigned int fastscape_nx; + + /** + * Number of y points in FastScape array. + */ + unsigned int fastscape_ny; + + /** + * Vertical exaggeration in FastScape visualization. + */ + double vexp; + + /** + * How many levels FastScape should be refined above the maximum ASPECT surface resolution. + */ + unsigned int additional_refinement_levels; + + /** + * Maximum expected refinement level at ASPECT's surface. + * This and resolution_difference are required to properly transfer node data from + * ASPECT to FastScape. + */ + unsigned int maximum_surface_refinement_level; + + /** + * Difference in refinement levels expected at the ASPECT surface, + * where this would be set to 2 if 3 refinement levels are set at the surface. + * This and surface_resolution are required to properly transfer node data from + * ASPECT to FastScape. + * + * TODO: Should this be kept this way, or make it so the input is the expected levels + * of refinement at the surface, and we can subtract one within the code? Also, + * it would be good to find a way to check these are correct, because they are a + * common source of errors. + */ + unsigned int surface_refinement_difference; + + /** + * If set to true, the FastScape surface is averaged along Y and returned + * to ASPECT. If set to false, the center slice of the FastScape model is + * returned to ASPECT. + */ + bool average_out_of_plane_surface_topography; + + /** + * Seed number for initial topography noise in FastScape. + */ + int fastscape_seed; + + /** + * Variable to hold ASPECT domain extents. + */ + std::array,dim> grid_extent; + + /** + * Table for interpolating FastScape surface velocities back to ASPECT. + */ + std::array table_intervals; + + /** + * Whether or not to use the ghost nodes. + */ + bool use_ghost_nodes; + + /** + * Magnitude (m) of the initial noise applied to FastScape. + * Applied as either a + or - value to the topography + * such that the total difference can be up to 2*noise_elevation. + */ + double noise_elevation; + + /** + * Sediment rain in m/yr, added as a flat increase to the FastScape surface + * in the marine domain every ASPECT timestep before running FastScape. + */ + std::vector sediment_rain_rates; + + /** + * Time at which each interval of sediment_rain_rates is active. Should contain + * one less value than sediment_rain_rates, assuming that sediment_rain_rates[0] + * is applied from model time 0 until sediment_rain_times[0]. + */ + std::vector sediment_rain_times; + + /** + * Flag for having FastScape advect/uplift the surface. If the free surface is used + * in conjunction with FastScape, this can be set to false, then FastScape will only + * apply erosion/deposition to the surface and not advect or uplift it. + */ + bool fastscape_advection_uplift; + + /** + * Node tolerance for how close a ASPECT node must be to the FastScape node + * for the value to be transferred. This is only necessary if use_v is set to 0 + * and the free surface is used to advect the surface with a normal projection, or + * if there is a surface refinement level difference leading to excess interpolation + * points in areas of high ASPECT resolution. + */ + double node_tolerance; + + /** + * Interval between the generation of graphical output. This parameter + * is read from the input file and consequently is not part of the + * state that needs to be saved and restored. + */ + double output_interval; + + /** + * A time (in seconds) at which the last graphical output was supposed + * to be produced. Used to check for the next necessary output time. + */ + mutable double last_output_time; + + /** + * @name Fastscape boundary conditions + * @{ + */ + + /** + * FastScape bottom boundary condition that determines topography at the FastScape bottom boundary. + * Where 1 represents a fixed height boundary (though this can still be uplifted through uplift velocities), and 0 a + * reflective boundary. When two opposing boundaries are reflective (e.g., top and bottom are both zero), then the boundaries + * become cyclic. + */ + unsigned int bottom; + + /** + * FastScape top boundary condition that determines topography at the FastScape top boundary. + * Where 1 represents a fixed height boundary (though this can still be uplifted through uplift velocities), and 0 a + * reflective boundary. When two opposing boundaries are reflective (e.g., top and bottom are both zero), then the boundaries + * become cyclic. + */ + unsigned int top; + + /** + * FastScape right boundary condition that determines topography at the FastScape right boundary. + * Where 1 represents a fixed height boundary (though this can still be uplifted through uplift velocities), and 0 a + * reflective boundary. When two opposing boundaries are reflective (e.g., left and right are both zero), then the boundaries + * become cyclic. + */ + unsigned int right; + + /** + * FastScape left boundary condition that determines topography at the FastScape left boundary. + * Where 1 represents a fixed height boundary (though this can still be uplifted through uplift velocities), and 0 a + * reflective boundary. When two opposing boundaries are reflective (e.g., left and right are both zero), then the boundaries + * become cyclic. + */ + unsigned int left; + + /** + * Parameters that set the FastScape boundaries periodic even though the ghost nodes are set 'fixed' + */ + bool topbottom_ghost_nodes_periodic; + bool leftright_ghost_nodes_periodic; + + /** + * Integer that holds the full boundary conditions sent to FastScape (e.g., 1111). + */ + unsigned int fastscape_boundary_conditions; + + /** + * Prescribed flux per unit length into the model through the bottom boundary (m^2/yr). + */ + double bottom_flux; + + /** + * Prescribed flux per unit length into the model through the top boundary (m^2/yr). + */ + double top_flux; + + /** + * Prescribed flux per unit length into the model through the right boundary (m^2/yr). + */ + double right_flux; + + /** + * Prescribed flux per unit length into the model through the left boundary (m^2/yr). + */ + double left_flux; + /** + * @} + */ + + /** + * @name FastScape subaerial erosional parameters + * @{ + */ + + /** + * Drainage area exponent for the stream power law. ($m$ variable in FastScape surface equation.) + */ + double drainage_area_exponent_m; + + /** + * Slope exponent for the stream power law. ($n$ variable in FastScape surface equation.) + */ + double slope_exponent_n; + + /** + * Slope exponent for multi-direction flow, where 0 is uniform, and 10 is steepest descent. (-1 varies with slope.) + * ($p$ variable in FastScape surface equation.) + */ + double slope_exponent_p; + + /** + * Bedrock deposition coefficient. Higher values deposit more sediment + * inside the domain. ($G$ variable in FastScape surface equation.) + */ + double bedrock_deposition_g; + + /** + * Sediment deposition coefficient. Higher values deposit more sediment inside the domain. + * When set to -1 this is identical to the bedrock value. + * ($G$ variable in FastScape surface equation applied to sediment.) + */ + double sediment_deposition_g; + + /** + * Bedrock river incision rate for the stream power law. + * (meters^(1-2m)/yr, $kf$ variable in FastScape surface equation.) + */ + double bedrock_river_incision_rate; + + /** + * Sediment river incision rate for the stream power law (meters^(1-2m)/yr). + * When set to -1 this is identical to the bedrock value. + * ($kf$ variable in FastScape surface equation applied to sediment.) + */ + double sediment_river_incision_rate; + + /** + * Bedrock transport coefficient for hillslope diffusion (m^2/yr, kd in FastScape surface equation.) + */ + double bedrock_transport_coefficient; + + /** + * Sediment transport coefficient for hillslope diffusion (m^2/yr). When set to -1 this is + * identical to the bedrock value. + * (kd in FastScape surface equation applied to sediment). + */ + double sediment_transport_coefficient; + /** + * @} + */ + + /** + * @name Fastscape marine parameters + * @{ + */ + + /** + * Fastscape sea level (m), set relative to the ASPECT surface where + * a sea level of zero will represent the initial maximum unperturbed + * Y (2D) or Z (3D) extent of the ASPECT domain. A negative value of + * the sea level means the sea level lies below the initial unperturbed + * top boundary of the domain. + */ + double sea_level; + + /** + * Parameters to set an extra erosional base level + * on the ghost nodes that differs from sea level. + */ + bool use_fixed_erosional_base; + + /** + * Height of the extra erosional base level. + */ + double h_erosional_base; + + /** + * Surface porosity for sand. + */ + double sand_surface_porosity; + + /** + * Surface porosity for silt. + */ + double silt_surface_porosity; + + /** + * Sands e-folding depth for exponential porosity law (m). + */ + double sand_efold_depth; + + /** + * Silts e-folding depth for exponential porosity law (m). + */ + double silt_efold_depth; + + /** + * Sand-silt ratio + */ + double sand_silt_ratio; + + /** + * Averaging depth/thickness for sand-silt equation (m). + */ + double sand_silt_averaging_depth; + + /** + * Sand marine transport coefficient. (marine diffusion, m^2/yr.) + */ + double sand_transport_coefficient; + + /** + * Silt marine transport coefficient. (marine diffusion, m^2/yr.) + */ + double silt_transport_coefficient; + + /** + * Flag to use the marine component of FastScape. + */ + bool use_marine_component; + /** + * @} + */ + + /** + * @name Orographic parameters + * @{ + */ + + /** + * Set a flat height (m) after which the flat_erosional_factor + * is applied to the bedrock river incision rate and transport coefficient. + */ + int flat_elevation; + + /** + * Set the height (m) after which the model will track the ridge line + * and based on the wind direction will apply the wind_barrier_erosional_factor + * to the bedrock river incision rate and transport coefficient. + */ + int wind_barrier_elevation; + + /** + * Wind direction for wind_barrier_erosional_factor. + */ + unsigned int wind_direction; + + /** + * Factor to multiply the bedrock river incision rate and transport coefficient by depending on them + * flat_elevation. + */ + double flat_erosional_factor; + + /** + * Factor to multiply the bedrock river incision rate and transport coefficient by depending on them + * wind_barrier_elevation and wind direction. + */ + double wind_barrier_erosional_factor; + + /** + * Flag to stack both orographic controls. + */ + bool stack_controls; + + /** + * Flag to use orographic controls. + */ + bool use_orographic_controls; + /** + * @} + */ + }; + } +} + +#endif +#endif diff --git a/include/aspect/mesh_deformation/free_surface.h.bak b/include/aspect/mesh_deformation/free_surface.h.bak new file mode 100644 index 00000000000..7cb6c1fd631 --- /dev/null +++ b/include/aspect/mesh_deformation/free_surface.h.bak @@ -0,0 +1,116 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_deformation_free_surface_h +#define _aspect_mesh_deformation_free_surface_h + +#include + +#include +#include + + +namespace aspect +{ + using namespace dealii; + + namespace MeshDeformation + { + /** + * A plugin that computes the deformation of surface + * vertices according to the solution of the flow problem. + * In particular this means if the surface of the domain is + * left open to flow, this flow will carry the mesh with it. + */ + template + class FreeSurface : public Interface, public SimulatorAccess + { + public: + /** + * Initialize function, which connects the set_assemblers function + * to the appropriate Simulator signal. + */ + void initialize() override; + + /** + * Called by Simulator::set_assemblers() to allow the FreeSurface plugin + * to register its assembler. + */ + void set_assemblers(const SimulatorAccess &simulator_access, + aspect::Assemblers::Manager &assemblers) const; + + + /** + * A function that creates constraints for the velocity of certain mesh + * vertices (e.g. the surface vertices) for a specific boundary. + * The calling class will respect + * these constraints when computing the new vertex positions. + */ + void + compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, + AffineConstraints &mesh_velocity_constraints, + const std::set &boundary_id) const override; + + /** + * Returns whether or not the plugin requires surface stabilization + */ + bool needs_surface_stabilization () const override; + + /** + * Declare parameters for the free surface handling. + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * Parse parameters for the free surface handling. + */ + void parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Project the Stokes velocity solution onto the + * free surface. Called by make_constraints() + */ + void project_velocity_onto_boundary (const DoFHandler &free_surface_dof_handler, + const IndexSet &mesh_locally_owned, + const IndexSet &mesh_locally_relevant, + LinearAlgebra::Vector &output) const; + + /** + * A struct for holding information about how to advect the free surface. + */ + struct SurfaceAdvection + { + enum Direction { normal, vertical }; + }; + + /** + * Stores whether to advect the free surface in the normal direction + * or the direction of the local vertical. + */ + typename SurfaceAdvection::Direction advection_direction; + }; + } +} + + +#endif diff --git a/include/aspect/mesh_deformation/function.h.bak b/include/aspect/mesh_deformation/function.h.bak new file mode 100644 index 00000000000..7f2d29a5258 --- /dev/null +++ b/include/aspect/mesh_deformation/function.h.bak @@ -0,0 +1,87 @@ +/* + Copyright (C) 2018 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_deformation_boundary_function_h +#define _aspect_mesh_deformation_boundary_function_h + +#include +#include + +#include + +namespace aspect +{ + using namespace dealii; + + namespace MeshDeformation + { + template + class BoundaryFunction : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + BoundaryFunction(); + + /** + * + */ + void update() override; + + /** + * A function that creates constraints for the velocity of certain mesh + * vertices (e.g. the surface vertices) for a specific boundary. + * The calling class will respect + * these constraints when computing the new vertex positions. + */ + void + compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, + AffineConstraints &mesh_velocity_constraints, + const std::set &boundary_id) const override; + + /** + * Returns whether or not the plugin requires surface stabilization + */ + bool needs_surface_stabilization () const override; + + /** + * Declare parameters for the free surface handling. + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * Parse parameters for the free surface handling. + */ + void parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A function object representing the mesh deformation. + */ + Functions::ParsedFunction function; + }; + } +} + + +#endif diff --git a/include/aspect/mesh_deformation/interface.h.bak b/include/aspect/mesh_deformation/interface.h.bak new file mode 100644 index 00000000000..210b61651d5 --- /dev/null +++ b/include/aspect/mesh_deformation/interface.h.bak @@ -0,0 +1,649 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_deformation_interface_h +#define _aspect_mesh_deformation_interface_h + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace aspect +{ + using namespace dealii; + + namespace Assemblers + { + /** + * Apply stabilization to a cell of the system matrix. The + * stabilization is only added to cells on a free surface. The + * scheme is based on that of Kaus et. al., 2010. Called during + * assembly of the system matrix. + */ + template + class ApplyStabilization: public Assemblers::Interface, + public SimulatorAccess + { + public: + ApplyStabilization(const double stabilization_theta); + + void + execute (internal::Assembly::Scratch::ScratchBase &scratch, + internal::Assembly::CopyData::CopyDataBase &data) const override; + + private: + /** + * Stabilization parameter for the free surface. Should be between + * zero and one. A value of zero means no stabilization. See Kaus + * et. al. 2010 for more details. + */ + const double free_surface_theta; + }; + } + + template class Simulator; + + /** + * A namespace that contains everything that is related to the deformation + * of the mesh vertices over time. + */ + namespace MeshDeformation + { + /** + * A base class for mesh deformation plugins. Each derived class should + * implement a function that determines the deformation velocity for certain + * mesh vertices and store them in a AffineConstraints object. The velocities + * for all non-constrained vertices will be computed by solving a Laplace + * problem with the given constraints. + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * A function that will be called to check whether stabilization is needed. + */ + virtual bool needs_surface_stabilization() const; + + + /** + * A function that returns the initial deformation of points on the + * boundary (e.g. the surface vertices). @p position is the undeformed + * position and this function is expected to return the + * displacement vector of this position. The default implementation + * returns a zero displacement (= no initial deformation). + */ + virtual + Tensor<1,dim> + compute_initial_deformation_on_boundary(const types::boundary_id boundary_indicator, + const Point &position) const; + + /** + * A function that creates constraints for the velocity of certain mesh + * vertices (e.g. the surface vertices) for a specific set of boundaries. + * The calling class will respect + * these constraints when computing the new vertex positions. + * The default implementation creates no constraints. + */ + virtual + void + compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, + AffineConstraints &mesh_velocity_constraints, + const std::set &boundary_id) const; + }; + + + + /** + * The MeshDeformationHandler that handles the motion + * of the surface, the internal nodes and computes the + * Arbitrary-Lagrangian-Eulerian correction terms. + */ + template + class MeshDeformationHandler: public SimulatorAccess + { + public: + /** + * Initialize the mesh deformation handler, allowing it to read in + * relevant parameters as well as giving it a reference to the + * Simulator that owns it, since it needs to make fairly extensive + * changes to the internals of the simulator. + */ + MeshDeformationHandler(Simulator &simulator); + + /** + * Destructor for the mesh deformation handler. + */ + ~MeshDeformationHandler() override; + + /** + * Initialization function of the MeshDeformationHandler. + * + * The default implementation of this function does nothing. + */ + void initialize(); + + /** + * Called by Simulator::set_assemblers() to allow the FreeSurface plugin + * to register its assembler. + */ + void set_assemblers(const SimulatorAccess &simulator_access, + aspect::Assemblers::Manager &assemblers) const; + + /** + * Update function of the MeshDeformationHandler. This function + * allows the individual mesh deformation objects to update. + */ + void update(); + + /** + * The main execution step for the mesh deformation implementation. This + * computes the motion of the surface, moves the boundary nodes + * accordingly, redistributes the internal nodes in order to + * preserve mesh regularity, and calculates the + * Arbitrary-Lagrangian-Eulerian correction terms for advected quantities. + */ + void execute(); + + /** + * Allocates and sets up the members of the MeshDeformationHandler. This + * is called by Simulator::setup_dofs() + */ + void setup_dofs(); + + /** + * Declare parameters for the mesh deformation handling. + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * Parse parameters for the mesh deformation handling. + */ + void parse_parameters (ParameterHandler &prm); + + /** + * A function that is used to register mesh deformation objects in such + * a way that the Manager can deal with all of them without having to + * know them by name. This allows the files in which individual + * plugins are implemented to register these plugins, rather than also + * having to modify the Manager class by adding the new initial + * mesh deformation plugin class. + * + * @param name A string that identifies the mesh deformation model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this mesh deformation model + * wants to read from input files. + * @param factory_function A pointer to a function that can create an + * object of this mesh deformation model. + */ + static + void + register_mesh_deformation + (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * Return a map of boundary indicators to the names of all mesh deformation models currently + * used in the computation, as specified in the input file. + */ + const std::map> & + get_active_mesh_deformation_names () const; + + /** + * Return a map of boundary indicators to vectors of pointers to all mesh deformation models + * currently used in the computation, as specified in the input file. + */ + const std::map>>> & + get_active_mesh_deformation_models () const; + + /** + * Return a set of all the indicators of boundaries with + * mesh deformation objects on them. + */ + const std::set & + get_active_mesh_deformation_boundary_indicators () const; + + /** + * Return a set of all the indicators of boundaries that + * require surface stabilization. + */ + const std::set & + get_boundary_indicators_requiring_stabilization () const; + + /** + * Return the boundary id of the surface that has a free surface + * mesh deformation object. If no free surface is used, + * an empty set is returned. + */ + const std::set & + get_free_surface_boundary_indicators () const; + + /** + * Return the stabilization parameter for the free surface. + */ + double get_free_surface_theta () const; + + /** + * Return the initial topography stored on + * the Q1 finite element that describes the mesh geometry. + * Note that a topography is set for all mesh nodes, + * but only the values of surface boundary nodes are correct. + * The internal nodes get the same initial topography as the + * corresponding surface node. In other words, there is + * no decrease of the initial topography with depth. + * However, only the topography stored at the surface nodes + * is taken into account in the diffusion plugin that + * uses this function. TODO Once all initial_topography + * is prescribed through initial_mesh_deformation, this + * function can be removed. + */ + const LinearAlgebra::Vector & + get_initial_topography () const; + + /** + * Return the mesh displacements based on the mesh deformation + * DoFHandler you can access with get_mesh_deformation_dof_handler(). + */ + const LinearAlgebra::Vector & + get_mesh_displacements () const; + + /** + * Return the DoFHandler used to represent the mesh deformation space. + */ + const DoFHandler & + get_mesh_deformation_dof_handler () const; + + /** + * Go through the list of all mesh deformation objects that have been selected + * in the input file (and are consequently currently active) and return + * true if one of them has the desired type specified by the template + * argument. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,MeshDeformationType>::value>> + bool + has_matching_mesh_deformation_object () const; + + /** + * Go through the list of all mesh deformation objects that have been selected + * in the input file (and are consequently currently active) and see + * if one of them has the type specified by the template + * argument or can be cast to that type. If so, return a reference + * to it. If no mesh deformation object is active that matches the given type, + * throw an exception. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,MeshDeformationType>::value>> + const MeshDeformationType & + get_matching_mesh_deformation_object () const; + + + /** + * If multilevel solvers are used, we need a mapping on each multigrid level. These + * are automatically updated by this handler class and can be accessed with this + * method. + */ + const Mapping & + get_level_mapping(const unsigned int level) const; + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + /** + * Exception. + */ + DeclException1 (ExcMeshDeformationNameNotFound, + std::string, + << "Could not find entry <" + << arg1 + << "> among the names of registered mesh deformation objects."); + + private: + /** + * Compute the initial constraints for the mesh displacement + * on the boundaries of the domain. This is used on the mesh + * deformation boundaries to describe a displacement (initial + * topography) to be used during the simulation. The + * displacement is given by the active deformation plugins. + */ + void make_initial_constraints (); + + /** + * Compute the constraints for the mesh velocity on the + * boundaries of the domain. On the mesh deformation + * boundaries, the velocity is given by the active deformation + * plugins. + * + * Velocities on free-slip boundaries are constrained to be + * tangential to those boundaries. Velocities on no-slip + * boundaries are set to be zero. If a no-slip boundary is + * marked as additional tangential, then velocities are + * constrained as tangential. + */ + void make_constraints (); + + /** + * Solve vector Laplacian equation for internal mesh displacements and update + * the current displacement vector based on the solution. + */ + void compute_mesh_displacements (); + + /** + * Solve vector Laplacian equation using GMG for internal mesh displacements and update + * the current displacement vector based on the solution. + */ + void compute_mesh_displacements_gmg (); + + /** + * Set up the vector with initial displacements of the mesh + * due to the initial topography, as supplied by the initial + * topography plugin based on the surface coordinates of the + * mesh nodes. We set all entries to the initial topography + * based on its surface coordinates, i.e. the initial topography + * is not corrected for depth from the surface as it is + * for the initial mesh deformation. TODO this is ok for now, + * because the surface diffusion plugin only cares about the + * initial topography at the surface, but it would be more correct if it + * sets the initial topography to the actual initial distortion of + * the mesh cells. When all initial_topography plugins are converted + * to the new initial_mesh_deformation functionality, this function + * can be removed. + */ + void set_initial_topography (); + + /** + * Calculate the velocity of the mesh for ALE corrections. + */ + void interpolate_mesh_velocity (); + + /** + * Update the mesh deformation for the multigrid levels. + */ + void update_multilevel_deformation (); + + /** + * Reference to the Simulator object to which a MeshDeformationHandler + * instance belongs. + */ + Simulator ∼ + + /** + * Finite element for the mesh deformation implementation, which is + * used for tracking mesh deformation. + */ + const FESystem mesh_deformation_fe; + + /** + * DoFHandler for the mesh deformation implementation. + */ + DoFHandler mesh_deformation_dof_handler; + + /** + * BlockVector which stores the mesh velocity in the + * Stokes finite element space. + * This is used for ALE corrections. + */ + LinearAlgebra::BlockVector mesh_velocity; + + /** + * Vector for storing the positions of the mesh vertices. This + * is used for calculating the mapping from the reference cell to + * the position of the cell in the deformed mesh. This must be + * redistributed upon mesh refinement. + */ + LinearAlgebra::Vector mesh_displacements; + + /** + * mesh_displacements from the last time step. + */ + LinearAlgebra::Vector old_mesh_displacements; + + /** + * Vector for storing the positions of the mesh vertices at the initial timestep. + * This must be redistributed upon mesh refinement. + * We need to store the initial topography because it is not taken + * into account into the mesh displacements used by the MappingQ1Eulerian. + * The current mesh displacements plus the initial topography provide + * the actual topography at any time. + */ + LinearAlgebra::Vector initial_topography; + + /** + * Vector for storing the mesh velocity in the mesh deformation finite + * element space, which is, in general, not the same finite element + * space as the Stokes system. This is used for interpolating + * the mesh velocity in the mesh deformation finite element space onto + * the velocity in the Stokes finite element space, which is then + * used for making the ALE correction in the advection equations. + */ + LinearAlgebra::Vector fs_mesh_velocity; + + /** + * IndexSet for the locally owned DoFs for the mesh system + */ + IndexSet mesh_locally_owned; + + /** + * IndexSet for the locally relevant DoFs for the mesh system + */ + IndexSet mesh_locally_relevant; + + /** + * Storage for the mesh velocity constraints for solving the + * elliptic problem. + */ + AffineConstraints mesh_velocity_constraints; + + /** + * Storage for the mesh vertex constraints for keeping the mesh conforming + * upon redistribution. + */ + AffineConstraints mesh_vertex_constraints; + + /** + * A map of boundary ids to mesh deformation objects that have been requested + * in the parameter file. + */ + std::map>>> mesh_deformation_objects; + + /** + * Map from boundary id to a vector of names representing + * mesh deformation objects. + */ + std::map> mesh_deformation_object_names; + + /** + * The set of boundary indicators for which mesh deformation + * objects are set and that therefore can deform over time as + * prescribed in the mesh_deformation_objects. + */ + std::set prescribed_mesh_deformation_boundary_indicators; + + /** + * A set of boundary indicators that denote those boundaries that are + * allowed to move their mesh tangential to the boundary. + */ + std::set tangential_mesh_deformation_boundary_indicators; + + /** + * A set of boundary indicators, on which mesh deformation is prescribed to + * be zero (fixed boundaries that never move). All boundaries except those + * in prescribed_mesh_deformation_boundary_indicators and + * tangential_mesh_deformation_boundary_indicators are in this set. + */ + std::set zero_mesh_deformation_boundary_indicators; + + /** + * The boundary indicator(s) of the free surface(s). This is the + * subset of prescribed_mesh_deformation_boundary_indicators for which + * the 'free surface' plugin was selected. + */ + std::set free_surface_boundary_indicators; + + /** + * The set of boundary indicators for which the mesh deformation + * objects need surface stabilization. + */ + std::set boundary_indicators_requiring_stabilization; + + bool include_initial_topography; + + /** + * Stabilization parameter for the free surface. Should be between + * zero and one. A value of zero means no stabilization. See Kaus + * et. al. 2010 for more details. + */ + double surface_theta; + + /** + * If required, store a mapping for each multigrid level. + */ + MGLevelObject>> level_mappings; + + /** + * One vector on each multigrid level for the mesh displacement used in the mapping. + */ + MGLevelObject> level_displacements; + + /** + * Multigrid transfer operator for the displacements + */ + MGTransferMF mg_transfer; + + /** + * Multigrid level constraints for the displacements + */ + MGConstrainedDoFs mg_constrained_dofs; + + friend class Simulator; + friend class SimulatorAccess; + }; + + + + template + template + inline + bool + MeshDeformationHandler::has_matching_mesh_deformation_object () const + { + for (const auto &object_iterator : mesh_deformation_objects) + for (const auto &p : object_iterator.second) + if (Plugins::plugin_type_matches(*p)) + return true; + + return false; + } + + + + template + template + inline + const MeshDeformationType & + MeshDeformationHandler::get_matching_mesh_deformation_object () const + { + AssertThrow(has_matching_mesh_deformation_object (), + ExcMessage("You asked MeshDeformation::MeshDeformationHandler::get_matching_mesh_deformation_object() for a " + "mesh deformation object of type <" + boost::core::demangle(typeid(MeshDeformationType).name()) + "> " + "that could not be found in the current model. Activate this " + "mesh deformation in the input file.")); + + for (const auto &object_iterator : mesh_deformation_objects) + for (const auto &p : object_iterator.second) + if (Plugins::plugin_type_matches(*p)) + return Plugins::get_plugin_as_type(*p); + + // We will never get here, because we had the Assert above. Just to avoid warnings. + typename std::vector>>::const_iterator mesh_def; + return Plugins::get_plugin_as_type(*(*mesh_def)); + + } + + + /** + * Return a string that consists of the names of mesh deformation models that can + * be selected. These names are separated by a vertical line '|' so + * that the string can be an input to the deal.II classes + * Patterns::Selection or Patterns::MultipleSelection. + */ + template + std::string + get_valid_model_names_pattern (); + + + + /** + * Given a class name, a name, and a description for the parameter file + * for a mesh deformation model, register it with the functions that can + * declare their parameters and create these objects. + * + * @ingroup MeshDeformations + */ +#define ASPECT_REGISTER_MESH_DEFORMATION_MODEL(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_MESH_DEFORMATION_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::MeshDeformation::MeshDeformationHandler<2>::register_mesh_deformation, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::MeshDeformation::MeshDeformationHandler<3>::register_mesh_deformation, \ + name, description); \ + } + } +} + +#endif diff --git a/include/aspect/mesh_refinement/artificial_viscosity.h.bak b/include/aspect/mesh_refinement/artificial_viscosity.h.bak new file mode 100644 index 00000000000..7a1ef789a3b --- /dev/null +++ b/include/aspect/mesh_refinement/artificial_viscosity.h.bak @@ -0,0 +1,78 @@ +/* + Copyright (C) 2015 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_artificial_viscosity_h +#define _aspect_mesh_refinement_artificial_viscosity_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on the + * artificial viscosity of the temperature or compositional fields. + * + * @ingroup MeshRefinement + */ + template + class ArtificialViscosity : public Interface, + public SimulatorAccess + { + public: + /** + * @copydoc Interface::execute() + */ + void + execute (Vector &error_indicators) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * Scaling factor for the temperature indicator. + */ + double temperature_scaling_factor; + + /** + * The scaling factors for each compositional field. + */ + std::vector composition_scaling_factors; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/boundary.h.bak b/include/aspect/mesh_refinement/boundary.h.bak new file mode 100644 index 00000000000..b74aa534652 --- /dev/null +++ b/include/aspect/mesh_refinement/boundary.h.bak @@ -0,0 +1,81 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_boundary_h +#define _aspect_mesh_refinement_boundary_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion that refines the + * mesh on selected boundaries. This is useful for cases where one wants + * to accurately model processes at a boundary. Frequently, there are + * also strong temperature or compositional gradients at boundaries, so + * this refinement criterion can be redundant. + * + * @ingroup MeshRefinement + */ + template + class Boundary : public Interface, + public SimulatorAccess + { + public: + + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A set of boundary indicators marked for refinement + */ + std::set boundary_refinement_indicators; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/compaction_length.h.bak b/include/aspect/mesh_refinement/compaction_length.h.bak new file mode 100644 index 00000000000..60199d3d1fd --- /dev/null +++ b/include/aspect/mesh_refinement/compaction_length.h.bak @@ -0,0 +1,79 @@ +/* + Copyright (C) 2015 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_compaction_length_h +#define _aspect_mesh_refinement_compaction_length_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on the + * compaction length, a typical length scale in models with melt + * migration. The user can specify a desired ratio between the + * compaction length and the size of the mesh cells, and every cell + * where this ratio is smaller than specified is marked for refinement. + * This means that there will always be a given (minimum) number of + * mesh cells per compaction length. + * + * @ingroup MeshRefinement + */ + template + class CompactionLength : public Interface, + public SimulatorAccess + { + public: + /** + * After cells have been marked for coarsening/refinement, apply + * additional criteria independent of the error estimate. + */ + void + tag_additional_cells () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The desired ratio between compaction length and size of the mesh cells, + * in other words, how many cells the mesh should have per compaction length. + */ + double cells_per_compaction_length; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/composition.h.bak b/include/aspect/mesh_refinement/composition.h.bak new file mode 100644 index 00000000000..05e100701fa --- /dev/null +++ b/include/aspect/mesh_refinement/composition.h.bak @@ -0,0 +1,78 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_composition_h +#define _aspect_mesh_refinement_composition_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on the + * compositional fields (if available). + * + * @ingroup MeshRefinement + */ + template + class Composition : public Interface, + public SimulatorAccess + { + public: + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The scaling factors that should be applied to the individual + * refinement indicators before merging. + */ + std::vector composition_scaling_factors; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/composition_approximate_gradient.h.bak b/include/aspect/mesh_refinement/composition_approximate_gradient.h.bak new file mode 100644 index 00000000000..357560ff0e9 --- /dev/null +++ b/include/aspect/mesh_refinement/composition_approximate_gradient.h.bak @@ -0,0 +1,78 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_composition_approximate_gradient_h +#define _aspect_mesh_refinement_composition_approximate_gradient_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on + * the approximated gradient of the compositional fields (if available). + * + * @ingroup MeshRefinement + */ + template + class CompositionApproximateGradient : public Interface, + public SimulatorAccess + { + public: + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The scaling factors that should be applied to the individual + * refinement indicators before merging. + */ + std::vector composition_scaling_factors; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/composition_gradient.h.bak b/include/aspect/mesh_refinement/composition_gradient.h.bak new file mode 100644 index 00000000000..dae9c4daf06 --- /dev/null +++ b/include/aspect/mesh_refinement/composition_gradient.h.bak @@ -0,0 +1,78 @@ +/* + Copyright (C) 2015 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_composition_gradient_h +#define _aspect_mesh_refinement_composition_gradient_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on the + * gradient of the compositional fields (if available). + * + * @ingroup MeshRefinement + */ + template + class CompositionGradient : public Interface, + public SimulatorAccess + { + public: + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The scaling factors that should be applied to the individual + * refinement indicators before merging. + */ + std::vector composition_scaling_factors; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/composition_threshold.h.bak b/include/aspect/mesh_refinement/composition_threshold.h.bak new file mode 100644 index 00000000000..159112ba6df --- /dev/null +++ b/include/aspect/mesh_refinement/composition_threshold.h.bak @@ -0,0 +1,76 @@ +/* + Copyright (C) 2015 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_composition_threshold_h +#define _aspect_mesh_refinement_composition_threshold_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on the + * absolute value of the compositional fields. Every cell that contains a + * value exceeding a threshold given in the input file is marked for + * refinement. + * + * @ingroup MeshRefinement + */ + template + class CompositionThreshold : public Interface, + public SimulatorAccess + { + public: + /** + * After cells have been marked for coarsening/refinement, apply + * additional criteria independent of the error estimate. + */ + void + tag_additional_cells () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The thresholds that should be used for the individual + * compositional fields. + */ + std::vector composition_thresholds; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/density.h.bak b/include/aspect/mesh_refinement/density.h.bak new file mode 100644 index 00000000000..3e326927d1e --- /dev/null +++ b/include/aspect/mesh_refinement/density.h.bak @@ -0,0 +1,60 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_density_h +#define _aspect_mesh_refinement_density_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on a field + * representing the density $\rho$ as a spatially variable function and + * that we compute from the solution vector (assuming the density actually + * depends on the solution). + * + * @ingroup MeshRefinement + */ + template + class Density : public Interface, + public SimulatorAccess + { + public: + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/interface.h.bak b/include/aspect/mesh_refinement/interface.h.bak new file mode 100644 index 00000000000..69b2a480d14 --- /dev/null +++ b/include/aspect/mesh_refinement/interface.h.bak @@ -0,0 +1,318 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_interface_h +#define _aspect_mesh_refinement_interface_h + +#include +#include +#include + +#include +#include +#include +#include + + +namespace aspect +{ + using namespace dealii; + + template class Simulator; + template class SimulatorAccess; + + + /** + * A namespace for everything to do with the decision on how to refine the + * mesh every few time steps. + * + * @ingroup MeshRefinement + */ + namespace MeshRefinement + { + + /** + * This class declares the public interface of mesh refinement plugins. + * Plugins have two different ways to influence adaptive refinement (and + * can make use of either or both): + * + * First, execute() allows the plugin to specify weights for individual + * cells that are then used to coarsen and refine (where larger numbers + * indicate a larger error). + * + * Second, after cells get flagged for coarsening and refinement (using + * the first approach), tag_additional_cells() is executed for each + * plugin. Here the plugin is free to set or clear coarsen and refine + * flags on any cell. + * + * Access to the data of the simulator is granted by the @p protected + * member functions of the SimulatorAccess class, i.e., classes + * implementing this interface will in general want to derive from both + * this Interface class as well as from the SimulatorAccess class. + * + * @ingroup MeshRefinement + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Execute this mesh refinement criterion. The default implementation + * sets all the error indicators to zero. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + virtual + void + execute (Vector &error_indicators) const; + + /** + * After cells have been marked for coarsening/refinement, apply + * additional criteria independent of the error estimate. The default + * implementation does nothing. + * + * This function is also called during the initial global refinement + * cycle. At this point you do not have access to solutions, + * DoFHandlers, or finite element spaces. You can check if this is the + * case by querying this->get_dof_handler().n_dofs() == 0. + */ + virtual + void + tag_additional_cells () const; + }; + + + + + + + /** + * A class that manages all objects that provide functionality to refine + * meshes. + * + * @ingroup MeshRefinement + */ + template + class Manager : public Plugins::ManagerBase>, public SimulatorAccess + { + public: + /** + * Destructor. Made virtual since this class has virtual member + * functions. + */ + ~Manager () override; + + /** + * Update all of the mesh refinement objects that have been requested + * in the input file. Individual mesh refinement objects may choose to + * implement an update function to modify object variables once per + * time step. + */ + void + update () override; + + /** + * Execute all of the mesh refinement objects that have been requested + * in the input file. The error indicators are then each individually + * normalized and merged according to the operation specified in the + * input file (e.g., via a plus, a maximum operation, etc). + */ + virtual + void + execute (Vector &error_indicators) const; + + /** + * Apply additional refinement criteria independent of the error + * estimate for all of the mesh refinement objects that have been + * requested in the input file. + */ + virtual + void + tag_additional_cells () const; + + /** + * Declare the parameters of all known mesh refinement plugins, as + * well as of ones this class has itself. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * This determines which mesh refinement objects will be created; then + * let these objects read their parameters as well. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Go through the list of all mesh refinement strategies that have been selected + * in the input file (and are consequently currently active) and return + * true if one of them has the desired type specified by the template + * argument. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,MeshRefinementType>::value>> + bool + has_matching_mesh_refinement_strategy () const; + + /** + * Go through the list of all mesh refinement strategies that have been selected + * in the input file (and are consequently currently active) and see + * if one of them has the type specified by the template + * argument or can be cast to that type. If so, return a reference + * to it. If no mesh refinement strategy is active that matches the + * given type, throw an exception. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,MeshRefinementType>::value>> + const MeshRefinementType & + get_matching_mesh_refinement_strategy () const; + + /** + * A function that is used to register mesh refinement objects in such + * a way that the Manager can deal with all of them without having to + * know them by name. This allows the files in which individual + * plugins are implemented to register these plugins, rather than also + * having to modify the Manager class by adding the new mesh + * refinement class. + * + * @param name The name under which this plugin is to be called in + * parameter files. + * @param description A text description of what this model does and + * that will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that + * declares the parameters for this plugin. + * @param factory_function A pointer to a function that creates such a + * mesh refinement object and returns a pointer to it. + */ + static + void + register_mesh_refinement_criterion (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + /** + * Exception. + */ + DeclException1 (ExcMeshRefinementNameNotFound, + std::string, + << "Could not find entry <" + << arg1 + << "> among the names of registered mesh refinement objects."); + private: + /** + * An enum that describes the different ways in which we can merge the + * results of multiple mesh refinement criteria. + */ + enum MergeOperation + { plus, max }; + + /** + * How to merge the results of multiple mesh refinement criteria. + */ + MergeOperation merge_operation; + + /** + * Whether to normalize the individual refinement indicators to the + * range $[0,1]$ before merging. + */ + bool normalize_criteria; + + /** + * The scaling factors that should be applied to the individual + * refinement indicators before merging. + */ + std::vector scaling_factors; + }; + + + + template + template + inline + bool + Manager::has_matching_mesh_refinement_strategy () const + { + return this->template has_matching_plugin_object(); + } + + + + template + template + inline + const MeshRefinementType & + Manager::get_matching_mesh_refinement_strategy () const + { + return this->template get_matching_plugin_object(); + } + + + + /** + * Given a class name, a name, and a description for the parameter file + * for a mesh refinement object, register it with the + * aspect::MeshRefinement::Manager class. + * + * @ingroup MeshRefinement + */ +#define ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_MESH_REFINEMENT_CRITERION_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::MeshRefinement::Manager<2>::register_mesh_refinement_criterion, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::MeshRefinement::Manager<3>::register_mesh_refinement_criterion, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/mesh_refinement/isosurfaces.h.bak b/include/aspect/mesh_refinement/isosurfaces.h.bak new file mode 100644 index 00000000000..452474bb62c --- /dev/null +++ b/include/aspect/mesh_refinement/isosurfaces.h.bak @@ -0,0 +1,145 @@ +/* + Copyright (C) 2014 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_mesh_refinement_isosurfaces_h +#define _aspect_mesh_refinement_isosurfaces_h + +#include +#include +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + namespace internal + { + enum class PropertyType + { + Temperature, + Composition + }; + + struct Property + { + public: + /** + * Constructor. Converts a property name into a structure containing a property type + * and an index. If the property contains multiple items (e.g. the property compositional field has a + * field index) the index referring to the particular item of that property is stored in the variable index. + * @param property_name The name of a property, which can be Temperature for the temperature field or + * the name of a compositional field listed in the parameter available_compositions. + * @param available_compositions A list of names of the available compositional fields. + */ + Property(const std::string &property_name, + const std::vector &available_compositions); + + /** + * The Property type of the property + */ + PropertyType type; + + /** + * An index, in case the property type contains multiple values. This is + * currently only used for storing which compositional field the property + * corresponds to. + */ + unsigned int index; + }; + + struct Isosurface + { + public: + /** + * Checks whether the provided values are between the min and max value for the + * set properties of the isosurface. This function assumes that the order of the + * provided @p values matches the order in which the properties are stored. + * + * This function assumes that @p values and all the vectors in isosurfaces already + * have the same length. + */ + bool are_all_values_in_range(const std::vector &values) const; + + std::vector min_values; + std::vector max_values; + int min_refinement; + int max_refinement; + std::vector properties; + }; + + } + + /** + * A class that implements an Isosurfaces mesh refinement plugin. This + * plugin allows for setting a minimum and a maximum refinement level in + * a part of the model domain where a variable/property (e.g. Temperature) + * is between two values (e.g. two isotherms of 274K and 1600K). This is + * currently implemented for temperature and compositions. + * + * @ingroup MeshRefinement + */ + template + class Isosurfaces : public Interface, + public SimulatorAccess + { + public: + /** + * At the beginning of each time step, update the time for the + * ParsedFunction. + */ + void + update () override; + + /** + * After cells have been marked for coarsening/refinement, apply + * additional criteria independent of the error estimate. + * + */ + void + tag_additional_cells () const override; + + /** + * Declare the parameters this class takes from input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + + private: + /** + * A vector of the isosurfaces used by this class. + */ + std::vector isosurfaces; + + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/maximum_refinement_function.h.bak b/include/aspect/mesh_refinement/maximum_refinement_function.h.bak new file mode 100644 index 00000000000..4728cec3b83 --- /dev/null +++ b/include/aspect/mesh_refinement/maximum_refinement_function.h.bak @@ -0,0 +1,94 @@ +/* + Copyright (C) 2014 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_mesh_refinement_maximum_refinement_function_h +#define _aspect_mesh_refinement_maximum_refinement_function_h + +#include +#include +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a maximum refinement level based on a + * functional description provided in the input file. + * + * @ingroup MeshRefinement + */ + template + class MaximumRefinementFunction : public Interface, + public SimulatorAccess + { + public: + /** + * At the beginning of each time step, update the time for the + * ParsedFunction. + */ + void + update () override; + + /** + * After cells have been marked for coarsening/refinement, apply + * additional criteria independent of the error estimate. + * + */ + void + tag_additional_cells () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The coordinate representation to evaluate the function. Possible + * choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + + /** + * A function object representing the maximum refinement level. The + * function always depends on 3 variables, although in the case of the + * 'depth' coordinate system only the first is used to evaluate the + * function. + */ + Functions::ParsedFunction max_refinement_level; + + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/minimum_refinement_function.h.bak b/include/aspect/mesh_refinement/minimum_refinement_function.h.bak new file mode 100644 index 00000000000..c7e82d266b2 --- /dev/null +++ b/include/aspect/mesh_refinement/minimum_refinement_function.h.bak @@ -0,0 +1,95 @@ +/* + Copyright (C) 2014 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_mesh_refinement_minimum_refinement_function_h +#define _aspect_mesh_refinement_minimum_refinement_function_h + +#include +#include +#include + +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a minimum refinement level based on a + * functional description provided in the input file. + * + * @ingroup MeshRefinement + */ + template + class MinimumRefinementFunction : public Interface, + public SimulatorAccess + { + public: + /** + * At the beginning of each time step, update the time for the + * ParsedFunction. + */ + void + update () override; + + /** + * After cells have been marked for coarsening/refinement, apply + * additional criteria independent of the error estimate. + * + */ + void + tag_additional_cells () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The coordinate representation to evaluate the function. Possible + * choices are depth, cartesian and spherical. + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + + /** + * A function object representing the minimum refinement level. The + * function always depends on 3 variables, although in the case of the + * 'depth' coordinate system only the first is used to evaluate the + * function. + */ + Functions::ParsedFunction min_refinement_level; + + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/nonadiabatic_temperature.h.bak b/include/aspect/mesh_refinement/nonadiabatic_temperature.h.bak new file mode 100644 index 00000000000..2e60b9809aa --- /dev/null +++ b/include/aspect/mesh_refinement/nonadiabatic_temperature.h.bak @@ -0,0 +1,58 @@ +/* + Copyright (C) 2013 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_nonadiabatic_temperature_h +#define _aspect_mesh_refinement_nonadiabatic_temperature_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on the excess + * temperature (difference between temperature and adiabatic temperature). + * + * @ingroup MeshRefinement + */ + template + class NonadiabaticTemperature : public Interface, + public SimulatorAccess + { + public: + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/nonadiabatic_temperature_threshold.h.bak b/include/aspect/mesh_refinement/nonadiabatic_temperature_threshold.h.bak new file mode 100644 index 00000000000..fcdf35846bc --- /dev/null +++ b/include/aspect/mesh_refinement/nonadiabatic_temperature_threshold.h.bak @@ -0,0 +1,90 @@ +/* + Copyright (C) 2015 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_nonadiabatic_temperature_threshold_h +#define _aspect_mesh_refinement_nonadiabatic_temperature_threshold_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on the + * nonadiabatic temperature. Every cell that contains a value + * exceeding a threshold given in the input file is marked for + * refinement. + * + * @ingroup MeshRefinement + */ + template + class NonadiabaticTemperatureThreshold : public Interface, + public SimulatorAccess + { + public: + /** + * After cells have been marked for coarsening/refinement, apply + * additional criteria independent of the error estimate. + */ + void + tag_additional_cells () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The thresholds that should be used for the nonadiabatic + * temperature. + */ + double threshold; + + /** + * What type of temperature anomaly should be considered when + * evaluating against the threshold: Only negative anomalies + * (subadiabatic temperatures), only positive anomalies + * (superadiabatic temperatures) or the absolute value of the + * nonadiabatic temperature. + */ + enum anomaly + { + negative_only, + positive_only, + absolute_value + } temperature_anomaly_type; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/particle_density.h.bak b/include/aspect/mesh_refinement/particle_density.h.bak new file mode 100644 index 00000000000..8c8b6ab39f9 --- /dev/null +++ b/include/aspect/mesh_refinement/particle_density.h.bak @@ -0,0 +1,69 @@ +/* + Copyright (C) 2015 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_particle_density_h +#define _aspect_mesh_refinement_particle_density_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A mesh refinement criterion that computes + * refinement indicators based on the density + * of particles. In practice this plugin + * equilibrates the number of particles per cell, + * leading to fine cells in high particle density regions + * and coarse cells in low particle density regions. + * This plugin is mostly useful for models with inhomogeneous + * particle density, e.g. when tracking an initial interface + * with a high particle density, or when the spatial particle + * density denotes the region of interest. Additionally, this + * plugin tends to balance the computational load between + * processes in parallel computations, because the particle + * and mesh density is more aligned. + * + * @ingroup MeshRefinement + */ + template + class ParticleDensity : public Interface, + public SimulatorAccess + { + public: + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/slope.h.bak b/include/aspect/mesh_refinement/slope.h.bak new file mode 100644 index 00000000000..bdc7cce5690 --- /dev/null +++ b/include/aspect/mesh_refinement/slope.h.bak @@ -0,0 +1,62 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_slope_h +#define _aspect_mesh_refinement_slope_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion that refines the + * mesh with a deforming surface. Specifically, it calculates the slope of the + * surface by comparing the local normal and gravity vectors. + * Cells with steeper slopes get refined. This is useful for cases where + * there is steep topography which needs to be tracked better. + * + * @ingroup MeshRefinement + */ + template + class Slope : public Interface, + public SimulatorAccess + { + public: + + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/strain_rate.h.bak b/include/aspect/mesh_refinement/strain_rate.h.bak new file mode 100644 index 00000000000..0ae2a83c6b9 --- /dev/null +++ b/include/aspect/mesh_refinement/strain_rate.h.bak @@ -0,0 +1,58 @@ +/* + Copyright (C) 2013 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_strain_rate_h +#define _aspect_mesh_refinement_strain_rate_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on + * the strain rate field. + * + * @ingroup MeshRefinement + */ + template + class StrainRate : public Interface, + public SimulatorAccess + { + public: + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/temperature.h.bak b/include/aspect/mesh_refinement/temperature.h.bak new file mode 100644 index 00000000000..33b7edb1e05 --- /dev/null +++ b/include/aspect/mesh_refinement/temperature.h.bak @@ -0,0 +1,58 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_temperature_h +#define _aspect_mesh_refinement_temperature_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on the + * temperature field. + * + * @ingroup MeshRefinement + */ + template + class Temperature : public Interface, + public SimulatorAccess + { + public: + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/thermal_energy_density.h.bak b/include/aspect/mesh_refinement/thermal_energy_density.h.bak new file mode 100644 index 00000000000..98c7fc9c10c --- /dev/null +++ b/include/aspect/mesh_refinement/thermal_energy_density.h.bak @@ -0,0 +1,59 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_thermal_energy_density_h +#define _aspect_mesh_refinement_thermal_energy_density_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on a field + * representing the energy density $\rho c_P T$ as a spatially variable + * function and that we compute from the solution vector. + * + * @ingroup MeshRefinement + */ + template + class ThermalEnergyDensity : public Interface, + public SimulatorAccess + { + public: + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/topography.h.bak b/include/aspect/mesh_refinement/topography.h.bak new file mode 100644 index 00000000000..b5ec954826f --- /dev/null +++ b/include/aspect/mesh_refinement/topography.h.bak @@ -0,0 +1,59 @@ +/* + Copyright (C) 2013 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_topography_h +#define _aspect_mesh_refinement_topography_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion that refines the + * mesh in the uppermost nodes. This is useful for cases where one wants + * to accurately model processes at of close to the surface of the model. + * + * @ingroup MeshRefinement + */ + template + class Topography : public Interface, + public SimulatorAccess + { + public: + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/velocity.h.bak b/include/aspect/mesh_refinement/velocity.h.bak new file mode 100644 index 00000000000..4e4b3dc73ed --- /dev/null +++ b/include/aspect/mesh_refinement/velocity.h.bak @@ -0,0 +1,58 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_velocity_h +#define _aspect_mesh_refinement_velocity_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on the + * velocity field. + * + * @ingroup MeshRefinement + */ + template + class Velocity : public Interface, + public SimulatorAccess + { + public: + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/viscosity.h.bak b/include/aspect/mesh_refinement/viscosity.h.bak new file mode 100644 index 00000000000..cf30f892b15 --- /dev/null +++ b/include/aspect/mesh_refinement/viscosity.h.bak @@ -0,0 +1,60 @@ +/* + Copyright (C) 2013 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_viscosity_h +#define _aspect_mesh_refinement_viscosity_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion based on a field + * representing the viscosity $\eta$ as a spatially variable function and + * that we compute from the solution vector (assuming the viscosity + * actually depends on the solution). + * + * @ingroup MeshRefinement + */ + template + class Viscosity : public Interface, + public SimulatorAccess + { + public: + /** + * Execute this mesh refinement criterion. + * + * @param[out] error_indicators A vector that for every active cell of + * the current mesh (which may be a partition of a distributed mesh) + * provides an error indicator. This vector will already have the + * correct size when the function is called. + */ + void + execute (Vector &error_indicators) const override; + }; + } +} + +#endif diff --git a/include/aspect/mesh_refinement/volume_of_fluid_interface.h.bak b/include/aspect/mesh_refinement/volume_of_fluid_interface.h.bak new file mode 100644 index 00000000000..1e906fc517b --- /dev/null +++ b/include/aspect/mesh_refinement/volume_of_fluid_interface.h.bak @@ -0,0 +1,73 @@ +/* + Copyright (C) 2016 - 2019-2018 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_mesh_refinement_volume_of_fluid_interface_h +#define _aspect_mesh_refinement_volume_of_fluid_interface_h + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + + /** + * A class that implements a mesh refinement criterion that refines the + * mesh near boundaries for the volume of fluid interface tracking algorithm. + * + * @ingroup MeshRefinement + */ + template + class VolumeOfFluidInterface: public Interface, + public SimulatorAccess + { + public: + /** + * Mark large unrefined neighboring cells for refinement and prevent + * coarsening + */ + void + tag_additional_cells() const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * If true, flag cells for coarsening if they are not flagged for refinement + */ + bool strict_coarsening; + }; + } +} + +#endif diff --git a/include/aspect/newton.h.bak b/include/aspect/newton.h.bak new file mode 100644 index 00000000000..f7e4fc70c46 --- /dev/null +++ b/include/aspect/newton.h.bak @@ -0,0 +1,358 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#ifndef _aspect_newton_h +#define _aspect_newton_h + +#include +#include +#include +#include + +#include + +namespace aspect +{ + using namespace dealii; + + namespace MaterialModel + { + /** + * This class holds the derivatives for the Newton solver. + */ + template + class MaterialModelDerivatives : public AdditionalMaterialOutputs + { + public: + /** + * Constructor. Initialize the various arrays of this structure with the + * given number of quadrature points. + */ + MaterialModelDerivatives (const unsigned int n_points); + + /** + * The derivatives of the viscosities with respect to pressure. + */ + std::vector viscosity_derivative_wrt_pressure; + + /** + * The derivatives of the viscosities with respect to strain rate. + */ + std::vector> viscosity_derivative_wrt_strain_rate; + + /** + * The weights used for calculating the averages of viscosity + * derivatives when material averaging is applied. + */ + std::vector viscosity_derivative_averaging_weights; + }; + } + + + namespace Newton + { + struct Parameters + { + + /** + * This enum describes the type of stabilization is used + * for the Newton solver. None represents no stabilization, + * SPD represent that the resulting matrix is made Symmetric + * Positive Definite, symmetric represents that the matrix is + * only symmetrized, and PD represents that we do the same as + * what we do for SPD, but without the symmetrization. + */ + enum Stabilization + { + none = 0, + symmetric = 1, + PD = 2, + SPD = symmetric | PD + }; + + + /** + * A binary 'or' operator that concatenates a set of stabilization + * flags by returning an object that combines the bits set in each + * of the two arguments. + */ + friend + Stabilization + operator| (const Stabilization a, + const Stabilization b) + { + return static_cast( + static_cast(a) | static_cast(b)); + } + + + /** + * A binary 'and' operator that takes the intersection of two sets + * of stabilization flags by returning an object that selects those bits + * that are set in both of the two arguments. + */ + friend + Stabilization + operator& (const Stabilization a, + const Stabilization b) + { + return static_cast( + static_cast(a) & static_cast(b)); + } + + + /** + * Declare additional parameters that are needed for the Newton. + * solver. + */ + static void declare_parameters (ParameterHandler &prm); + + /** + * Parse additional parameters that are needed for the Newton. + * solver. + */ + void parse_parameters (ParameterHandler &prm); + + /** + * A scaling factor used for scaling the + * derivative part of the Newton Stokes solver in the assembly. + * + * The exact Newton matrix consists of the Stokes matrix plus a term + * that results from the linearization of the material coefficients. + * The scaling factor multiplies these additional terms. In a full + * Newton method, it would be equal to one, but it can be chosen + * smaller in cases where the resulting linear system has undesirable + * properties. + * + * If the scaling factor is zero, the resulting matrix is simply the + * Stokes matrix, and the resulting scheme is a defect correction + * (i.e., Picard iteration). + */ + double newton_derivative_scaling_factor; + + Stabilization preconditioner_stabilization; + Stabilization velocity_block_stabilization; + + /** + * Whether to use the Newton failsafe or not. If the failsafe is used, a failure + * of the linear solver is caught and we try to solve it again with both the + * preconditioner and the velocity block being stabilized with the SPD stabilization. + */ + bool use_Newton_failsafe; + + /** + * The nonlinear tolerance at which to switch the + * nonlinear solver from defect correction Picard to + * Newton. + */ + double nonlinear_switch_tolerance; + + bool use_Eisenstat_Walker_method_for_Picard_iterations; + unsigned int max_pre_newton_nonlinear_iterations; + unsigned int max_newton_line_search_iterations; + bool use_newton_residual_scaling_method; + double maximum_linear_stokes_solver_tolerance; + double SPD_safety_factor; + }; + + + /** + * Get a std::string describing the stabilization type used for the + * preconditioner. + */ + std::string + to_string(const Newton::Parameters::Stabilization preconditioner_stabilization); + } + + + + /** + * A class that supports the functionality of the Newton solver. + */ + template + class NewtonHandler : public SimulatorAccess + { + public: + /** + * Determine, based on the run-time parameters of the current simulation, + * which functions need to be called in order to assemble linear systems, + * matrices, and right hand side vectors. + */ + void set_assemblers (Assemblers::Manager &assemblers) const; + + /** + * Create an additional material model output object that contains + * the additional output variables (the derivatives) needed for the + * Newton solver. + */ + static void create_material_model_outputs(MaterialModel::MaterialModelOutputs &output); + + /** + * The object that stores the run-time parameters that control the Newton + * method. + */ + Newton::Parameters parameters; + }; + + + namespace Assemblers + { + /** + * A base class for the definition of assemblers that implement the linear + * system terms for the NewtonStokes solver scheme. + */ + template + class NewtonInterface : public aspect::Assemblers::Interface, + public SimulatorAccess + { + public: + /** + * Attach Newton outputs. Since most Newton assemblers require the + * material model derivatives they are created in this base class + * already. + */ + void + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const override; + }; + + /** + * This class assembles the terms of the Newton Stokes preconditioner matrix for the current cell. + */ + template + class NewtonStokesPreconditioner : public NewtonInterface + { + public: + void + execute (internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + + /** + * Create additional material models outputs for computing viscoelastic strain rate when + * elasticity is enabled. + */ + void create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const override; + }; + + /** + * This class assembles the terms for the matrix and right-hand-side of the incompressible + * Newton Stokes system for the current cell. + */ + template + class NewtonStokesIncompressibleTerms : public NewtonInterface + { + public: + void + execute (internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + + /** + * Create additional material models outputs for assembly of derivatives or adding additional + * terms to the right hand side of the Stokes equations. The latter could include viscoelastic + * forces or other user-defined values calculated within the material model. + */ + void create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const override; + }; + + /** + * This class assembles the term that arises in the viscosity term of the Newton Stokes matrix for + * compressible models, because the divergence of the velocity is not longer zero. + */ + template + class NewtonStokesCompressibleStrainRateViscosityTerm : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class assembles the right-hand-side term of the Newton Stokes system + * that is caused by the compressibility in the mass conservation equation. + * This function approximates this term as + * $- \nabla \mathbf{u} = \frac{1}{\rho} \frac{\partial rho}{\partial z} \frac{\mathbf{g}}{||\mathbf{g}||} \cdot \mathbf{u}$ + */ + template + class NewtonStokesReferenceDensityCompressibilityTerm : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class assembles the compressibility term of the Newton Stokes system + * that is caused by the compressibility in the mass conservation equation. + * It includes this term implicitly in the matrix, + * which is therefore not longer symmetric. + * This function approximates this term as + * $ - \nabla \mathbf{u} - \frac{1}{\rho} \frac{\partial rho}{\partial z} \frac{\mathbf{g}}{||\mathbf{g}||} \cdot \mathbf{u} = 0$ + */ + template + class NewtonStokesImplicitReferenceDensityCompressibilityTerm : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class assembles the right-hand-side term of the Newton Stokes system + * that is caused by the compressibility in the mass conservation equation. + * This function approximates this term as + * $ - \nabla \mathbf{u} = \frac{1}{\rho} \frac{\partial rho}{\partial p} \rho \mathbf{g} \cdot \mathbf{u}$ + */ + template + class NewtonStokesIsentropicCompressionTerm : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class assembles the right-hand-side term of the Stokes equation + * that is caused by the variable density in the mass conservation equation. + * This class approximates this term as + * $ - \nabla \cdot \mathbf{u} = \frac{1}{\rho} \frac{\partial \rho}{\partial t} + \frac{1}{\rho} \nabla \rho \cdot \mathbf{u}$ + * where the right-hand side velocity is explicitly taken from the last timestep, + * and the density is taken from a compositional field of the type 'density'. + */ + template + class NewtonStokesProjectedDensityFieldTerm : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch, + internal::Assembly::CopyData::CopyDataBase &data) const override; + }; + } +} + +#endif diff --git a/include/aspect/parameters.h b/include/aspect/parameters.h index 4890ac4c987..baabeb3865a 100644 --- a/include/aspect/parameters.h +++ b/include/aspect/parameters.h @@ -674,7 +674,7 @@ namespace aspect std::vector additional_refinement_times; unsigned int adaptive_refinement_interval; bool skip_solvers_on_initial_refinement; - bool skip_setup_initial_conditions_on_initial_refinement; + bool skip_setup_initial_temperature_on_initial_refinement; bool run_postprocessors_on_initial_refinement; bool run_postprocessors_on_nonlinear_iterations; /** diff --git a/include/aspect/parameters.h.bak b/include/aspect/parameters.h.bak new file mode 100644 index 00000000000..4890ac4c987 --- /dev/null +++ b/include/aspect/parameters.h.bak @@ -0,0 +1,802 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_parameters_h +#define _aspect_parameters_h + +#include + +#include +#include + + +namespace aspect +{ + using namespace dealii; + + struct CompositionalFieldDescription; + + // forward declaration: + namespace GeometryModel + { + template + class Interface; + } + + /** + * A structure that holds run-time parameters. These parameters are all + * declared for the ParameterHandler class in the declare_parameters() + * member function, and read in the parse_parameters() function. + * + * Each of the member variables of this class corresponds to a parameter + * declared for the ParameterHandler class. Rather than duplicating the + * documentation of each of these parameters for the member variables here, + * please refer to the documentation of run-time parameters in the ASPECT + * manual for more information. + * + * @ingroup Simulator + */ + template + struct Parameters + { + + /** + * A structure that contains enum values that identify the nonlinear + * solver in use. + */ + struct NonlinearSolver + { + enum Kind + { + single_Advection_single_Stokes, + iterated_Advection_and_Stokes, + single_Advection_iterated_Stokes, + no_Advection_iterated_Stokes, + no_Advection_single_Stokes, + no_Advection_iterated_defect_correction_Stokes, + single_Advection_iterated_defect_correction_Stokes, + iterated_Advection_and_defect_correction_Stokes, + iterated_Advection_and_Newton_Stokes, + single_Advection_iterated_Newton_Stokes, + single_Advection_no_Stokes, + first_timestep_only_single_Stokes, + no_Advection_no_Stokes + }; + }; + + static + bool + is_defect_correction(const typename NonlinearSolver::Kind &input) + { + return input == NonlinearSolver::iterated_Advection_and_Newton_Stokes || + input == NonlinearSolver::single_Advection_iterated_Newton_Stokes || + input == NonlinearSolver::no_Advection_iterated_defect_correction_Stokes || + input == NonlinearSolver::single_Advection_iterated_defect_correction_Stokes || + input == NonlinearSolver::iterated_Advection_and_defect_correction_Stokes + ? + true + : + false; + } + + /** + * @brief The NullspaceRemoval struct + */ + struct NullspaceRemoval + { + enum Kind + { + none = 0, + net_translation_x = 0x1, + net_translation_y = 0x2, + net_translation_z = 0x4, + net_translation = 0x1+0x2+0x4, + linear_momentum_x = 0x8, + linear_momentum_y = 0x10, + linear_momentum_z = 0x20, + linear_momentum = linear_momentum_x+linear_momentum_y+linear_momentum_z, + net_rotation = 0x40, + angular_momentum = 0x80, + net_surface_rotation = 0x100, + any_translation = net_translation+linear_momentum, + any_rotation = net_rotation+angular_momentum+net_surface_rotation, + }; + }; + + /** + * A struct that describes the available methods to solve + * advected fields. This type is at the moment only used to determine how + * to advect each compositional field -- or what else to do with it if + * it doesn't satisfy an advection equation, for example if the + * compositional field just contains data interpolated from + * particles in each time step (`particles`) or if it contains + * data interpolated from other sources such as material outputs + * (`prescribed_field`), neither of which is further advected. + */ + struct AdvectionFieldMethod + { + enum Kind + { + fem_field, + particles, + volume_of_fluid, + static_field, + fem_melt_field, + fem_darcy_field, + prescribed_field, + prescribed_field_with_diffusion + }; + }; + + /** + * A struct that contains information about which + * formulation of the basic equations should be solved, + * i.e. which terms to consider, which terms to neglect, and + * which to simplify in different ways. + */ + struct Formulation + { + /** + * This enum lists available formulations that + * determine the combined approximations made in + * all solved equations. 'Custom' allows to set + * approximations individually for single equations. + */ + enum Kind + { + boussinesq_approximation, + anelastic_liquid_approximation, + isentropic_compression, + custom + }; + + /** + * This function translates an input string into the + * available enum options. + */ + static + Kind + parse(const std::string &input) + { + if (input == "isentropic compression") + return Formulation::isentropic_compression; + else if (input == "anelastic liquid approximation") + return Formulation::anelastic_liquid_approximation; + else if (input == "Boussinesq approximation") + return Formulation::boussinesq_approximation; + else if (input == "custom") + return Formulation::custom; + else + AssertThrow(false, ExcNotImplemented()); + + return Formulation::Kind(); + } + + /** + * This struct contains information about the approximation + * made to the term containing the gradient of the density + * in the mass conservation equation. The different possible + * ways to approximate this term are described in the manual. + */ + struct MassConservation + { + /** + * This enum lists available approximations to the + * density gradient term of the mass conservation equation. + */ + enum Kind + { + isentropic_compression, + hydrostatic_compression, + reference_density_profile, + implicit_reference_density_profile, + incompressible, + projected_density_field, + ask_material_model + }; + + /** + * This function translates an input string into the + * available enum options. + */ + static Kind + parse(const std::string &input) + { + if (input == "isentropic compression") + return Formulation::MassConservation::isentropic_compression; + else if (input == "hydrostatic compression") + return Formulation::MassConservation::hydrostatic_compression; + else if (input == "reference density profile") + return Formulation::MassConservation::reference_density_profile; + else if (input == "implicit reference density profile") + return Formulation::MassConservation::implicit_reference_density_profile; + else if (input == "incompressible") + return Formulation::MassConservation::incompressible; + else if (input == "projected density field") + return Formulation::MassConservation::projected_density_field; + else if (input == "ask material model") + return Formulation::MassConservation::ask_material_model; + else + AssertThrow(false, ExcNotImplemented()); + + return Formulation::MassConservation::Kind(); + } + }; + + /** + * This struct contains information about the approximation + * made to temperature equation. The different possible + * ways to approximate this term are described in the manual. + */ + struct TemperatureEquation + { + /** + * This enum lists available approximations to the + * density in the temperature equation. + */ + enum Kind + { + real_density, + reference_density_profile + }; + + /** + * This function translates an input string into the + * available enum options. + */ + static + Kind + parse(const std::string &input) + { + if (input == "real density") + return Formulation::TemperatureEquation::real_density; + else if (input == "reference density profile") + return Formulation::TemperatureEquation::reference_density_profile; + else + AssertThrow(false, ExcNotImplemented()); + + return Formulation::TemperatureEquation::Kind(); + } + }; + }; + + /** + * A struct to provide the setting for "Stabilization method" + */ + struct AdvectionStabilizationMethod + { + enum Kind + { + entropy_viscosity, + supg + }; + + /** + * This function translates an input string into the + * available enum options. + */ + static + Kind + parse(const std::string &input) + { + if (input == "entropy viscosity") + return entropy_viscosity; + else if (input == "SUPG") + return supg; + else + AssertThrow(false, ExcNotImplemented()); + + return Kind(); + } + + static std::string get_options_string() + { + return "entropy viscosity|SUPG"; + } + }; + + /** + * A struct to provide the different choices of limiters for + * the discontinuous Galerkin method. + */ + struct DGLimiterType + { + enum Kind + { + bound_preserving, + WENO, + none + }; + + static + Kind + parse(const std::string &input) + { + if (input == "bound preserving") + return bound_preserving; + else if (input == "WENO") + return WENO; + else if (input == "none") + return none; + else + AssertThrow(false, ExcNotImplemented()); + + return Kind(); + } + + static const std::string pattern() + { + return "bound preserving|WENO|none"; + } + }; + + /** + * This enum represents the different choices for the linear solver + * for the Stoke system. See @p stokes_solver_type. + */ + struct StokesSolverType + { + enum Kind + { + block_amg, + direct_solver, + block_gmg, + default_solver + }; + + static const std::string pattern() + { + return "default solver|block AMG|direct solver|block GMG"; + } + + static Kind + parse(const std::string &input) + { + if (input == "block AMG") + return block_amg; + else if (input == "direct solver") + return direct_solver; + else if (input == "block GMG") + return block_gmg; + else if (input == "default solver") + return default_solver; + else + AssertThrow(false, ExcNotImplemented()); + + return Kind(); + } + }; + + /** + * This enum represents the different choices for the Krylov method + * used in the cheap GMG Stokes solve. + */ + struct StokesKrylovType + { + enum Kind + { + gmres, + idr_s + }; + + static const std::string pattern() + { + return "GMRES|IDR(s)"; + } + + static Kind + parse(const std::string &input) + { + if (input == "GMRES") + return gmres; + else if (input == "IDR(s)") + return idr_s; + else + AssertThrow(false, ExcNotImplemented()); + + return Kind(); + } + }; + + /** + * This enum represents the different choices for the reaction solver. + * See @p reaction_solver_type. + */ + struct ReactionSolverType + { + enum Kind + { + ARKode, + fixed_step + }; + + static const std::string pattern() + { + return "ARKode|fixed step"; + } + + static Kind + parse(const std::string &input) + { + if (input == "ARKode") + return ARKode; + else if (input == "fixed step") + return fixed_step; + else + AssertThrow(false, ExcNotImplemented()); + + return Kind(); + } + }; + + /** + * Use the struct aspect::CompositionalFieldDescription + */ + using CompositionalFieldDescription DEAL_II_DEPRECATED = aspect::CompositionalFieldDescription; + + /** + * Constructor. Fills the values of member functions from the given + * parameter object. + * + * @param prm The parameter object that has previously been filled with + * content by reading an input file. + * + * @param mpi_communicator The MPI communicator we will use for this + * simulation. We need this when calling parse_parameters() so that we can + * verify some of the input arguments. + */ + Parameters (ParameterHandler &prm, + const MPI_Comm mpi_communicator); + + /** + * Declare the run-time parameters this class takes, and call the + * respective declare_parameters functions of the namespaces + * that describe geometries, material models, etc. + * + * @param prm The object in which the run-time parameters are to be + * declared. + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * Read run-time parameters from an object that has previously parsed an + * input file. This reads all parameters that do not require knowledge of + * the geometry model we use. There is a separate function + * parse_geometry_dependent_parameters() that is called as soon as the + * geometry object has been created and that can translate between the + * symbolic names for boundary components that the geometry model + * publishes and the boundary indicators used internally. + * + * @param prm The object from which to obtain the run-time parameters. + * + * @param mpi_communicator The MPI communicator we will use for this + * simulation. We need this when calling parse_parameters() so that we can + * verify some of the input arguments. + */ + void parse_parameters (ParameterHandler &prm, + const MPI_Comm mpi_communicator); + + /** + * Read those run-time parameters from a ParameterHandler object that + * depend on knowing which geometry object we use. This function + * complements parse_parameters() but is only called once the geometry + * object has been created. This function is separate because we allow the + * use of symbolic names in defining which boundary components have which + * boundary conditions, and the names one can specify there are not + * available until after the geometry object has been created. + * + * This function is called from the GeometryModel::create_geometry() + * function. + * + * @param prm The object from which to obtain the run-time parameters. + * @param geometry_model The geometry model that provides boundary names + * etc. + */ + void parse_geometry_dependent_parameters (ParameterHandler &prm, + const GeometryModel::Interface &geometry_model); + + /** + * @name Global parameters + * @{ + */ + typename NonlinearSolver::Kind nonlinear_solver; + + typename AdvectionStabilizationMethod::Kind advection_stabilization_method; + double nonlinear_tolerance; + bool resume_computation; + double start_time; + double end_time; + double CFL_number; + double maximum_time_step; + double maximum_relative_increase_time_step; + double maximum_first_time_step; + bool use_artificial_viscosity_smoothing; + bool use_conduction_timestep; + bool convert_to_years; + std::string output_directory; + double surface_pressure; + double adiabatic_surface_temperature; + unsigned int timing_output_frequency; + unsigned int max_nonlinear_iterations; + unsigned int max_nonlinear_iterations_in_prerefinement; + bool use_operator_splitting; + std::string world_builder_file; + + /** + * @} + */ + + /** + * @name section: Solver parameters + * @{ + */ + double temperature_solver_tolerance; + double composition_solver_tolerance; + + // subsection: Advection solver parameters + unsigned int advection_gmres_restart_length; + + // subsection: Stokes solver parameters + bool use_direct_stokes_solver; + bool use_bfbt; + typename StokesSolverType::Kind stokes_solver_type; + typename StokesKrylovType::Kind stokes_krylov_type; + unsigned int idr_s_parameter; + + double linear_stokes_solver_tolerance; + unsigned int n_cheap_stokes_solver_steps; + unsigned int n_expensive_stokes_solver_steps; + double linear_solver_A_block_tolerance; + bool use_full_A_block_preconditioner; + bool force_nonsymmetric_A_block_solver; + double linear_solver_S_block_tolerance; + unsigned int stokes_gmres_restart_length; + + // subsection: AMG parameters + std::string AMG_smoother_type; + unsigned int AMG_smoother_sweeps; + double AMG_aggregation_threshold; + bool AMG_output_details; + + // subsection: Operator splitting parameters + typename ReactionSolverType::Kind reaction_solver_type; + double ARKode_relative_tolerance; + double reaction_time_step; + unsigned int reaction_steps_per_advection_step; + + // subsection: Diffusion solver parameters + double diffusion_length_scale; + + /** + * @} + */ + + /** + * @name Formulation settings + * @{ + */ + + /** + * This variable determines which of the several ways to formulate the + * equations ASPECT will solve. + * Common formulations are the Boussinesq or Anelastic Liquid + * Approximations (BA, ALA). ASPECT's original formulation is termed + * 'isentropic compression'. 'Custom' allows + * to set the approximations individually per equation. + */ + typename Formulation::Kind formulation; + + /** + * Determines how to formulate the mass conservation equation in ASPECT. + * Common approximations are 'incompressible' or 'reference density profile'. + * ASPECT's original formulation is termed 'isentropic compression'. See the + * manual for more details about the individual terms. + */ + typename Formulation::MassConservation::Kind formulation_mass_conservation; + + /** + * Determines how to formulate the density in the temperature equation + * in ASPECT. Possible approximations are 'reference density profile' or + * 'real density'. + */ + typename Formulation::TemperatureEquation::Kind formulation_temperature_equation; + + /** + * This variable determines whether additional terms related to elastic forces + * are added to the Stokes equation. + */ + bool enable_elasticity; + + /** + * @} + */ + + /** + * @name Parameters that have to do with terms in the model + * @{ + */ + bool include_melt_transport; + bool enable_additional_stokes_rhs; + bool enable_prescribed_dilation; + + /** + * Map from boundary id to a pair "components", "traction boundary type", + * where components is of the format "[x][y][z]" and the traction type is + * mapped to one of the plugins of traction boundary conditions (e.g. + * "function") + */ + std::map> prescribed_traction_boundary_indicators; + + /** + * A set of boundary ids on which the boundary_heat_flux objects + * will be applied. + */ + std::set fixed_heat_flux_boundary_indicators; + + /** + * Selection of operations to perform to remove nullspace from velocity + * field. + */ + typename NullspaceRemoval::Kind nullspace_removal; + /** + * @} + */ + + /** + * @name Parameters that have to do with mesh refinement + * @{ + */ + unsigned int initial_global_refinement; + unsigned int initial_adaptive_refinement; + double refinement_fraction; + double coarsening_fraction; + bool adapt_by_fraction_of_cells; + unsigned int min_grid_level; + std::vector additional_refinement_times; + unsigned int adaptive_refinement_interval; + bool skip_solvers_on_initial_refinement; + bool skip_setup_initial_conditions_on_initial_refinement; + bool run_postprocessors_on_initial_refinement; + bool run_postprocessors_on_nonlinear_iterations; + /** + * @} + */ + + /** + * @name Parameters that have to do with the stabilization of transport + * equations + * @{ + */ + unsigned int stabilization_alpha; + std::vector stabilization_c_R; + std::vector stabilization_beta; + double stabilization_gamma; + double discontinuous_penalty; + typename DGLimiterType::Kind limiter_for_discontinuous_temperature_solution; + std::vector limiter_for_discontinuous_composition_solution; + double global_temperature_max_preset; + double global_temperature_min_preset; + std::vector global_composition_max_preset; + std::vector global_composition_min_preset; + double temperature_KXRCF_indicator_threshold; + std::vector composition_KXRCF_indicator_threshold; + double WENO_linear_weight; + + std::vector compositional_fields_with_disabled_boundary_entropy_viscosity; + /** + * @} + */ + + /** + * @name Parameters that have to do with checkpointing + * @{ + */ + int checkpoint_time_secs; + int checkpoint_steps; + /** + * @} + */ + + /** + * @name Parameters that have to do with spatial discretizations + * @{ + */ + unsigned int stokes_velocity_degree; + bool use_locally_conservative_discretization; + bool use_equal_order_interpolation_for_stokes; + bool use_discontinuous_temperature_discretization; + std::vector use_discontinuous_composition_discretization; + bool have_discontinuous_composition_discretization; + unsigned int temperature_degree; + unsigned int composition_degree; + std::string pressure_normalization; + MaterialModel::MaterialAveraging::AveragingOperation material_averaging; + + /** + * @} + */ + + /** + * @name Parameters that have to do with the temperature field + * @{ + */ + + typename AdvectionFieldMethod::Kind temperature_method; + + /** + * @} + */ + + /** + * @name Parameters that have to do with compositional fields + * @{ + */ + unsigned int n_compositional_fields; + std::vector names_of_compositional_fields; + std::vector composition_descriptions; + unsigned int n_chemical_compositions; + std::vector chemical_composition_indices; + + /** + * A vector that contains the advection field method for every compositional + * field. Consequently the vector has n_compositional_fields entries. + */ + std::vector compositional_field_methods; + + /** + * Map from compositional index to a pair "particle property", "component", + * where particle property is a string that can be mapped to one of the + * particle property plugins. + * Component denotes which component of the particle property is to be + * mapped in case there are several. Therefore, it is optional to specify + * the component and it is of the format "[0][1][2]". In case no component + * is specified it defaults to 0. + */ + std::map> mapped_particle_properties; + + std::vector normalized_fields; + /** + * @} + */ + /** + * @name Parameters that have to do with mesh deformation + * @{ + */ + bool mesh_deformation_enabled; + /** + * @} + */ + + /** + * @name Parameters that have to do with volume of fluid calculations + * @{ + */ + bool volume_of_fluid_tracking_enabled; + /** + * @} + */ + + + }; + +} +#endif diff --git a/include/aspect/particle/generator/ascii_file.h.bak b/include/aspect/particle/generator/ascii_file.h.bak new file mode 100644 index 00000000000..035ef0a7d24 --- /dev/null +++ b/include/aspect/particle/generator/ascii_file.h.bak @@ -0,0 +1,80 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_generator_ascii_file_h +#define _aspect_particle_generator_ascii_file_h + +#include + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + /** + * Generate a distribution of particles that is determined by the + * coordinates given in an ascii data file. + * + * @ingroup ParticleGenerators + */ + template + class AsciiFile : public Interface + { + public: + /** + * Reads in a file and generate a set of particles at the prescribed + * positions. + * + * @param [in,out] particle_handler The particle handler into which + * the generated particles should be inserted. + */ + void + generate_particles(Particles::ParticleHandler &particle_handler) override; + + // avoid -Woverloaded-virtual + // TODO: remove this using directive once the following deprecated + // function in the interface class has been removed: + // generate_particles(std::multimap> &particles) + using Generator::Interface::generate_particles; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + std::string data_directory; + std::string data_filename; + }; + + } + } +} + +#endif diff --git a/include/aspect/particle/generator/interface.h.bak b/include/aspect/particle/generator/interface.h.bak new file mode 100644 index 00000000000..13508fa1c41 --- /dev/null +++ b/include/aspect/particle/generator/interface.h.bak @@ -0,0 +1,251 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_generator_interface_h +#define _aspect_particle_generator_interface_h + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +namespace aspect +{ + namespace Particle + { + /** + * A namespace in which we define everything that has to do with defining + * the particle generation. + * + * @ingroup ParticleGenerators + */ + namespace Generator + { + using namespace dealii::Particles; + using dealii::Particles::Particle; + + /** + * Exception denoting a division by zero. + */ + DeclExceptionMsg (ExcParticlePointNotInDomain, + "You requested to generate a particle at a position that " + "is not owned by this process, therefore the " + "Particle::Generator::Interface::generate_particle() function " + "refused to create it. You can circumvent this error message " + "by catching the ExcParticlePointNotInDomain exception and " + "do whatever you think is appropriate in this case."); + + /** + * Abstract base class used for classes that generate particles. + * + * @ingroup ParticleGenerators + */ + template + class Interface : public SimulatorAccess, public ParticleInterfaceBase + { + public: + virtual + void + initialize () override; + + /** + * Generate particles. Every derived class + * has to decide on the method and number of particles to generate, + * for example using input parameters declared in their + * declare_parameters and parse_parameters functions. This function + * should generate the particles and associate them to their according + * cells by inserting them into a multimap between cell and particle. + * This map becomes very large if the particle count per process + * is large, so we hand it over by reference instead of returning + * the multimap. + * + * @param [in,out] particles A multimap between cells and their + * particles. This map will be filled in this function. + */ + DEAL_II_DEPRECATED + virtual + void + generate_particles(std::multimap> &particles); + + /** + * Generate particles. Every derived class + * has to decide on the method and number of particles to generate, + * for example using input parameters declared in their + * declare_parameters and parse_parameters functions. This function + * should generate the particles and insert them into @p particle_handler + * by calling its respective functions. + * + * @param [in,out] particle_handler The particle handler into which + * the generated particles should be inserted. + */ + virtual + void + generate_particles(Particles::ParticleHandler &particle_handler); + + /** + * Generate one particle in the given cell. This function's main purpose + * is to provide functionality to fill up cells with too few particles + * after refinement. Of course it can also be utilized by derived classes + * to generate the initial particle distribution. + */ + std::pair> + generate_particle (const typename parallel::distributed::Triangulation::active_cell_iterator &cell, + const types::particle_index id); + + protected: + /** + * Generate a particle at the specified position and with the + * specified id. Many derived classes use this functionality, + * therefore it is implemented here to avoid duplication. + * In case the position is not in the local domain this function + * throws an exception of type ExcParticlePointNotInDomain, which + * can be caught in the calling plugin. + * + * @deprecated: This function uses an old return type and is deprecated. + * Use the insert_particle_at_position() function below instead. + */ + DEAL_II_DEPRECATED + std::pair> + generate_particle(const Point &position, + const types::particle_index id) const; + + /** + * Generate a particle at the specified position and with the + * specified id and insert it into the @p particle_handler. + * Many derived classes use this functionality, + * therefore it is implemented here to avoid duplication. + * In case the position is not in the local domain this function + * throws an exception of type ExcParticlePointNotInDomain, which + * can be caught in the calling plugin. Note that since the cell + * in which the particle is generated is not known, it has to be + * found, which is an expensive operation. + * + * @param position Position of the particle. + * @param id The id of the particle. + * @param particle_handler The particle handler into which the particle + * should be inserted. + * + * @return An iterator to the inserted particle. If the position was + * not in the local domain, an iterator to particle_handler.end() is + * returned. + */ + Particles::ParticleIterator + insert_particle_at_position(const Point &position, + const types::particle_index id, + Particles::ParticleHandler &particle_handler) const; + + /** + * Random number generator. For reproducibility of tests it is + * initialized in the constructor with a constant. + */ + std::mt19937 random_number_generator; + }; + + /** + * Register a particle generator so that it can be selected from + * the parameter file. + * + * @param name A string that identifies the particle generator + * @param description A text description of what this generator does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this particle generator wants to read + * from input files. + * @param factory_function A pointer to a function that can create an + * object of this particle generator. + * + * @ingroup ParticleGenerators + */ + template + void + register_particle_generator (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * A function that given the name of a model returns a pointer to an + * object that describes it. Ownership of the pointer is transferred to + * the caller. + * + * The model object returned is not yet initialized and has not + * read its runtime parameters yet. + * + * @ingroup ParticleGenerators + */ + template + std::unique_ptr> + create_particle_generator (ParameterHandler &prm); + + /** + * Declare the runtime parameters of the registered particle generators. + * + * @ingroup ParticleGenerators + */ + template + void + declare_parameters (ParameterHandler &prm); + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + template + void + write_plugin_graph (std::ostream &output_stream); + + + /** + * Given a class name, a name, and a description for the parameter file + * for a particle generator, register it with the functions that + * can declare their parameters and create these objects. + * + * @ingroup ParticleGenerators + */ +#define ASPECT_REGISTER_PARTICLE_GENERATOR(classname, name, description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_PARTICLE_GENERATOR_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2 >> \ + dummy_ ## classname ## _2d (&aspect::Particle::Generator::register_particle_generator<2>, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::Particle::Generator::register_particle_generator<3>, \ + name, description); \ + } + } + } +} + +#endif diff --git a/include/aspect/particle/generator/probability_density_function.h.bak b/include/aspect/particle/generator/probability_density_function.h.bak new file mode 100644 index 00000000000..5fa3cafd224 --- /dev/null +++ b/include/aspect/particle/generator/probability_density_function.h.bak @@ -0,0 +1,128 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_generator_probability_density_function_h +#define _aspect_particle_generator_probability_density_function_h + +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + /** + * Exception + */ + template + DeclException1 (ProbabilityFunctionNegative, + Point, + << "Your probability density function in the particle generator " + "returned a negative probability density for the following position: " + << arg1 << ". Please check your function expression."); + + + /** + * Generates a random distribution of particles over the simulation + * domain. The particle density is determined by a user-defined + * probability density function in the parameter file. This is done using + * a "roulette wheel" style selection. Every cell is weighted by the value + * of the provided function at its center multiplied with the cell + * volume. Then a map between the accumulated cell weight + * and the cell index of the current cell is constructed. Consequently, + * a random number between zero and the global integral of the + * probability density function uniquely defines one particular cell. + * Afterwards, every process generates n_global_particles random numbers, + * but only generates a particle if it is the owner of the active cell + * that is associated with this random number. + * + * @ingroup ParticleGenerators + */ + template + class ProbabilityDensityFunction : public Interface + { + public: + /** + * Generate a set of particles in the given + * particle handler. The particle density is set by an analytically + * prescribed density function that is set as an input parameter. + * + * @param [in,out] particle_handler The particle handler into which + * the generated particles should be inserted. + */ + void + generate_particles(Particles::ParticleHandler &particle_handler) override; + + // avoid -Woverloaded-virtual + // TODO: remove this using directive once the following deprecated + // function in the interface class has been removed: + // generate_particles(std::multimap> &particles) + using Generator::Interface::generate_particles; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Number of particles to create + */ + types::particle_index n_particles; + + /** + * If true, particle numbers per cell are calculated randomly + * according to their respective probability density. If false, + * first determine how many particles each cell should have based + * on the integral of the density over each of the cells, and then + * once we know how many particles we want on each cell, choose their + * locations randomly within each cell. + */ + bool random_cell_selection; + + /** + * The seed for the random number generator that controls the + * particle generation. + */ + unsigned int random_number_seed; + + /** + * A function object representing the particle location probability + * density. + */ + Functions::ParsedFunction function; + }; + + } + } +} + +#endif diff --git a/include/aspect/particle/generator/quadrature_points.h.bak b/include/aspect/particle/generator/quadrature_points.h.bak new file mode 100644 index 00000000000..bbf6ad5882a --- /dev/null +++ b/include/aspect/particle/generator/quadrature_points.h.bak @@ -0,0 +1,63 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_generator_quadrature_points_h +#define _aspect_particle_generator_quadrature_points_h + +#include + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + /** + * Generates particles at the quadrature points of each active cell of the triangulation. + * Here, Gauss quadrature of degree, (velocity_degree + 1), is used similarly to the assembly of the + * Stokes matrix. + * @ingroup ParticleGenerators + */ + template + class QuadraturePoints : public Interface + { + public: + /** + * Generates particles at the quadrature points of each active cell of the triangulation. + * Here, Gauss quadrature of degree, (velocity_degree + 1), is used similarly to the assembly of the + * Stokes matrix. + * + * @param [in,out] particle_handler The particle handler into which + * the generated particles should be inserted. + */ + void + generate_particles(Particles::ParticleHandler &particle_handler) override; + + // avoid -Woverloaded-virtual + // TODO: remove this using directive once the following deprecated + // function in the interface class has been removed: + // generate_particles(std::multimap> &particles) + using Generator::Interface::generate_particles; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/generator/random_uniform.h.bak b/include/aspect/particle/generator/random_uniform.h.bak new file mode 100644 index 00000000000..a69fab590d1 --- /dev/null +++ b/include/aspect/particle/generator/random_uniform.h.bak @@ -0,0 +1,98 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_generator_random_uniform_h +#define _aspect_particle_generator_random_uniform_h + +#include + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + /** + * Generate random uniform distribution of particles over entire simulation domain. + * + * @ingroup ParticleGenerators + */ + template + class RandomUniform : public Interface + { + public: + /** + * Generate a set of particles in the given + * particle handler. The particles are generated + * with a uniform density in the whole domain. + * + * @param [in,out] particle_handler The particle handler into which + * the generated particles should be inserted. + */ + void + generate_particles(Particles::ParticleHandler &particle_handler) override; + + // avoid -Woverloaded-virtual + // TODO: remove this using directive once the following deprecated + // function in the interface class has been removed: + // generate_particles(std::multimap> &particles) + using Generator::Interface::generate_particles; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Number of particles to create + */ + types::particle_index n_particles; + + /** + * If true, particle numbers per cell are calculated randomly + * according to their respective probability density. If false, + * first determine how many particles each cell should have based + * on the integral of the density over each of the cells, and then + * once we know how many particles we want on each cell, choose their + * locations randomly within each cell. + */ + bool random_cell_selection; + + /** + * The seed for the random number generator that controls the + * particle generation. + */ + unsigned int random_number_seed; + }; + + } + } +} + +#endif diff --git a/include/aspect/particle/generator/reference_cell.h.bak b/include/aspect/particle/generator/reference_cell.h.bak new file mode 100644 index 00000000000..2721c62e4de --- /dev/null +++ b/include/aspect/particle/generator/reference_cell.h.bak @@ -0,0 +1,94 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_generator_reference_cell_h +#define _aspect_particle_generator_reference_cell_h + +#include + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + /** + * Generate a uniform distribution of particles in the unit cell and transforms + * each of the particles back to real region in the model domain. + * Uniform here means the particles will be generated with + * an equal spacing in each spatial dimension. + * + * @ingroup ParticleGenerators + */ + template + class ReferenceCell : public Interface + { + public: + /** + * Generate a uniform distribution of particles in the unit cell and transforms + * each of the particles back to real region in the model domain. + * Uniform here means the particles will be generated with + * an equal spacing in each spatial dimension. + * + * @param [in,out] particle_handler The particle handler into which + * the generated particles should be inserted. + */ + void + generate_particles(Particles::ParticleHandler &particle_handler) override; + + // avoid -Woverloaded-virtual + // TODO: remove this using directive once the following deprecated + // function in the interface class has been removed: + // generate_particles(std::multimap> &particles) + using Generator::Interface::generate_particles; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Calculates particle position in the unit cell. + * + * @return A vector container of points each of size dim. + */ + std::vector> generate_particle_positions_in_unit_cell(); + + /** + * Number of particles to create for each spatial dimension as + * specified within the parameter file. + */ + std::vector number_of_particles; + }; + + } + } +} + +#endif diff --git a/include/aspect/particle/generator/uniform_box.h.bak b/include/aspect/particle/generator/uniform_box.h.bak new file mode 100644 index 00000000000..1ba743d6675 --- /dev/null +++ b/include/aspect/particle/generator/uniform_box.h.bak @@ -0,0 +1,99 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_generator_uniform_box_h +#define _aspect_particle_generator_uniform_box_h + +#include + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + /** + * Generate a uniform distribution of particles in a box region in the + * model domain. Uniform here means the particles will be generated with + * an equal spacing in each spatial dimension. Note that in order + * to produce a regular distribution the number of generated + * particles might not exactly match the one specified in the + * input file. + * + * @ingroup ParticleGenerators + */ + template + class UniformBox : public Interface + { + public: + /** + * Generate a uniformly randomly distributed set of particles in a + * box-like subdomain of the global domain. + * + * @param [in,out] particle_handler The particle handler into which + * the generated particles should be inserted. + */ + void + generate_particles(Particles::ParticleHandler &particle_handler) override; + + // avoid -Woverloaded-virtual + // TODO: remove this using directive once the following deprecated + // function in the interface class has been removed: + // generate_particles(std::multimap> &particles) + using Generator::Interface::generate_particles; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Number of initial particles to create. + */ + types::particle_index n_particles; + + /** + * The minimum coordinates of the particle region, i.e. one corner of + * the n-dimensional box region in which particles are generated. + */ + Point P_min; + + /** + * The maximum coordinates of the particle region, i.e. the opposite + * corner of the n-dimensional box region in which particles are + * generated. + */ + Point P_max; + }; + + } + } +} + +#endif diff --git a/include/aspect/particle/generator/uniform_radial.h.bak b/include/aspect/particle/generator/uniform_radial.h.bak new file mode 100644 index 00000000000..b403b950674 --- /dev/null +++ b/include/aspect/particle/generator/uniform_radial.h.bak @@ -0,0 +1,124 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_generator_uniform_radial_h +#define _aspect_particle_generator_uniform_radial_h + +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + using namespace dealii; + + /** + * Generate a uniform radial distribution of particles over the entire + * simulation domain. Uniform here means + * the particles will be generated with an equal spacing in + * each spherical spatial dimension, i.e. the particles are + * created at coordinates that increase linearly with equal + * spacing in radius, colatitude and longitude around a + * certain center point. Note that in order + * to produce a regular distribution the number of generated + * particles might not exactly match the one specified in the + * input file. + * + * @ingroup ParticleGenerators + */ + template + class UniformRadial : public Interface + { + public: + /** + * Generate a uniformly distributed set of particles in a + * circular or spherical subdomain of the global domain. + * + * @param [in,out] particle_handler The particle handler into which + * the generated particles should be inserted. + */ + void + generate_particles(Particles::ParticleHandler &particle_handler) override; + + // avoid -Woverloaded-virtual + // TODO: remove this using directive once the following deprecated + // function in the interface class has been removed: + // generate_particles(std::multimap> &particles) + using Generator::Interface::generate_particles; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * The minimum spherical coordinates of the particle region, i.e. + * the first radius, colatitude and longitude from the given + * center position P_center where particles are generated. + */ + std::array P_min; + + /** + * The maximum spherical coordinates of the particle region, i.e. + * the last radius, colatitude and longitude from the given + * center position P_center where particles are generated. + */ + std::array P_max; + + /** + * The center of the particle region. Defaults to the origin. + */ + Point P_center; + + /** + * The number of radial layers of particles that will be generated. + * In particular this parameter determines the radial spacing between + * particle layers as Pmax[0] - P_min[0] / radial_layers. + */ + unsigned int radial_layers; + + /** + * Number of particles to create in total. To preserve the equal + * spacing (in spherical coordinates) between particles, the number + * of actually generated + * particles can differ slightly from this number. + */ + types::particle_index n_particles; + }; + + } + } +} + +#endif diff --git a/include/aspect/particle/integrator/euler.h.bak b/include/aspect/particle/integrator/euler.h.bak new file mode 100644 index 00000000000..ad93cb6febc --- /dev/null +++ b/include/aspect/particle/integrator/euler.h.bak @@ -0,0 +1,101 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_integrator_euler_h +#define _aspect_particle_integrator_euler_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Integrator + { + /** + * Explicit Euler scheme integrator. + * This requires only one step per integration, and doesn't involve any + * additional integration steps (it is a one-step method), therefore + * no data needs to be stored between subsequent steps. + * + * @ingroup ParticleIntegrators + */ + template + class Euler : public Interface, public SimulatorAccess + { + public: + /** + * Perform an integration step of moving the particles of one cell + * by the specified timestep dt. This function implements an explicit + * Euler integration scheme. + * + * @param [in] begin_particle An iterator to the first particle to be moved. + * @param [in] end_particle An iterator to the last particle to be moved. + * @param [in] old_velocities The velocities at t_n, i.e. before the + * particle movement, for all particles between @p begin_particle + * and @p end_particle at their current position. + * @param [in] velocities The velocities at the particle positions + * at t_{n+1}, i.e. after the particle movement. Note that this is + * the velocity at the old positions, but at the new time. It is the + * responsibility of this function to compute the new location of + * the particles. + * @param [in] dt The length of the integration timestep. + */ + void + local_integrate_step(const typename ParticleHandler::particle_iterator &begin_particle, + const typename ParticleHandler::particle_iterator &end_particle, + const std::vector> &old_velocities, + const std::vector> &velocities, + const double dt) override; + + /** + * Return a list of boolean values indicating which solution vectors + * are required for the integration. The first entry indicates if + * the particle integrator requires the solution vector at the old + * old time (k-1), the second entry indicates if the particle integrator + * requires the solution vector at the old time (k), and the third entry + * indicates if the particle integrator requires the solution vector + * at the new time (k+1). + * + * The forward Euler integrator only requires the solution vector at the + * old time (k), and consequently returns `{false, true, false}`. + */ + std::array required_solution_vectors() const override; + + /** + * We need to tell the property manager how many intermediate properties this integrator requires, + * so that it can allocate sufficient space for each particle. However, the integrator is not + * created at the time the property manager is set up and we can not reverse the order of creation, + * because the integrator needs to know where to store its properties, which requires the property manager + * to be finished setting up properties. Luckily the number of properties is constant, so we can make it + * a static property of this class. Therefore, the property manager can access this variable even + * before any object is constructed. + * + * The forward Euler integrator does not need any intermediate storage space. + */ + static const unsigned int n_integrator_properties = 0; + }; + + } + } +} + +#endif diff --git a/include/aspect/particle/integrator/interface.h.bak b/include/aspect/particle/integrator/interface.h.bak new file mode 100644 index 00000000000..dab8f945625 --- /dev/null +++ b/include/aspect/particle/integrator/interface.h.bak @@ -0,0 +1,242 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_integrator_interface_h +#define _aspect_particle_integrator_interface_h + +#include +#include + +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Integrator + { + using namespace dealii; + using namespace dealii::Particles; + + /** + * An abstract class defining virtual methods for performing integration + * of particle paths through the simulation velocity field. + * + * @ingroup ParticleIntegrators + */ + template + class Interface : public ParticleInterfaceBase + { + public: + /** + * Perform an integration step of moving the particles of one cell + * by the specified timestep dt. Implementations of this function + * must update the particle location. Between calls to this function + * the velocity at the updated particle positions is evaluated and + * passed as input argument during the next call. + * + * @param [in] begin_particle An iterator to the first particle to be moved. + * @param [in] end_particle An iterator to the last particle to be moved. + * @param [in] old_velocities The velocities at t_n, i.e. before the + * particle movement, for all particles between @p begin_particle + * and @p end_particle at their current position. + * @param [in] velocities The velocities at the particle positions + * at t_{n+1}, i.e. after the particle movement. Note that this is + * the velocity at the old positions, but at the new time. It is the + * responsibility of this function to compute the new location of + * the particles. + * @param [in] dt The length of the integration timestep. + */ + virtual + void + local_integrate_step(const typename ParticleHandler::particle_iterator &begin_particle, + const typename ParticleHandler::particle_iterator &end_particle, + const std::vector> &old_velocities, + const std::vector> &velocities, + const double dt) = 0; + + /** + * This function is called at the end of every integration step. + * In case of multi-step integrators it signals the beginning of a + * new integration step. The default implementation always returns + * false, which is ok for single-step integration methods. + * + * @return This function returns true if the integrator requires + * another integration step. The particle world will continue + * to start new integration steps until this function returns false. + */ + virtual bool new_integration_step(); + + /** + * Return data length of the integration related data required for + * communication in terms of number of bytes. When data about + * particles is transported from one processor to another, or stored + * on disk for snapshots, integrators get the chance to store + * whatever information they need with each particle. This function + * returns how many pieces of additional information a concrete + * integrator class needs to store for each particle. + * + * @return The number of bytes required to store the relevant + * integrator data for one particle. + */ + virtual std::size_t get_data_size() const; + + /** + * Return a list of boolean values indicating which solution vectors + * are required for the integration. The first entry indicates if + * the particle integrator requires the solution vector at the old + * old time (k-1), the second entry indicates if the particle integrator + * requires the solution vector at the old time (k), and the third entry + * indicates if the particle integrator requires the solution vector + * at the new time (k+1). + */ + virtual std::array required_solution_vectors() const = 0; + + /** + * Read integration related data for a particle specified by particle_id + * from the data array. This function is called after transferring + * a particle to the local domain during an integration step. + * + * @param [in] data A pointer into the data array. The pointer + * marks the position where this function starts reading. + * @param [in] particle An iterator pointing to the particle to read + * the data for. + * @return The updated position of the pointer into the data array. + * The return value is @p data advanced by get_data_size() bytes. + */ + virtual + const void * + read_data(const typename ParticleHandler::particle_iterator &particle, + const void *data); + + /** + * Write integration related data to a vector for a particle + * specified by particle_id. This function is called in cases where + * particles leave the local domain during an integration step to + * transfer this data to another process. + * + * @param [in] particle An iterator pointing to the particle to + * write the data for. + * @param [in] data A pointer into the array of integrator data. + * @return The updated position of the pointer into the data array. + * The return value is @p data advanced by get_data_size() bytes. + */ + virtual + void * + write_data(const typename ParticleHandler::particle_iterator &particle, + void *data) const; + }; + + + /** + * Return a list of names (separated by '|') of possible integrator + * classes for particles. + */ + std::string + integrator_object_names (); + + + /** + * Register a particle integrator so that it can be selected from + * the parameter file. + * + * @param name A string that identifies the particle integrator + * @param description A text description of what this integrator does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this particle integrator wants to read + * from input files. + * @param factory_function A pointer to a function that can create an + * object of this particle integrator. + * + * @ingroup ParticleIntegrators + */ + template + void + register_particle_integrator (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * A function that given the name of a model returns a pointer to an + * object that describes it. Ownership of the pointer is transferred to + * the caller. + * + * The model object returned is not yet initialized and has not + * read its runtime parameters yet. + * + * @ingroup ParticleIntegrators + */ + template + std::unique_ptr> + create_particle_integrator (ParameterHandler &prm); + + + /** + * Declare the runtime parameters of the registered particle integrators. + * + * @ingroup ParticleIntegrators + */ + template + void + declare_parameters (ParameterHandler &prm); + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + template + void + write_plugin_graph (std::ostream &output_stream); + + /** + * Given a class name, a name, and a description for the parameter file + * for a particle integrator, register it with the functions that + * can declare their parameters and create these objects. + * + * @ingroup ParticleIntegrators + */ +#define ASPECT_REGISTER_PARTICLE_INTEGRATOR(classname, name, description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_PARTICLE_INTEGRATOR_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::Particle::Integrator::register_particle_integrator<2>, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::Particle::Integrator::register_particle_integrator<3>, \ + name, description); \ + } + } + } +} + + +#endif diff --git a/include/aspect/particle/integrator/rk_2.h.bak b/include/aspect/particle/integrator/rk_2.h.bak new file mode 100644 index 00000000000..2a307def6d8 --- /dev/null +++ b/include/aspect/particle/integrator/rk_2.h.bak @@ -0,0 +1,155 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_integrator_rk_2_h +#define _aspect_particle_integrator_rk_2_h + +#include + +#include + + +namespace aspect +{ + namespace Particle + { + namespace Integrator + { + /** + * Runge Kutta second order integrator. + * This scheme requires storing the original location in the particle properties. + * + * @ingroup ParticleIntegrators + */ + template + class RK2 : public Interface, public SimulatorAccess + { + public: + RK2(); + + /** + * Look up where the RK2 data is stored. Done once and cached to + * avoid repeated lookups. + */ + void + initialize () override; + + /** + * Perform an integration step of moving the particles of one cell + * by the specified timestep dt. This function implements a + * second-order accurate Runge-Kutta integration scheme. + * + * @param [in] begin_particle An iterator to the first particle to be moved. + * @param [in] end_particle An iterator to the last particle to be moved. + * @param [in] old_velocities The velocities at t_n, i.e. before the + * particle movement, for all particles between @p begin_particle + * and @p end_particle at their current position. + * @param [in] velocities The velocities at the particle positions + * at t_{n+1}, i.e. after the particle movement. Note that this is + * the velocity at the old positions, but at the new time. It is the + * responsibility of this function to compute the new location of + * the particles. + * @param [in] dt The length of the integration timestep. + */ + void + local_integrate_step(const typename ParticleHandler::particle_iterator &begin_particle, + const typename ParticleHandler::particle_iterator &end_particle, + const std::vector> &old_velocities, + const std::vector> &velocities, + const double dt) override; + + /** + * This function is called at the end of every integration step. + * For the current class it will either increment the step variable + * and return true to request another integration step, or reset the + * step variable to 0 and return false if we are already in step 2. + * + * @return This function returns true if the integrator requires + * another integration step. The particle integration will continue + * to start new integration steps until this function returns false. + */ + bool new_integration_step() override; + + /** + * Return a list of boolean values indicating which solution vectors + * are required for the integration. The first entry indicates if + * the particle integrator requires the solution vector at the old + * old time (k-1), the second entry indicates if the particle integrator + * requires the solution vector at the old time (k), and the third entry + * indicates if the particle integrator requires the solution vector + * at the new time (k+1). + * + * The RK2 integrator requires the solution vector at the + * old time (k) for the first integration step, and the solution + * vector at both the old and new time for the second integration step + * (if higher_order_in_time is set to true). + */ + std::array required_solution_vectors() const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * We need to tell the property manager how many intermediate properties this integrator requires, + * so that it can allocate sufficient space for each particle. However, the integrator is not + * created at the time the property manager is set up and we can not reverse the order of creation, + * because the integrator needs to know where to store its properties, which requires the property manager + * to be finished setting up properties. Luckily the number of properties is constant, so we can make it + * a static property of this class. Therefore, the property manager can access this variable even + * before any object is constructed. + * + * The Runge-Kutta 2 integrator requires a single point with dim components. + */ + static const unsigned int n_integrator_properties = dim; + + private: + /** + * The current integration step, i.e for RK2 a number that is either + * 0 or 1. + */ + unsigned int integrator_substep; + + /** + * The location of the RK2 data that is stored in the particle properties. + */ + unsigned int property_index_old_location; + + /** + * Whether to evaluate old and current velocity to compute a solution + * that is higher order accurate in time. + */ + bool higher_order_in_time; + }; + + } + } +} + +#endif diff --git a/include/aspect/particle/integrator/rk_4.h.bak b/include/aspect/particle/integrator/rk_4.h.bak new file mode 100644 index 00000000000..ae27e8446bc --- /dev/null +++ b/include/aspect/particle/integrator/rk_4.h.bak @@ -0,0 +1,135 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_integrator_rk_4_h +#define _aspect_particle_integrator_rk_4_h + +#include + +namespace aspect +{ + namespace Particle + { + namespace Integrator + { + /** + * Runge Kutta fourth order integrator. This scheme requires + * storing the original location and intermediate k1, k2, k3 + * values in the particle properties. + * + * @ingroup ParticleIntegrators + */ + template + class RK4 : public Interface, public SimulatorAccess + { + public: + RK4(); + + /** + * Look up where the RK4 data is stored. Done once and cached to + * avoid repeated lookups. + */ + void + initialize () override; + + /** + * Perform an integration step of moving the particles of one cell + * by the specified timestep dt. This class implements a Runge-Kutta + * integration scheme that is fourth order accurate + * in space. + * + * @param [in] begin_particle An iterator to the first particle to be moved. + * @param [in] end_particle An iterator to the last particle to be moved. + * @param [in] old_velocities The velocities at t_n, i.e. before the + * particle movement, for all particles between @p begin_particle + * and @p end_particle at their current position. + * @param [in] velocities The velocities at the particle positions + * at t_{n+1}, i.e. after the particle movement. Note that this is + * the velocity at the old positions, but at the new time. It is the + * responsibility of this function to compute the new location of + * the particles. + * @param [in] dt The length of the integration timestep. + */ + void + local_integrate_step(const typename ParticleHandler::particle_iterator &begin_particle, + const typename ParticleHandler::particle_iterator &end_particle, + const std::vector> &old_velocities, + const std::vector> &velocities, + const double dt) override; + + /** + * This function is called at the end of every integration step. + * For the current class it will either increment the step variable + * and return true to request another integration step, or reset the + * step variable to 0 and return false if we are already in step 4. + * + * @return This function returns true if the integrator requires + * another integration step. The particle integration will continue + * to start new integration steps until this function returns false. + */ + bool new_integration_step() override; + + /** + * Return a list of boolean values indicating which solution vectors + * are required for the integration. The first entry indicates if + * the particle integrator requires the solution vector at the old + * old time (k-1), the second entry indicates if the particle integrator + * requires the solution vector at the old time (k), and the third entry + * indicates if the particle integrator requires the solution vector + * at the new time (k+1). + * + * The RK4 integrator requires the solution vector at the + * old time (k) for the first integration step, the solution + * vector at both the old and new time for the second + * and third integration steps and the solution vector at the + * new time (k+1) for the fourth integration step. + */ + std::array required_solution_vectors() const override; + + /** + * We need to tell the property manager how many intermediate properties this integrator requires, + * so that it can allocate sufficient space for each particle. However, the integrator is not + * created at the time the property manager is set up and we can not reverse the order of creation, + * because the integrator needs to know where to store its properties, which requires the property manager + * to be finished setting up properties. Luckily the number of properties is constant, so we can make it + * a static property of this class. Therefore, the property manager can access this variable even + * before any object is constructed. + * + * The Runge-Kutta 4 integrator requires 4 tensors with dim components each. + */ + static const unsigned int n_integrator_properties = 4*dim; + + private: + /** + * The current integration step, i.e. for RK4 a number between 0 + * and 3. + */ + unsigned int integrator_substep; + + /** + * The location of the 4 RK4 data fields stored in the particle properties. + */ + std::array property_indices; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/interface.h.bak b/include/aspect/particle/interface.h.bak new file mode 100644 index 00000000000..04ab2a319ba --- /dev/null +++ b/include/aspect/particle/interface.h.bak @@ -0,0 +1,63 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_interface_h +#define _aspect_particle_interface_h + +#include + +namespace aspect +{ + namespace Particle + { + /** + * A base class defining methods and member variables + * shared along all the particle plugins. This includes the generator, + * integrator, interpolator and the property classes. + * + * @ingroup Particle + */ + class ParticleInterfaceBase : public Plugins::InterfaceBase + { + public: + /** + * @brief Set which particle world the plugin belongs to. + * + * @param particle_world_index The index of the particle world this plugin belongs to. + */ + void set_particle_world_index(unsigned int particle_world_index); + + /** + * @brief Gets which particle world the plugin belong to. + */ + unsigned int get_particle_world_index() const; + + private: + /** + * Stores the index to the particle world, to which the plugin belongs. + */ + unsigned int particle_world_index; + }; + + } +} + + +#endif diff --git a/include/aspect/particle/interpolator/bilinear_least_squares.h.bak b/include/aspect/particle/interpolator/bilinear_least_squares.h.bak new file mode 100644 index 00000000000..fb4f34b640d --- /dev/null +++ b/include/aspect/particle/interpolator/bilinear_least_squares.h.bak @@ -0,0 +1,103 @@ +/* + Copyright (C) 2017 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_interpolator_bilinear_least_squares_h +#define _aspect_particle_interpolator_bilinear_least_squares_h + +#include +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + /** + * Evaluate the properties of all particles of the given cell + * using a least squares projection onto the set of bilinear + * (or, in 3d, trilinear) functions. + * + * @ingroup ParticleInterpolators + */ + template + class BilinearLeastSquares : public Interface, public aspect::SimulatorAccess + { + public: + /** + * Return the cell-wise evaluated properties of the bilinear least squares function at the positions. + */ + std::vector> + properties_at_points(const ParticleHandler &particle_handler, + const std::vector> &positions, + const ComponentMask &selected_properties, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const override; + + // avoid -Woverloaded-virtual: + using Interface::properties_at_points; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A component mask that determines whether a limiting scheme is + * used for each interpolated property. The limiting scheme + * prevents overshoot and undershoot of interpolated particle + * properties based on the local max and min of the particle + * properties in that cell (i.e. the interpolated properties + * will never exxceed the max and min of the properties on the particles). + */ + ComponentMask use_linear_least_squares_limiter; + + /** + * A component mask that determines whether a boundary condition + * can be extrapolated for use in the limiting scheme. If boundary + * extrapolation is enabled for a given property index, then the + * limiter should be as well. Boundary extrapolation should help + * the accuracy of properties that are smooth, although it can allow + * undershoots and overshoots to occur if used with characteristic + * functions or functions with discontinuities near a model boundary. + */ + ComponentMask use_boundary_extrapolation; + + /** + * Fallback method if there are too few particles in a cell to + * perform a bilinear least squares interpolation. + */ + Interpolator::CellAverage fallback_interpolator; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/interpolator/cell_average.h.bak b/include/aspect/particle/interpolator/cell_average.h.bak new file mode 100644 index 00000000000..38bdcb2fd98 --- /dev/null +++ b/include/aspect/particle/interpolator/cell_average.h.bak @@ -0,0 +1,80 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_interpolator_cell_average_h +#define _aspect_particle_interpolator_cell_average_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + /** + * Return the averaged properties of all particles on the given cell. + * + * @ingroup ParticleInterpolators + */ + template + class CellAverage : public Interface, public aspect::SimulatorAccess + { + public: + /** + * Return the cell-wise averaged properties of all particles of the cell containing the + * given positions. + */ + std::vector> + properties_at_points(const ParticleHandler &particle_handler, + const std::vector> &positions, + const ComponentMask &selected_properties, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const override; + + // avoid -Woverloaded-virtual: + using Interface::properties_at_points; + + /** + * @copydoc Interface::declare_parameters() + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * @copydoc Interface::parse_parameters() + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * By default, every cell needs to contain particles to use this interpolator + * plugin. If this parameter is set to true, cells are allowed to have no particles, + * in which case the interpolator will return 0 for the cell's properties. + */ + bool allow_cells_without_particles; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/interpolator/harmonic_average.h.bak b/include/aspect/particle/interpolator/harmonic_average.h.bak new file mode 100644 index 00000000000..78effa04340 --- /dev/null +++ b/include/aspect/particle/interpolator/harmonic_average.h.bak @@ -0,0 +1,80 @@ +/* + Copyright (C) 2017 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_interpolator_harmonic_average_h +#define _aspect_particle_interpolator_harmonic_average_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + /** + * Return the harmonic averaged properties of all particles on the given cell. + * + * @ingroup ParticleInterpolators + */ + template + class HarmonicAverage : public Interface, public aspect::SimulatorAccess + { + public: + /** + * Return the cell-wise harmonic averaged properties of all particles of the cell containing the + * given positions. + */ + std::vector> + properties_at_points(const ParticleHandler &particle_handler, + const std::vector> &positions, + const ComponentMask &selected_properties, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const override; + + // avoid -Woverloaded-virtual: + using Interface::properties_at_points; + + /** + * @copydoc Interface::declare_parameters() + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * @copydoc Interface::parse_parameters() + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * By default, every cell needs to contain particles to use this interpolator + * plugin. If this parameter is set to true, cells are allowed to have no particles, + * in which case the interpolator will return 0 for the cell's properties. + */ + bool allow_cells_without_particles; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/interpolator/interface.h.bak b/include/aspect/particle/interpolator/interface.h.bak new file mode 100644 index 00000000000..6d52b743356 --- /dev/null +++ b/include/aspect/particle/interpolator/interface.h.bak @@ -0,0 +1,179 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_interpolator_interface_h +#define _aspect_particle_interpolator_interface_h + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + using namespace dealii; + using namespace dealii::Particles; + + /** + * An abstract class defining virtual methods for performing + * interpolation of particle properties to arbitrary points. + * + * @ingroup ParticleInterpolators + */ + template + class Interface : public ParticleInterfaceBase + { + public: + /** + * Perform an interpolation of the properties of the particles in + * this cell onto a vector of positions in this cell. + * Implementations of this function must return a vector of a vector + * of doubles with as many entries as positions in @p positions. + * Each entry is a vector with as many entries as there are particle + * properties in this computation. + * All in @p selected_properties selected components + * will be filled with computed properties, all other components + * are not filled (or filled with invalid values). + * + * @param [in] particle_handler Reference to the particle handler + * that allows accessing the particles in the domain. + * @param [in] positions The vector of positions where the properties + * should be evaluated. + * @param [in] selected_properties A component mask that determines + * which particle properties are interpolated in this function. + * @param [in] cell An iterator to the cell containing the + * positions. + * @return A vector with as many entries as @p positions. Each entry + * is a vector of interpolated particle properties at this position. + * This property vector has as many entries as there are particle + * properties, however entries that have not been selected in + * @p selected_properties are filled with signalling NaNs. + */ + virtual + std::vector> + properties_at_points(const ParticleHandler &particle_handler, + const std::vector> &positions, + const ComponentMask &selected_properties, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const = 0; + }; + + + /** + * Return a list of names (separated by '|') of possible interpolator + * classes for particles. + */ + std::string + interpolator_object_names (); + + + /** + * Register a particle interpolator so that it can be selected from + * the parameter file. + * + * @param name A string that identifies the particle interpolator + * @param description A text description of what this interpolator does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this particle interpolator wants to read + * from input files. + * @param factory_function A pointer to a function that can create an + * object of this particle interpolator. + * + * @ingroup ParticleInterpolators + */ + template + void + register_particle_interpolator (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * A function that given the name of a model returns a pointer to an + * object that describes it. Ownership of the pointer is transferred to + * the caller. + * + * The model object returned is not yet initialized and has not + * read its runtime parameters yet. + * + * @ingroup ParticleInterpolators + */ + template + std::unique_ptr> + create_particle_interpolator (ParameterHandler &prm); + + + /** + * Declare the runtime parameters of the registered particle interpolators. + * + * @ingroup ParticleInterpolators + */ + template + void + declare_parameters (ParameterHandler &prm); + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + template + void + write_plugin_graph (std::ostream &output_stream); + + /** + * Given a class name, a name, and a description for the parameter file + * for a particle interpolator, register it with the functions that + * can declare their parameters and create these objects. + * + * @ingroup ParticleInterpolators + */ +#define ASPECT_REGISTER_PARTICLE_INTERPOLATOR(classname, name, description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_PARTICLE_INTERPOLATOR_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::Particle::Interpolator::register_particle_interpolator<2>, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::Particle::Interpolator::register_particle_interpolator<3>, \ + name, description); \ + } + } + } +} + + +#endif diff --git a/include/aspect/particle/interpolator/nearest_neighbor.h.bak b/include/aspect/particle/interpolator/nearest_neighbor.h.bak new file mode 100644 index 00000000000..feacd4d12f6 --- /dev/null +++ b/include/aspect/particle/interpolator/nearest_neighbor.h.bak @@ -0,0 +1,81 @@ +/* + Copyright (C) 2017 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_interpolator_nearest_neighbor_h +#define _aspect_particle_interpolator_nearest_neighbor_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + /** + * Return the properties of the nearest particle within the current cell, or + * in a neighboring cell if this one is empty. + * + * @ingroup ParticleInterpolators + */ + template + class NearestNeighbor : public Interface, public aspect::SimulatorAccess + { + public: + /** + * Return the properties of the particles nearest to the given positions within the same cell, + * or adjacent cells if none is present in same cell. + */ + std::vector> + properties_at_points(const ParticleHandler &particle_handler, + const std::vector> &positions, + const ComponentMask &selected_properties, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const override; + + // avoid -Woverloaded-virtual: + using Interface::properties_at_points; + + /** + * @copydoc Interface::declare_parameters() + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * @copydoc Interface::parse_parameters() + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * By default, every cell needs to contain particles to use this interpolator + * plugin. If this parameter is set to true, cells are allowed to have no particles, + * in which case the interpolator will return 0 for the cell's properties. + */ + bool allow_cells_without_particles; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/interpolator/quadratic_least_squares.h.bak b/include/aspect/particle/interpolator/quadratic_least_squares.h.bak new file mode 100644 index 00000000000..416c705b122 --- /dev/null +++ b/include/aspect/particle/interpolator/quadratic_least_squares.h.bak @@ -0,0 +1,117 @@ +/* + Copyright (C) 2019 - 2022-2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_interpolator_quadratic_least_squares_h +#define _aspect_particle_interpolator_quadratic_least_squares_h + +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + /** + * Return the properties of all particles of the given cell by using a least squares + * projection onto the space of quadratic functions. + * For more details on the implementation and properties of this plugin see: + * Mack Gregory and Elbridge Gerry Puckett (2020), + * "Improving the Accuracy and Efficiency of Hybrid Finite + * Element / Particle-In-Cell Methods for Modeling Geologic Processes", + * Abstract Submission ID# 743654 + * https://agu.confex.com/agu/fm20/prelim.cgi/Paper/743654 + * Session: A002 - Addressing Challenges for the Next Generation of Earth System Models + * Submitted to 2020 AGU Fall Meeting, San Francisco, CA Dec. 7-11, 2020 + * + * @ingroup ParticleInterpolators + */ + template + class QuadraticLeastSquares : public Interface, public aspect::SimulatorAccess + { + public: + /** + * Return the cell-wise evaluated properties of the quadratic least squares function at the positions. + */ + std::vector> + properties_at_points(const ParticleHandler &particle_handler, + const std::vector> &positions, + const ComponentMask &selected_properties, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const override; + + // avoid -Woverloaded-virtual: + using Interface::properties_at_points; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Use the cell average interpolator in case the quadratic least + * squares interpolator fails due to a lack of particles. + */ + Interpolator::CellAverage fallback_interpolator; + + /** + * Enables a limiting scheme that prevents overshoot and + * undershoot of interpolated particles based upon the range + * of property values found in the area of the cell. + */ + ComponentMask use_quadratic_least_squares_limiter; + + /** + * Enables a linear extrapolation of boundary values for the limiting scheme + */ + ComponentMask use_boundary_extrapolation; + + /** + * Calculate the value of the interpolation function at a given position + */ + double evaluate_interpolation_function(const Vector &coefficients, const Point &position) const; + + /** + * Update the bounds of where the plane reaches by checking whether each of the critical points + * are in the cell and evauating their value. + */ + std::pair get_interpolation_bounds(const dealii::Vector &coefficients) const; + + /* + * Find all points that may contain the minimum or maximum values of the interpolation in the cell. + */ + std::vector> get_critical_points(const dealii::Vector &coefficients) const; + + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/composition.h.bak b/include/aspect/particle/property/composition.h.bak new file mode 100644 index 00000000000..a115a811e3a --- /dev/null +++ b/include/aspect/particle/property/composition.h.bak @@ -0,0 +1,98 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_composition_h +#define _aspect_particle_property_composition_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * Implementation of a plugin in which the particle + * property is defined by the compositional fields in + * the model. This can be used to track solid composition + * evolution over time. + * + * @ingroup ParticleProperties + */ + template + class Composition : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::update_particle_property() + */ + virtual + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * This implementation tells the particle manager that + * we need to update particle properties over time. + */ + UpdateTimeFlags + need_update () const override; + + /** + * Return which data has to be provided to update the property. + * The pressure and temperature need the values of their variables. + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/cpo_bingham_average.h.bak b/include/aspect/particle/property/cpo_bingham_average.h.bak new file mode 100644 index 00000000000..a2ffd097350 --- /dev/null +++ b/include/aspect/particle/property/cpo_bingham_average.h.bak @@ -0,0 +1,224 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_cpo_bingham_average_h +#define _aspect_particle_property_cpo_bingham_average_h + +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + + /** + * Computes the Bingham average of the CPO particle properties. + * See https://courses.eas.ualberta.ca/eas421/lecturepages/orientation.html for more info. + * + * The layout of the data vector per particle is the following (note that for this plugin the following dim's are always 3): + * 1 averaged a axis of olivine -> 3 (dim) doubles, starts at: + * data_position + 1, + * 2 eigenvalues of a axis of olivine -> 3 (dim) doubles, starts at: + * data_position + 4, + * 3 averaged b axis of olivine -> 3 (dim) doubles, starts at: + * data_position + 7, + * 4 eigenvalues of b axis of olivine -> 3 (dim) doubles, starts at: + * data_position + 10, + * 5 averaged c axis of olivine -> 3 (dim) doubles, starts at: + * data_position + 13, + * 6 eigenvalues of c axis of olivine -> 3 (dim) doubles, starts at: + * data_position + 16, + * 7 averaged a axis of enstatite -> 3 (dim) doubles, starts at: + * data_position + 19, + * 8 eigenvalues of a axis of enstatite -> 3 (dim) doubles, starts at: + * data_position + 22, + * 9 averaged a axis of enstatite -> 3 (dim) doubles, starts at: + * data_position + 25, + * 10 eigenvalues of a axis of enstatite -> 3 (dim) doubles, starts at: + * data_position + 28, + * 11 averaged a axis of enstatite -> 3 (dim) doubles, starts at: + * data_position + 31, + * 12 eigenvalues of a axis of enstatite -> 3 (dim) doubles, starts at: + * data_position + 34, + * + * @ingroup ParticleProperties + */ + template + class CpoBinghamAverage : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * constructor + */ + CpoBinghamAverage() = default; + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run. + */ + void + initialize () override; + + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * Update function. This function is called every time an update is + * request by need_update() for every particle for every property. + * It is obvious that + * this function is called a lot, so its code should be efficient. + * The interface provides a default implementation that does nothing, + * therefore derived plugins that do not require an update do not + * need to implement this function. + * + * @param [in] data_position An unsigned integer that denotes which + * component of the particle property vector is associated with the + * current property. For properties that own several components it + * denotes the first component of this property, all other components + * fill consecutive entries in the @p particle_properties vector. + * + * @param [in] solution The values of the solution variables at the + * current particle position. + * + * @param [in] gradients The gradients of the solution variables at + * the current particle position. + * + * @param [in,out] particle The particle that is updated within + * the call of this function. The particle location can be accessed + * using particle->get_location() and its properties using + * particle->get_properties(). + */ + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * This implementation tells the particle manager that + * we need to update particle properties every time step. + */ + UpdateTimeFlags + need_update () const override; + + /** + * Return which data has to be provided to update the property. + * The integrated strains needs the gradients of the velocity. + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + + /** + * Computes the Bingham average. This is a way to average directions. The method comes from + * https://courses.eas.ualberta.ca/eas421/lecturepages/orientation.html, where it is explained + * with the anology that each vector/pole has a weight on a sphere. This method allows to find + * the moment of inertia for spinning that sphere. Here we just use it to get three averaged + * axis associated with the densest clustering of points for each axis. the a to c axis vectors + * are stored in the first to last array respectively. + */ + std::array,3> + compute_bingham_average(std::vector> matrices) const; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * stores the position of the cpo data in the particle property vector + */ + unsigned int cpo_data_position; + + /** + * A pointer to the crystal preferred orientation particle property. + * Avoids repeated searches for that property. + */ + std::unique_ptr> cpo_particle_property; + + /** + * Random number generator. For reproducibility of tests it is + * initialized in the constructor with a constant plus the MPI rank. + */ + mutable std::mt19937 random_number_generator; + + /** + * the random number generator seed used to initialize the random number generator. + */ + unsigned int random_number_seed; + + /** + * Number of grains + */ + unsigned int n_grains; + + /** + * Number of minerals + */ + unsigned int n_minerals; + + /** + * when doing the random draw volume weighting, this sets how many samples are taken. + */ + unsigned int n_samples; + + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/cpo_elastic_tensor.h.bak b/include/aspect/particle/property/cpo_elastic_tensor.h.bak new file mode 100644 index 00000000000..1b7cc82a201 --- /dev/null +++ b/include/aspect/particle/property/cpo_elastic_tensor.h.bak @@ -0,0 +1,206 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_cpo_elastic_tensor_h +#define _aspect_particle_property_cpo_elastic_tensor_h + +#include +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + + /** + * Computes the elastic tensor $C_{ijkl}$ based on the cpo in both olivine + * and enstatite. It uses a Voigt average. + * + * The layout of the data vector per particle is the following (note that + * for this plugin the following dims are always 3): + * 1 unrolled tensor -> 3x3x3x3 (dim*dim*dim*dim) doubles, starts at: + * data_position + * + * @ingroup ParticleProperties + */ + template + class CpoElasticTensor : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor + */ + CpoElasticTensor(); + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run. + */ + void + initialize () override; + + /** + * This implements the Voigt averaging as described in the equation at the + * bottom of page 385 in Mainprice (1990, doi: 10.1016/0098-3004(90)90072-2): + * $C^V_{ijkl} = \sum^S_l F_s \sum^{N_s}_l C_{ijkl}/N_s$, where $F_s$ is the + * grain size, $N_s$ is the number of grains and $C_{ijkl}$ is the elastic + * tensor. This elastic tensor is computed by the equation above in + * Mainprice (1990): $C_{ijkl} = R_{ip} R_{jg} R_{kr} R_{is} C_{pgrs}$, where + * R_{ij} is the cpo orientation matrix. + */ + SymmetricTensor<2,6> + voigt_average_elastic_tensor (const Particle::Property::CrystalPreferredOrientation &cpo_particle_property, + const unsigned int cpo_data_position, + const ArrayView &data) const; + + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * Update function. This function is called every time an update is + * request by need_update() for every particle for every property. + * It is obvious that + * this function is called a lot, so its code should be efficient. + * The interface provides a default implementation that does nothing, + * therefore derived plugins that do not require an update do not + * need to implement this function. + * + * @param [in] data_position An unsigned integer that denotes which + * component of the particle property vector is associated with the + * current property. For properties that own several components it + * denotes the first component of this property, all other components + * fill consecutive entries in the @p particle_properties vector. + * + * @param [in] solution The values of the solution variables at the + * current particle position. + * + * @param [in] gradients The gradients of the solution variables at + * the current particle position. + * + * @param [in,out] particle The particle that is updated within + * the call of this function. The particle location can be accessed + * using particle->get_location() and its properties using + * particle->get_properties(). + */ + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * This function tells the particle manager that + * we need to update particle properties every time step. + */ + UpdateTimeFlags + need_update () const override; + + /** + * Return which data has to be provided to update the property. + * For example, the strains needs the gradients of the velocity. + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + + /** + * returns the elastic tensor from the particle data + */ + static + SymmetricTensor<2,6> + get_elastic_tensor(unsigned int cpo_index, + const ArrayView &data); + + /** + * Stores the elastic tensor into the particle data array + */ + static + void + set_elastic_tensor(unsigned int cpo_data_position, + const ArrayView &data, + const SymmetricTensor<2,6> &elastic_tensor); + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Parses the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The position of the cpo in the particle data array. + */ + unsigned int cpo_data_position; + + /** + * The stiffness tensors for olivine and enstatite. + * Todo: generalize this into a vector. + */ + SymmetricTensor<2,6> stiffness_matrix_olivine; + SymmetricTensor<2,6> stiffness_matrix_enstatite; + + /** + * The number of grains per particle. + */ + unsigned int n_grains; + + /** + * The number of minerals per particle. + */ + unsigned int n_minerals; + + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/crystal_preferred_orientation.h b/include/aspect/particle/property/crystal_preferred_orientation.h index 1c10dcc087b..29c038f87c8 100644 --- a/include/aspect/particle/property/crystal_preferred_orientation.h +++ b/include/aspect/particle/property/crystal_preferred_orientation.h @@ -121,7 +121,7 @@ namespace aspect * * We store the same number of grains for all minerals (e.g. olivine and enstatite * grains), although their volume fractions may not be the same. This is because we need a minimum number - * of grains per tracer to perform reliable statistics on it. This minimum should be the same for all + * of grains per particle to perform reliable statistics on it. This minimum should be the same for all * minerals. * * @ingroup ParticleProperties diff --git a/include/aspect/particle/property/crystal_preferred_orientation.h.bak b/include/aspect/particle/property/crystal_preferred_orientation.h.bak new file mode 100644 index 00000000000..1c10dcc087b --- /dev/null +++ b/include/aspect/particle/property/crystal_preferred_orientation.h.bak @@ -0,0 +1,649 @@ +/* + Copyright (C) 2022 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_cpo_h +#define _aspect_particle_property_cpo_h + +#include +#include +#include + +DEAL_II_DISABLE_EXTRA_DIAGNOSTICS +#include +DEAL_II_ENABLE_EXTRA_DIAGNOSTICS + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * @brief The type of deformation used by the CPO code. + * + * passive: Only to be used with the spin tensor CPO Derivative algorithm. + * olivine_a_fabric to olivine_e_fabric: Only to be used with the D-Rex CPO Derivative algorithm. + * Sets the deformation type of the mineral to a Olivine A-E Fabric, which influences the relative strength of the slip planes. See table 1 in Fraters and Billen (2021). + * enstatite: Only to be used with the D-Rex CPO Derivative algorithm. Sets the deformation type of the mineral to a enstatite Fabric, which influences the relative strength of the slip planes. + */ + enum class DeformationType + { + passive, olivine_a_fabric, olivine_b_fabric, olivine_c_fabric, olivine_d_fabric, olivine_e_fabric, enstatite + }; + + + /** + * @brief The type of deformation selector used by the CPO code. + * + * The selector is a input parameter and it can either set a deformation type directly or determine the deformation type through an algorithm. + * The deformation type selector is used to determine/select the deformation type. It can be a fixed deformation type, for example, + * by setting it to olivine_a_fabric, or it can be dynamically chosen, which is what the olivine_karato_2008 option does. + * + * passive: Only to be used with the spin tensor CPO Derivative algorithm. + * olivine_a_fabric to olivine_e_fabric: Only to be used with the D-Rex CPO Derivative algorithm. + * Sets the deformation type of the mineral to a Olivine A-E Fabric, which influences the relative strength of the slip planes. See table 1 in Fraters and Billen (2021). + * enstatite: Only to be used with the D-Rex CPO Derivative algorithm. Sets the deformation type of the mineral to a enstatite Fabric, which influences the relative strength of the slip planes. + * olivine_karato_2008: Only to be used with the D-Rex CPO Derivative algorithm. Sets the deformation type of the mineral to a olivine fabric based on the table in Karato 2008. + */ + enum class DeformationTypeSelector + { + passive, olivine_a_fabric, olivine_b_fabric, olivine_c_fabric, olivine_d_fabric, olivine_e_fabric, enstatite, olivine_karato_2008 + }; + + /** + * @brief The type of Advection method used to advect the CPO properties. + */ + enum class AdvectionMethod + { + forward_euler, backward_euler + }; + + /** + * @brief The algorithm used to compute the derivatives of the grain size and rotation matrix used in the advection. + * + * spin_tensor: Rotates the CPO properties soly with the rotation of the particle itself. + * drex_2004: Rotates the CPO properties based on the D-Rex 2004 algorithm. + */ + enum class CPODerivativeAlgorithm + { + spin_tensor, drex_2004 + }; + + /** + * @brief An enum used to determine how the initial grain sizes and orientations are set for all particles + * + * uniform_grains_and_random_uniform_rotations: all particles are set to a uniform grain-size of 1/n_grains + * world_builder: all particle grain-sizes and orientations are set by the world builder. + */ + enum class CPOInitialGrainsModel + { + uniform_grains_and_random_uniform_rotations, world_builder + }; + + /** + * The plugin manages and computes the evolution of Lattice/Crystal Preferred Orientations (LPO/CPO) + * on particles. Each ASPECT particle represents many grains. Each grain is assigned a size and a orientation + * matrix. This allows tracking the LPO evolution with kinematic polycrystal CPO evolution models such + * as D-Rex (Kaminski and Ribe, 2001; ́Kaminski et al., 2004). + * + * This plugin stores M minerals and for each mineral it stores N grains. The total amount of memory stored is 2 + * doubles per mineral plus 10 doubles per grain, resulting in a total memory of M * (2 + N * 10) . The layout of + * the data stored is the following (note that for this plugin the following dims are always 3): + * 1. M minerals times + * 1.1 Mineral deformation type -> 1 double, at location + * => 0 + mineral_i * (n_grains * 10 + 2) + * 2.1. Mineral volume fraction -> 1 double, at location + * => 1 + mineral_i * (n_grains * 10 + 2) + * 2.2. N grains times: + * 2.1. volume fraction grain -> 1 double, at location: + * => 2 + grain_i * 10 + mineral_i * (n_grains * 10 + 2) + * 2.2. rotation_matrix grain -> 9 (Tensor<2,dim>::n_independent_components) doubles, starts at: + * => 3 + grain_i * 10 + mineral_i * (n_grains * 10 + 2) + * + * Last used data entry is n_minerals * (n_grains * 10 + 2). + * + * We store the same number of grains for all minerals (e.g. olivine and enstatite + * grains), although their volume fractions may not be the same. This is because we need a minimum number + * of grains per tracer to perform reliable statistics on it. This minimum should be the same for all + * minerals. + * + * @ingroup ParticleProperties + */ + template + class CrystalPreferredOrientation : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor + */ + CrystalPreferredOrientation() = default; + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run. + */ + void + initialize () override; + + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * Update function. This function is called every time an update is + * request by need_update() for every particle for every property. + * It is obvious that + * this function is called a lot, so its code should be efficient. + * The interface provides a default implementation that does nothing, + * therefore derived plugins that do not require an update do not + * need to implement this function. + * + * @param [in] data_position An unsigned integer that denotes which + * component of the particle property vector is associated with the + * current property. For properties that own several components it + * denotes the first component of this property, all other components + * fill consecutive entries in the @p particle_properties vector. + * + * @param [in] solution The values of the solution variables at the + * current particle position. + * + * @param [in] gradients The gradients of the solution variables at + * the current particle position. + * + * @param [in,out] particle The particle that is updated within + * the call of this function. The particle location can be accessed + * using particle->get_location() and its properties using + * particle->get_properties(). + */ + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * This implementation tells the particle manager that + * we need to update particle properties every time step. + */ + UpdateTimeFlags + need_update () const override; + + /** + * The CPO of late particles is initialized by interpolating from existing particles. + */ + InitializationModeForLateParticles + late_initialization_mode () const override; + + /** + * Return which data has to be provided to update the property. + * The integrated strains needs the gradients of the velocity. + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + + /** + * @brief Computes the volume fraction and grain orientation derivatives of all the grains of a mineral. + * + * @param cpo_index The location where the CPO data starts in the data array. + * @param data The data array containing the CPO data. + * @param mineral_i The mineral for which to compute the derivatives for. + * @param strain_rate_3d The 3D strain rate at the location where the derivative is requested. + * @param velocity_gradient_tensor The velocity gradient tensor at the location where the derivative is requested. + * @param position the location for which the derivative is requested. + * @param temperature The temperature at the location where the derivative is requested. + * @param pressure The pressure at the location where the derivative is requested. + * @param velocity The veloicty at the location where the derivative is requested. + * @param compositions The compositios at the location where the derivative is requested. + * @param strain_rate The strain-rate at the location where the derivative is requested. + * @param deviatoric_strain_rate The deviatoric strain-rate at the location where the derivative is requested. + * @param water_content The water content at the location where the derivative is requested. + */ + std::pair, std::vector>> + compute_derivatives(const unsigned int cpo_index, + const ArrayView &data, + const unsigned int mineral_i, + const SymmetricTensor<2,3> &strain_rate_3d, + const Tensor<2,3> &velocity_gradient_tensor, + const Point &position, + const double temperature, + const double pressure, + const Tensor<1,dim> &velocity, + const std::vector &compositions, + const SymmetricTensor<2,dim> &strain_rate, + const SymmetricTensor<2,dim> &deviatoric_strain_rate, + const double water_content) const; + + /** + * @brief Computes the CPO derivatives with the D-Rex 2004 algorithm. + * + * @param cpo_index The location where the CPO data starts in the data array. + * @param data The data array containing the CPO data. + * @param mineral_i The mineral for which to compute the derivatives for. + * @param strain_rate_3d The 3D strain rate + * @param velocity_gradient_tensor The velocity gradient tensor + * @param ref_resolved_shear_stress Represent one value per slip plane. + * The planes are ordered from weakest to strongest with relative values, + * where the inactive plane is infinity strong. So it is a measure of strength + * on each slip plane. + * @param prevent_nondimensionalization Prevent nondimensializing values internally. + * Only for unit testing purposes. + */ + std::pair, std::vector>> + compute_derivatives_drex_2004(const unsigned int cpo_index, + const ArrayView &data, + const unsigned int mineral_i, + const SymmetricTensor<2,3> &strain_rate_3d, + const Tensor<2,3> &velocity_gradient_tensor, + const std::array ref_resolved_shear_stress, + const bool prevent_nondimensionalization = false) const; + + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Return the number of grains per particle + */ + unsigned int + get_number_of_grains() const; + + /** + * Return the number of minerals per particle + */ + unsigned int + get_number_of_minerals() const; + + /** + * @brief Determines the deformation type from the deformation type selector. + * If the provided @p deformation_type_selector is a specific deformation type, + * the function will simply return the corresponding deformation type. However, + * if the @p deformation_type_selector is an algorithm to determine the current + * deformation type (e.g. based on measured lab data or analytical models), then + * the function computes the appropriate deformation type at the given conditions + * and returns the compute deformation type. + */ + DeformationType + determine_deformation_type(const DeformationTypeSelector deformation_type_selector, + const Point &position, + const double temperature, + const double pressure, + const Tensor<1,dim> &velocity, + const std::vector &compositions, + const SymmetricTensor<2,dim> &strain_rate, + const SymmetricTensor<2,dim> &deviatoric_strain_rate, + const double water_content) const; + + /** + * @brief Computes the deformation type given the stress and water content according to the + * table in Karato 2008. + */ + DeformationType + determine_deformation_type_karato_2008(const double stress, + const double water_content) const; + + /** + * @brief Computes the reference resolved shear stress (RRSS) based on the selected deformation type. + * + * The inactive plane should theoretically be infinitely strong, but this is nummerically not desirable, + * so an optional max_value can be set to indicate an inactive plane. + * + * It is currently designed to return the relative strength of the slip planes for olivine, which are are 4, + * but this could be generalized. + */ + std::array + reference_resolved_shear_stress_from_deformation_type(DeformationType deformation_type, + double max_value = 1e60) const; + + /** + * @brief Returns the value in the data array representing the deformation type. + * + * @param cpo_data_position The starting index/position of the cpo data in the particle data vector. + * @param data The particle data vector. + * @param mineral_i The mineral to get the value of the deformation type for. + */ + inline + DeformationType get_deformation_type(const unsigned int cpo_data_position, + const ArrayView &data, + const unsigned int mineral_i) const + { + return static_cast(data[cpo_data_position + 0 + mineral_i * (n_grains * 10 + 2)]); + } + + /** + * @brief Sets the value in the data array representing the deformation type. + * + * @param cpo_data_position The starting index/position of the cpo data in the particle data vector. + * @param data The particle data vector. + * @param mineral_i The mineral to set the value deformation type for. + * @param deformation_type The value of the deformation type to set. + */ + inline + void set_deformation_type(const unsigned int cpo_data_position, + const ArrayView &data, + const unsigned int mineral_i, + const DeformationType deformation_type) const + { + data[cpo_data_position + 0 + mineral_i * (n_grains * 10 + 2)] = static_cast(deformation_type); + } + + /** + * @brief Returns the value in the data array representing the volume fraction of a mineral. + * + * @param cpo_data_position The starting index/position of the cpo data in the particle data vector. + * @param data The particle data vector. + * @param mineral_i The mineral to get the value of the volume fraction of a mineral for. + */ + inline + double get_volume_fraction_mineral(const unsigned int cpo_data_position, + const ArrayView &data, + const unsigned int mineral_i) const + { + return data[cpo_data_position + 1 + mineral_i *(n_grains * 10 + 2)]; + } + + /** + * @brief Sets the value in the data array representing the volume fraction of a mineral. + * + * @param cpo_data_position The starting index/position of the cpo data in the particle data vector. + * @param data The particle data vector. + * @param mineral_i The mineral to set the value of the volume fraction of a mineral for. + * @param volume_fraction_mineral The value of the volume fraction of a mineral to set. + */ + inline + void set_volume_fraction_mineral(const unsigned int cpo_data_position, + const ArrayView &data, + const unsigned int mineral_i, + const double volume_fraction_mineral) const + { + data[cpo_data_position + 1 + mineral_i *(n_grains * 10 + 2)] = volume_fraction_mineral; + } + + /** + * @brief Returns the value in the data array representing the volume fraction of a grain. + * + * @param cpo_data_position The starting index/position of the cpo data in the particle data vector. + * @param data The particle data vector. + * @param mineral_i The mineral to get the value of the volume fraction of a grain for. + * @param grain_i The grain to get the value of the volume fraction of. + */ + inline + double get_volume_fractions_grains(const unsigned int cpo_data_position, + const ArrayView &data, + const unsigned int mineral_i, + const unsigned int grain_i) const + { + return data[cpo_data_position + 2 + grain_i * 10 + mineral_i * (n_grains * 10 + 2)]; + } + + /** + * @brief Sets the value in the data array representing the volume fraction of a grain. + * + * @param cpo_data_position The starting index/position of the cpo data in the particle data vector. + * @param data The particle data vector. + * @param mineral_i The mineral to set the value of the volume fraction of a grain for. + * @param grain_i The grain to set the value of the volume fraction of. + * @param volume_fractions_grains The value of the volume fraction of a grain to set. + */ + inline + void set_volume_fractions_grains(const unsigned int cpo_data_position, + const ArrayView &data, + const unsigned int mineral_i, + const unsigned int grain_i, + const double volume_fractions_grains) const + { + data[cpo_data_position + 2 + grain_i * 10 + mineral_i * (n_grains * 10 + 2)] = volume_fractions_grains; + } + + /** + * @brief Gets the rotation matrix for a grain in a mineral. + * + * @param cpo_data_position The starting index/position of the cpo data in the particle data vector. + * @param data The particle data vector. + * @param mineral_i The mineral to get the value of the rotation matrix of a grain for. + * @param grain_i The grain to get the value of the rotation matrix of. + * @return Tensor<2,3> The rotation matrix of a grain in a mineral + */ + inline + Tensor<2,3> get_rotation_matrix_grains(const unsigned int cpo_data_position, + const ArrayView &data, + const unsigned int mineral_i, + const unsigned int grain_i) const + { + Tensor<2,3> rotation_matrix; + for (unsigned int i = 0; i < Tensor<2,3>::n_independent_components ; ++i) + { + const dealii::TableIndices<2> index = Tensor<2,3>::unrolled_to_component_indices(i); + rotation_matrix[index] = data[cpo_data_position + 3 + grain_i * 10 + mineral_i * (n_grains * 10 + 2) + i]; + } + return rotation_matrix; + } + + /** + * @brief Sets the rotation matrix for a grain in a mineral. + * + * @param cpo_data_position The starting index/position of the cpo data in the particle data vector. + * @param data The particle data vector. + * @param mineral_i The mineral to set the value of the rotation matrix of a grain for. + * @param grain_i The grain to get the value of the rotation matrix of. + * @param rotation_matrix The rotation matrix to set for the grain in the mineral. + */ + inline + void set_rotation_matrix_grains(const unsigned int cpo_data_position, + const ArrayView &data, + const unsigned int mineral_i, + const unsigned int grain_i, + const Tensor<2,3> &rotation_matrix) const + { + for (unsigned int i = 0; i < Tensor<2,3>::n_independent_components ; ++i) + { + const dealii::TableIndices<2> index = Tensor<2,3>::unrolled_to_component_indices(i); + data[cpo_data_position + 3 + grain_i * 10 + mineral_i * (n_grains * 10 + 2) + i] = rotation_matrix[index]; + } + } + + + private: + /** + * Computes a random rotation matrix. + */ + void + compute_random_rotation_matrix(Tensor<2,3> &rotation_matrix) const; + + /** + * @brief Updates the volume fractions and rotation matrices with a Forward Euler scheme. + * + * Updates the volume fractions and rotation matrices with a Forward Euler scheme: + * $x_t = x_{t-1} + dt * x_{t-1} * \frac{dx_t}{dt}$. The function returns the sum of + * the new volume fractions. + * + * @param cpo_data_position The starting index/position of the cpo data in the particle data vector. + * @param data The particle data vector. + * @param mineral_i Which mineral to advect for. + * @param dt The time step used for the advection step + * @param derivatives A pair containing the derivatives for the volume fractions and + * orientations respectively. + * @return double The sum of all volume fractions. + */ + double + advect_forward_euler(const unsigned int cpo_data_position, + const ArrayView &data, + const unsigned int mineral_i, + const double dt, + const std::pair, std::vector>> &derivatives) const; + + /** + * @brief Updates the volume fractions and rotation matrices with a Backward Euler scheme. + * + * Updates the volume fractions and rotation matrices with a Backward Euler scheme: + * $x_t = x_{t-1} + dt * x_{t-1} * \frac{dx_t}{dt}$. The function returns the sum of + * the new volume fractions. + * + * @param cpo_data_position The starting index/position of the cpo data in the particle data vector. + * @param data The particle data vector. + * @param mineral_i Which mineral to advect for. + * @param dt The time step used for the advection step + * @param derivatives A pair containing the derivatives for the volume fractions and + * orientations respectively. + * @return double The sum of all volume fractions. + */ + double + advect_backward_euler(const unsigned int cpo_data_position, + const ArrayView &data, + const unsigned int mineral_i, + const double dt, + const std::pair, std::vector>> &derivatives) const; + + + /** + * Computes and returns the volume fraction and grain orientation derivatives such that + * the grains stay the same size and the orientations rotating passively with the particle. + * + * @param velocity_gradient_tensor is the velocity gradient tensor at the location of the particle. + */ + std::pair, std::vector>> + compute_derivatives_spin_tensor(const Tensor<2,3> &velocity_gradient_tensor) const; + + /** + * Random number generator used for initialization of particles + */ + mutable boost::mt19937 random_number_generator; + unsigned int random_number_seed; + + unsigned int n_grains; + + unsigned int n_minerals; + + /** + * The index of the water composition. + */ + unsigned int water_index; + + /** + * A vector containing the deformation type selectors provided by the user. + * Should be one of the following: "Olivine: Karato 2008", "Olivine: A-fabric", + * "Olivine: B-fabric", "Olivine: C-fabric", "Olivine: D-fabric", "Olivine: E-fabric", + * "Enstatite" or "Passive". + */ + std::vector deformation_type_selector; + + /** + * Store the volume fraction for each mineral. + */ + std::vector volume_fractions_minerals; + + /** + * Advection method for particle properties + */ + AdvectionMethod advection_method; + + /** + * What algorithm to use to compute the derivatives + */ + CPODerivativeAlgorithm cpo_derivative_algorithm; + + /** + * This value determines the tolerance used for the Backward Euler and + * Crank-Nicolson iterations. + */ + double property_advection_tolerance; + + /** + * This value determines the the maximum number of iterations used for the + * Backward Euler and Crank-Nicolson iterations. + */ + unsigned int property_advection_max_iterations; + + /** + * @name D-Rex variables + */ + /** @{ */ + /** + * Stress exponent + */ + double stress_exponent; + + /** + * efficiency of nucleation parameter. + * lambda_m in equation 8 of Kaminski et al. (2004, Geophys. J. Int) + */ + double nucleation_efficiency; + + /** + * An exponent described in equation 10 of Kaminski and Ribe (2001, EPSL) + */ + double exponent_p; + + /** + * The Dimensionless Grain Boundary Sliding (GBS) threshold. + * This is a grain size threshold below which grain deform by GBS and + * become strain-free grains. + */ + double threshold_GBS; + + /** + * Dimensionless grain boundary mobility as described by equation 14 + * in Kaminski and Ribe (2001, EPSL). + */ + double mobility; + + /** + * Sets which type of initial grain model is used to create the gain sizes and orientations + */ + CPOInitialGrainsModel initial_grains_model; + + /** @} */ + + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/elastic_stress.h.bak b/include/aspect/particle/property/elastic_stress.h.bak new file mode 100644 index 00000000000..d4d70d7da7f --- /dev/null +++ b/include/aspect/particle/property/elastic_stress.h.bak @@ -0,0 +1,104 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_elastic_stress_h +#define _aspect_particle_property_elastic_stress_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * A class that calculates the viscoelastic stress a particle + * has accumulated through time. + * The implementation of this property is equivalent to the implementation + * for compositional fields that is described in the viscoelastic material + * model and elastic stress rheology module. + * + * @ingroup ParticleProperties + */ + template + class ElasticStress : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + ElasticStress (); + + void initialize () override; + + /** + * @copydoc aspect::Particle::Property::Interface::initialize_one_particle_property() + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::update_particle_property() + */ + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::need_update() + */ + UpdateTimeFlags + need_update () const override; + + /** + * @copydoc aspect::Particle::Property::Interface::get_needed_update_flags() + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * @copydoc aspect::Particle::Property::Interface::get_property_information() + */ + std::vector> + get_property_information() const override; + + private: + /** + * Objects that are used to compute the particle property. Since the + * object is expensive to create and is needed often it is kept as a + * member variable. Because it is changed inside a const member function + * (update_particle_property) it has to be mutable, but since it is + * only used inside that function and always set before being used + * that is not a problem. This implementation is not thread safe, + * but it is currently not used in a threaded context. + */ + mutable MaterialModel::MaterialModelInputs material_inputs; + mutable MaterialModel::MaterialModelOutputs material_outputs; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/elastic_tensor_decomposition.h.bak b/include/aspect/particle/property/elastic_tensor_decomposition.h.bak new file mode 100644 index 00000000000..76ec5a314e0 --- /dev/null +++ b/include/aspect/particle/property/elastic_tensor_decomposition.h.bak @@ -0,0 +1,274 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + This file is part of ASPECT. + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + ASPECT 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 General Public License for more details. + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_elastic_tensor_decomposition_h +#define _aspect_particle_property_elastic_tensor_decomposition_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + namespace Utilities + { + /** + * Return an even permutation based on an index. This is an internal + * utilities function, also used by the unit tester. + */ + std::array + indexed_even_permutation(const unsigned int index); + + /** + * Computes the Voigt stiffness tensor from the elastic tensor. + * The Voigt stiffness tensor (see Browaeys and Chevrot, 2004) + * defines the stress needed to cause an isotropic strain in the + * material. + */ + SymmetricTensor<2,3> + compute_voigt_stiffness_tensor(const SymmetricTensor<2,6> &elastic_tensor); + + /** + * Computes the dilatation stiffness tensor from the elastic tensor + * The dilatational stiffness tensor (see Browaeys and Chevrot, 2004) + * defines the stress to cause isotropic dilatation in the material. + */ + SymmetricTensor<2,3> + compute_dilatation_stiffness_tensor(const SymmetricTensor<2,6> &elastic_tensor); + + /** + * Computes the Symmetry Cartesian Coordinate System (SCCS). + * + * This is based on Browaeys and Chevrot (2004), GJI (doi: 10.1111/j.1365-246X.2004.024115.x), + * which states at the end of paragraph 3.3 that "... an important property of an orthogonal projection + * is that the distance between a vector $X$ and its orthogonal projection $X_H = p(X)$ on a given + * subspace is minimum. These two features ensure that the decomposition is optimal once a 3-D Cartesian + * coordinate system is chosen.". The other property they talk about is that "The space of elastic + * vectors has a finite dimension [...], i.e. using a different norm from eq. 2.3 will change distances + * but not the resulting decomposition.". + * + * With the three SCCS directions, the elastic tensor can be decomposed into the different + * symmetries in those three SCCS direction, that is, triclinic, monoclinic, orthorhombic, + * tetragonal, hexagonal, and isotropic (Browaeys & Chevrot, 2004). + * + * The dilatation_stiffness_tensor defines the stress to cause isotropic dilatation in the material. + * The voigt_stiffness_tensor defines the stress needed to cause an isotropic strain in the material + */ + Tensor<2,3> compute_unpermutated_SCCS(const SymmetricTensor<2,3> &dilatation_stiffness_tensor, + const SymmetricTensor<2,3> &voigt_stiffness_tensor); + + /** + * Uses the Symmetry Cartesian Coordinate System (SCCS) to try the different permutations to + * determine what is the best projection. + * This is based on Browaeys and Chevrot (2004), GJI (doi: 10.1111/j.1365-246X.2004.024115.x), + * which states at the end of paragraph 3.3 that "... an important property of an orthogonal projection + * is that the distance between a vector $X$ and its orthogonal projection $X_H = p(X)$ on a given + * subspace is minimum. These two features ensure that the decomposition is optimal once a 3-D Cartesian + * coordinate system is chosen.". The other property they talk about is that "The space of elastic + * vectors has a finite dimension [...], i.e. using a different norm from eq. 2.3 will change distances + * but not the resulting decomposition.". + */ + std::array,7> + compute_elastic_tensor_SCCS_decompositions( + const Tensor<2,3> &unpermutated_SCCS, + const SymmetricTensor<2,6> &elastic_matrix); + + + /** + * The tensors below can be used to project matrices to different symmetries. + * See Browaeys and Chevrot, 2004. + */ + static const SymmetricTensor<2,21> projection_matrix_triclinic_to_monoclinic( + Tensor<2,21>( + { + {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, + }) + ); + static const SymmetricTensor<2,9> projection_matrix_monoclinic_to_orthorhombic( + Tensor<2,9>( + { + {1,0,0,0,0,0,0,0,0}, + {0,1,0,0,0,0,0,0,0}, + {0,0,1,0,0,0,0,0,0}, + {0,0,0,1,0,0,0,0,0}, + {0,0,0,0,1,0,0,0,0}, + {0,0,0,0,0,1,0,0,0}, + {0,0,0,0,0,0,1,0,0}, + {0,0,0,0,0,0,0,1,0}, + {0,0,0,0,0,0,0,0,1} + }) + ); + static const SymmetricTensor<2,9> projection_matrix_orthorhombic_to_tetragonal( + Tensor<2,9>( + { + {0.5,0.5,0.0,0.0,0.0,0.0,0.0,0.0,0.0}, + {0.5,0.5,0.0,0.0,0.0,0.0,0.0,0.0,0.0}, + {0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.5,0.5,0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.5,0.5,0.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0}, + {0.0,0.0,0.0,0.0,0.0,0.0,0.5,0.5,0.0}, + {0.0,0.0,0.0,0.0,0.0,0.0,0.5,0.5,0.0}, + {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0} + }) + ); + static const SymmetricTensor<2,9> projection_matrix_tetragonal_to_hexagonal( + Tensor<2,9>( + { + {3./8. , 3./8. , 0.0, 0.0, 0.0, 1./(4.*sqrt(2.)) , 0.0, 0.0, 1./4. }, + {3./8. , 3./8. , 0.0, 0.0, 0.0, 1./(4.*sqrt(2.)) , 0.0, 0.0, 1./4. }, + {0.0 , 0.0 , 1.0, 0.0, 0.0, 0.0 , 0.0, 0.0, 0.0 }, + {0.0 , 0.0 , 0.0, 0.5, 0.5, 0.0 , 0.0, 0.0, 0.0 }, + {0.0 , 0.0 , 0.0, 0.5, 0.5, 0.0 , 0.0, 0.0, 0.0 }, + {1./(4.*sqrt(2.)), 1./(4.*sqrt(2.)), 0.0, 0.0, 0.0, 3./4. , 0.0, 0.0, -1./(2.*sqrt(2.))}, + {0.0 , 0.0 , 0.0, 0.0, 0.0, 0.0 , 0.5, 0.5, 0.0 }, + {0.0 , 0.0 , 0.0, 0.0, 0.0, 0.0 , 0.5, 0.5, 0.0 }, + {1./4. , 1./4. , 0.0, 0.0, 0.0, -1./(2.*sqrt(2.)) , 0.0, 0.0, 0.5 } + }) + ); + static const SymmetricTensor<2,9> projection_matrix_hexagonal_to_isotropic( + Tensor<2,9>( + { + {3./15. , 3./15. , 3./15. , sqrt(2.)/15. , sqrt(2.)/15. , sqrt(2.)/15. , 2./15. , 2./15. , 2./15. }, + {3./15. , 3./15. , 3./15. , sqrt(2.)/15. , sqrt(2.)/15. , sqrt(2.)/15. , 2./15. , 2./15. , 2./15. }, + {3./15. , 3./15. , 3./15. , sqrt(2.)/15. , sqrt(2.)/15. , sqrt(2.)/15. , 2./15. , 2./15. , 2./15. }, + {sqrt(2.)/15., sqrt(2.)/15., sqrt(2.)/15., 4./15. , 4./15. , 4./15. , -sqrt(2.)/15., -sqrt(2.)/15., -sqrt(2.)/15. }, + {sqrt(2.)/15., sqrt(2.)/15., sqrt(2.)/15., 4./15. , 4./15. , 4./15. , -sqrt(2.)/15., -sqrt(2.)/15., -sqrt(2.)/15. }, + {sqrt(2.)/15., sqrt(2.)/15., sqrt(2.)/15., 4./15. , 4./15. , 4./15. , -sqrt(2.)/15., -sqrt(2.)/15., -sqrt(2.)/15. }, + {2./15. , 2./15. , 2./15. , -sqrt(2.)/15., -sqrt(2.)/15., -sqrt(2.)/15., 1./5. , 1./5. , 1./5. }, + {2./15. , 2./15. , 2./15. , -sqrt(2.)/15., -sqrt(2.)/15., -sqrt(2.)/15., 1./5. , 1./5. , 1./5. }, + {2./15. , 2./15. , 2./15. , -sqrt(2.)/15., -sqrt(2.)/15., -sqrt(2.)/15., 1./5. , 1./5. , 1./5. } + }) + ); + } + + /** + * Computes several properties of a elastic tensor stored on a particle. + * These include the eigenvectors and conversions between different forms of 4th order tensors. + * + * @ingroup ParticleProperties + */ + template + class ElasticTensorDecomposition : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor + */ + ElasticTensorDecomposition() = default; + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run. + */ + void + initialize () override; + + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * Update function. This function is called every time an update is + * request by need_update() for every particle for every property. + * It is obvious that + * this function is called a lot, so its code should be efficient. + * The interface provides a default implementation that does nothing, + * therefore derived plugins that do not require an update do not + * need to implement this function. + * + * @param [in] data_position An unsigned integer that denotes which + * component of the particle property vector is associated with the + * current property. For properties that own several components it + * denotes the first component of this property, all other components + * fill consecutive entries in the @p particle_properties vector. + * + * @param [in] solution The values of the solution variables at the + * current particle position. + * + * @param [in] gradients The gradients of the solution variables at + * the current particle position. + * + * @param [in,out] particle The particle that is updated within + * the call of this function. The particle location can be accessed + * using particle->get_location() and its properties using + * particle->get_properties(). + */ + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * This function tells the particle manager that + * we need to update particle properties. + */ + UpdateTimeFlags + need_update () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + + private: + unsigned int cpo_elastic_tensor_data_position; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/function.h.bak b/include/aspect/particle/property/function.h.bak new file mode 100644 index 00000000000..f45d52de16c --- /dev/null +++ b/include/aspect/particle/property/function.h.bak @@ -0,0 +1,101 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_function_h +#define _aspect_particle_property_function_h + +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * A class that initializes particle properties based on a + * functional description provided in the input file. + * + * @ingroup ParticleProperties + */ + template + class Function : public Interface + { + public: + Function(); + + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A function object representing the particle property. + */ + std::unique_ptr> function; + + /** + * A private variable that stores the number of particle property + * function components. + */ + unsigned int n_components; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/grain_size.h.bak b/include/aspect/particle/property/grain_size.h.bak new file mode 100644 index 00000000000..bdfa42aac07 --- /dev/null +++ b/include/aspect/particle/property/grain_size.h.bak @@ -0,0 +1,123 @@ +/* + Copyright (C) 2022 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_grain_size_h +#define _aspect_particle_property_grain_size_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * A class that calculates the evolving grain size of a particle. + * The implementation of this property is equivalent to the implementation + * for compositional fields that is described in the grain_size material + * model. + * + * @ingroup ParticleProperties + */ + template + class GrainSize : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + GrainSize (); + + /** + * Initialize variables that stay constant + * during a model. + */ + void initialize () override; + + /** + * @copydoc aspect::Particle::Property::Interface::initialize_one_particle_property() + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::update_particle_properties() + */ + void + update_particle_properties (const unsigned int data_position, + const std::vector> &solution, + const std::vector>> &gradients, + typename ParticleHandler::particle_iterator_range &particles) const override; + + /** + * Returns an enum, which determines how this particle property is + * initialized for particles that are created later than the initial + * particle generation. For this property the value of + * generated particles is interpolated from existing particles, unless + * the particle is in a boundary cell that has a Dirichlet boundary + * condition, in which case it uses the boundary condition value. + */ + InitializationModeForLateParticles + late_initialization_mode () const override; + + /** + * @copydoc aspect::Particle::Property::Interface::need_update() + */ + UpdateTimeFlags + need_update () const override; + + /** + * @copydoc aspect::Particle::Property::Interface::get_needed_update_flags() + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * @copydoc aspect::Particle::Property::Interface::get_property_information() + */ + std::vector> + get_property_information() const override; + + private: + /** + * Objects that are used to compute the particle property. Since the + * object is expensive to create and is needed often it is kept as a + * member variable. Because it is changed inside a const member function + * (update_particle_property) it has to be mutable, but since it is + * only used inside that function and always set before being used + * that is not a problem. This implementation is not thread safe, + * but it is currently not used in a threaded context. + */ + mutable MaterialModel::MaterialModelInputs material_inputs; + mutable MaterialModel::MaterialModelOutputs material_outputs; + + /** + * The index of the compositional field that stores the grain size. + */ + unsigned int grain_size_index; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/initial_composition.h.bak b/include/aspect/particle/property/initial_composition.h.bak new file mode 100644 index 00000000000..e59b2c67ca1 --- /dev/null +++ b/include/aspect/particle/property/initial_composition.h.bak @@ -0,0 +1,83 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_initial_composition_h +#define _aspect_particle_property_initial_composition_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * A class that initializes particle properties based on a + * functional description provided in the input file. + * + * @ingroup ParticleProperties + */ + template + class InitialComposition : public Interface, public SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * Returns an enum, which determines how this particle property is + * initialized for particles that are created later than the initial + * particle generation. For this property the value of + * generated particles is interpolated from existing particles, unless + * the particle is in a boundary cell that has a Dirichlet boundary + * condition, in which case it uses the boundary condition value. + */ + InitializationModeForLateParticles + late_initialization_mode () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/initial_position.h.bak b/include/aspect/particle/property/initial_position.h.bak new file mode 100644 index 00000000000..d9d86d9862b --- /dev/null +++ b/include/aspect/particle/property/initial_position.h.bak @@ -0,0 +1,71 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_initial_position_h +#define _aspect_particle_property_initial_position_h + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * A class that initializes particle properties based on the + * initial position of the particles. + * + * @ingroup ParticleProperties + */ + template + class InitialPosition : public Interface + { + public: + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/integrated_strain.h.bak b/include/aspect/particle/property/integrated_strain.h.bak new file mode 100644 index 00000000000..e773dd9089f --- /dev/null +++ b/include/aspect/particle/property/integrated_strain.h.bak @@ -0,0 +1,99 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_integrated_strain_h +#define _aspect_particle_property_integrated_strain_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * A class that integrates the finite strain that a particle has + * experienced. + * The implementation of this property is equivalent to the implementation + * for compositional fields that is described in the cookbook + * finite_strain cookbooks/finite_strain/finite_strain.cc. + * + * @ingroup ParticleProperties + */ + template + class IntegratedStrain : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::update_particle_property() + */ + virtual + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * This implementation tells the particle manager that + * we need to update particle properties every time step. + */ + UpdateTimeFlags + need_update () const override; + + /** + * Return which data has to be provided to update the property. + * The integrated strains needs the gradients of the velocity. + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/integrated_strain_invariant.h.bak b/include/aspect/particle/property/integrated_strain_invariant.h.bak new file mode 100644 index 00000000000..5ef0c8e78d9 --- /dev/null +++ b/include/aspect/particle/property/integrated_strain_invariant.h.bak @@ -0,0 +1,98 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_integrated_strain_invariant_h +#define _aspect_particle_property_integrated_strain_invariant_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * A class that calculates the finite strain invariant a particle has + * experienced. The implementation of this property is equivalent to the + * implementation for compositional fields that is located in the plugin + * benchmarks/buiter_et_al_2008_jgr/plugin/finite_strain_invariant.cc. + * + * @ingroup ParticleProperties + */ + template + class IntegratedStrainInvariant : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::update_particle_property() + */ + virtual + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * This implementation tells the particle manager that + * we need to update particle properties every time step. + */ + UpdateTimeFlags + need_update () const override; + + /** + * Return which data has to be provided to update the property. + * The integrated strains needs the gradients of the velocity. + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/interface.h.bak b/include/aspect/particle/property/interface.h.bak new file mode 100644 index 00000000000..9d943da535a --- /dev/null +++ b/include/aspect/particle/property/interface.h.bak @@ -0,0 +1,816 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_interface_h +#define _aspect_particle_property_interface_h + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + using namespace dealii::Particles; + + /** + * This class is used to store all the necessary information to translate + * between the data structure of the particle properties (a flat vector of + * doubles) and the semantic meaning of these properties. It contains + * information about the three layers of particle property information: + * + * By 'property plugins' we mean each separate class that is derived from + * aspect::Particle::Property::Interface, and that is selected in + * the input file. This means in any model there are as many property + * plugins as entries in the 'List of particle properties' input parameter. + * + * Each plugin can create one or more 'property fields'. Property fields + * are interpreted as distinctly named particle properties. Most plugins + * contain only one field, but some group distinctly named properties + * into groups, such as the 'InitialComposition' plugin, which creates + * one property field per compositional field and names the property + * fields according to the compositional field names. When writing particle + * data to output files each 'property field' will be written into a + * separate output field. + * + * Last each field can contain several 'property components' + * if it represents a vector or tensor property. These components can + * not be named individually, but it is still important to be able to + * know how many components belong to a particular field. + * + * Information that is often required by other algorithms is for example + * the number of components (= number of doubles in the property vector) + * of a particle field or plugin, and its position within the particle + * property vector. All of this information might be required within + * loops over all fields, or for a specific field either identified by + * its index, or by its name. + * + * @ingroup ParticleProperties + */ + class ParticlePropertyInformation + { + public: + /** + * Empty default constructor. + */ + ParticlePropertyInformation(); + + /** + * Constructor. Initialize the various arrays of this structure with the + * given property information collected from the individual plugins. + * + * @p property_information A vector that contains one vector per + * property plugin. Each of these vectors contains one or more pairs + * that represent a property field name and the number of components + * for this field. The input argument can be constructed by + * concatenating the output of the + * Particle::Property::Interface::get_property_information() + * functions of all property plugins. + */ + ParticlePropertyInformation(const std::vector>> &property_information); + + /** + * Checks if the particle property specified by @p name exists + * in this model. + */ + bool + fieldname_exists(const std::string &name) const; + + /** + * Get the field index of the particle property specified by @p name. + */ + unsigned int + get_field_index_by_name(const std::string &name) const; + + /** + * Get the field index of the particle property specified by @p name. + */ + std::string + get_field_name_by_index(const unsigned int field_index) const; + + /** + * Get the data position of the first component of the particle + * property specified by @p name in the property vector of a particle. + */ + unsigned int + get_position_by_field_name(const std::string &name) const; + + /** + * Get the number of components of the particle property specified + * by @p name. + */ + unsigned int + get_components_by_field_name(const std::string &name) const; + + /** + * Get the data position of the first component of the particle + * property specified by @p field_index in the property vector + * of a particle. + */ + unsigned int + get_position_by_field_index(const unsigned int field_index) const; + + /** + * Get the number of components of the particle property specified + * by @p field_index. + */ + unsigned int + get_components_by_field_index(const unsigned int field_index) const; + + /** + * Get the data position of the first component of the particle + * property specified by @p plugin_index in the property vector + * of a particle. + */ + unsigned int + get_position_by_plugin_index(const unsigned int plugin_index) const; + + /** + * Get the number of components of the particle property specified + * by @p plugin_index. + */ + unsigned int + get_components_by_plugin_index(const unsigned int plugin_index) const; + + /** + * Get the number of fields of the particle property specified + * by @p plugin_index. + */ + unsigned int + get_fields_by_plugin_index(const unsigned int plugin_index) const; + + + /** + * Return the number of active particle property plugins. + */ + unsigned int + n_plugins() const; + + /** + * Return the number of active particle property fields. + */ + unsigned int + n_fields() const; + + /** + * Return the number of active particle property components. + */ + unsigned int + n_components() const; + + private: + /** + * A vector of all property field names. + */ + std::vector field_names; + + /** + * A vector containing the number of components per property field. + */ + std::vector components_per_field; + + /** + * A vector containing the position index of the first data component + * of each field in the property vector of every particle. + */ + std::vector position_per_field; + + /** + * A vector containing the number of property fields per property + * plugin. + */ + std::vector fields_per_plugin; + + /** + * A vector containing the number of components per property plugin. + */ + std::vector components_per_plugin; + + /** + * A vector containing the position index of the first data component + * of each plugin in the property vector of every particle. + */ + std::vector position_per_plugin; + + /** + * The number of doubles needed to represent a particle's + * additional properties. + */ + unsigned int number_of_components; + + /** + * The number of distinctly named particle property fields. + */ + unsigned int number_of_fields; + + /** + * The number of active particle property plugins. + */ + unsigned int number_of_plugins; + }; + + enum UpdateTimeFlags + { + /** + * Never update the initially set properties. This is the default + * behavior, which is sufficient for particle properties that are + * set at the beginning of the model and constant for the whole + * simulation time. + */ + update_never, + /** + * Update the particle properties before every output. This is + * sufficient for all passive particle properties that depend on the + * current solution, like the current velocity or pressure. + */ + update_output_step, + /** + * Update the particle properties every nonlinear iteration. This is only necessary + * if the properties at the output time depend on some sort of time + * integration of solution properties or time varying particle + * properties are used while solving the model problem. + */ + update_time_step + }; + + /** + * This enum controls how to initialize the properties of particles that + * have been added later than the initial particle creation, e.g. to + * improve the load balance or to prevent empty cells. + */ + enum InitializationModeForLateParticles + { + /** + * Initialize the particle as if it were created at the beginning of + * the model at its current position with the current solution. + */ + initialize, + /** + * Use the interpolated properties of the surrounding particles as + * calculated by the selected interpolator. + */ + interpolate, + /** + * Use the interpolated properties of the surrounding particles as + * calculated by the selected interpolator except for particles in + * boundary cells. These will use the boundary condition of the + * compositional fields instead. This mode only makes sense for + * properties that are associated with compositional fields through + * the parameter 'Compositional fields/Mapped particle properties'. + */ + interpolate_respect_boundary, + /** + * Initialize the particle properties to zero. If the property is + * updated over time its update function is called as usual, if not + * the property will remain zero throughout the model run. + */ + initialize_to_zero + }; + + /** + * Interface provides an example of how to extend the Particle class to + * include related particle data. This allows users to attach + * scalars/vectors/tensors/etc to particles and ensure they are + * transmitted correctly over MPI and written to output files. + * + * @ingroup ParticleProperties + */ + template + class Interface : public ParticleInterfaceBase + { + public: + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + virtual + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const; + + /** + * Update function. This function is called every time an update is + * requested by need_update() for every cell for every property. + * It is expected to update the properties of all particles in the + * given range @p particles, which are all in one cell. + * It is obvious that + * this function is called a lot, so its code should be efficient. + * The interface provides a default implementation that does nothing, + * therefore derived plugins that do not require an update do not + * need to implement this function. + * + * @param [in] data_position An unsigned integer that denotes which + * component of each particle property vector is associated with the + * current property. For properties that own several components it + * denotes the first component of this property, all other components + * fill consecutive entries in the properties vector. + * + * @param [in] solution A vector of values of the solution variables + * at the given particle positions. + * + * @param [in] gradients A vector of gradients of the solution + * variables at the given particle positions. + * + * @param [in,out] particles The particles that are to be updated + * within this function. + */ + virtual + void + update_particle_properties (const unsigned int data_position, + const std::vector> &solution, + const std::vector>> &gradients, + typename ParticleHandler::particle_iterator_range &particles) const; + + /** + * Update function. This function is called every time an update is + * request by need_update() for every particle for every property. + * It is obvious that + * this function is called a lot, so its code should be efficient. + * The interface provides a default implementation that does nothing, + * therefore derived plugins that do not require an update do not + * need to implement this function. + * + * @param [in] data_position An unsigned integer that denotes which + * component of the particle property vector is associated with the + * current property. For properties that own several components it + * denotes the first component of this property, all other components + * fill consecutive entries in the @p particle_properties vector. + * + * @param [in] solution The values of the solution variables at the + * current particle position. + * + * @param [in] gradients The gradients of the solution variables at + * the current particle position. + * + * @param [in,out] particle The particle that is updated within + * the call of this function. The particle location can be accessed + * using particle->get_location() and its properties using + * particle->get_properties(). + * + * @deprecated Use update_particle_properties() instead. + */ + DEAL_II_DEPRECATED + virtual + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const; + + + /** + * Returns an enum, which determines at what times particle properties + * are updated. The default implementation returns update_never, which + * signals that particle properties should never be updated. + * See the documentation of UpdateTimeFlags for a list of possible + * values and examples for their use. Every + * plugin that implements this function should return the value + * appropriate for its purpose, unless it does not need any update, + * which is the default. This option saves considerable computation + * time in cases, when no plugin needs to update particle properties + * over time. + */ + virtual + UpdateTimeFlags + need_update () const; + + /** + * Return which data has to be provided to update all properties. + * Note that particle properties can only ask for update_default + * (no data), update_values (solution values), and update_gradients + * (solution gradients). All other update flags will have no effect. + * + * @return The necessary update flags for this particle property. + */ + virtual + UpdateFlags + get_needed_update_flags () const; + + /** + * Returns an enum, which determines how this particle property is + * initialized for particles that are created later than the initial + * particle generation, e.g. to balance the particle load or prevent + * empty cells. The default implementation returns + * interpolate, which will use the particle interpolator to + * set the new particle properties to a value that is interpolated + * from the other particles in the cell. + * See the documentation of InitializationModeForLateParticles for a + * list of possible values and examples for their use. Every + * plugin that implements this function should return the value + * appropriate for its purpose, unless it wants to use the default + * value. + */ + virtual + InitializationModeForLateParticles + late_initialization_mode () const; + + /** + * Set up the information about the names and number of components + * this property requires. Derived classes need to implement this + * function. + * + * The purpose of this function is to return a vector of pairs of a + * property name and the number of components associated with this + * name (e.g. 1 for scalar properties, + * n for n-dimensional vectors). + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + virtual + std::vector> + get_property_information() const = 0; + }; + + /** + * A particle property that provides storage space for + * the properties that particle integrators need to + * store. This is an internal property that is not + * intended for use outside of the particle integrators + * and that will not be written to output files. + * + * @ingroup ParticleProperties + */ + template + class IntegratorProperties : public Interface + { + public: + /** + * Initialization function. Since these properties are set and used + * by the integrator this function only resizes them to the correct + * size, but does not need to do any initialization. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * Set up the information about the names and number of components + * this property requires. This depends on the chosen integration scheme. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + + /** + * Read the parameters this class needs to determine which integrator is used, + * and therefore how many properties to reserve. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The number of integrator properties to store. This variable is initialized in + * parse_parameters(). + */ + unsigned int n_integrator_properties; + }; + + + + /** + * Manager class of properties - This class sets the data of the + * collection of particles and updates it over time if requested by the + * user selected properties. + */ + template + class Manager : public Plugins::ManagerBase>, public SimulatorAccess + { + public: + /** + * Empty constructor for Manager + */ + Manager (); + + /** + * Destructor for Manager + */ + ~Manager () override; + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run. + */ + void + initialize () override; + + /** + * Update function. This function is called once at the + * beginning of each timestep. + */ + void + update () override; + + /** + * Initialization function for particle properties. This function is + * called once for each of the particles of a particle + * collection after it was created. + */ + void + initialize_one_particle (typename ParticleHandler::particle_iterator &particle) const; + + /** + * Initialization function for particle properties. This function is + * called once for each of the particles of a particle + * collection that were created later than the initial particle + * generation. + */ + std::vector + initialize_late_particle (const Point &particle_location, + const ParticleHandler &particle_handler, + const Interpolator::Interface &interpolator, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell = typename parallel::distributed::Triangulation::active_cell_iterator()) const; + + /** + * Update function for particle properties. This function is + * called once every time step for every cell. + * + * @param particles The particles that are to be updated within + * this function. + * @param solution The values of the solution variables at the + * given particle positions. + * @param gradients The gradients of the solution variables at + * the given particle positions. + */ + void + update_particles (typename ParticleHandler::particle_iterator_range &particles, + const std::vector> &solution, + const std::vector>> &gradients) const; + + /** + * Returns an enum, which denotes at what time this class needs to + * update particle properties. The result of this class is a + * combination of the need_update() functions of all individual + * properties that are selected. More precise, it will choose to + * update the particle properties as often as the plugin that needs the + * most frequent update option requires. This saves considerable + * computation time, e.g. in cases when no plugin needs to update particle + * properties over time, because the solution does not need to be + * evaluated in this case. + */ + UpdateTimeFlags + need_update () const; + + /** + * Return which data has to be provided to update all properties. + * Note that particle properties can only ask for update_default + * (no data), update_values (solution values), and update_gradients + * (solution gradients). All other update flags will have no effect. + */ + UpdateFlags + get_needed_update_flags () const; + + /** + * Checks if the particle plugin specified by @p name exists + * in this model. + */ + bool + plugin_name_exists(const std::string &name) const; + + /** + * Checks if the particle property plugin specified by @p first + * is executed before another particle property plugin specified + * by @p second. + * + * Throws an assert when one of the plugin names does not + * exist. You can use the function plugin_name_exists() to + * check in advance whether a plugin exists + */ + bool + check_plugin_order(const std::string &first, const std::string &second) const; + + /** + * Get the plugin index of the particle plugin specified by @p name. + */ + unsigned int get_plugin_index_by_name(const std::string &name) const; + + /** + * Go through the list of all particle properties that have been selected + * in the input file (and are consequently currently active) and return + * true if one of them has the desired type specified by the template + * argument. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,ParticlePropertyType>::value>> + bool + has_matching_property () const; + + /** + * Go through the list of all particle properties that have been selected + * in the input file (and are consequently currently active) and see + * if one of them has the type specified by the template + * argument or can be cast to that type. If so, return a reference + * to it. If no property is active that matches the given type, + * throw an exception. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,ParticlePropertyType>::value>> + const ParticlePropertyType & + get_matching_property () const; + + /** + * Get the number of components required to represent this particle's + * properties. + * + * @return Number of doubles required to represent this particle's + * additional properties. + */ + unsigned int + get_n_property_components () const; + + /** + * Get the size in number of bytes required to represent this + * particle's properties for communication. This is essentially the + * space needed for the property components plus the space for the + * particle position and the space needed for its ID. + * + * @return Number of bytes required to represent this particle. + */ + std::size_t + get_particle_size () const; + + /** + * Get the names and number of components of particle properties. + * + * @return A vector of pairs for each property name and the + * corresponding number of components attached to particles. + */ + const ParticlePropertyInformation & + get_data_info() const; + + /** + * Get the position of the property specified by name in the property + * vector of the particles. + * + * @deprecated This function will be replaced by + * ParticlePropertyInformation::get_position_by_field_name(name) + */ + DEAL_II_DEPRECATED + unsigned int + get_property_component_by_name(const std::string &name) const; + + /** + * A function that is used to register particle property + * objects in such a way that the Manager can deal with all of them + * without having to know them by name. This allows the files in which + * individual properties are implemented to register these + * properties, rather than also having to modify the Manager class + * by adding the new properties class. + * + * @param name The name under which this particle property + * is to be called in parameter files. + * @param description A text description of what this particle property + * does and that will be listed in the documentation of the + * parameter file. + * @param declare_parameters_function A pointer to a function that + * declares the parameters for this property. + * @param factory_function A pointer to a function that creates such a + * property object and returns a pointer to it. + */ + static + void + register_particle_property (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * @brief Set the particle world index for all particle properties + * + * @param particle_world_index The index of the particle world. + */ + void set_particle_world_index(unsigned int particle_world_index); + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + private: + /** + * Stores the names of the plugins which are present + * in the order they are executed. + */ + std::vector plugin_names; + + /** + * A class that stores all information about the particle properties, + * their association with property plugins and their storage pattern. + */ + ParticlePropertyInformation property_information; + }; + + /* -------------------------- inline and template functions ---------------------- */ + + + template + template + inline + bool + Manager::has_matching_property () const + { + return this->template has_matching_plugin_object(); + } + + + template + template + inline + const ParticlePropertyType & + Manager::get_matching_property () const + { + return this->template get_matching_plugin_object(); + } + + + /** + * Given a class name, a name, and a description for the parameter file for + * a particle property, register it with the aspect::Particle:: class. + * + * @ingroup Particle + */ +#define ASPECT_REGISTER_PARTICLE_PROPERTY(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_PARTICLE_PROPERTY_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::Particle::Property::Manager<2>::register_particle_property, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::Particle::Property::Manager<3>::register_particle_property, \ + name, description); \ + } + + } + } +} + +#endif diff --git a/include/aspect/particle/property/melt_particle.h.bak b/include/aspect/particle/property/melt_particle.h.bak new file mode 100644 index 00000000000..52a8ce8efbf --- /dev/null +++ b/include/aspect/particle/property/melt_particle.h.bak @@ -0,0 +1,115 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_melt_particle_h +#define _aspect_particle_property_melt_particle_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * Implementation of a plugin in which the particle + * property is defined as presence of melt above the + * melt transport threshold. This property is set + * to 0 if melt is not present and set to 1 if melt + * is present. + * + * @ingroup ParticleProperties + */ + template + class MeltParticle : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::update_particle_property() + */ + virtual + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * This implementation tells the particle manager that + * we need to update particle properties over time. + */ + UpdateTimeFlags + need_update () const override; + + /** + * Return which data has to be provided to update the property. + * The pressure and temperature need the values of their variables. + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + double threshold_for_melt_presence; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/pT_path.h.bak b/include/aspect/particle/property/pT_path.h.bak new file mode 100644 index 00000000000..6c6331a883a --- /dev/null +++ b/include/aspect/particle/property/pT_path.h.bak @@ -0,0 +1,119 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_pT_path_h +#define _aspect_particle_property_pT_path_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * Implementation of a plugin in which the particle + * property is defined as the current pressure and + * temperature at this position. This can be used + * to generate pressure-temperature paths of + * material points over time. + * + * @ingroup ParticleProperties + */ + template + class PTPath : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run. + * + * This specific function makes sure that the objects that describe + * initial conditions remain available throughout the run of the + * program. + */ + void + initialize () override; + + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::update_particle_property() + */ + virtual + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * This implementation tells the particle manager that + * we need to update particle properties over time. + */ + UpdateTimeFlags + need_update () const override; + + /** + * Return which data has to be provided to update the property. + * The pressure and temperature need the values of their variables. + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + + private: + /** + * A shared pointer to the initial temperature object + * that ensures that the current object can continue + * to access the initial temperature object beyond the + * first time step. + */ + std::shared_ptr> initial_temperature; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/position.h.bak b/include/aspect/particle/property/position.h.bak new file mode 100644 index 00000000000..67f24247df6 --- /dev/null +++ b/include/aspect/particle/property/position.h.bak @@ -0,0 +1,87 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_position_h +#define _aspect_particle_property_position_h + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * A class that sets particle properties to the current position. + * + * @ingroup ParticleProperties + */ + template + class Position : public Interface + { + public: + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::update_particle_property() + */ + virtual + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * This implementation tells the particle manager that + * we need to update particle properties over time. + */ + UpdateTimeFlags + need_update () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/reference_position.h.bak b/include/aspect/particle/property/reference_position.h.bak new file mode 100644 index 00000000000..0de6a35f06b --- /dev/null +++ b/include/aspect/particle/property/reference_position.h.bak @@ -0,0 +1,87 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_reference_position_h +#define _aspect_particle_property_reference_position_h + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * A class that sets particle properties to the current position. + * + * @ingroup ParticleProperties + */ + template + class ReferencePosition : public Interface + { + public: + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle reference position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::update_particle_property() + */ + virtual + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * This implementation tells the particle manager that + * we need to update particle properties over time. + */ + UpdateTimeFlags + need_update () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/strain_rate.h.bak b/include/aspect/particle/property/strain_rate.h.bak new file mode 100644 index 00000000000..d8c7460757d --- /dev/null +++ b/include/aspect/particle/property/strain_rate.h.bak @@ -0,0 +1,97 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_strain_rate_h +#define _aspect_particle_property_strain_rate_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * A class that saves the time evolution of strain rate onto the particles. + * + * @ingroup ParticleProperties + */ + template + class StrainRate : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::update_particle_property() + */ + virtual + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + + /** + * This implementation tells the particle manager that + * we need to update particle properties over time. + */ + UpdateTimeFlags + need_update () const override; + + /** + * Return which data has to be provided to update the property. + * The velocity particle property needs the values of the velocity + * solution. + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/velocity.h.bak b/include/aspect/particle/property/velocity.h.bak new file mode 100644 index 00000000000..70d710430bd --- /dev/null +++ b/include/aspect/particle/property/velocity.h.bak @@ -0,0 +1,96 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_velocity_h +#define _aspect_particle_property_velocity_h + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * A class that sets particle properties to the current velocity. + * + * @ingroup ParticleProperties + */ + template + class Velocity : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Initialization function. This function is called once at the + * creation of every particle for every property to initialize its + * value. + * + * @param [in] position The current particle position. + * @param [in,out] particle_properties The properties of the particle + * that is initialized within the call of this function. The purpose + * of this function should be to extend this vector by a number of + * properties. + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::update_particle_property() + */ + virtual + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * This implementation tells the particle manager that + * we need to update particle properties over time. + */ + UpdateTimeFlags + need_update () const override; + + /** + * Return which data has to be provided to update the property. + * The velocity particle property needs the values of the velocity + * solution. + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * Set up the information about the names and number of components + * this property requires. + * + * @return A vector that contains pairs of the property names and the + * number of components this property plugin defines. + */ + std::vector> + get_property_information() const override; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/property/viscoplastic_strain_invariants.h.bak b/include/aspect/particle/property/viscoplastic_strain_invariants.h.bak new file mode 100644 index 00000000000..d7a9c18da85 --- /dev/null +++ b/include/aspect/particle/property/viscoplastic_strain_invariants.h.bak @@ -0,0 +1,109 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_property_viscoplastic_strain_invariant_h +#define _aspect_particle_property_viscoplastic_strain_invariant_h + +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + /** + * A class that calculates the finite strain invariant a particle has + * experienced and assigns it to either the plastic and/or viscous strain field based + * on whether the material is plastically yielding, or the total strain field + * used in the visco plastic material model. The implementation of this property + * is equivalent to the implementation for compositional fields that is located in + * the plugin benchmarks/buiter_et_al_2008_jgr/plugin/finite_strain_invariant.cc, + * and is effectively the same as what the visco plastic material model uses for compositional fields. + * @ingroup ParticleProperties + */ + template + class ViscoPlasticStrainInvariant : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + ViscoPlasticStrainInvariant (); + + void initialize () override; + + + /** + * @copydoc aspect::Particle::Property::Interface::initialize_one_particle_property() + */ + void + initialize_one_particle_property (const Point &position, + std::vector &particle_properties) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::update_particle_property() + */ + virtual + void + update_particle_property (const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const override; + + /** + * @copydoc aspect::Particle::Property::Interface::need_update() + */ + UpdateTimeFlags + need_update () const override; + + /** + * @copydoc aspect::Particle::Property::Interface::get_needed_update_flags() + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * @copydoc aspect::Particle::Property::Interface::get_property_information() + */ + std::vector> + get_property_information() const override; + + private: + unsigned int n_components; + + /** + * An object that is used to compute the particle property. Since the + * object is expensive to create and is needed often it is kept as a + * member variable. Because it is changed inside a const member function + * (update_particle_property) it has to be mutable, but since it is + * only used inside that function and always set before being used + * that is not a problem. This implementation is not thread safe, + * but it is currently not used in a threaded context. + */ + mutable MaterialModel::MaterialModelInputs material_inputs; + }; + } + } +} + +#endif diff --git a/include/aspect/particle/world.h.bak b/include/aspect/particle/world.h.bak new file mode 100644 index 00000000000..ad5578d3b3e --- /dev/null +++ b/include/aspect/particle/world.h.bak @@ -0,0 +1,531 @@ +/* + Copyright (C) 2012 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_particle_world_h +#define _aspect_particle_world_h + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +namespace aspect +{ + template + struct SimulatorSignals; + + namespace Particle + { + using namespace dealii; + using namespace dealii::Particles; + + namespace Generator + { + template + class Interface; + } + + + namespace Property + { + template + class Manager; + } + + namespace internal + { + /** + * This class evaluates the solution vector at arbitrary positions inside a cell. + * This base class only provides the interface for SolutionEvaluatorsImplementation. + * See there for more details. + */ + template + class SolutionEvaluators + { + public: + /** + * virtual Destructor. + */ + virtual ~SolutionEvaluators() = default; + + /** + * Reinitialize all variables to evaluate the given solution for the given cell + * and the given positions. The update flags control if only the solution or + * also the gradients should be evaluated. + * If other flags are set an assertion is triggered. + */ + virtual void + reinit(const typename DoFHandler::active_cell_iterator &cell, + const ArrayView> &positions, + const ArrayView &solution_values, + const UpdateFlags update_flags) = 0; + + /** + * Fill @p solution with all solution components at the given @p evaluation_point. Note + * that this function only works after a successful call to reinit(), + * because this function only returns the results of the computation that + * happened in reinit(). + */ + virtual void get_solution(const unsigned int evaluation_point, + Vector &solution) = 0; + + /** + * Fill @p gradients with all solution gradients at the given @p evaluation_point. Note + * that this function only works after a successful call to reinit(), + * because this function only returns the results of the computation that + * happened in reinit(). + */ + virtual void get_gradients(const unsigned int evaluation_point, + std::vector> &gradients) = 0; + + /** + * Return the evaluator for velocity or fluid velocity. This is the only + * information necessary for advecting particles. + */ + virtual FEPointEvaluation & + get_velocity_or_fluid_velocity_evaluator(const bool use_fluid_velocity) = 0; + + /** + * Return the cached mapping information. + */ + virtual NonMatching::MappingInfo & + get_mapping_info() = 0; + }; + + /** + * A function to create a pointer to a SolutionEvaluators object. + */ + template + std::unique_ptr> + construct_solution_evaluators(const SimulatorAccess &simulator_access, + const UpdateFlags update_flags); + } + + /** + * This class manages the storage and handling of particles. It provides + * interfaces to generate and store particles, functions to initialize, + * update and advect them, and ways to retrieve information about the + * particles. The implementation of most of these methods is outsourced + * to different plugin systems, this class is mostly concerned with + * managing the interactions of the different systems with the code + * outside the particle world. + * + * @ingroup Particle + */ + template + class World : public SimulatorAccess + { + public: + /** + * Default World constructor. + */ + World(); + + /** + * Default World destructor. + */ + ~World() override; + + /** + * Initialize the particle world. + */ + void initialize(); + + /** + * Update the particle world. + */ + void update(); + + /** + * Get the particle property manager for this particle world. + * + * @return The property manager for this world. + */ + const Property::Manager & + get_property_manager() const; + + /** + * Get the const particle handler for this particle world. + * + * @return The particle handler for this world. + */ + const Particles::ParticleHandler & + get_particle_handler() const; + + /** + * Get the particle handler for this particle world. + * There is no get_particles() function in the deal.II + * ParticleHandler, so we get and set the positions + * of the particles. These getter/setter functions are + * not const, and neither are the calling functions, + * but the existing get_particle_handler is. + * Therefore this non-const function is added. + * + * @return The particle handler for this world. + */ + Particles::ParticleHandler & + get_particle_handler(); + + /** + * Copy the state of particle handler @p from_particle_handler into the + * particle handler @p to_particle_handler. This will copy + * all particles and properties and leave @p to_particle_handler + * as an identical copy of @p from_particle_handler, assuming it + * was set up by this particle world class. This means we assume + * @p from_particle_handler uses the same triangulation and + * particle properties as are used in this model. Existing + * particles in @p to_particle_handler are deleted. + * + * This function is expensive as it has to duplicate all data + * in @p from_particle_handler, and insert it into @p to_particle_handler, + * which may be a significant amount of data. However, it can + * be useful to save the state of a particle + * collection at a certain point in time and reset this + * state later under certain conditions, for example if + * a timestep has to be undone and repeated. + */ + void copy_particle_handler (const Particles::ParticleHandler &from_particle_handler, + Particles::ParticleHandler &to_particle_handler) const; + + /** + * @brief Stores a copy of the particle handler in particle_handler_backup. This copy can be + * used to restore the position and properties of the particles for example after advection + * solver iterations of the iterated advection scheme or when a timestep has to be repeated. + */ + void backup_particles (); + + /** + * @brief Restores the particle handler particle_handler based on the copy + * in particle_handler_backup. This restores the position and properties of the particles + * to those in the copy and can be used for example after advection solver iterations + * of the iterated advection scheme or when a timestep has to be repeated. + */ + void restore_particles (); + + + /** + * Do initial logic for handling pre-refinement steps + */ + void setup_initial_state (); + + /** + * Get the particle interpolator for this particle world. + * + * @return The interpolator for this world. + */ + const Interpolator::Interface & + get_interpolator() const; + + /** + * Initialize the particle properties. + */ + void generate_particles(); + /** + * Initialize the particle properties. + */ + void initialize_particles(); + + /** + * Advance particles by the old timestep using the current + * integration scheme. This accounts for the fact that the particles + * are actually still at their old positions and the current timestep + * length is already updated for the next step at the time this + * function is called. + */ + void advance_timestep(); + + /** + * Return the total number of particles in the simulation. This + * function is useful for monitoring how many particles have been + * lost by falling out of the domain. Note that this function does + * not compute the number of particles, because that is an expensive + * global MPI operation. Instead it returns the number, which is + * updated internally every time it might change by a call to + * update_n_global_particles(). + * + * @return Total number of particles in simulation. + */ + types::particle_index n_global_particles() const; + + /** + * This callback function is registered within Simulator by the + * constructor of this class and will be + * called from Simulator during construction. It allows to attach slot + * functions to the provided SimulatorSignals. This world will register + * the register_store_callback_function() and + * register_load_callback_function() to the + * pre_refinement_store_user_data signal and the + * post_refinement_load_user_data signal respectively. + */ + void + connect_to_signals(aspect::SimulatorSignals &signals); + + /** + * Called by listener functions from Triangulation for every cell + * before a refinement step. A weight is attached to every cell + * depending on the number of contained particles. + */ +#if DEAL_II_VERSION_GTE(9,6,0) + unsigned int + cell_weight(const typename parallel::distributed::Triangulation::cell_iterator &cell, + const CellStatus status); +#else + unsigned int + cell_weight(const typename parallel::distributed::Triangulation::cell_iterator &cell, + const typename parallel::distributed::Triangulation::CellStatus status); +#endif + + /** + * Update the particle properties if necessary. + */ + void update_particles(); + + /** + * Serialize the contents of this class. + */ + template + void serialize (Archive &ar, const unsigned int version); + + /** + * Save the state of the object. + */ + virtual + void + save (std::ostringstream &os) const; + + /** + * Restore the state of the object. + */ + virtual + void + load (std::istringstream &is); + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * + * @param world_index Parse the parameters for the Particle world with this index. + */ + virtual + void + parse_parameters (ParameterHandler &prm, const unsigned int world_index); + + private: + struct ParticleLoadBalancing + { + enum Kind + { + no_balancing = 0x0, + remove_particles = 0x1, + add_particles = 0x2, + repartition = 0x4, + remove_and_add_particles = remove_particles | add_particles + }; + }; + + /** + * Generation scheme for creating particles in this world + */ + std::unique_ptr> generator; + + /** + * Integration scheme for moving particles in this world + */ + std::unique_ptr> integrator; + + /** + * Interpolation scheme for moving particles in this world + */ + std::unique_ptr> interpolator; + + /** + * Particle handler object that is responsible for storing and + * managing the internal particle structures. + */ + std::unique_ptr> particle_handler; + + /** + * Particle handler object that is responsible for storing and + * managing the internal particle structures before starting nonlinear iterations + * such that the particle position and properties can be restored after + * each outer advection iteration. + */ + Particles::ParticleHandler particle_handler_backup; + + /** + * The property manager stores information about the additional + * particle properties and handles the initialization and update of + * these properties. + */ + std::unique_ptr> property_manager; + + /** + * Strategy for particle load balancing. + */ + typename ParticleLoadBalancing::Kind particle_load_balancing; + + /** + * Lower limit for particle number per cell. This limit is + * useful for adaptive meshes to prevent fine cells from being empty + * of particles. It will be checked and enforced after mesh + * refinement and after particle movement. If there are + * n_number_of_particles < min_particles_per_cell + * particles in one cell then + * min_particles_per_cell - n_number_of_particles particles are + * generated and randomly placed in this cell. If the particles carry + * properties the individual property plugins control how the + * properties of the new particles are initialized. + */ + unsigned int min_particles_per_cell; + + /** + * Upper limit for particle number per cell. This limit is + * useful for adaptive meshes to prevent coarse cells from slowing down + * the whole model. It will be checked and enforced after mesh + * refinement, after MPI transfer of particles and after particle + * movement. If there are + * n_number_of_particles > max_particles_per_cell + * particles in one cell then + * n_number_of_particles - max_particles_per_cell + * particles in this cell are randomly chosen and destroyed. + */ + unsigned int max_particles_per_cell; + + /** + * The computational cost of a single particle. This is an input + * parameter that is set during initialization and is only used if the + * particle load balancing strategy 'repartition' is used. This value + * determines how costly the computation of a single particle is compared + * to the computation of a whole cell, which is arbitrarily defined + * to represent a cost of 1000. + */ + unsigned int particle_weight; + + /** + * Some particle interpolation algorithms require knowledge + * about particles in neighboring cells. To allow this, + * particles in ghost cells need to be exchanged between the + * processes neighboring this cell. This parameter determines + * whether this transport is happening. + */ + bool update_ghost_particles; + + /** + * Get a map between subdomain id and the neighbor index. In other words + * the returned map answers the question: Given a subdomain id, which + * neighbor of the current processor's domain (in terms of a contiguous + * number from 0 to n_neighbors) owns this subdomain? + */ + std::map + get_subdomain_id_to_neighbor_map() const; + + /** + * Apply the bounds for the maximum and minimum number of particles + * per cell, if the appropriate @p particle_load_balancing strategy + * has been selected. + */ + void + apply_particle_per_cell_bounds(); + + /** + * Advect the particle positions by one integration step. Needs to be + * called until integrator->continue() returns false. + */ + void advect_particles(); + + /** + * Initialize the particle properties of one cell. + */ + void + local_initialize_particles(const typename ParticleHandler::particle_iterator &begin_particle, + const typename ParticleHandler::particle_iterator &end_particle); + + /** + * Update the particle properties of one cell. + */ + void + local_update_particles(const typename DoFHandler::active_cell_iterator &cell, + internal::SolutionEvaluators &evaluators); + + /** + * Advect the particles of one cell. Performs only one step for + * multi-step integrators. Needs to be called until integrator->continue() + * evaluates to false. Particles that moved out of their old cell + * during this advection step are removed from the local multimap and + * stored in @p particles_out_of_cell for further treatment (sorting + * them into the new cell). + */ + void + local_advect_particles(const typename DoFHandler::active_cell_iterator &cell, + const typename ParticleHandler::particle_iterator &begin_particle, + const typename ParticleHandler::particle_iterator &end_particle, + internal::SolutionEvaluators &evaluators); + + /** + * This function registers the necessary functions to the + * @p signals that the @p particle_handler needs to know about. + */ + void + connect_particle_handler_signals(aspect::SimulatorSignals &signals, + ParticleHandler &particle_handler, + const bool connect_to_checkpoint_signals = true) const; + }; + + /* -------------------------- inline and template functions ---------------------- */ + + template + template + void World::serialize (Archive &ar, const unsigned int) + { + // Note that although Boost claims to handle serialization of pointers + // correctly, at least for the case of unique_ptr it seems to not work. + // It works correctly when archiving the content of the pointer instead. + ar + &(*particle_handler) + ; + } + } +} + +#endif diff --git a/include/aspect/plugins.h.bak b/include/aspect/plugins.h.bak new file mode 100644 index 00000000000..86d77fc9f1e --- /dev/null +++ b/include/aspect/plugins.h.bak @@ -0,0 +1,808 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_plugins_h +#define _aspect_plugins_h + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace aspect +{ + template class SimulatorAccess; + + namespace Plugins + { + using namespace dealii; + + /** + * This function returns if a given plugin (e.g. a material model returned + * from SimulatorAccess::get_material_model() ) matches a certain plugin + * type (e.g. MaterialModel::Simple). This check is needed, because often + * it is only possible to get a reference to an Interface, not the actual + * plugin type, but the actual plugin type might be important. For example + * a radial gravity model might only be implemented for spherical geometry + * models, and would want to check if the current geometry is in fact a + * spherical shell. + * + * This function can only be called with types that correspond to the same + * plugin system. In other words, the type of the plugin has to either be + * derived from the type of the object being tested, or they have to both + * be derived from a common base class. This function is not appropriate + * to check whether a class `TestType` derived from an interface base + * class is *also* derived from a second base class `PluginType`. For these + * cases, use a `dynamic_cast`. + */ + template ::value>> + inline + bool + plugin_type_matches (const PluginType &object) + { + return (dynamic_cast (&object) != nullptr); + } + + /** + * This function converts a reference to a type (in particular a reference + * to an interface class) into a reference to a different type (in + * particular a plugin class). This allows accessing members of the plugin + * that are not specified in the interface class. Note that you should + * first check if the plugin type is actually convertible by calling + * plugin_matches_type() before calling this function. If the plugin is + * not convertible this function throws an exception. + * + * This function can only be called with types that correspond to the same + * plugin system. In other words, the type of the plugin has to either be + * derived from the type of the object being tested, or they have to both + * be derived from a common base class. This function is not appropriate + * to convert references to classes whether a class `TestType` derived + * from an interface base class is *also* derived from a second base + * class `PluginType`. For these cases, use a `dynamic_cast`. + */ + template ::value>> + inline + TestType & + get_plugin_as_type (PluginType &object) + { + AssertThrow(plugin_type_matches(object), + ExcMessage("You have requested to convert a plugin of type <" + + boost::core::demangle(typeid(PluginType).name()) + + "> into type <" + + boost::core::demangle(typeid(TestType).name()) + + ">, but this cast cannot be performed.")); + + // We can safely dereference the pointer, because we checked above that + // the object is actually of type TestType, and so the result + // is not a nullptr. + return *dynamic_cast (&object); + } + } + + namespace Plugins + { + using namespace dealii; + + + /** + * A base class for all plugin systems. The class ensures that a + * common set of functions is declared as `virtual` (namely, the + * destructor, `initialize()`, `update()`, and + * `parse_parameters()`) and implemented with empty bodies so that + * derived interface classes do not have to declare these + * functions themselves. Furthermore, the class provides an empty, + * `static` function `declare_parameters()` that derived classes + * can re-implement to declare their parameters. + */ + class InterfaceBase + { + public: + /** + * Destructor. Made virtual to enforce that derived classes also have + * virtual destructors. + */ + virtual ~InterfaceBase() = default; + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters() is run and after + * the SimulatorAccess (if applicable) is initialized. + * + * The default implementation of this function does nothing, but + * plugins that derive from this class (via the Interface + * classes of their respective plugin systems) may overload it + * if they want something to happen upon startup of the + * Simulator object to which the plugin contributes. + */ + virtual + void + initialize (); + + /** + * A function that is called at the beginning of each time step. + * + * The default implementation of this function does nothing, but + * plugins that derive from this class (via the Interface + * classes of their respective plugin systems) may overload it + * if they want something to happen upon startup of the + * Simulator object to which the plugin contributes. + */ + virtual + void + update (); + + /** + * Declare the parameters the plugin takes through input files. The + * default implementation of this function does not describe any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. On + * the other hand, most plugins do have run-time parameters, and + * they may then overload this function. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * The default implementation of this function does not read any + * parameters. Consequently, derived classes do not have to overload + * this function if they do not take any runtime parameters. On + * the other hand, most plugins do have run-time parameters, and + * they may then overload this function. + */ + virtual + void + parse_parameters (ParameterHandler &prm); + }; + + + + /** + * A base class for "plugin manager" classes. Plugin manager classes are + * used in places where one can legitimately use more than one plugin of + * a certain kind. For example, while there can only ever be one geometry + * (and consequently, the Simulator class only stores a single object of + * type derived from GeometryModels::Interface), one can have many different + * postprocessor objects at the same time. In these circumstances, the + * Simulator class stores a Postprocess::Manager object that internally + * stores zero or more objects of type derived from Postprocess::Interface. + * Since there are many places inside ASPECT where we need these "plugin + * manager" classes, the current class provides some common functionality + * to all of these classes. + * + * The class takes as template argument the type of the derived + * class's interface type. Since a manager is always also a plugin + * (to the Simulator class) itself, the current class is derived from + * the `InterfaceBase` class as well. + */ + template + class ManagerBase : public InterfaceBase + { + public: + /** + * A function that is called at the beginning of each time step, + * calling the update function of the individual heating models. + */ + void + update () override; + + /** + * Go through the list of all plugins that have been selected + * in the input file (and are consequently currently active) and return + * true if one of them has the desired type specified by the template + * argument. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ::value>> + bool + has_matching_plugin_object () const; + + /** + * Go through the list of all plugins that have been selected + * in the input file (and are consequently currently active) and see + * if one of them has the type specified by the template + * argument or can be cast to that type. If so, return a reference + * to it. If no postprocessor is active that matches the given type, + * throw an exception. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ::value>> + const PluginType & + get_matching_plugin_object () const; + + protected: + /** + * A list of plugin objects that have been requested in the + * parameter file. + */ + std::list> plugin_objects; + }; + + + template + void ManagerBase::update() + { + for (const auto &plugin : plugin_objects) + { + plugin->update(); + } + } + + + template + template + inline + bool + ManagerBase::has_matching_plugin_object () const + { + for (const auto &p : plugin_objects) + if (Plugins::plugin_type_matches(*p)) + return true; + return false; + } + + + template + template + inline + const PluginType & + ManagerBase::get_matching_plugin_object () const + { + AssertThrow(has_matching_plugin_object (), + ExcMessage("You asked the object managing a collection of plugins for a " + "plugin object of type <" + boost::core::demangle(typeid(PluginType).name()) + "> " + "that could not be found in the current model. You need to " + "activate this plugin in the input file for it to be " + "available.")); + + for (const auto &p : plugin_objects) + if (Plugins::plugin_type_matches(*p)) + return Plugins::get_plugin_as_type(*p); + + // We will never get here, because we had the Assert above. Just to avoid warnings. + return Plugins::get_plugin_as_type(**(plugin_objects.begin())); + } + } + + namespace internal + { + /** + * A namespace for the definition of classes that have to do with the + * plugin architecture of ASPECT. + */ + namespace Plugins + { + using namespace dealii; + + + + /** + * An internal class that is used in the definition of the + * ASPECT_REGISTER_* macros. Given a registration function, a classname, + * a description of what it does, and a name for the parameter file, it + * registers the model with the proper authorities. + * + * The registration happens in the constructor. The typical use case of + * this function is thus the creation of a dummy object in some + * otherwise unused namespace. + */ + template + struct RegisterHelper + { + /** + * Constructor. Given a pointer to a registration function and name + * and description of the class, this constructor registers the class + * passed as second template argument. + */ + RegisterHelper (void (*register_function) (const std::string &, + const std::string &, + void ( *)(ParameterHandler &), + std::unique_ptr ( *)()), + const char *name, + const char *description) + { + register_function (name, + description, + &ModelClass::declare_parameters, + &factory); + } + + /** + * A factory object that just creates object of the type registered by + * this class. + */ + static + std::unique_ptr factory () + { + return std::make_unique(); + } + }; + + + /** + * A class that stores a list of registered plugins for the given + * interface type. + */ + template + struct PluginList + { + /** + * A type describing everything we need to know about a plugin. + * + * The entries in the tuple are: + * - The name by which it can be selected. + * - A description of this plugin that will show up in the + * documentation in the parameter file. + * - A function that can declare the run-time parameters this + * plugin takes from the parameter file. + * - A function that can produce objects of this plugin type. + */ + using PluginInfo + = std::tuple( *) ()>; + + /** + * A pointer to a list of all registered plugins. + * + * The object is a pointer rather than an object for the following + * reason: objects with static initializers (such as =0) are + * initialized before any objects for which one needs to run + * constructors. Consequently, we can be sure that this pointer is set + * to zero before we ever try to register a postprocessor, and + * consequently whenever we run Manager::register_postprocessor, we + * need not worry whether we try to add something to this list before + * the lists's constructor has successfully run + */ + static std::list *plugins; + + /** + * Destructor. + */ + ~PluginList (); + + /** + * Register a plugin by name, description, parameter declaration + * function, and factory function. See the discussion for the + * PluginInfo type above for more information on their meaning. + */ + static + void register_plugin (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr (*factory_function) ()); + + /** + * Generate a list of names of the registered plugins separated by '|' + * so that they can be taken as the input for Patterns::Selection. + * + * To make it easier to visually scan through the list of plugins, + * names are sorted alphabetically. + */ + static + std::string get_pattern_of_names (); + + /** + * Return a string that describes all registered plugins using the + * descriptions that have been provided at the time of registration. + * + * To make it easier to visually scan through the list of plugins, + * names are sorted alphabetically. + */ + static + std::string get_description_string (); + + /** + * Let all registered plugins define their parameters. + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * Given the name of one plugin, create a corresponding object and + * return a pointer to it. The second argument provides a hint where + * this function was called from, to be printed in case there is an + * error. + * + * Ownership of the object is handed over to the caller of this + * function. + */ + static + std::unique_ptr + create_plugin (const std::string &name, + const std::string &documentation); + + /** + * Given the name of one plugin, create a corresponding object and + * return a pointer to it. The second argument provides a hint where + * this function was called from, to be printed in case there is an + * error. Before returning, let the newly created object read its + * run-time parameters from the parameter object. + * + * Ownership of the object is handed over to the caller of this + * function. + */ + static + std::unique_ptr + create_plugin (const std::string &name, + const std::string &documentation, + ParameterHandler &prm); + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param plugin_system_name The name to be used for the current + * plugin system. This name will be used for the "Interface" + * class to which all plugins connect. + * @param output_stream The stream to write the output to. + * @param attachment_point The point to which a plugin subsystem + * feeds information. By default, this is the Simulator class, + * but some plugin systems (most notably the visualization + * postprocessors, which feeds to one of the postprocessor + * classes) hook into other places. If other than the + * "Simulator" default, the attachment point should be of + * the form typeid(ClassName).name() as this is + * the form used by this function to identify nodes in the + * plugin graph. + */ + static + void + write_plugin_graph (const std::string &plugin_system_name, + std::ostream &output_stream, + const std::string &attachment_point = "Simulator"); + + /** + * Exception. + */ + DeclException1 (ExcUnknownPlugin, + std::string, + << "Can't create a plugin of name <" << arg1 + << "> because such a plugin hasn't been declared."); + }; + + + /* ------------------------ template and inline functions --------------------- */ + + template + PluginList:: + ~PluginList () + { + // if any plugins have been registered, then delete + // the list + if (plugins != nullptr) + delete plugins; + plugins = nullptr; + } + + + + template + void + PluginList:: + register_plugin (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr (*factory_function) ()) + { + // see if this is the first time we get into this + // function and if so initialize the static member variable + if (plugins == nullptr) + plugins = new std::list(); + + // verify that the same name has not previously been + // used to register a plugin, since we would then no + // longer be able to identify the plugin + for (const auto &p : *plugins) + { + Assert (std::get<0>(p) != name, + ExcMessage ("A plugin with name <" + name + "> has " + "already been registered!")); + (void)p; + } + + + // now add one record to the list + plugins->emplace_back (name, + description, + declare_parameters_function, + factory_function); + } + + + + template + std::string + PluginList:: + get_pattern_of_names () + { + Assert (plugins != nullptr, + ExcMessage ("No plugins registered!?")); + + // get all names and put them into a data structure that keeps + // them sorted + std::set names; + for (typename std::list::const_iterator + p = plugins->begin(); + p != plugins->end(); ++p) + names.insert (std::get<0>(*p)); + + // now create a pattern from all of these sorted names + std::string pattern_of_names; + for (const auto &name : names) + { + if (pattern_of_names.size() > 0) + pattern_of_names += "|"; + pattern_of_names += name; + } + + return pattern_of_names; + } + + + + template + std::string + PluginList:: + get_description_string () + { + std::string description; + + // get all names_and_descriptions and put them into a data structure that keeps + // them sorted + std::map names_and_descriptions; + for (typename std::list::const_iterator + p = plugins->begin(); + p != plugins->end(); ++p) + names_and_descriptions[std::get<0>(*p)] = std::get<1>(*p); + + // then output it all + std::map::const_iterator + p = names_and_descriptions.begin(); + while (true) + { + // write the name and + // description of the + // parameter + description += "`"; + description += p->first; + description += "': "; + description += p->second; + + // increment the pointer + // by one. if we are not + // at the end yet then + // add an empty line + ++p; + if (p != names_and_descriptions.end()) + description += "\n\n"; + else + break; + } + + return description; + } + + + + + template + void + PluginList:: + declare_parameters (ParameterHandler &prm) + { + Assert (plugins != nullptr, + ExcMessage ("No postprocessors registered!?")); + + for (typename std::list::const_iterator + p = plugins->begin(); + p != plugins->end(); ++p) + (std::get<2>(*p))(prm); + } + + + + template + std::unique_ptr + PluginList:: + create_plugin (const std::string &name, + const std::string &documentation) + { + (void)documentation; + Assert (plugins != nullptr, + ExcMessage ("No postprocessors registered!?")); + AssertThrow (name != "unspecified", + ExcMessage(std::string("A plugin must have a name!\n\n" + "This function was asked to create a plugin but no name for the " + "plugin was provided. This may be due to the fact that you did not " + "explicitly specify a name for this plugin in your input file and " + "ASPECT does not provide a default for this kind of plugin, for " + "example because no generally useful plugin exists. An example " + "is that there is no default geometry: You need to explicitly " + "provide one in the input file, and it seems like you have not " + "done so.\n\n" + "To find out which kind of plugin this function tries to create, " + "take a look at the backtrace of this error message.\n\n" + "The place that called this function also provided as " + "additional information this:\n\n" + " <") + + documentation + ">")); + + for (typename std::list::const_iterator p = plugins->begin(); + p != plugins->end(); ++p) + if (std::get<0>(*p) == name) + { + std::unique_ptr i = std::get<3>(*p)(); + return i; + } + + AssertThrow (false, ExcUnknownPlugin(name)); + return nullptr; + } + + + + template + std::unique_ptr + PluginList:: + create_plugin (const std::string &name, + const std::string &documentation, + ParameterHandler &prm) + { + std::unique_ptr i = create_plugin(name, documentation); + i->parse_parameters (prm); + return i; + } + + + + template + void + PluginList:: + write_plugin_graph (const std::string &plugin_system_name, + std::ostream &output_stream, + const std::string &attachment_point) + { + // first output a graph node for the interface class as the central + // hub of this plugin system, plotted as a square. + // + // we use the typeid name of the interface class to label + // nodes within this plugin system, as they are unique among + // all other plugin systems + output_stream << std::string(typeid(InterfaceClass).name()) + << " [label=\"" + << plugin_system_name + << "\", height=.8,width=.8,shape=\"rect\",fillcolor=\"green\"]" + << std::endl; + + // then output the graph nodes for each plugin, with links to the + // interface class and, as appropriate, from the SimulatorAccess class + // + // we would like to establish a predictable order of output here, but + // plugins self-register via static global variables, and their + // initialization order is not deterministic. consequently, let us + // loop over all plugins first and put pointers to them into a + // map with deterministic keys. as key, we use the declared name + // of the plugin by which it is referred in the .prm file + std::map::const_iterator> + plugin_map; + for (typename std::list::const_iterator p = plugins->begin(); + p != plugins->end(); ++p) + plugin_map[std::get<0>(*p)] = p; + + // now output the information sorted by the plugin names + for (typename std::map::const_iterator>::const_iterator + p = plugin_map.begin(); + p != plugin_map.end(); ++p) + { + // take the name of the plugin and split it into strings of + // 15 characters at most; then combine them + // again using \n to make dot/neato show these parts of + // the name on separate lines + const std::vector plugin_label_parts + = dealii::Utilities::break_text_into_lines(p->first, 15); + Assert (plugin_label_parts.size()>0, ExcInternalError()); + std::string plugin_name = plugin_label_parts[0]; + for (unsigned int i=1; i instance (create_plugin (p->first, "")); + const std::string node_name = typeid(*instance).name(); + + // then output the whole shebang describing this node + output_stream << node_name + << " [label=\"" + << plugin_name + << "\", height=.8,width=.8,shape=\"circle\",fillcolor=\"lightblue\"];" + << std::endl; + + // next build connections from this plugin to the + // interface class + output_stream << node_name + << " -> " + << std::string(typeid(InterfaceClass).name()) + << " [len=3, weight=50]" + << ';' + << std::endl; + + // finally see if this plugin is derived from + // SimulatorAccess; if so, draw an arrow from SimulatorAccess + // also to the plugin's name + if (dynamic_cast*>(instance.get()) != nullptr + || + dynamic_cast*>(instance.get()) != nullptr) + output_stream << "SimulatorAccess" + << " -> " + << node_name + << " [style=\"dotted\", arrowhead=\"empty\", constraint=false, color=\"gray\", len=20, weight=0.1];" + << std::endl; + } + + // as a last step, also draw a connection from the interface class + // to the Simulator class, or whatever the calling function indicates + // as the attachment point + output_stream << std::string(typeid(InterfaceClass).name()) + << " -> " + << attachment_point + << " [len=15, weight=50]" + << ';' + << std::endl; + + // end it with an empty line to make things easier to + // read when looking over stuff visually + output_stream << std::endl; + } + } + } +} + + +#endif diff --git a/include/aspect/postprocess/ODE_statistics.h.bak b/include/aspect/postprocess/ODE_statistics.h.bak new file mode 100644 index 00000000000..ea04ec501e0 --- /dev/null +++ b/include/aspect/postprocess/ODE_statistics.h.bak @@ -0,0 +1,82 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_ODE_statistics_h +#define _aspect_postprocess_ODE_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes statistics about the ODEs solved in ASPECT. + * + * @ingroup Postprocessing + */ + template + class ODEStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Connect the callback functions to the respective signals. + */ + void initialize() override; + + /** + * Write the ODE statistics into the statistics file. + */ + std::pair + execute (TableHandler &statistics) override; + + private: + /** + * This function clears all the saved solver information that is + * stored in this class. It is executed every time the output is + * written into the statistics object. + */ + void + clear_data(); + + /** + * Callback function that is connected to the post_ARKode_solve + * signal to store the solver history. + */ + void + store_ODE_solver_history(const unsigned int iteration_count); + + /** + * Variables that store the ODE solver history of the current + * timestep, until they are written into the statistics object + * upon the call to execute(). They are cleared after writing + * the content. + */ + unsigned int total_iteration_count; + unsigned int number_of_solves; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/basic_statistics.h.bak b/include/aspect/postprocess/basic_statistics.h.bak new file mode 100644 index 00000000000..5ddc6b16e41 --- /dev/null +++ b/include/aspect/postprocess/basic_statistics.h.bak @@ -0,0 +1,62 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_basic_statistics_h +#define _aspect_postprocess_basic_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that outputs some simplified statistics + * like the Rayleigh number and other quantities that only + * make sense in certain model setups. The output is written + * after completing initial adaptive refinement steps. + * The postprocessor assumes a point at the surface at the adiabatic + * surface temperature and pressure is a reasonable reference condition + * for computing these properties. Furthermore, the Rayleigh + * number is computed using the model depth (i.e. not the + * radius of the Earth), as we need a definition that is geometry + * independent. Take care when comparing these values to published + * studies and make sure they use the same definitions. + * + * @ingroup Postprocessing + */ + template + class BasicStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some general statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/boundary_densities.h.bak b/include/aspect/postprocess/boundary_densities.h.bak new file mode 100644 index 00000000000..e422a4de3b9 --- /dev/null +++ b/include/aspect/postprocess/boundary_densities.h.bak @@ -0,0 +1,79 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_boundary_densities_h +#define _aspect_postprocess_boundary_densities_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes the laterally averaged density + * at the top and bottom boundaries of the solution. This is useful + * for calculating the geoid at those surfaces. + * + * @ingroup Postprocessing + */ + template + class BoundaryDensities : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for laterally averaged density at the top + * and bottom of the domain. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Query the density at the top surface + */ + double density_at_top() const; + + /** + * Query the density at the bottom surface + */ + double density_at_bottom() const; + + private: + + /** + * Density at the top of the domain. + * Filled when execute() is called. + */ + double top_density; + + /** + * Density at the bottom of the domain. + * Filled when execute() is called. + */ + double bottom_density; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/boundary_pressures.h.bak b/include/aspect/postprocess/boundary_pressures.h.bak new file mode 100644 index 00000000000..decca391fae --- /dev/null +++ b/include/aspect/postprocess/boundary_pressures.h.bak @@ -0,0 +1,79 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_boundary_pressures_h +#define _aspect_postprocess_boundary_pressures_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes the laterally averaged pressure + * at the top and bottom boundaries of the solution. This is useful + * for calculating the dynamic topography at those surfaces. + * + * @ingroup Postprocessing + */ + template + class BoundaryPressures : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for the laterally averaged pressure at + * the top and bottom of the domain. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Query the pressure at the top surface + */ + double pressure_at_top() const; + + /** + * Query the pressure at the bottom surface + */ + double pressure_at_bottom() const; + + private: + + /** + * Pressure at the top of the domain. + * Filled when execute() is called. + */ + double top_pressure; + + /** + * Pressure at the bottom of the domain. + * Filled when execute() is called. + */ + double bottom_pressure; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/boundary_strain_rate_residual_statistics.h.bak b/include/aspect/postprocess/boundary_strain_rate_residual_statistics.h.bak new file mode 100644 index 00000000000..1931f32ab3a --- /dev/null +++ b/include/aspect/postprocess/boundary_strain_rate_residual_statistics.h.bak @@ -0,0 +1,106 @@ +/* + Copyright (C) 2014 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_postprocess_boundary_strain_rate_residual_statistics_h +#define _aspect_postprocess_boundary_strain_rate_residual_statistics_h + +#include +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the residual of the second invariant of the strain + * rate at the top surface. The residual is calculated as the difference between the second invariant of + * the modeled strain rate and a data file containing the second invariant of strain rate observations. + * + * @ingroup Postprocessing + */ + + template + class BoundaryStrainRateResidualStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * This function reads the specified input surface strain rate data files as an ascii data file. + */ + void initialize () override; + + /** + * This function returns the reference surface strain rate read from the data file at the given point @p p. + */ + double + get_data_surface_strain_rate (const Point &p) const; + + /** + * Evaluate the solution to compute statistics about the residual of the second invariant of strain rate + * residual at the top boundary. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Pointer to the structured data containing the surface strain rate. + */ + std::unique_ptr> strain_rate_data_lookup; + + /** + * Directory in which the input data files are present. + */ + std::string data_directory; + + /** + * Filename of the input ascii data file containing the surface strain rate components. + */ + std::string data_file_name; + + /** + * Scale the input data by a scalar factor. Can be used to transform + * the unit of the data (if they are not specified in SI units (/s or + * /yr depending on the "Use years in output instead of seconds" + * parameter). + */ + double scale_factor; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/boundary_velocity_residual_statistics.h.bak b/include/aspect/postprocess/boundary_velocity_residual_statistics.h.bak new file mode 100644 index 00000000000..2c8873beae6 --- /dev/null +++ b/include/aspect/postprocess/boundary_velocity_residual_statistics.h.bak @@ -0,0 +1,128 @@ +/* + Copyright (C) 2014 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_postprocess_boundary_velocity_residual_statistics_h +#define _aspect_postprocess_boundary_velocity_residual_statistics_h + +#include +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the velocity residual at the top surface. + * The velocity residual is calculated as the difference between the modeled velocities and + * input data velocities (GPlates model or ascii data). + * + * @ingroup Postprocessing + */ + template + class BoundaryVelocityResidualStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * This function reads the specified input velocity data files, i.e., either an ascii data file or + * a file from the GPlates model. + */ + void initialize () override; + + /** + * This function returns the input data velocity, (GPlates model or ascii data) + * value at a point. This function is called from execute() function. + */ + Tensor<1,dim> + get_data_velocity (const Point &p) const; + + /** + * Evaluate the solution statistics for some velocity residual at the top boundary. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Determines if the input ascii data file has velocity components in + * spherical, i.e., (r, phi, theta) or in cartesian, i.e., (x, y, z) + * coordinate system. + */ + bool use_spherical_unit_vectors; + + /** + * Determines if the model velocities are compared against ascii data + * files, or a gplates model. + */ + bool use_ascii_data; + + /** + * Pointer to the gplates boundary velocity model + */ + std::unique_ptr> gplates_lookup; + + /** + * Pointer to the structured data + */ + std::unique_ptr> data_lookup; + + /** + * Directory in which the input data files, i.e., GPlates model or ascii data + * are present. + */ + std::string data_directory; + + /** + * Filename of the input Gplates model or ascii data file. For GPlates, the file names + * can contain the specifiers %s and/or %c (in this order), meaning the name of the + * boundary and the number of the data file time step. + */ + std::string data_file_name; + + /** + * Scale the input data by a scalar factor. Can be used to transform + * the unit of the data (if they are not specified in SI units (m/s or + * m/yr depending on the "Use years in output instead of seconds" + * parameter). + */ + double scale_factor; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/command.h.bak b/include/aspect/postprocess/command.h.bak new file mode 100644 index 00000000000..f354c890cba --- /dev/null +++ b/include/aspect/postprocess/command.h.bak @@ -0,0 +1,72 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_command_h +#define _aspect_postprocess_command_h + +#include +#include + +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that runs a shell command at the end of each time step. + * + * @ingroup Postprocessing + */ + template + class Command : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Declare new parameters + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Parse parameters + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Execute the command + */ + std::pair + execute (TableHandler &statistics) override; + + private: + std::string command; + bool terminate_on_failure; + bool on_all_processes; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/composition_statistics.h.bak b/include/aspect/postprocess/composition_statistics.h.bak new file mode 100644 index 00000000000..6f815ca96b0 --- /dev/null +++ b/include/aspect/postprocess/composition_statistics.h.bak @@ -0,0 +1,53 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_composition_statistics_h +#define _aspect_postprocess_composition_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the compositional + * fields, if any. + * + * @ingroup Postprocessing + */ + template + class CompositionStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some temperature statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/composition_velocity_statistics.h.bak b/include/aspect/postprocess/composition_velocity_statistics.h.bak new file mode 100644 index 00000000000..c9e68b32173 --- /dev/null +++ b/include/aspect/postprocess/composition_velocity_statistics.h.bak @@ -0,0 +1,75 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_composition_velocity_statistics_h +#define _aspect_postprocess_composition_velocity_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes the root mean square velocity + * over the area spanned by each of the compositional fields. + * + * @ingroup Postprocessing + */ + template + class CompositionVelocityStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution to compute the RMS velocity for each composition. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static void + declare_parameters(ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters(ParameterHandler &prm) override; + /** + * @} + */ + + private: + std::vector selected_fields; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/core_statistics.h.bak b/include/aspect/postprocess/core_statistics.h.bak new file mode 100644 index 00000000000..8dc7e84dc5c --- /dev/null +++ b/include/aspect/postprocess/core_statistics.h.bak @@ -0,0 +1,106 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_postprocess_core_statistics_h +#define _aspect_postprocess_core_statistics_h + +#include +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the dynamic core. + * + * @ingroup Postprocessing + */ + template + class CoreStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + CoreStatistics (); + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Evaluate statistics. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Export core data stored in this object. Doing this only because the boundary + * temperature doesn't allowed to store restart data there. So we store the data needed + * for restart here and exported to boundary temperature object if required. + */ + const BoundaryTemperature::internal::CoreData & + get_core_data() const; + + /** + * Serialize the contents of this class as far as they are not read + * from input parameter files. + */ + template + void serialize (Archive &ar, const unsigned int version); + + /** + * Save the state of this object. + */ + void save (std::map &status_strings) const override; + + /** + * Restore the state of the object. + */ + void load (const std::map &status_strings) override; + + private: + /** + * Controls whether output the total excess entropy or the individual entropy terms + * (i.e. entropy for specific heat, radioactive heating, gravitational contribution, + * and adiabatic contribution). + */ + bool excess_entropy_only; + + /** + * Stores the core data from boundary temperature. + */ + struct BoundaryTemperature::internal::CoreData core_data; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/crystal_preferred_orientation.h.bak b/include/aspect/postprocess/crystal_preferred_orientation.h.bak new file mode 100644 index 00000000000..554f8f744af --- /dev/null +++ b/include/aspect/postprocess/crystal_preferred_orientation.h.bak @@ -0,0 +1,279 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_postprocess_crystal_preferred_orientation_h +#define _aspect_postprocess_crystal_preferred_orientation_h + +#include +#include + +#include + +#include +#include +#include + +namespace aspect +{ + namespace Postprocess + { + /** + * A Postprocessor that writes out CPO specific particle data. + * It can write out the CPO data as it is stored (raw) and/or as a + * random draw volume weighted representation. The latter one + * is recommended for plotting against real data. For both representations + * the specific output fields and their order can be set. + */ + template + class CrystalPreferredOrientation : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + CrystalPreferredOrientation(); + + /** + * Destructor. + */ + ~CrystalPreferredOrientation(); + + + /** + * Initialize function. + */ + void initialize () override; + + /** + * A Postprocessor that writes out CPO specific particle data. + * It can write out the CPO data as it is stored (raw) and/or as a + * random draw volume weighted representation. The latter one + * is recommended for plotting against real data. For both representations + * the specific output fields and their order can be set. + */ + std::pair execute (TableHandler &statistics) override; + + /** + * This function ensures that the particle postprocessor is run before + * this postprocessor. + */ + std::list + required_other_postprocessors () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * Stores the simulation end time, so that it always produces output + * at the last timestep. + */ + double end_time; + + /** + * Enums specifying what information to write: + * + * VolumeFraction: Write the volume fraction + * RotationMatrix: Write the whole rotation matrix of a grain (in deal.ii order) + * EulerAngles: Write out the Z-X-Z Euler angle of a grain + * not_found: Error enum, the requested output was not found + */ + enum class Output + { + VolumeFraction, RotationMatrix, EulerAngles, not_found + }; + + /** + * Converts a string to an Output enum. + */ + Output string_to_output_enum(const std::string &string); + + /** + * Random number generator used for random draw volume weighting. + */ + mutable std::mt19937 random_number_generator; + + /** + * Random number generator seed used to initialize the random number generator. + */ + unsigned int random_number_seed; + + /** + * Interval between output (in years if appropriate simulation + * parameter is set, otherwise seconds) + */ + double output_interval; + + /** + * Records time for next output to occur + */ + double last_output_time; + + /** + * Set the time output was supposed to be written. In the simplest + * case, this is the previous last output time plus the interval, but + * in general we'd like to ensure that it is the largest supposed + * output time, which is smaller than the current time, to avoid + * falling behind with last_output_time and having to catch up once + * the time step becomes larger. This is done after every output. + */ + void set_last_output_time (const double current_time); + + /** + * Consecutively counted number indicating the how-manyth time we will + * create output the next time we get to it. + */ + unsigned int output_file_number; + + /** + * Graphical output format. + */ + std::vector output_formats; + + /** + * A list of pairs (time, pvtu_filename) that have so far been written + * and that we will pass to DataOutInterface::write_pvd_record + * to create a main file that can make the association + * between simulation time and corresponding file name (this + * is done because there is no way to store the simulation + * time inside the .pvtu or .vtu files). + */ + std::vector> times_and_pvtu_file_names; + + /** + * A corresponding variable that we use for the .visit files created + * by DataOutInterface::write_visit_record. The second part of a + * pair contains all files that together form a time step. + */ + std::vector>> times_and_vtu_file_names; + + /** + * A list of list of filenames, sorted by timestep, that correspond to + * what has been created as output. This is used to create a main + * .visit file for the entire simulation. + */ + std::vector> output_file_names_by_timestep; + + /** + * A set of data related to XDMF file sections describing the HDF5 + * heavy data files created. These contain things such as the + * dimensions and names of data written at all steps during the + * simulation. + */ + std::vector xdmf_entries; + + /** + * VTU file output supports grouping files from several CPUs into one + * file using MPI I/O when writing on a parallel filesystem. 0 means + * no grouping (and no parallel I/O). 1 will generate one big file + * containing the whole solution. + */ + unsigned int group_files; + + /** + * On large clusters it can be advantageous to first write the + * output to a temporary file on a local file system and later + * move this file to a network file system. If this variable is + * set to a non-empty string it will be interpreted as a temporary + * storage location. + */ + std::string temporary_output_location; + + /** + * File operations can potentially take a long time, blocking the + * progress of the rest of the model run. Setting this variable to + * 'true' moves this process into a background thread, while the + * rest of the model continues. + */ + bool write_in_background_thread; + + /** + * Handle to a thread that is used to write main file data in the + * background. The writer() function runs on this background thread. + */ + std::thread background_thread_main; + + /** + * What "raw" CPO data to write out. + */ + std::vector> write_raw_cpo; + + /** + * Whether computing raw Euler angles is needed. + */ + bool compute_raw_euler_angles; + + /** + * Handle to a thread that is used to write content file data in the + * background. The writer() function runs on this background thread. + */ + std::thread background_thread_content_raw; + + /** + * What "draw volume weighted" CPO data to write out. Draw volume weighted means + * the grain properties (size and rotation) are put in a list sorted based by volume + * and picked randomly, with large volumes having a higher chance of being picked. + */ + std::vector> write_draw_volume_weighted_cpo; + + /** + * Whether computing weighted A matrix is needed. + */ + bool compute_weighted_rotation_matrix; + + /** + * Handle to a thread that is used to write content file data in the + * background. The writer() function runs on this background thread. + */ + std::thread background_thread_content_draw_volume_weighting; + + /** + * Whether to compress the raw and weighed cpo data output files with zlib. + */ + bool compress_cpo_data_files; + + /** + * A function that writes the text in the second argument to a file + * with the name given in the first argument. The function is run on a + * separate thread to allow computations to continue even though + * writing data is still continuing. The function takes over ownership + * of these arguments and deletes them at the end of its work. + */ + static + void writer (const std::string &filename, + const std::string &temporary_filename, + const std::string &file_contents, + const bool compress_contents); + }; + } +} + +#endif diff --git a/include/aspect/postprocess/depth_average.h.bak b/include/aspect/postprocess/depth_average.h.bak new file mode 100644 index 00000000000..f8fa3dc5f0f --- /dev/null +++ b/include/aspect/postprocess/depth_average.h.bak @@ -0,0 +1,156 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_depth_average_h +#define _aspect_postprocess_depth_average_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that generates depth average output in periodic + * intervals or every time step. + * + * @ingroup Postprocessing + */ + template + class DepthAverage : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + DepthAverage (); + + /** + * Evaluate the solution and compute the requested depth averages. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Save the state of this object. + */ + void save (std::map &status_strings) const override; + + /** + * Restore the state of the object. + */ + void load (const std::map &status_strings) override; + + /** + * Serialize the contents of this class as far as they are not read + * from input parameter files. + */ + template + void serialize (Archive &ar, const unsigned int version); + + private: + /** + * Interval between the generation of output in seconds. This parameter is read + * from the input file and consequently is not part of the state that + * needs to be saved and restored. + */ + double output_interval; + + /** + * A time (in seconds) the last output has been produced. + */ + double last_output_time; + + /** + * The formats in which to produce graphical output. This also + * determines the extension of the file names to which to write. + */ + std::vector output_formats; + + /** + * Number of zones in depth direction over which we are supposed to + * average. + */ + unsigned int n_depth_zones; + + /** + * The boundaries of the depth zones. + * This vector contains exactly n_depth_zones + 1 entries, + * and entries i and i+1 represent the lower and upper depth bound + * of zone i. + */ + std::vector depth_bounds; + + /** + * List of the quantities to calculate for each depth zone. + */ + std::vector variables; + + /** + * A structure for a single time step record. + */ + struct DataPoint + { + double time; + std::vector> values; + + template + void serialize (Archive &ar, const unsigned int version); + }; + + /** + * An array of all the past values + */ + std::vector entries; + + /** + * Set the time output was supposed to be written. In the simplest + * case, this is the previous last output time plus the interval, but + * in general we'd like to ensure that it is the largest supposed + * output time, which is smaller than the current time, to avoid + * falling behind with last_output_time and having to catch up once + * the time step becomes larger. This is done after every output. + */ + void set_last_output_time (const double current_time); + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/domain_volume_statistics.h.bak b/include/aspect/postprocess/domain_volume_statistics.h.bak new file mode 100644 index 00000000000..5912863fa66 --- /dev/null +++ b/include/aspect/postprocess/domain_volume_statistics.h.bak @@ -0,0 +1,54 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_domain_volume_statistics_h +#define _aspect_postprocess_domain_volume_statistics_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes the total area (2D) or volume (3D) + * of the computational domain. + * + * @ingroup Postprocessing + */ + template + class DomainVolume : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some mass_flux statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/dynamic_topography.h.bak b/include/aspect/postprocess/dynamic_topography.h.bak new file mode 100644 index 00000000000..a9f218cd3fe --- /dev/null +++ b/include/aspect/postprocess/dynamic_topography.h.bak @@ -0,0 +1,136 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_surface_topography_h +#define _aspect_postprocess_surface_topography_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes dynamic topography at the top and bottom of the domain. + * + * @ingroup Postprocessing + */ + template + class DynamicTopography : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for the dynamic topography. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Return the topography vector as calculated by the consistent + * boundary flux (CBF) formulation. + * The velocity components store the surface-normal traction, + * and the temperature component stores the dynamic topography + * computed from that traction. + */ + const LinearAlgebra::BlockVector & + topography_vector() const; + + /** + * Return the cell-wise topography vector as calculated by the CBF formulation, + * where indices of the vector correspond to cell indices. + * This vector is considerably smaller than the full topography vector returned + * by topography_vector(), and is useful for text output and visualization. + */ + const Vector & + cellwise_topography() const; + + /** + * Register the other postprocessor that we need: BoundaryPressures + */ + std::list + required_other_postprocessors() const override; + + /** + * Parse the parameters for the postprocessor. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Declare the parameters for the postprocessor. + */ + static + void + declare_parameters (ParameterHandler &prm); + + private: + /** + * Output the dynamic topography solution to + * a file for a given boundary id. All the values + * in @p position_and_topography are written to a file + * with a file name determined by @p boundary_id. + */ + void output_to_file(const types::boundary_id boundary_id, + const std::vector, double>> &position_and_topography); + + /** + * A vector which stores the surface stress values calculated + * by the postprocessor. + */ + LinearAlgebra::BlockVector topo_vector; + + /** + * A vector which stores the surface stress values calculated + * at the midpoint of each surface cell face. This can be + * given to a visualization postprocessor to output dynamic topography. + */ + Vector visualization_values; + + /** + * A parameter that allows users to set the density value + * above the top surface. + */ + double density_above; + + /** + * A parameter that allows users to set the density value + * below the bottom surface. + */ + double density_below; + + /** + * Whether to output the surface topography. + */ + bool output_surface; + + /** + * Whether to output the bottom topography. + */ + bool output_bottom; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/entropy_viscosity_statistics.h.bak b/include/aspect/postprocess/entropy_viscosity_statistics.h.bak new file mode 100644 index 00000000000..17d0f002cf1 --- /dev/null +++ b/include/aspect/postprocess/entropy_viscosity_statistics.h.bak @@ -0,0 +1,52 @@ +/* + Copyright (C) 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_entropy_viscosity_statistics_h +#define _aspect_postprocess_entropy_viscosity_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + /** + * A postprocessor that computes the maximum and volume averaged + * entropy viscosity stabilization for the temperature equation. + * + * @ingroup Postprocessing + */ + template + class EntropyViscosityStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some entropy viscosity stabilization statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/geoid.h.bak b/include/aspect/postprocess/geoid.h.bak new file mode 100644 index 00000000000..cecc6cad96e --- /dev/null +++ b/include/aspect/postprocess/geoid.h.bak @@ -0,0 +1,188 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#ifndef _aspect_postprocess_geoid_h +#define _aspect_postprocess_geoid_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + /** + * A postprocessor that computes the geoid anomaly at the surface. + * + * @ingroup Postprocessing + */ + template + class Geoid : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for the geoid in spherical harmonics and then transfer it to grid output. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Register with the simulator the other postprocessors that we need + * (namely: dynamic topography). + */ + std::list + required_other_postprocessors() const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Find if the top or bottom boundaries are free surfaces. + */ + void initialize() override; + + /** + * Evaluate the geoid solution at a point. The evaluation point + * must be outside of the model domain, and it must be called + * after execute(). + */ + double + evaluate (const Point &) const; + + private: + /** + * Parameters to set the maximum and minimum degree when computing geoid from spherical harmonics + */ + unsigned int max_degree; + unsigned int min_degree; + + /** + * A parameter to control whether to output the data in geographical coordinates. + * If true, output the data in longitudes and latitudes; if false, output data in x y z. + */ + bool output_in_lat_lon; + + /** + * A parameter to control whether to output the spherical harmonic coefficients of the geoid anomaly + */ + bool output_geoid_anomaly_SH_coes; + + /** + * A parameter to control whether to output the spherical harmonic coefficients of the surface topography contribution + */ + bool output_surface_topo_contribution_SH_coes; + + /** + * A parameter to control whether to output the spherical harmonic coefficients of the CMB topography contribution + */ + bool output_CMB_topo_contribution_SH_coes; + + /** + * A parameter to control whether to output the spherical harmonic coefficients of the density anomaly + */ + bool output_density_anomaly_contribution_SH_coes; + + /** + * A parameter to control whether to output the free-air gravity anomaly + */ + bool output_gravity_anomaly; + + /** + * Parameters to set the density value out of the surface and CMB boundary + */ + double density_above; + double density_below; + + /** + * A parameter to control whether to include the surface topography contribution on geoid + */ + bool include_surface_topo_contribution; + + /** + * A parameter to control whether to include the CMB topography contribution on geoid + */ + bool include_CMB_topo_contribution; + + /** + * A parameter to specify if the top boundary is an active free surface + */ + bool use_free_surface_topography; + + /** + * A parameter to specify if the bottom boundary is an active free surface + */ + bool use_free_CMB_topography; + + /** + * Function to compute the real spherical harmonic coefficients (cos and sin part) from min degree to max degree + * The input spherical_function is a vector of vectors. + * The inner vector stores theta, phi, spherical infinitesimal, and function value on a spherical surface. + * The outer vector stores the inner vector associated with each quadrature point on a spherical surface. + */ + std::pair,std::vector> + to_spherical_harmonic_coefficients(const std::vector> &spherical_function) const; + + /** + * Function to compute the density contribution in spherical harmonic expansion throughout the mantle + * The input outer radius is needed to evaluate the density integral contribution of whole model domain at the surface + * This function returns a pair containing real spherical harmonics of density integral (cos and sin part) from min degree to max degree. + */ + std::pair,std::vector> + density_contribution (const double &outer_radius) const; + + /** + * Function to compute the surface and CMB topography contribution in spherical harmonic expansion + * The input inner and outer radius are used to calculate spherical infinitesimal area, i.e., sin(theta)*d_theta*d_phi + * associated with each quadrature point on surface and bottom respectively. + * This function returns a pair containing surface and CMB topography's real spherical harmonic coefficients (cos and sin part) + * from min degree to max degree. The surface and CMB average density are also included as the first single element of each subpair respectively. + * The topography is based on the dynamic topography postprocessor in case of no free surface, + * and based on the real surface from the geometry model in case of a free surface. + */ + std::pair,std::vector>>, std::pair,std::vector>>> + topography_contribution(const double &outer_radius, + const double &inner_radius) const; + + /** + * A vector to store the cosine terms of the geoid anomaly spherical harmonic coefficients. + */ + std::vector geoid_coecos; + /** + * A vector to store the sine terms of the geoid anomaly spherical harmonic coefficients. + */ + std::vector geoid_coesin; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/global_statistics.h.bak b/include/aspect/postprocess/global_statistics.h.bak new file mode 100644 index 00000000000..9e643447dad --- /dev/null +++ b/include/aspect/postprocess/global_statistics.h.bak @@ -0,0 +1,153 @@ +/* + Copyright (C) 2017 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_global_statistics_h +#define _aspect_postprocess_global_statistics_h + +#include +#include + +#include + +namespace aspect +{ + + namespace Postprocess + { + /** + * A postprocessor that outputs all the global statistics + * information, e.g. the time of the simulation, the timestep + * number, number of degrees of freedom and solver iterations + * for each timestep. The postprocessor can output different + * formats, the first printing one line in the statistics file + * per nonlinear solver iteration (if a nonlinear solver scheme + * is selected). The second prints one line per timestep, + * summing the information about all nonlinear iterations in + * this line. Note that this postprocessor is always active + * independent on whether or not it is selected in the + * parameter file. + * + * @ingroup Postprocessing + */ + template + class GlobalStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Connect the callback functions to the respective signals. + */ + void initialize() override; + + /** + * Write all global statistics columns into the statistics object. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + + private: + /** + * Write global statistics such as the time step number and the + * number of degrees of freedom into the statistics object. + */ + void + generate_global_statistics(TableHandler &statistics); + + /** + * This function clears all the saved solver information that is + * stored in this class. It is executed every time the output is + * written into the statistics object, but also after each initial + * refinement step, in case it is not written (to avoid summing + * information across different refinement steps). + */ + void + clear_data(); + + /** + * Callback function that is connected to the post_stokes_solver + * signal to store the solver history. + */ + void + store_stokes_solver_history(const unsigned int number_S_iterations, + const unsigned int number_A_iterations, + const SolverControl &solver_control_cheap, + const SolverControl &solver_control_expensive); + + /** + * Callback function that is connected to the post_advection_solver + * signal to store the solver history. + */ + void + store_advection_solver_history(const bool solved_temperature_field, + const unsigned int compositional_index, + const SolverControl &solver_control); + + /** + * Variables that store the Stokes solver history of the current + * timestep, until they are written into the statistics object + * upon the call to execute(). They are cleared after writing + * the content. + */ + std::vector list_of_S_iterations; + std::vector list_of_A_iterations; + std::vector stokes_iterations_cheap; + std::vector stokes_iterations_expensive; + + /** + * A container that stores the advection solver history of the current + * timestep, until it is written into the statistics object + * upon the call to execute(). It is cleared after writing + * the content. The vector contains pairs, which consist + * of a column name (for the temperature or one of the + * compositional fields), and a vector of SolverControl + * objects (one per nonlinear iteration for this particular + * field). This layout allows storing varying numbers of + * nonlinear iterations for temperature and compositional fields + * (if any nonlinear solver scheme would implement that at + * some point). + */ + std::vector>> advection_iterations; + + /** + * Whether to put every nonlinear iteration into a separate + * line in the statistics file or to only output one line + * per time step. + */ + bool one_line_per_iteration; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/gravity_point_values.h.bak b/include/aspect/postprocess/gravity_point_values.h.bak new file mode 100644 index 00000000000..463a30adeb3 --- /dev/null +++ b/include/aspect/postprocess/gravity_point_values.h.bak @@ -0,0 +1,291 @@ +/* + Copyright (C) 2018 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_gravity_point_values_h +#define _aspect_postprocess_gravity_point_values_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes gravity, gravity anomalies, gravity potential and + * gravity gradients for a set of points (e.g. satellites) in or above the model + * surface for a user-defined range of latitudes, longitudes and radius, or a list + * of point coordinates. Spherical coordinates in the output file are radius, + * colatitude and colongitude. Gravity is here based on the density distribution + * from the material model (and non adiabatic). This means that the density may + * come directly from an ascii file. This postprocessor also computes theoretical + * gravity and its derivatives, which corresponds to the analytical solution of gravity + * in the same geometry but filled with a reference density. The reference density + * is also used to determine the density difference for computing gravity anomalies. + * Thus one must carefully evaluate the meaning of the gravity anomaly output, + * because the solution may not reflect the actual gravity anomaly (due to + * differences in the assumed reference density). One way to guarantee correct + * gravity anomalies is to subtract the gravity of a certain point from the average + * gravity on the map. Another way is to directly use density anomalies for this + * postprocessor. + * The average- minimum- and maximum gravity acceleration and potential are written + * into the statistics file. + * + * @ingroup Postprocessing + */ + template + class GravityPointValues : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + GravityPointValues (); + + /** + * @copydoc Interface::initialize(). + */ + void initialize() override; + + /** + * Specify the creation of output_gravity.txt. + */ + std::pair execute (TableHandler &) override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Serialize the contents of this class as far as they are not read + * from input parameter files. + */ + template + void serialize (Archive &ar, const unsigned int version); + + /** + * Save the state of this object. + */ + void save (std::map &status_strings) const override; + + /** + * Restore the state of the object. + */ + void load (const std::map &status_strings) override; + + private: + /** + * Interval between the generation of gravity output. + */ + double output_interval; + + /** + * A time (in seconds) at which the last graphical output was supposed + * to be produced. Used to check for the next necessary output time. + */ + double last_output_time; + + /** + * Maximum number of steps between the generation of gravity output. + */ + unsigned int maximum_timesteps_between_outputs; + + /** + * Timestep at which the last gravity output was produced + * Used to check for the next necessary output time. + */ + unsigned int last_output_timestep; + + /** + * Consecutively counted number indicating the how-manyth time we will + * create output the next time we get to it. + */ + unsigned int output_file_number; + + /** + * end_time is taken from parameter file. It is used to tell the + * postprocessor to write gravity output at the end time. + */ + double end_time; + + /** + * Set the time output was supposed to be written. In the simplest + * case, this is the previous last output time plus the interval, but + * in general we'd like to ensure that it is the largest supposed + * output time, which is smaller than the current time, to avoid + * falling behind with last_output_time and having to catch up once + * the time step becomes larger. This is done after every output. + */ + void set_last_output_time (const double current_time); + + /** + * Set the precision of the gravity acceleration, potential and gradients + * in the gravity output and statistics file. + */ + unsigned int precision; + + /** + * Quadrature degree increase over the velocity element degree may be required when + * gravity is calculated near the surface or inside the model. An increase in the + * quadrature element adds accuracy to the gravity solution from noise due to the + * model grid. + */ + unsigned int quadrature_degree_increase; + + /** + * Parameter for the fibonacci spiral sampling scheme: + */ + unsigned int n_points_spiral; + + /** + * Parameter for the map and fibonacci spiral sampling scheme: + * Gravity may be calculated for a sets of points along the radius (e.g. depth + * profile) between a minimum and maximum radius. Number of points along the radius + * is specified with n_points_radius. + */ + unsigned int n_points_radius; + + /** + * Parameter for the map sampling scheme: + * Gravity may be calculated for a sets of points along the longitude (e.g. satellite + * mapping) between a minimum and maximum longitude. Number of points along the + * longitude is specified with n_points_longitude. + */ + unsigned int n_points_longitude; + + /** + * Parameter for the map sampling scheme: + * Gravity may be calculated for a sets of points along the latitude (e.g. satellite + * mapping) between a minimum and maximum latitude. Number of points along the + * latitude is specified with n_points_latitude. + */ + unsigned int n_points_latitude; + + /** + * Parameter for the map and fibonacci spiral sampling scheme: + * Prescribe a minimum radius for a sampling coverage at a specific height. + * May be set in- or outside the model domain. + */ + double minimum_radius; + + /** + * Parameter for the map and fibonacci spiral sampling scheme: + * Maximum radius for the radius range. + * May be set in- or outside the model domain. + * No need to specify maximum_radius if n_points_radius is 1. + */ + double maximum_radius; + + /** + * Parameter for the map sampling scheme: + * Minimum longitude for longitude range. + */ + double minimum_colongitude; + + /** + * Parameter for the map sampling scheme: + * Maximum longitude for the longitude range. + * No need to specify maximum_longitude if n_points_longitude is 1. + */ + double maximum_colongitude; + + /** + * Parameter for the map sampling scheme: + * Minimum latitude for the latitude range. + */ + double minimum_colatitude; + + /** + * Parameter for the map sampling scheme: + * Maximum latitude for the latitude range. + * No need to specify maximum_latitude if n_points_latitude is 1. + */ + double maximum_colatitude; + + /** + * A reference density is required for two purposes: + * 1) benchmark the gravity postprocessor with computing analytically gravity + * acceleration and gradients in the domain filled with a constant density. + * 2) calculate the density difference of the density given by the material + * model and a constant density, in order to compute gravity anomalies. + */ + double reference_density; + + /** + * Specify the sampling scheme determining if gravity calculation is performed. + */ + enum SamplingScheme + { + map, + fibonacci_spiral, + list_of_points + } sampling_scheme; + + /** + * Parameter for the list of points sampling scheme: + * List of radius coordinates for the list of points sampling scheme. + * Must follow the same order as the lists of longitude and latitude. + */ + std::vector radius_list; + + /** + * Parameter for the list of points sampling scheme: + * List of longitude coordinates for the list of points sampling scheme. + * Must follow the same order as the lists of radius and latitude. + */ + std::vector longitude_list; + + /** + * Parameter for the list of points sampling scheme: + * List of latitude coordinates for the list of points sampling scheme. + * Must follow the same order as the lists of longitude and longitude. + */ + std::vector latitude_list; + + // ------------ the following variables are not set from parameters, + // but are instead computed up front from input + // parameters and other parts of the overall model + double model_outer_radius; + double model_inner_radius; + + /** + * The positions of all satellite positions in spherical and + * Cartesian coordinate systems. + */ + std::vector> satellite_positions_spherical; + std::vector> satellite_positions_cartesian; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/heat_flux_densities.h.bak b/include/aspect/postprocess/heat_flux_densities.h.bak new file mode 100644 index 00000000000..4167c75b2fa --- /dev/null +++ b/include/aspect/postprocess/heat_flux_densities.h.bak @@ -0,0 +1,54 @@ +/* + Copyright (C) 2016 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_heat_flux_densities_h +#define _aspect_postprocess_heat_flux_densities_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes average heat flux densities for each + * boundary. + * + * @ingroup Postprocessing + */ + template + class HeatFluxDensities : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/heat_flux_map.h.bak b/include/aspect/postprocess/heat_flux_map.h.bak new file mode 100644 index 00000000000..84477eddbbb --- /dev/null +++ b/include/aspect/postprocess/heat_flux_map.h.bak @@ -0,0 +1,109 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_heat_flux_map_h +#define _aspect_postprocess_heat_flux_map_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace internal + { + /** + * Compute the heat flux for boundaries with prescribed temperature (Dirichlet + * boundary conditions) using the consistent boundary flux method. The method + * is described in + * + * Gresho, P. M., Lee, R. L., Sani, R. L., Maslanik, M. K., & Eaton, B. E. (1987). + * The consistent Galerkin FEM for computing derived boundary quantities in thermal and or fluids + * problems. International Journal for Numerical Methods in Fluids, 7(4), 371-394. + * + * In summary, the method solves the temperature equation again on the boundary faces, with known + * temperatures and solving for the boundary fluxes that satisfy the equation. Since the + * equation is only formed on the faces and it can be solved using only diagonal matrices, + * the computation is cheap. Conceptually simpler methods like evaluating the temperature + * gradient on the face are significantly less accurate. + * + * The function returns a solution vector, which contains the heat flux in the temperature + * block of the vector. + */ + template + LinearAlgebra::BlockVector + compute_dirichlet_boundary_heat_flux_solution_vector (const SimulatorAccess &simulator_access); + + /** + * This function computes the combined heat flux through each boundary face (conductive + advective). + * For reflecting boundaries the conductive heat flux is 0, for boundaries with prescribed heat flux + * (inhomogeneous Neumann boundary conditions) it is simply the integral of the prescribed heat flux over + * the face, and for boundaries with non-tangential velocities the advective heat flux is computed as + * the integral over the advective heat flux density. + * For boundaries with prescribed temperature (Dirichlet boundary conditions) the heat flux + * is computed using the compute_dirichlet_boundary_heat_flux_solution_vector() function. + * + * The function returns a vector with as many entries as active cells. For each locally owned + * cell it contains a vector with one entry per face. Each of these entries contains a pair + * of doubles, containing the combined heat flux (first entry) and face area (second entry). + * This function is a helper function that unifies the complex heat flux computation necessary + * for several postprocessors. + */ + template + std::vector>> + compute_heat_flux_through_boundary_faces (const SimulatorAccess &simulator_access); + } + + /** + * A postprocessor that computes the point-wise heat flux density through the boundaries. + * + * @ingroup Postprocessing + */ + template + class HeatFluxMap : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for the heat flux. + */ + std::pair + execute (TableHandler &statistics) override; + + private: + /** + * Output the heat flux density for the boundary determined + * by @p boundary_id to a file. The heat flux density is + * handed over in the vector @p heat_flux_and_area. This vector + * is expected to be of the structure described for the return value + * of the function compute_heat_flux_through_boundary_faces() and + * only the values at the faces of the given @p boundary_id are + * written to the file. + */ + void output_to_file(const types::boundary_id boundary_id, + const std::vector>> &heat_flux_and_area); + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/heat_flux_statistics.h.bak b/include/aspect/postprocess/heat_flux_statistics.h.bak new file mode 100644 index 00000000000..fb9e7ee6983 --- /dev/null +++ b/include/aspect/postprocess/heat_flux_statistics.h.bak @@ -0,0 +1,53 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_heat_flux_statistics_h +#define _aspect_postprocess_heat_flux_statistics_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the heat_flux. + * + * @ingroup Postprocessing + */ + template + class HeatFluxStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some heat_flux statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/heating_statistics.h.bak b/include/aspect/postprocess/heating_statistics.h.bak new file mode 100644 index 00000000000..77fa48fd012 --- /dev/null +++ b/include/aspect/postprocess/heating_statistics.h.bak @@ -0,0 +1,56 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_postprocess_heating_statistics_h +#define _aspect_postprocess_heating_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the + * heating rate. This includes all of the heating processes + * specified in the parameter file, i.e. shear heating, + * adiabatic heating and radiogenic heat production. + * + * @ingroup Postprocessing + */ + template + class HeatingStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some heating rate statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/interface.h.bak b/include/aspect/postprocess/interface.h.bak new file mode 100644 index 00000000000..623d4facf62 --- /dev/null +++ b/include/aspect/postprocess/interface.h.bak @@ -0,0 +1,380 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_interface_h +#define _aspect_postprocess_interface_h + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + + +namespace aspect +{ + using namespace dealii; + + template class Simulator; + template class SimulatorAccess; + + + /** + * A namespace for everything to do with postprocessing solutions every time + * step or every few time steps. + * + * @ingroup Postprocessing + */ + namespace Postprocess + { + + /** + * This class declares the public interface of postprocessors. + * Postprocessors must implement a function that can be called at the end + * of each time step to evaluate the current solution, as well as + * functions that save the state of the object and restore it (for + * checkpoint/restart capabilities). + * + * Access to the data of the simulator is granted by the @p protected + * member functions of the SimulatorAccess class, i.e., classes + * implementing this interface will in general want to derive from both + * this Interface class as well as from the SimulatorAccess class. + * + * @ingroup Postprocessing + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Execute this postprocessor. Derived classes will implement this + * function to do whatever they want to do to evaluate the solution at + * the current time step. + * + * @param[in,out] statistics An object that contains statistics that + * are collected throughout the simulation and that will be written to + * an output file at the end of each time step. Postprocessors may + * deposit data in these tables for later visualization or further + * processing. + * + * @return A pair of strings that will be printed to the screen after + * running the postprocessor in two columns; typically the first + * column contains a description of what the data is and the second + * contains a numerical value of this data. If there is nothing to + * print, simply return two empty strings. + */ + virtual + std::pair + execute (TableHandler &statistics) = 0; + + /** + * A function that is used to indicate to the postprocessor manager which + * other postprocessor(s) the current one depends upon. The returned + * list contains the names (as strings, as you would write them in + * the input file) of the postprocessors it requires. The manager + * will ensure that these postprocessors are indeed used, even if + * they were not explicitly listed in the input file, and are indeed + * run before this postprocessor every time they are executed. + * + * The default implementation of this function returns an empty list. + * + * @note This mechanism is intended to support postprocessors that + * do not want to recompute information that other postprocessors + * already compute (or could compute, if they were run -- which + * we can ensure using the current function). To do so, a postprocessor + * of course needs to be able to access these other postprocessors. + * This can be done by deriving your postprocessor from + * SimulatorAccess, and then using the + * SimulatorAccess::get_postprocess_manager::get_matching_postprocessor + * function. + */ + virtual + std::list + required_other_postprocessors () const; + + /** + * Save the state of this object to the argument given to this + * function. This function is in support of checkpoint/restart + * functionality. + * + * Derived classes can implement this function and should store their + * state in a string that is deposited under a key in the map through + * which the respective class can later find the status again when the + * program is restarted. A legitimate key to store data under is + * typeid(*this).name(). It is up to derived classes to + * decide how they want to encode their state. + * + * The default implementation of this function does nothing, i.e., it + * represents a stateless object for which nothing needs to be stored + * at checkpoint time and nothing needs to be restored at restart + * time. + * + * @param[in,out] status_strings The object into which implementations + * in derived classes can place their status under a key that they can + * use to retrieve the data. + */ + virtual + void save (std::map &status_strings) const; + + /** + * Restore the state of the object by looking up a description of the + * state in the passed argument under the same key under which it was + * previously stored. + * + * The default implementation does nothing. + * + * @param[in] status_strings The object from which the status will be + * restored by looking up the value for a key specific to this derived + * class. + */ + virtual + void load (const std::map &status_strings); + }; + + + + + + + /** + * A class that manages all objects that provide functionality to + * postprocess solutions. It declares run time parameters for input files, + * reads their values from such an input file, manages a list of all + * postprocessors selected in the input file, and upon request through the + * execute() function calls them in turn. + * + * @ingroup Postprocessing + */ + template + class Manager : public Plugins::ManagerBase>, public SimulatorAccess + { + public: + /** + * Execute all of the postprocessor objects that have been requested + * in the input file. These objects also fill the contents of the + * statistics object. + * + * The function returns a concatenation of the text returned by the + * individual postprocessors. + */ + std::list> + execute (TableHandler &statistics); + + /** + * Go through the list of all postprocessors that have been selected + * in the input file (and are consequently currently active) and return + * true if one of them has the desired type specified by the template + * argument. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,PostprocessorType>::value>> + bool + has_matching_postprocessor () const; + + /** + * Go through the list of all postprocessors that have been selected + * in the input file (and are consequently currently active) and see + * if one of them has the type specified by the template + * argument or can be cast to that type. If so, return a reference + * to it. If no postprocessor is active that matches the given type, + * throw an exception. + * + * This function can only be called if the given template type (the first template + * argument) is a class derived from the Interface class in this namespace. + */ + template ,PostprocessorType>::value>> + const PostprocessorType & + get_matching_postprocessor () const; + + /** + * Declare the parameters of all known postprocessors, as well as of + * ones this class has itself. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * This determines which postprocessor objects will be created; then + * let these objects read their parameters as well. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Write the data of this object to a stream for the purpose of + * serialization. + */ + template + void save (Archive &ar, + const unsigned int version) const; + + /** + * Read the data of this object from a stream for the purpose of + * serialization. + */ + template + void load (Archive &ar, + const unsigned int version); + + BOOST_SERIALIZATION_SPLIT_MEMBER() + + + /** + * A function that is used to register postprocessor objects in such a + * way that the Manager can deal with all of them without having to + * know them by name. This allows the files in which individual + * postprocessors are implement to register these postprocessors, + * rather than also having to modify the Manager class by adding the + * new postprocessor class. + * + * @param name The name under which this postprocessor is to be called + * in parameter files. + * @param description A text description of what this model does and + * that will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that + * declares the parameters for this postprocessor. + * @param factory_function A pointer to a function that creates such a + * postprocessor object and returns a pointer to it. + */ + static + void + register_postprocessor (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + /** + * Exception. + */ + DeclException1 (ExcPostprocessorNameNotFound, + std::string, + << "Could not find entry <" + << arg1 + << "> among the names of registered postprocessors."); + }; + + + /* -------------------------- inline and template functions ---------------------- */ + + template + template + void Manager::save (Archive &ar, + const unsigned int) const + { + // let all the postprocessors save their data in a map and then + // serialize that + std::map saved_text; + for (const auto &p : this->plugin_objects) + p->save (saved_text); + + ar &saved_text; + } + + + template + template + void Manager::load (Archive &ar, + const unsigned int) + { + // get the map back out of the stream; then let the postprocessors + // that we currently have get their data from there. note that this + // may not be the same set of postprocessors we had when we saved + // their data + std::map saved_text; + ar &saved_text; + + for (auto &p : this->plugin_objects) + p->load (saved_text); + } + + + + template + template + inline + bool + Manager::has_matching_postprocessor () const + { + return this->template has_matching_plugin_object(); + } + + + + template + template + inline + const PostprocessorType & + Manager::get_matching_postprocessor () const + { + return this->template get_matching_plugin_object(); + } + + + /** + * Given a class name, a name, and a description for the parameter file + * for a postprocessor, register it with the aspect::Postprocess::Manager + * class. + * + * @ingroup Postprocessing + */ +#define ASPECT_REGISTER_POSTPROCESSOR(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_POSTPROCESSOR_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::Postprocess::Manager<2>::register_postprocessor, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::Postprocess::Manager<3>::register_postprocessor, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/postprocess/load_balance_statistics.h.bak b/include/aspect/postprocess/load_balance_statistics.h.bak new file mode 100644 index 00000000000..43ff120abd5 --- /dev/null +++ b/include/aspect/postprocess/load_balance_statistics.h.bak @@ -0,0 +1,66 @@ +/* + Copyright (C) 2016 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_postprocess_load_balance_statistics_h +#define _aspect_postprocess_load_balance_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes statistics about + * the distribution of cells, and if present particles + * across subdomains. + * + * In particular, it computes maximal, average and + * minimal number of cells across all ranks. + * If there are particles it also computes the + * maximal, average, and minimum number of particles across + * all ranks, and maximal, average, and minimal ratio + * between local number of particles and local number + * of cells across all processes. All of these numbers + * can be useful to assess the load balance between + * different MPI ranks, as the difference between the + * minimal and maximal load should be as small as + * possible. + * + * @ingroup Postprocessing + */ + template + class LoadBalanceStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Compute load balance statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/mass_flux_statistics.h.bak b/include/aspect/postprocess/mass_flux_statistics.h.bak new file mode 100644 index 00000000000..a0c7a1cb18f --- /dev/null +++ b/include/aspect/postprocess/mass_flux_statistics.h.bak @@ -0,0 +1,54 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_mass_flux_statistics_h +#define _aspect_postprocess_mass_flux_statistics_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the material_flux + * in and out of boundaries. + * + * @ingroup Postprocessing + */ + template + class MassFluxStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some mass_flux statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/material_statistics.h.bak b/include/aspect/postprocess/material_statistics.h.bak new file mode 100644 index 00000000000..b63d214d5a5 --- /dev/null +++ b/include/aspect/postprocess/material_statistics.h.bak @@ -0,0 +1,54 @@ +/* + Copyright (C) 2018 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_material_statistics_h +#define _aspect_postprocess_material_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the + * material properties, in particular average density, + * average viscosity and total mass. + * + * @ingroup Postprocessing + */ + template + class MaterialStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some material property statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/matrix_statistics.h.bak b/include/aspect/postprocess/matrix_statistics.h.bak new file mode 100644 index 00000000000..d317c00f87f --- /dev/null +++ b/include/aspect/postprocess/matrix_statistics.h.bak @@ -0,0 +1,52 @@ +/* + Copyright (C) 2016 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_matrix_statistics_h +#define _aspect_postprocess_matrix_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the matrices + * + * @ingroup Postprocessing + */ + template + class MatrixStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Compute matrix statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/max_depth_field.h.bak b/include/aspect/postprocess/max_depth_field.h.bak new file mode 100644 index 00000000000..07b6808a879 --- /dev/null +++ b/include/aspect/postprocess/max_depth_field.h.bak @@ -0,0 +1,52 @@ +/* + Copyright (C) 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_postprocess_max_depth_field_h +#define _aspect_postprocess_max_depth_field_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + /** + * A postprocessor that computes the deepest point of the given composition. + * + * @ingroup Postprocessing + */ + template + class MaxDepthField : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for the biggest depth of the + * compositional field indicated by the user. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/melt_statistics.h.bak b/include/aspect/postprocess/melt_statistics.h.bak new file mode 100644 index 00000000000..dd1daf88da4 --- /dev/null +++ b/include/aspect/postprocess/melt_statistics.h.bak @@ -0,0 +1,57 @@ +/* + Copyright (C) 2015 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_postprocess_melt_statistics_h +#define _aspect_postprocess_melt_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the + * melt fraction. This only works for material models that + * are derived from MaterialModel::MeltFractionModel and + * implement their own + * MaterialModel::MeltFractionModel::melt_fraction function. + * + * @ingroup Postprocessing + */ + template + class MeltStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the melt fraction in the material model. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/memory_statistics.h.bak b/include/aspect/postprocess/memory_statistics.h.bak new file mode 100644 index 00000000000..f3f62f48dea --- /dev/null +++ b/include/aspect/postprocess/memory_statistics.h.bak @@ -0,0 +1,68 @@ +/* + Copyright (C) 2016 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#ifndef _aspect_postprocess_memory_statistics_h +#define _aspect_postprocess_memory_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the memory consumption. + * + * @ingroup Postprocessing + */ + template + class MemoryStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Calculate some statistics about the memory. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + bool output_vmpeak; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/mobility_statistics.h.bak b/include/aspect/postprocess/mobility_statistics.h.bak new file mode 100644 index 00000000000..d6ff4e11598 --- /dev/null +++ b/include/aspect/postprocess/mobility_statistics.h.bak @@ -0,0 +1,52 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_mobility_statistics_h +#define _aspect_postprocess_mobility_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about mobility following Tackley (2000) and Lourenco et al. (2020) + * + * @ingroup Postprocessing + */ + template + class MobilityStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some mobility statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/particle_count_statistics.h.bak b/include/aspect/postprocess/particle_count_statistics.h.bak new file mode 100644 index 00000000000..7b5dd94c9d5 --- /dev/null +++ b/include/aspect/postprocess/particle_count_statistics.h.bak @@ -0,0 +1,60 @@ +/* + Copyright (C) 2016 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_particle_count_statistics_h +#define _aspect_postprocess_particle_count_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the distribution + * of particles, if possible. + * + * @ingroup Postprocessing + */ + template + class ParticleCountStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some particle statistics. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Let the postprocessor manager know about the other postprocessors + * this one depends on. Specifically, the particles postprocessor. + */ + std::list + required_other_postprocessors() const override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/particles.h.bak b/include/aspect/postprocess/particles.h.bak new file mode 100644 index 00000000000..3a05da0d581 --- /dev/null +++ b/include/aspect/postprocess/particles.h.bak @@ -0,0 +1,319 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#ifndef _aspect_postprocess_particle_h +#define _aspect_postprocess_particle_h + +#include + +#include +#include + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace internal + { + /** + * This class is responsible for writing the particle data into a format that can + * be written by deal.II, in particular a list of 'patches' that contain one + * particle per patch. The base class DataOutInterface is templated with a + * dimension of zero (the dimension of the particle / point), and a space dimension + * of dim (the dimension in which this zero-dimensional particle lives). + */ + template + class ParticleOutput : public dealii::DataOutInterface<0,dim> + { + public: + /** + * This function prepares the data for writing. It reads the data from @p particle_handler and their + * property information from @p property_information, and builds a list of patches that is stored + * internally until the destructor is called. This function needs to be called before one of the + * write function of the base class can be called to write the output data. + */ + void build_patches(const Particles::ParticleHandler &particle_handler, + const aspect::Particle::Property::ParticlePropertyInformation &property_information, + const std::vector &exclude_output_properties, + const bool only_group_3d_vectors); + + private: + /** + * Implementation of the corresponding function of the base class. + */ + const std::vector> & + get_patches () const override; + + /** + * Implementation of the corresponding function of the base class. + */ + std::vector + get_dataset_names () const override; + + /** + * Implementation of the corresponding function of the base class. + */ + std::vector< + std::tuple> + get_nonscalar_data_ranges () const override; + + /** + * Output information that is filled by build_patches() and + * written by the write function of the base class. + */ + std::vector> patches; + + /** + * A list of field names for all data components stored in patches. + */ + std::vector dataset_names; + + /** + * Store which of the data fields are vectors. + */ + std::vector< + std::tuple> + vector_datasets; + }; + } + + /** + * A Postprocessor that creates particles, which follow the + * velocity field of the simulation. The particles can be generated + * and propagated in various ways and they can carry a number of + * constant or time-varying properties. The postprocessor can write + * output positions and properties of all particles at chosen intervals, + * although this is not mandatory. It also allows other parts of the + * code to query the particles for information. + */ + template + class Particles : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + Particles(); + + /** + * Destructor. + */ + ~Particles() override; + + /** + * Execute this postprocessor. Derived classes will implement this + * function to do whatever they want to do to evaluate the solution at + * the current time step. + * + * @param[in,out] statistics An object that contains statistics that + * are collected throughout the simulation and that will be written to + * an output file at the end of each time step. Postprocessors may + * deposit data in these tables for later visualization or further + * processing. + * + * @return A pair of strings that will be printed to the screen after + * running the postprocessor in two columns; typically the first + * column contains a description of what the data is and the second + * contains a numerical value of this data. If there is nothing to + * print, simply return two empty strings. + */ + std::pair execute (TableHandler &statistics) override; + + /** + * Save the state of this object. + */ + void save (std::map &status_strings) const override; + + /** + * Restore the state of the object. + */ + void load (const std::map &status_strings) override; + + /** + * Serialize the contents of this class as far as they are not read + * from input parameter files. + */ + template + void serialize (Archive &ar, const unsigned int version); + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Interval between output (in years if appropriate simulation + * parameter is set, otherwise seconds) + */ + double output_interval; + + /** + * Records time for next output to occur + */ + double last_output_time; + + /** + * Set the time output was supposed to be written. In the simplest + * case, this is the previous last output time plus the interval, but + * in general we'd like to ensure that it is the largest supposed + * output time, which is smaller than the current time, to avoid + * falling behind with last_output_time and having to catch up once + * the time step becomes larger. This is done after every output. + */ + void set_last_output_time (const double current_time); + + /** + * Consecutively counted number indicating the how-manyth time we will + * create output the next time we get to it. + */ + unsigned int output_file_number; + + /** + * Graphical output format. + */ + std::vector output_formats; + + /** + * A list of pairs (time, pvtu_filename) that have so far been written + * and that we will pass to DataOutInterface::write_pvd_record + * to create a description file that can make the association + * between simulation time and corresponding file name (this + * is done because there is no way to store the simulation + * time inside the .pvtu or .vtu files). + */ + std::vector> times_and_pvtu_file_names; + + /** + * A corresponding variable that we use for the .visit files created + * by DataOutInterface::write_visit_record. The second part of a + * pair contains all files that together form a time step. + */ + std::vector>> times_and_vtu_file_names; + + /** + * A list of list of filenames, sorted by timestep, that correspond to + * what has been created as output. This is used to create a descriptive + * .visit file for the entire simulation. + */ + std::vector> output_file_names_by_timestep; + + /** + * A set of data related to XDMF file sections describing the HDF5 + * heavy data files created. These contain things such as the + * dimensions and names of data written at all steps during the + * simulation. + */ + std::vector xdmf_entries; + + /** + * VTU file output supports grouping files from several CPUs into one + * file using MPI I/O when writing on a parallel filesystem. 0 means + * no grouping (and no parallel I/O). 1 will generate one big file + * containing the whole solution. + */ + unsigned int group_files; + + /** + * On large clusters it can be advantageous to first write the + * output to a temporary file on a local file system and later + * move this file to a network file system. If this variable is + * set to a non-empty string it will be interpreted as a temporary + * storage location. + */ + std::string temporary_output_location; + + /** + * File operations can potentially take a long time, blocking the + * progress of the rest of the model run. Setting this variable to + * 'true' moves this process into a background thread, while the + * rest of the model continues. + */ + bool write_in_background_thread; + + /** + * Handle to a thread that is used to write data in the background. + * The writer() function runs on this background thread. + */ + std::thread background_thread; + + /** + * Stores the particle property fields which are excluded from output + * to the visualization file. + */ + std::vector exclude_output_properties; + + /** + * A function that writes the text in the second argument to a file + * with the name given in the first argument. The function is run on a + * separate thread to allow computations to continue even though + * writing data is still continuing. The function takes over ownership + * of these arguments and deletes them at the end of its work. + */ + static + void writer (const std::string &filename, + const std::string &temporary_filename, + const std::string &file_contents); + + /** + * Write the various descriptive record files. These files are used by + * visualization programs to identify which of the output files in a + * directory, possibly one file written by each processor, belong to a + * single time step and/or form the different time steps of a + * simulation. For Paraview, this is a .pvtu file per + * time step and a .pvd for all time steps. For VisIt it + * is a .visit file per time step and one for all time + * steps. + * + * @param data_out The DataOut object that was used to write the + * solutions. + * @param solution_file_prefix The stem of the filename to be written. + * @param filenames List of filenames for the current output from all + * processors. + */ + void write_description_files (const internal::ParticleOutput &data_out, + const std::string &solution_file_prefix, + const std::vector &filenames); + }; + } +} + +#endif diff --git a/include/aspect/postprocess/point_values.h.bak b/include/aspect/postprocess/point_values.h.bak new file mode 100644 index 00000000000..61b61fc887a --- /dev/null +++ b/include/aspect/postprocess/point_values.h.bak @@ -0,0 +1,128 @@ +/* + Copyright (C) 2016 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_point_values_h +#define _aspect_postprocess_point_values_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that evaluates the solution vector at individual + * points. + * + * @ingroup Postprocessing + */ + template + class PointValues : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor + */ + PointValues (); + + /** + * Evaluate the solution and determine the values at the + * selected points. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Save the state of this object. + */ + void save (std::map &status_strings) const override; + + /** + * Restore the state of the object. + */ + void load (const std::map &status_strings) override; + + /** + * Serialize the contents of this class as far as they are not read + * from input parameter files. + */ + template + void serialize (Archive &ar, const unsigned int version); + + private: + /** + * Set the time output was supposed to be written. In the simplest + * case, this is the previous last output time plus the interval, but + * in general we'd like to ensure that it is the largest supposed + * output time, which is smaller than the current time, to avoid + * falling behind with last_output_time and having to catch up once + * the time step becomes larger. This is done after every output. + */ + void set_last_output_time (const double current_time); + + /** + * Interval between the generation of output in seconds. + */ + double output_interval; + + /** + * A time (in seconds) the last output has been produced. + */ + double last_output_time; + + /** + * Vector of Points representing the points where the solution is to be evaluated + * that can be used by VectorTools. + */ + std::vector> evaluation_points_cartesian; + /** + * The values of the solution at the evaluation points. + */ + std::vector>>> point_values; + /** + * Whether or not to interpret the evaluation points in the input file + * as natural coordinates or not. + */ + bool use_natural_coordinates; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/pressure_statistics.h.bak b/include/aspect/postprocess/pressure_statistics.h.bak new file mode 100644 index 00000000000..b05c892ffc3 --- /dev/null +++ b/include/aspect/postprocess/pressure_statistics.h.bak @@ -0,0 +1,52 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_pressure_statistics_h +#define _aspect_postprocess_pressure_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the pressure. + * + * @ingroup Postprocessing + */ + template + class PressureStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some pressure statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/rotation_statistics.h.bak b/include/aspect/postprocess/rotation_statistics.h.bak new file mode 100644 index 00000000000..031fc0e30ea --- /dev/null +++ b/include/aspect/postprocess/rotation_statistics.h.bak @@ -0,0 +1,85 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_rotation_statistics_h +#define _aspect_postprocess_rotation_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the rotational + * velocity of the model (i.e. integrated net rotation and angular momentum). + * + * @ingroup Postprocessing + */ + template + class RotationStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some velocity statistics. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Whether to use a constant density of one for the computation of the + * angular momentum and moment of inertia. This is an approximation + * that assumes that the 'volumetric' rotation is equal to the 'mass' + * rotation. If this parameter is true this postprocessor computes + * 'net rotation' instead of 'angular momentum'. + */ + bool use_constant_density; + + /** + * Whether to write the full moment of inertia tensor into the + * statistics output instead of its norm for the current rotation + * axis. This is a second-order symmetric tensor with + * 6 components in 3D. In 2D this option has no effect, because + * the rotation axis is fixed and thus it is always a scalar. + */ + bool output_full_tensor; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/sea_level.h.bak b/include/aspect/postprocess/sea_level.h.bak new file mode 100644 index 00000000000..4efe24fbc48 --- /dev/null +++ b/include/aspect/postprocess/sea_level.h.bak @@ -0,0 +1,178 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_sea_level_h +#define _aspect_postprocess_sea_level_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that outputs the sea level to file. The sea level is based + * on the ice heights input data, the solid Earth topography input data for + * defining the ocean basin, the geoid displacement from the geoid postprocessor, + * and the free surface topography from the geometry model. The sea level + * postprocessor requires a 3D spherical shell geometry with a free surface. + * The sea level computation is based on \\cite{Martinec2018}. + * + * @ingroup Postprocessing + */ + template + class SeaLevel : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Sets up structured data lookup for topography and ice height input data. + */ + void initialize() override; + + /** + * Output non-uniform sea level change [m] to file. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Evaluate the total surface pressure from ice and water loading at + * a point at the top surface of the domain. While the function will + * return pressure values for any location, it will always assume the + * volume between the point and the sea level is filled with water or ice, + * therefore calling this function for positions inside the domain will result + * in unrealistic pressure values. + */ + double + compute_total_surface_pressure(const Point &position) const; + + /** + * Register with the simulator the other postprocessors that we need + * (namely: geoid). + */ + std::list + required_other_postprocessors() const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Save the state of this object. + */ + void save (std::map &status_strings) const override; + + /** + * Restore the state of the object. + */ + void load (const std::map &status_strings) override; + + /** + * Serialize the contents of this class as far as they are not read + * from input parameter files. + */ + template + void serialize (Archive &ar, const unsigned int version); + + private: + /** + * Function to determine non-uniform sea level change for any given location. + * This is a local computation that makes use of the computed sea level offset, + * so make sure to call compute_sea_level_offset() before calling this function. + */ + double + compute_nonuniform_sea_level_change(const Point &position) const; + + /** + * Function to determine the global sea level offset. + */ + double + compute_sea_level_offset(); + + /** + * Information about the location of topography data files. + */ + std::string data_directory_topography; + std::string data_file_name_topography; + + /** + * Information about the location of ice height data files. + */ + std::string data_directory_ice_height; + std::string data_file_name_ice_height; + + /** + * Pointer to the StructuredDataLookup object that holds the topography and ice height data. + */ + std::unique_ptr> topography_lookup; + std::unique_ptr> ice_height_lookup; + + /** + * The density of water. + */ + double density_water; + + /** + * The density of ice. + */ + double density_ice; + + /** + * The global sea level offset. + */ + double sea_level_offset; + + /** + * Whether or not to produce text files with sea level values. + */ + bool write_to_file; + + /** + * Interval between the generation of text output. This parameter + * is read from the input file and consequently is not part of the + * state that needs to be saved and restored. + */ + double output_interval; + + /** + * A time (in seconds) at which the last text output was supposed + * to be produced. Used to check for the next necessary output time. + */ + double last_output_time; + + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/spherical_velocity_statistics.h.bak b/include/aspect/postprocess/spherical_velocity_statistics.h.bak new file mode 100644 index 00000000000..16fa2efb7ac --- /dev/null +++ b/include/aspect/postprocess/spherical_velocity_statistics.h.bak @@ -0,0 +1,54 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_postprocess_spherical_velocity_statistics_h +#define _aspect_postprocess_spherical_velocity_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the radial and + * tangential components of the velocity in spherical/cylindrical models. + * + * @ingroup Postprocessing + */ + template + class SphericalVelocityStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some velocity statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/stokes_residual.h.bak b/include/aspect/postprocess/stokes_residual.h.bak new file mode 100644 index 00000000000..3890824e104 --- /dev/null +++ b/include/aspect/postprocess/stokes_residual.h.bak @@ -0,0 +1,108 @@ +/* + Copyright (C) 2015 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_stokes_residual_h +#define _aspect_postprocess_stokes_residual_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that outputs Stokes residuals to a file stokes_residuals.txt. + * + * @ingroup Postprocessing + */ + template + class StokesResidual : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + StokesResidual (); + + /** + * This attaches to the Stokes solver signal. + */ + void initialize() override; + + /** + * Generate the output file. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Save the state of this object. + */ + void save (std::map &status_strings) const override; + + /** + * Restore the state of the object. + */ + void load (const std::map &status_strings) override; + + /** + * Serialize the contents of this class as far as they are not read + * from input parameter files. + */ + template + void serialize (Archive &ar, const unsigned int version); + + private: + /** + * A structure for a single time step record. + */ + struct DataPoint + { + double time; + unsigned int solve_index; + std::vector values; + + template + void serialize (Archive &ar, const unsigned int version); + }; + + /** + * Callback function to collect the data. + */ + void stokes_solver_callback (const SolverControl &solver_control_cheap, + const SolverControl &solver_control_expensive); + + /** + * An array of all the past values + */ + std::vector entries; + + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/temperature_statistics.h.bak b/include/aspect/postprocess/temperature_statistics.h.bak new file mode 100644 index 00000000000..b059802482a --- /dev/null +++ b/include/aspect/postprocess/temperature_statistics.h.bak @@ -0,0 +1,52 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_temperature_statistics_h +#define _aspect_postprocess_temperature_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the temperature. + * + * @ingroup Postprocessing + */ + template + class TemperatureStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some temperature statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/topography.h.bak b/include/aspect/postprocess/topography.h.bak new file mode 100644 index 00000000000..46f29389c9a --- /dev/null +++ b/include/aspect/postprocess/topography.h.bak @@ -0,0 +1,91 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_topography_h +#define _aspect_postprocess_topography_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that outputs the surface topography to file. + * + * @ingroup Postprocessing + */ + template + class Topography : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Output topography [m] to file + */ + std::pair execute (TableHandler &statistics) override; + + /** + * @name Functions used in dealing with run-time parameters + * @{ + */ + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + /** + * @} + */ + + private: + /** + * Whether or not to produce text files with topography values + */ + bool write_to_file; + + /** + * Interval between the generation of text output. This parameter + * is read from the input file and consequently is not part of the + * state that needs to be saved and restored. + */ + double output_interval; + + /** + * A time (in seconds) at which the last text output was supposed + * to be produced. Used to check for the next necessary output time. + */ + double last_output_time; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/velocity_boundary_statistics.h.bak b/include/aspect/postprocess/velocity_boundary_statistics.h.bak new file mode 100644 index 00000000000..3c6ec0496ba --- /dev/null +++ b/include/aspect/postprocess/velocity_boundary_statistics.h.bak @@ -0,0 +1,55 @@ +/* + Copyright (C) 2014 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_postprocess_velocity_boundary_statistics_h +#define _aspect_postprocess_velocity_boundary_statistics_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the velocity at + * different parts of the boundary. + * + * @ingroup Postprocessing + */ + template + class VelocityBoundaryStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some velocity boundary statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/velocity_statistics.h.bak b/include/aspect/postprocess/velocity_statistics.h.bak new file mode 100644 index 00000000000..0fff1d21e95 --- /dev/null +++ b/include/aspect/postprocess/velocity_statistics.h.bak @@ -0,0 +1,52 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_velocity_statistics_h +#define _aspect_postprocess_velocity_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the velocity. + * + * @ingroup Postprocessing + */ + template + class VelocityStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some velocity statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/viscous_dissipation_statistics.h.bak b/include/aspect/postprocess/viscous_dissipation_statistics.h.bak new file mode 100644 index 00000000000..575b3d58070 --- /dev/null +++ b/include/aspect/postprocess/viscous_dissipation_statistics.h.bak @@ -0,0 +1,54 @@ +/* + Copyright (C) 2011 - 2021-2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_postprocess_viscous_dissipation_statistics_h +#define _aspect_postprocess_viscous_dissipation_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes the viscous dissipation over the area + * spanned by each compositional field and over the whole domain. + * + * @ingroup Postprocessing + */ + template + class ViscousDissipationStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution to compute the viscous dissipation + * per compositional field and over the whole domain. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/postprocess/visualization.h.bak b/include/aspect/postprocess/visualization.h.bak new file mode 100644 index 00000000000..f483e78ae99 --- /dev/null +++ b/include/aspect/postprocess/visualization.h.bak @@ -0,0 +1,747 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_h +#define _aspect_postprocess_visualization_h + +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * Compute the arithmetic average over q for each m of the variable quantities[q](m). + */ + inline void average_quantities(std::vector> &quantities) + { + const unsigned int N = quantities.size(); + const unsigned int M = quantities[0].size(); + for (unsigned int m=0; m How visualization plugins work + * + * There are two ways in which visualization plugins can work to get + * data from a simulation into an output file: + *
    + *
  • Classes derived from this class can also derive from the deal.II + * class DataPostprocessor or any of the classes like + * DataPostprocessorScalar or DataPostprocessorVector. These classes can + * be thought of as filters: DataOut will call a function in them for + * every cell and this function will transform the values or gradients + * of the solution and other information such as the location of + * quadrature points into the desired quantity to output. A typical case + * would be if the quantity $g(x)$ you want to output can be written as + * a function $g(x) = G(u(x),\nabla u(x), x, ...)$ in a point-wise sense + * where $u(x)$ is the value of the solution vector (i.e., the + * velocities, pressure, temperature, etc) at an evaluation point. In + * the context of this program an example would be to output the density + * of the medium as a spatially variable function since this is a + * quantity that for realistic media depends point-wise on the values of + * the solution. + * + * Using this way of describing a visualization postprocessor will yield + * a class that would then have the following base classes: + * - aspect::Postprocess::VisualizationPostprocessors::Interface + * - aspect::SimulatorAccess + * - dealii::DataPostprocessor or any of the other ones listed above + * + *
  • The second possibility is for a class to not derive from + * dealii::DataPostprocessor but instead from the CellDataVectorCreator + * class. In this case, a visualization postprocessor would generate and + * return a vector that consists of one element per cell. The intent of + * this option is to output quantities that are not point-wise functions + * of the solution but instead can only be computed as integrals or + * other functionals on a per-cell basis. A typical case would be error + * estimators that do depend on the solution but not in a point-wise + * sense; rather, they yield one value per cell of the mesh. See the + * documentation of the CellDataVectorCreator class for more + * information. + *
+ * @ingroup Postprocessing + * @ingroup Visualization + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Constructor. The constructor takes as argument the physical + * units of the quantity (scalar or vector-valued) computed by + * derived classes. The empty string, "", refers to an unknown + * or nonexistent unit. + * + * If a visualization postprocessor generates more than one + * output component, and if the different components have different + * physical units, then they should be separated by commas. If + * the different components have the same physical units, these units + * need to be specified only once and will apply to all components. + * + * There are cases where the physical units can only be determined + * at a time later than when this constructor is called. An example + * is when a velocity is output as either `m/s` or `m/year`, + * depending on some run-time parameter. In those cases, derived + * classes should simply pass in an empty string to this constructor + * and instead overload the get_physical_units() function. + */ + explicit Interface (const std::string &physical_units = ""); + + /** + * Return the string representation of the physical units that a + * derived class has provided to the constructor of this class. + * + * As mentioned in the documentation of the constructor, there are + * cases where a derived class doesn't know the physical units yet + * that correspond to what is being output at the time the + * constructor is called. In that case, the derived class can + * overload this function and return the correct units when the + * visualization postprocessor is executed. + */ + virtual + std::string + get_physical_units () const; + + /** + * A function that is used to indicate to the postprocessor manager which + * other postprocessor(s) the current one depends upon. The returned + * list contains the names (as strings, as you would write them in + * the input file) of the postprocessors it requires. The manager + * will ensure that these postprocessors are indeed used, even if + * they were not explicitly listed in the input file, and are indeed + * run before this postprocessor every time they are executed. + * + * The postprocessors you can nominate here are of the general + * postprocessor class, not visualization postprocessors. + * + * The default implementation of this function returns an empty list. + */ + virtual + std::list + required_other_postprocessors () const; + + /** + * Save the state of this object to the argument given to this + * function. This function is in support of checkpoint/restart + * functionality. + * + * Derived classes can implement this function and should store + * their state in a string that is deposited under a key in the map + * through which the respective class can later find the status + * again when the program is restarted. A legitimate key to store + * data under is typeid(*this).name(). It is up to + * derived classes to decide how they want to encode their state. + * + * The default implementation of this function does nothing, i.e., + * it represents a stateless object for which nothing needs to be + * stored at checkpoint time and nothing needs to be restored at + * restart time. + * + * @param[in,out] status_strings The object into which + * implementations in derived classes can place their status under a + * key that they can use to retrieve the data. + */ + virtual + void save (std::map &status_strings) const; + + /** + * Restore the state of the object by looking up a description of + * the state in the passed argument under the same key under which + * it was previously stored. + * + * The default implementation does nothing. + * + * @param[in] status_strings The object from which the status will + * be restored by looking up the value for a key specific to this + * derived class. + */ + virtual + void load (const std::map &status_strings); + + private: + /** + * The physical units encoded by this visualization postprocessor. + */ + const std::string physical_units; + }; + + + + /** + * As explained in the documentation of the Interface class, the second + * kind of visualization plugin is one that wants to generate cell-wise + * data. Classes derived from this class need to implement a function + * execute() that computes these cell-wise values and return a pair of + * values where the first one indicates the name of a variable and the + * second one is a vector with one entry per cell. This class is the + * interface that such plugins have to implement. + * + * @ingroup Postprocessing + * @ingroup Visualization + */ + template + class CellDataVectorCreator : public Interface + { + public: + /** + * Constructor. The constructor takes as argument the physical + * units of the quantity (scalar or vector-valued) computed by + * derived classes. + */ + explicit CellDataVectorCreator (const std::string &physical_units = ""); + + /** + * Destructor. + */ + ~CellDataVectorCreator () override = default; + + /** + * The function classes have to implement that want to output + * cell-wise data. + * + * @return A pair of values with the following meaning: + * - The first element provides the name by which this data should + * be written to the output file. + * - The second element is a pointer to a vector with one element + * per active cell on the current processor. Elements corresponding + * to active cells that are either artificial or ghost cells (in + * deal.II language, see the deal.II glossary) + * will be ignored but must nevertheless exist in the returned + * vector. + * While implementations of this function must create this + * vector, ownership is taken over by the caller of this function + * and the caller will take care of destroying the vector pointed + * to. + */ + virtual + std::pair>> + execute () const = 0; + }; + + + /** + * This class is a tag class: If a visualization postprocessor is derived + * from it, then this is interpreted as saying that the class will only + * be used to generate graphical output on the surface of the model, + * rather than for the entire domain. + */ + template + class SurfaceOnlyVisualization + { + public: + /** + * Destructor. Made `virtual` to ensure that it is possible to + * test whether a derived class is derived from this class via + * a `dynamic_cast`. + */ + virtual + ~SurfaceOnlyVisualization () = default; + }; + } + + + /** + * A postprocessor that generates graphical output in periodic intervals + * or every time step. The time interval between generating graphical + * output is obtained from the parameter file. + * + * While this class acts as a plugin, i.e. as a postprocessor that can be + * registered with the postprocessing manager class + * aspect::Postprocess::Manager, this class at the same time also acts as + * a manager for plugins itself, namely for classes derived from the + * VisualizationPostprocessors::Interface class that are used to output + * different aspects of the solution, such as for example a computed + * seismic wave speed from temperature, velocity and pressure. + * + * @ingroup Postprocessing + */ + template + class Visualization : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Constructor. + */ + Visualization (); + + /** + * Generate graphical output from the current solution. + */ + std::pair + execute (TableHandler &statistics) override; + + /** + * Update any temporary information needed by the visualization postprocessor. + */ + void + update () override; + + /** + * A function that is used to register visualization postprocessor + * objects in such a way that the Manager can deal with all of them + * without having to know them by name. This allows the files in which + * individual postprocessors are implement to register these + * postprocessors, rather than also having to modify the Manage class + * by adding the new postprocessor class. + * + * @param name The name under which this visualization postprocessor + * is to be called in parameter files. + * @param description A text description of what this visualization + * plugin does and that will be listed in the documentation of the + * parameter file. + * @param declare_parameters_function A pointer to a function that + * declares the parameters for this postprocessor. + * @param factory_function A pointer to a function that creates such a + * postprocessor object and returns a pointer to it. + */ + static + void + register_visualization_postprocessor (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr>(*factory_function) ()); + + /** + * A function that is used to indicate to the postprocessor manager which + * other postprocessor(s) the current one depends upon. + * + * For the current class, we simply loop over all of the visualization + * postprocessors and collect what they want. + */ + std::list + required_other_postprocessors () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * Save the state of this object. + */ + void save (std::map &status_strings) const override; + + /** + * Restore the state of the object. + */ + void load (const std::map &status_strings) override; + + /** + * Serialize the contents of this class as far as they are not read + * from input parameter files. + */ + template + void serialize (Archive &ar, const unsigned int version); + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + /** + * Return the value of the parameter @p pointwise_stress_and_strain + * that is controlled by the parameter "Point-wise stress and strain". + */ + bool output_pointwise_stress_and_strain() const; + + /** + * Exception. + */ + DeclException1 (ExcPostprocessorNameNotFound, + std::string, + << "Could not find entry <" + << arg1 + << "> among the names of registered postprocessors."); + + private: + /** + * Interval between the generation of graphical output. This parameter + * is read from the input file and consequently is not part of the + * state that needs to be saved and restored. + */ + double output_interval; + + /** + * A time (in seconds) at which the last graphical output was supposed + * to be produced. Used to check for the next necessary output time. + */ + double last_output_time; + + /** + * Maximum number of steps between the generation of graphical output. + * This parameter + * is read from the input file and consequently is not part of the + * state that needs to be saved and restored. + */ + unsigned int maximum_timesteps_between_outputs; + + /** + * Timestep at which the last graphical output was produced + * Used to check for the next necessary output time. + */ + unsigned int last_output_timestep; + + /** + * Consecutively counted number indicating the how-manyth time we will + * create output the next time we get to it. + */ + unsigned int output_file_number; + + /** + * Graphical output format. + */ + std::string output_format; + + /** + * VTU file output supports grouping files from several CPUs into one + * file using MPI I/O when writing on a parallel filesystem. 0 means + * no grouping (and no parallel I/O). 1 will generate one big file + * containing the whole solution. + */ + unsigned int group_files; + + /** + * On large clusters it can be advantageous to first write the + * output to a temporary file on a local file system and later + * move this file to a network file system. If this variable is + * set to a non-empty string it will be interpreted as a temporary + * storage location. + */ + std::string temporary_output_location; + + /** + * deal.II offers the possibility to linearly interpolate output + * fields of higher order elements to a finer resolution. This + * somewhat compensates the fact that most visualization software only + * offers linear interpolation between grid points and therefore the + * output file is a very coarse representation of the actual solution + * field. Activating this option increases the spatial resolution in + * each dimension by a factor equal to the polynomial degree used for + * the velocity finite element (usually 2). + */ + bool interpolate_output; + + /** + * deal.II offers the possibility to filter duplicate vertices in HDF5 + * output files. This merges the vertices of adjacent cells and + * therefore saves disk space, but misrepresents discontinuous + * output properties. Activating this function reduces the disk space + * by about a factor of $2^{dim}$ for hdf5 output. + */ + bool filter_output; + + /** + * If true, return quantities related to stresses and strain with + * point-wise values. Otherwise the values will be averaged on each + * cell. + */ + bool pointwise_stress_and_strain; + + /** + * deal.II offers the possibility to write vtu files with higher order + * representations of the output data. This means each cell will correctly + * show the higher order representation of the output data instead of the + * linear interpolation between vertices that ParaView and VisIt usually show. + * Note that activating this option is safe and recommended, but requires that + * (i) ``Output format'' is set to ``vtu'', (ii) ``Interpolate output'' is + * set to true, (iii) you use a sufficiently new version of Paraview + * or VisIt to read the files (Paraview version 5.5 or newer, and VisIt version + * to be determined), and (iv) you use deal.II version 9.1.0 or newer. + */ + bool write_higher_order_output; + + /** + * For mesh deformation computations ASPECT uses an + * Arbitrary-Lagrangian-Eulerian formulation to handle deforming the + * domain, so the mesh has its own velocity field. This may be + * written as an output field by setting output_mesh_velocity to true. + */ + bool output_mesh_velocity; + + /** + * For mesh deformation computations ASPECT uses an + * Arbitrary-Lagrangian-Eulerian formulation to handle deforming the domain, so the mesh + * has a field that determines the displacement from the reference + * configuration. This may be written as an output field by setting + * this flag to true. + */ + bool output_mesh_displacement; + + /** + * For mesh deformation computations ASPECT uses an + * Arbitrary-Lagrangian-Eulerian formulation to handle deforming the domain, and we output the + * mesh in its deformed state by default. If this flag is set to true, + * the mesh is written undeformed. + */ + bool output_undeformed_mesh; + + /** + * Whether or not ASPECT should also generate output for the base variables + * velocity, (fluid pressure and velocity), pressure, temperature + * and the compositional fields on the surface of the mesh. + * The mesh surface includes all boundaries of the domain. + */ + bool output_base_variables_on_mesh_surface; + + /** + * File operations can potentially take a long time, blocking the + * progress of the rest of the model run. Setting this variable to + * 'true' moves this process into a background thread, while the + * rest of the model continues. + */ + bool write_in_background_thread; + + /** + * Set the time output was supposed to be written. In the simplest + * case, this is the previous last output time plus the interval, but + * in general we'd like to ensure that it is the largest supposed + * output time, which is smaller than the current time, to avoid + * falling behind with last_output_time and having to catch up once + * the time step becomes larger. This is done after every output. + */ + void set_last_output_time (const double current_time); + + /** + * Record that the mesh changed. This helps some output writers avoid + * writing the same mesh multiple times. + */ + void mesh_changed_signal (); + + /** + * A function that writes the text in the second argument to a file + * with the name given in the first argument. The function is run on a + * separate thread to allow computations to continue even though + * writing data is still continuing. + */ + static + void writer (const std::string &filename, + const std::string &temporary_filename, + const std::string &file_contents); + + /** + * A list of postprocessor objects that have been requested in the + * parameter file. + */ + std::list>> postprocessors; + + /** + * A structure that keeps some history about past output operations. + * These variables are grouped into a structure because we need them + * twice: Once for the cell output case (via DataOut) and once for + * surface output (via DataOutFaces). + */ + struct OutputHistory + { + /** + * Constructor + */ + OutputHistory (); + + /** + * Destructor. Makes sure that any background thread that may still be + * running writing data to disk finishes before the current object is + * fully destroyed. + */ + ~OutputHistory (); + + /** + * Serialize the contents of this class as far as they are not read + * from input parameter files. + */ + template + void serialize (Archive &ar, const unsigned int version); + + /** + * Whether the mesh changed since the last time we produced cell-based + * output. + */ + bool mesh_changed; + + /** + * The most recent name of the mesh file, used to avoid redundant mesh + * output. + */ + std::string last_mesh_file_name; + + /** + * A list of pairs (time, pvtu_filename) that have so far been written + * and that we will pass to DataOutInterface::write_pvd_record to + * create a description file that can make the association between + * simulation time and corresponding file name (this is done because + * there is no way to store the simulation time inside the .pvtu or + * .vtu files). + */ + std::vector> times_and_pvtu_names; + + /** + * A list of list of filenames, sorted by timestep, that correspond to + * what has been created as output. This is used to create a descriptive + * .visit file for the entire simulation. + */ + std::vector> output_file_names_by_timestep; + + /** + * A set of data related to XDMF file sections describing the HDF5 + * heavy data files created. These contain things such as the + * dimensions and names of data written at all steps during the + * simulation. + */ + std::vector xdmf_entries; + + /** + * Handle to a thread that is used to write data in the background. + * The writer() function runs on this background thread when outputting + * data for the `data_out` object. + */ + std::thread background_thread; + }; + + /** + * Information about the history of writing graphical + * output for cells (via DataOut). + */ + OutputHistory cell_output_history; + + /** + * Information about the history of writing graphical + * output for faces (via DataOutFaces). + */ + OutputHistory face_output_history; + + /** + * Write the various descriptive record files. These files are used by + * visualization programs to identify which of the output files in a + * directory, possibly one file written by each processor, belong to a + * single time step and/or form the different time steps of a + * simulation. For Paraview, this is a .pvtu file per + * time step and a .pvd for all time steps. For VisIt it + * is a .visit file per time step and one for all time + * steps. + * + * @param data_out The DataOut object that was used to write the + * solutions. + * @param solution_file_prefix The stem of the filename to be written. + * @param filenames List of filenames for the current output from all + * processors. + * @param output_history The OutputHistory object to fill. + */ + template + void write_description_files (const DataOutType &data_out, + const std::string &solution_file_prefix, + const std::vector &filenames, + OutputHistory &output_history) const; + + + /** + * A function, called from the execute() function, that takes a + * DataOut object, does some preliminary work with it, and then + * writes the result out to files via the writer() function (in the + * case of VTU output) or through the XDMF facilities. + * + * The function returns the base name of the output files produced, + * which can then be used for the statistics file and screen output. + */ + template + std::string write_data_out_data(DataOutType &data_out, + OutputHistory &output_history, + const std::map &visualization_field_names_and_units) const; + }; + } + + + /** + * Given a class name, a name, and a description for the parameter file for + * a postprocessor, register it with the aspect::Postprocess::Manager class. + * + * @ingroup Postprocessing + */ +#define ASPECT_REGISTER_VISUALIZATION_POSTPROCESSOR(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_VISUALIZATION_POSTPROCESSOR_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::Postprocess::Visualization<2>::register_visualization_postprocessor, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::Postprocess::Visualization<3>::register_visualization_postprocessor, \ + name, description); \ + } +} + + +#endif diff --git a/include/aspect/postprocess/visualization/ISA_rotation_timescale.h.bak b/include/aspect/postprocess/visualization/ISA_rotation_timescale.h.bak new file mode 100644 index 00000000000..5c4790c8703 --- /dev/null +++ b/include/aspect/postprocess/visualization/ISA_rotation_timescale.h.bak @@ -0,0 +1,72 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_ISA_rotation_timescale_h +#define _aspect_postprocess_visualization_ISA_rotation_timescale_h + +#include +#include + + + + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * This postprocessor calculates and outputs the timescale for the rotation + * of grains toward the infinite strain axis. Kaminski and Ribe (2002, Gcubed) + * call this quantity $\tau_{ISA}$, and define it as + * $\tau_{ISA} \approx \frac{1}{\dot{\epsilon}}$ + * where $\dot{\epsilon}$ is the largest eigenvalue of the strain rate tensor. + * It can be used, along with the grain lag angle + * ($\Theta$), to calculate the grain orientation lag parameter (GOL). + * GOL is not calculated within ASPECT + * right now because it is proportional to the spatial gradient of theta, but in the + * future that calculation could be implemented in a material model with CopyOutputs + * (once they exist). For more thoughts on that, see the documentation for the + * grain lag angle postprocessor. + */ + template + class ISARotationTimescale: public CellDataVectorCreator, public SimulatorAccess + { + public: + /** + * Constructor. + */ + ISARotationTimescale(); + + /** + * @copydoc CellDataVectorCreator::execute() + */ + std::pair>> + execute() const override; + + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/adiabat.h.bak b/include/aspect/postprocess/visualization/adiabat.h.bak new file mode 100644 index 00000000000..90bf7e6634b --- /dev/null +++ b/include/aspect/postprocess/visualization/adiabat.h.bak @@ -0,0 +1,68 @@ +/* + Copyright (C) 2016 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_adiabat_h +#define _aspect_postprocess_visualization_adiabat_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that outputs adiabatic + * temperature, pressure, density, and density derivative. + */ + template + class Adiabat + : public DataPostprocessor, + public SimulatorAccess, + public Interface + { + public: + Adiabat (); + + std::vector + get_names () const override; + + std::vector + get_data_component_interpretation () const override; + + + UpdateFlags + get_needed_update_flags () const override; + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/artificial_viscosity.h.bak b/include/aspect/postprocess/visualization/artificial_viscosity.h.bak new file mode 100644 index 00000000000..40d088828f1 --- /dev/null +++ b/include/aspect/postprocess/visualization/artificial_viscosity.h.bak @@ -0,0 +1,60 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_artificial_viscosity_h +#define _aspect_postprocess_visualization_artificial_viscosity_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived that implements a function that provides the + * artificial viscosity for the temperature equation on each cell for + * graphical output. + */ + template + class ArtificialViscosity : public CellDataVectorCreator, + public SimulatorAccess + { + public: + /** + * Constructor. + */ + ArtificialViscosity(); + + /** + * @copydoc CellDataVectorCreator::execute() + */ + std::pair>> + execute () const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/artificial_viscosity_composition.h.bak b/include/aspect/postprocess/visualization/artificial_viscosity_composition.h.bak new file mode 100644 index 00000000000..047a2024f53 --- /dev/null +++ b/include/aspect/postprocess/visualization/artificial_viscosity_composition.h.bak @@ -0,0 +1,80 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_artificial_viscosity_composition_h +#define _aspect_postprocess_visualization_artificial_viscosity_composition_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived that implements a function that provides the + * artificial viscosity for a given composition on each cell for + * graphical output. + */ + template + class ArtificialViscosityComposition : public CellDataVectorCreator, + public SimulatorAccess + { + public: + /** + * Constructor. + */ + ArtificialViscosityComposition(); + + /** + * @copydoc CellDataVectorCreator::execute() + */ + std::pair>> + execute () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A parameter that tells us for which compositional field the + * artificial viscosity should be visualized. + */ + int compositional_field; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/boundary_indicator.h.bak b/include/aspect/postprocess/visualization/boundary_indicator.h.bak new file mode 100644 index 00000000000..7ae400a50c8 --- /dev/null +++ b/include/aspect/postprocess/visualization/boundary_indicator.h.bak @@ -0,0 +1,65 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_boundary_indicator_h +#define _aspect_postprocess_visualization_boundary_indicator_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from CellDataVectorCreator that takes an output + * vector and computes a variable that represents the boundary + * indicator of the triangulation's cells' faces. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class BoundaryIndicator + : public CellDataVectorCreator, + public SimulatorAccess + { + public: + /** + * Constructor. + */ + BoundaryIndicator(); + + /** + * @copydoc CellDataVectorCreator::execute() + */ + std::pair>> + execute () const override; + + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/boundary_strain_rate_residual.h.bak b/include/aspect/postprocess/visualization/boundary_strain_rate_residual.h.bak new file mode 100644 index 00000000000..d0319a81bf4 --- /dev/null +++ b/include/aspect/postprocess/visualization/boundary_strain_rate_residual.h.bak @@ -0,0 +1,87 @@ +/* + Copyright (C) 2020 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_boundary_strain_rate_residual_h +#define _aspect_postprocess_visualization_boundary_strain_rate_residual_h + +#include +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + using namespace dealii; + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the residual between + * the a reference strain rate dataset and the strain rate computed for the model domain. + * We only compute the residual between the second invariant of the strain rate + * and therefore, the input data is an ascii data file with columns corresponding + * to coordinates and one data column representing the second invariant of the strain rate. + * + * This quantity only makes sense at the surface of the domain. + * Thus, the value is set to zero in all the cells inside of the domain. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class BoundaryStrainRateResidual + : public DataPostprocessorScalar, + public SurfaceOnlyVisualization, + public SimulatorAccess, + public Interface + { + public: + BoundaryStrainRateResidual (); + + /** + * Evaluate the strain rate residual for each component at the top face of the current cell + * if it lies at the surface boundary. + * + * @copydoc DataPostprocessorTensor::evaluate_vector_field() + */ + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + /** + * Let the postprocessor manager know about the other postprocessors + * this one depends on. Specifically, the boundary strain rate residual statistics postprocessor. + */ + std::list + required_other_postprocessors() const override; + + std::string + get_physical_units () const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/boundary_velocity_residual.h.bak b/include/aspect/postprocess/visualization/boundary_velocity_residual.h.bak new file mode 100644 index 00000000000..9847498f7e9 --- /dev/null +++ b/include/aspect/postprocess/visualization/boundary_velocity_residual.h.bak @@ -0,0 +1,84 @@ +/* + Copyright (C) 2020 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_boundary_velocity_residual_h +#define _aspect_postprocess_visualization_boundary_velocity_residual_h + +#include +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + using namespace dealii; + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the velocity residual between + * the input velocity data and the velocity computed for the model domain. + * The input velocity could either be an ascii data file or a file generated + * by the GPlates model. + * This quantity only makes sense at the surface of the domain. + * Thus, the value is set to zero in all the cells inside of the domain. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class BoundaryVelocityResidual + : public DataPostprocessorVector, + public SurfaceOnlyVisualization, + public SimulatorAccess, + public Interface + { + public: + BoundaryVelocityResidual (); + + /** + * Evaluate the velocity residual for the current cell. + * + * @copydoc DataPostprocessorVector::evaluate_vector_field() + */ + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + /** + * Let the postprocessor manager know about the other postprocessors + * this one depends on. Specifically, the boundary velocity residual statistics postprocessor. + */ + std::list + required_other_postprocessors() const override; + + std::string + get_physical_units () const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/compositional_vector.h.bak b/include/aspect/postprocess/visualization/compositional_vector.h.bak new file mode 100644 index 00000000000..6b04b35cec7 --- /dev/null +++ b/include/aspect/postprocess/visualization/compositional_vector.h.bak @@ -0,0 +1,86 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_compositional_vector_h +#define _aspect_postprocess_visualization_compositional_vector_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that can output sets of dim + * compositional fields as vectors. + */ + template + class CompositionalVector + : public DataPostprocessor, + public SimulatorAccess, + public Interface + { + public: + CompositionalVector (); + + std::vector + get_names () const override; + + std::vector + get_data_component_interpretation () const override; + + UpdateFlags + get_needed_update_flags () const override; + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Names of vector fields. + */ + std::vector vector_names; + + /** + * Stores sets of compositional field indices to + * be visualized together as vector fields. + */ + std::vector> sets; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/depth.h.bak b/include/aspect/postprocess/visualization/depth.h.bak new file mode 100644 index 00000000000..46ad19f5d2a --- /dev/null +++ b/include/aspect/postprocess/visualization/depth.h.bak @@ -0,0 +1,58 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_depth_h +#define _aspect_postprocess_visualization_depth_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that outputs the depth + * according to the geometry model. + */ + template + class Depth + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + Depth (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/dynamic_topography.h.bak b/include/aspect/postprocess/visualization/dynamic_topography.h.bak new file mode 100644 index 00000000000..be84ab848b3 --- /dev/null +++ b/include/aspect/postprocess/visualization/dynamic_topography.h.bak @@ -0,0 +1,75 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_dynamic_topography_h +#define _aspect_postprocess_visualization_dynamic_topography_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessorScalar that computes a + * variable that represents the dynamic topography. This + * quantity, strictly speaking, only makes sense at the surface + * of the domain. Thus, the value is set to zero in all the + * cells inside of the domain. Consider using the + * SurfaceDynamicTopography to only output the dynamic + * topography at the boundary of the domain. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class DynamicTopography + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + DynamicTopography(); + + /** + * Evaluate the dynamic topography for the current cell. + * + * @copydoc DataPostprocessorScalar::evaluate_vector_field() + */ + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + /** + * Register the other postprocessor that we need: DynamicTopography + */ + std::list + required_other_postprocessors() const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/error_indicator.h.bak b/include/aspect/postprocess/visualization/error_indicator.h.bak new file mode 100644 index 00000000000..a649ba071b3 --- /dev/null +++ b/include/aspect/postprocess/visualization/error_indicator.h.bak @@ -0,0 +1,59 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_error_indicator_h +#define _aspect_postprocess_visualization_error_indicator_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived that implements a function that provides the computed + * mesh refinement/error indicators for graphical output. + */ + template + class ErrorIndicator : public CellDataVectorCreator, + public SimulatorAccess + { + public: + /** + * Constructor. + */ + ErrorIndicator(); + + /** + * @copydoc CellDataVectorCreator::execute() + */ + std::pair>> + execute () const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/geoid.h.bak b/include/aspect/postprocess/visualization/geoid.h.bak new file mode 100644 index 00000000000..8bde86ac743 --- /dev/null +++ b/include/aspect/postprocess/visualization/geoid.h.bak @@ -0,0 +1,84 @@ +/* + Copyright (C) 2016 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_geoid_h +#define _aspect_postprocess_visualization_geoid_h + +#include +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessorScalar that computes a variable + * that represents the geoid topography. This quantity, strictly + * speaking, only makes sense at the surface of the domain. Thus, the + * value is set to zero in all the cells inside of the domain. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class Geoid + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + Geoid(); + + /** + * Initialization function. This function is called once at the + * beginning of the program after parse_parameters is run and after + * the SimulatorAccess (if applicable) is initialized. + */ + void + initialize () override; + + /** + * @copydoc DataPostprocessorScalar::evaluate_vector_field() + */ + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + + /** + * Let the postprocessor manager know about the other postprocessors + * this one depends on. Specifically, the Geoid postprocessor. + */ + std::list + required_other_postprocessors() const override; + + private: + + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/grain_lag_angle.h.bak b/include/aspect/postprocess/visualization/grain_lag_angle.h.bak new file mode 100644 index 00000000000..8d5d5eb2204 --- /dev/null +++ b/include/aspect/postprocess/visualization/grain_lag_angle.h.bak @@ -0,0 +1,79 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_grain_lag_angle_h +#define _aspect_postprocess_visualization_grain_lag_angle_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + + /** + * This postprocessor calculates and outputs the angle between the ~infinite + * strain axis and the velocity. Kaminski & Ribe (2002, Gcubed) call this quantity + * $\Theta$ and define it as + * $\Theta = \cos^{-1}(\hat{u}\cdot\hat{e})$ + * where $\hat{u}=\vec{u}/|{u}|$, $\vec{u}$ is the local flow velocity, and + * $\hat{e}$ is the local infinite strain axis, which we calculate as the + * first eigenvector of the "left stretch" tensor. + * $\Theta$ can be used to calculate the grain orientation lag parameter (GOL). + * Calculating GOL also requires the ISA rotation timescale ($\tau_{ISA}$). + * GOL is not calculated within ASPECT + * right now because it is proportional to the spatial gradient of $\Theta$, but in the + * future that calculation could be implemented in a material model with CopyOutputs + * (once they exist). By tracking $\Theta$ as a CopyOutput (ie, a compositional field + * holding a calculated value that gets copied over instead of solved for), the spatial + * gradient of $\Theta$ could be calculated for the previous timestep by obtaining the + * old solution for the input material model. That gradient, and also the time derivative + * of $\Theta$, could then be used to calculate GOL at the previous timestep; $\Theta$ could + * be updated at the current timestep; and both quantities could be stored in CopyOutputs + * to step forward in time. Basically, the calculation of GOL would have to lag one + * timestep behind the other quantities in order to get the gradients, but we're + * often interested in GOL in a steady-state flow anyway. + */ + template + class GrainLagAngle: public CellDataVectorCreator, public SimulatorAccess + { + public: + /** + * Constructor. + */ + GrainLagAngle(); + + /** + * @copydoc CellDataVectorCreator::execute() + */ + std::pair>> + execute() const override; + + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/gravity.h.bak b/include/aspect/postprocess/visualization/gravity.h.bak new file mode 100644 index 00000000000..c58fb4ac5ff --- /dev/null +++ b/include/aspect/postprocess/visualization/gravity.h.bak @@ -0,0 +1,58 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_gravity_h +#define _aspect_postprocess_visualization_gravity_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessorVector that outputs the gravity + * as a vector field. + */ + template + class Gravity + : public DataPostprocessorVector, + public SimulatorAccess, + public Interface + { + public: + Gravity (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/heat_flux_map.h.bak b/include/aspect/postprocess/visualization/heat_flux_map.h.bak new file mode 100644 index 00000000000..8797826b787 --- /dev/null +++ b/include/aspect/postprocess/visualization/heat_flux_map.h.bak @@ -0,0 +1,105 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_heat_flux_map_h +#define _aspect_postprocess_visualization_heat_flux_map_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A postprocessor that computes the heat flux density through the top and bottom boundaries. + * + * @ingroup Postprocessing + */ + template + class HeatFluxMap + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + HeatFluxMap(); + + /** + * Fill the temporary storage variables with the + * heat flux for the current time step. + * + * @copydoc Interface::update() + */ + void update() override; + + /** + * Compute the heat flux for the given input cell. + * + * @copydoc DataPostprocessorScalar::evaluate_vector_field() + */ + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + /** + * @copydoc Interface::declare_parameters() + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * @copydoc Interface::parse_parameters() + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A flag that determines whether to use the point-wise + * heat flux calculation or the cell-wise averaged calculation. + */ + bool output_point_wise_heat_flux; + + /** + * A temporary storage place for the point-wise heat flux + * solution. Only initialized and used if output_point_wise_heat_flux + * is set to true. + */ + LinearAlgebra::BlockVector heat_flux_density_solution; + + /** + * A temporary storage place for the cell-wise heat flux + * solution. Only initialized and used if output_point_wise_heat_flux + * is set to false. + */ + std::vector>> heat_flux_and_area; + }; + } + } +} + + +#endif diff --git a/include/aspect/postprocess/visualization/heating.h.bak b/include/aspect/postprocess/visualization/heating.h.bak new file mode 100644 index 00000000000..ca4e2550253 --- /dev/null +++ b/include/aspect/postprocess/visualization/heating.h.bak @@ -0,0 +1,74 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_heating_h +#define _aspect_postprocess_visualization_heating_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes several scalar variables that represent the heating + * model outputs for every point. The list of written variables + * corresponds to the heating models that are used in the computation + * as specified in the 'Heating model' subsection in the input file. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class Heating + : public DataPostprocessor, + public SimulatorAccess, + public Interface + { + public: + Heating (); + + std::vector + get_names () const override; + + std::vector + get_data_component_interpretation () const override; + + UpdateFlags + get_needed_update_flags () const override; + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/kxrcf_indicator.h.bak b/include/aspect/postprocess/visualization/kxrcf_indicator.h.bak new file mode 100644 index 00000000000..bcd4022612d --- /dev/null +++ b/include/aspect/postprocess/visualization/kxrcf_indicator.h.bak @@ -0,0 +1,80 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_kxrcf_indicator_h +#define _aspect_postprocess_visualization_kxrcf_indicator_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived that implements a function that provides the + * KXRCF indicator for a given advection field on each cell for + * graphical output. + */ + template + class KXRCFIndicator : public CellDataVectorCreator, + public SimulatorAccess + { + public: + /** + * Constructor. + */ + KXRCFIndicator(); + + /** + * @copydoc CellDataVectorCreator::execute() + */ + std::pair>> + execute () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A parameter that tells us for which advection field the + * KXRCF indicator should be visualized. + */ + unsigned int field_index; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/material_properties.h.bak b/include/aspect/postprocess/visualization/material_properties.h.bak new file mode 100644 index 00000000000..5d1f91159a8 --- /dev/null +++ b/include/aspect/postprocess/visualization/material_properties.h.bak @@ -0,0 +1,92 @@ +/* + Copyright (C) 2014 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_material_properties_h +#define _aspect_postprocess_visualization_material_properties_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes several scalar variables that represent the material + * model outputs for every point. The list of written variables can be + * chosen as input parameter. The principal functionality of this class + * is already implemented in some other visualization plugins, the + * purpose of this plugin is to efficiently compute all the wanted + * parameters in one call to the material model. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class MaterialProperties + : public DataPostprocessor, + public SimulatorAccess, + public Interface + { + public: + MaterialProperties (); + + std::vector + get_names () const override; + + std::vector + get_data_component_interpretation () const override; + + UpdateFlags + get_needed_update_flags () const override; + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + std::vector property_names; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/maximum_horizontal_compressive_stress.h.bak b/include/aspect/postprocess/visualization/maximum_horizontal_compressive_stress.h.bak new file mode 100644 index 00000000000..2d178f54af6 --- /dev/null +++ b/include/aspect/postprocess/visualization/maximum_horizontal_compressive_stress.h.bak @@ -0,0 +1,92 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_maximum_horizontal_compressive_stress_h +#define _aspect_postprocess_visualization_maximum_horizontal_compressive_stress_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class that computes a field of horizontal vectors that + * represent the direction of maximal horizontal compressive + * stress. For an exact definition, see the documentation of + * this plugin in the manual. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class MaximumHorizontalCompressiveStress + : public DataPostprocessor, + public SimulatorAccess, + public Interface + { + public: + /** + * Constructor. + */ + MaximumHorizontalCompressiveStress(); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + /** + * Return the vector of strings describing the names of the computed + * quantities. Given the purpose of this class, this is a vector + * with entries all equal to the name of the plugin. + */ + std::vector get_names () const override; + + /** + * This functions returns information about how the individual + * components of output files that consist of more than one data set + * are to be interpreted. The returned value is + * DataComponentInterpretation::component_is_scalar repeated + * SymmetricTensor::n_independent_components times. (These + * components should really be part of a symmetric tensor, but + * deal.II does not allow marking components as such.) + */ + std::vector + get_data_component_interpretation () const override; + + /** + * Return which data has to be provided to compute the derived + * quantities. The flags returned here are the ones passed to the + * constructor of this class. + */ + UpdateFlags get_needed_update_flags () const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/melt.h.bak b/include/aspect/postprocess/visualization/melt.h.bak new file mode 100644 index 00000000000..e44f1537923 --- /dev/null +++ b/include/aspect/postprocess/visualization/melt.h.bak @@ -0,0 +1,84 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_melt_h +#define _aspect_postprocess_visualization_melt_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that outputs melt related + * properties of the material model. + */ + template + class MeltMaterialProperties + : public DataPostprocessor, + public SimulatorAccess, + public Interface + { + public: + MeltMaterialProperties (); + + std::vector + get_names () const override; + + std::vector + get_data_component_interpretation () const override; + + UpdateFlags + get_needed_update_flags () const override; + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + std::vector property_names; + }; + + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/melt_fraction.h.bak b/include/aspect/postprocess/visualization/melt_fraction.h.bak new file mode 100644 index 00000000000..8dd561cea61 --- /dev/null +++ b/include/aspect/postprocess/visualization/melt_fraction.h.bak @@ -0,0 +1,116 @@ +/* + Copyright (C) 2013 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_melt_fraction_h +#define _aspect_postprocess_visualization_melt_fraction_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the melt fraction at every + * point. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class MeltFraction + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + MeltFraction (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Parameters for anhydrous melting of peridotite after Katz, 2003 + */ + + // for the solidus temperature + double A1; // °C + double A2; // °C/Pa + double A3; // °C/(Pa^2) + + // for the lherzolite liquidus temperature + double B1; // °C + double B2; // °C/Pa + double B3; // °C/(Pa^2) + + // for the liquidus temperature + double C1; // °C + double C2; // °C/Pa + double C3; // °C/(Pa^2) + + // for the reaction coefficient of pyroxene + double r1; // cpx/melt + double r2; // cpx/melt/GPa + double M_cpx; // mass fraction of pyroxenite + + // melt fraction exponent + double beta; + + /** + * Parameters for melting of pyroxenite after Sobolev et al., 2011 + */ + + // for the melting temperature + double D1; // °C + double D2; // °C/Pa + double D3; // °C/(Pa^2) + + // for the melt-fraction dependence of productivity + double E1; + double E2; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/named_additional_outputs.h.bak b/include/aspect/postprocess/visualization/named_additional_outputs.h.bak new file mode 100644 index 00000000000..dcfb5f08681 --- /dev/null +++ b/include/aspect/postprocess/visualization/named_additional_outputs.h.bak @@ -0,0 +1,79 @@ +/* + Copyright (C) 2014 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_named_additional_outputs_h +#define _aspect_postprocess_visualization_named_additional_outputs_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that generates visualization + * output for all additional material outputs that are derived + * from the 'NamedAdditionalMaterialOutputs' base class if the are + * filled in the evaluate function of the material model used in the + * computation. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class NamedAdditionalOutputs + : public DataPostprocessor, + public SimulatorAccess, + public Interface + { + public: + NamedAdditionalOutputs (); + + void + initialize () override; + + std::vector + get_names () const override; + + std::vector + get_data_component_interpretation () const override; + + UpdateFlags + get_needed_update_flags () const override; + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + private: + std::vector property_names; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/nonadiabatic_pressure.h.bak b/include/aspect/postprocess/visualization/nonadiabatic_pressure.h.bak new file mode 100644 index 00000000000..c9d282fc51c --- /dev/null +++ b/include/aspect/postprocess/visualization/nonadiabatic_pressure.h.bak @@ -0,0 +1,62 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_nonadiabatic_pressure_h +#define _aspect_postprocess_visualization_nonadiabatic_pressure_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the non-adiabatic part of the + * pressure every point. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class NonadiabaticPressure + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + NonadiabaticPressure (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/nonadiabatic_temperature.h.bak b/include/aspect/postprocess/visualization/nonadiabatic_temperature.h.bak new file mode 100644 index 00000000000..b71d32a5727 --- /dev/null +++ b/include/aspect/postprocess/visualization/nonadiabatic_temperature.h.bak @@ -0,0 +1,62 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_nonadiabatic_temperature_h +#define _aspect_postprocess_visualization_nonadiabatic_temperature_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the non-adiabatic part of the + * temperature at every point. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class NonadiabaticTemperature + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + NonadiabaticTemperature (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/particle_count.h.bak b/include/aspect/postprocess/visualization/particle_count.h.bak new file mode 100644 index 00000000000..a64a5ae8baf --- /dev/null +++ b/include/aspect/postprocess/visualization/particle_count.h.bak @@ -0,0 +1,71 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_particle_count_h +#define _aspect_postprocess_visualization_particle_count_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from CellDataVectorCreator that takes an output + * vector and computes a variable that represents the number of particles + * in each cell. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class ParticleCount + : public CellDataVectorCreator, + public SimulatorAccess + { + public: + /** + * Constructor. + */ + ParticleCount(); + + /** + * @copydoc CellDataVectorCreator::execute() + */ + std::pair>> + execute () const override; + + /** + * Let the postprocessor manager know about the other postprocessors + * this one depends on. Specifically, the particles postprocessor. + */ + std::list + required_other_postprocessors() const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/partition.h.bak b/include/aspect/postprocess/visualization/partition.h.bak new file mode 100644 index 00000000000..30527e66be5 --- /dev/null +++ b/include/aspect/postprocess/visualization/partition.h.bak @@ -0,0 +1,62 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_partition_h +#define _aspect_postprocess_visualization_partition_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes puts the number of + * the parallel process (i.e., the partition number) for each cell into + * the output file. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class Partition + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + Partition (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/principal_stress.h.bak b/include/aspect/postprocess/visualization/principal_stress.h.bak new file mode 100644 index 00000000000..5e2c24a5b21 --- /dev/null +++ b/include/aspect/postprocess/visualization/principal_stress.h.bak @@ -0,0 +1,82 @@ +/* + Copyright (C) 2020 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_principal_stress_h +#define _aspect_postprocess_visualization_principal_stress_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that outputs the principal + * stress values and directions, i.e., the eigenvalues and eigenvectors + * of the stress tensor (or optionally of the deviatoric stress tensor). + */ + template + class PrincipalStress + : public DataPostprocessor, + public SimulatorAccess, + public Interface + { + public: + PrincipalStress (); + + std::vector + get_names () const override; + + std::vector + get_data_component_interpretation () const override; + + UpdateFlags + get_needed_update_flags () const override; + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Whether to use the deviatoric stress tensor instead of the full stress + * tensor to compute principal directions and values. + */ + bool use_deviatoric_stress; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/seismic_anomalies.h.bak b/include/aspect/postprocess/visualization/seismic_anomalies.h.bak new file mode 100644 index 00000000000..ac482026cb5 --- /dev/null +++ b/include/aspect/postprocess/visualization/seismic_anomalies.h.bak @@ -0,0 +1,156 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_seismic_anomalies_h +#define _aspect_postprocess_visualization_seismic_anomalies_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived that implements a function that provides the computed + * computed seismic anomaly in $V_s$ for graphical output. + */ + template + class SeismicVsAnomaly + : + public CellDataVectorCreator, + public SimulatorAccess + { + public: + /** + * Constructor. + */ + SeismicVsAnomaly(); + + /** + * @copydoc CellDataVectorCreator::execute() + */ + std::pair>> + execute () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * Scheme chosen to define the average seismic velocity as a + * function of depth. Reference profile evaluates the material model + * using the P-T profile defined by the reference adiabatic + * conditions and the lateral average option calculates the average + * velocity within a number n_slices of depth slices. + */ + enum VelocityScheme + { + reference_profile, + lateral_average + } average_velocity_scheme; + + /** + * Number of depth slices used to define average + * seismic shear wave velocities from which anomalies + * are calculated. + */ + unsigned int n_slices; + }; + + + + /** + * A class derived that implements a function that provides the computed + * computed seismic anomaly in $V_p$ for graphical output. + */ + template + class SeismicVpAnomaly + : + public CellDataVectorCreator, + public SimulatorAccess + { + public: + /** + * Constructor. + */ + SeismicVpAnomaly(); + + /** + * @copydoc CellDataVectorCreator::execute() + */ + std::pair>> + execute () const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + + /** + * Scheme chosen to define the average seismic velocity as a + * function of depth. Reference profile evaluates the material model + * using the P-T profile defined by the reference adiabatic + * conditions and the lateral average option calculates the average + * velocity within a number n_slices of depth slices. + */ + enum VelocityScheme + { + reference_profile, + lateral_average + } average_velocity_scheme; + + /** + * Number of depth slices used to define average + * seismic compressional wave velocities from which anomalies + * are calculated. + */ + unsigned int n_slices; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/shear_stress.h.bak b/include/aspect/postprocess/visualization/shear_stress.h.bak new file mode 100644 index 00000000000..460ba60ade4 --- /dev/null +++ b/include/aspect/postprocess/visualization/shear_stress.h.bak @@ -0,0 +1,72 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_shear_stress_h +#define _aspect_postprocess_visualization_shear_stress_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the 3 or 6 independent + * components (in 2d and 3d, respectively) of the shear stress tensor at + * every point. The shear stress is defined as $2 \eta + * (\varepsilon(\mathbf u) - \tfrac 13 \textrm{trace}\ + * \varepsilon(\mathbf u) \mathbf 1) = 2\eta (\varepsilon(\mathbf u) - + * \frac 13 (\nabla \cdot \mathbf u) \mathbf I)$ and differs from the + * full stress by the absence of the pressure. The second term in the + * difference is zero if the model is incompressible. + * If elasticity is used, the elastic contribution is being accounted for. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class ShearStress + : public DataPostprocessorTensor, + public SimulatorAccess, + public Interface + { + public: + /** + * Constructor. + */ + ShearStress (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/spd_factor.h.bak b/include/aspect/postprocess/visualization/spd_factor.h.bak new file mode 100644 index 00000000000..a001d55120c --- /dev/null +++ b/include/aspect/postprocess/visualization/spd_factor.h.bak @@ -0,0 +1,71 @@ +/* + Copyright (C) 2017 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_spd_factor_h +#define _aspect_postprocess_visualization_spd_factor_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the spd factor at every point. + * The spd factor is a factor which scales a part of the Jacobian used + * for the Newton solver to make sure that the Jacobian remains positive + * definite. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class SPD_Factor + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + SPD_Factor (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/spherical_velocity_components.h.bak b/include/aspect/postprocess/visualization/spherical_velocity_components.h.bak new file mode 100644 index 00000000000..e3d0749157d --- /dev/null +++ b/include/aspect/postprocess/visualization/spherical_velocity_components.h.bak @@ -0,0 +1,76 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_spherical_velocity_components_h +#define _aspect_postprocess_visualization_spherical_velocity_components_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + template + class SphericalVelocityComponents + : public DataPostprocessorVector, + public SimulatorAccess, + public Interface + { + public: + SphericalVelocityComponents (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + /** + * Return the vector of strings describing the names of the computed + * quantities. Given the purpose of this class, this is a vector + * with entries all equal to the name of the plugin. + */ + std::vector get_names () const override; + + /** + * This functions returns information about how the individual + * components of output files that consist of more than one data set + * are to be interpreted. The returned value is + * DataComponentInterpretation::component_is_scalar repeated + * SymmetricTensor::n_independent_components times. (These + * components should really be part of a symmetric tensor, but + * deal.II does not allow marking components as such.) + */ + std::vector + get_data_component_interpretation () const override; + + std::string + get_physical_units () const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/strain_rate.h.bak b/include/aspect/postprocess/visualization/strain_rate.h.bak new file mode 100644 index 00000000000..72668cb4228 --- /dev/null +++ b/include/aspect/postprocess/visualization/strain_rate.h.bak @@ -0,0 +1,67 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_strain_rate_h +#define _aspect_postprocess_visualization_strain_rate_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the strain rate at every + * point. The scalar strain rate is defined as $\sqrt{ (\varepsilon - + * \tfrac 13 \textrm{trace}\ \varepsilon \mathbf 1) : \varepsilon - + * \tfrac 13 \textrm{trace}\ \varepsilon \mathbf 1}$. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class StrainRate + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + /** + * Constructor. + */ + StrainRate (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/strain_rate_tensor.h.bak b/include/aspect/postprocess/visualization/strain_rate_tensor.h.bak new file mode 100644 index 00000000000..bdfed78dd4c --- /dev/null +++ b/include/aspect/postprocess/visualization/strain_rate_tensor.h.bak @@ -0,0 +1,65 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_strain_rate_tensor_h +#define _aspect_postprocess_visualization_strain_rate_tensor_h + +#include +#include + +#include + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the 4 or 9 + * components (in 2d and 3d, respectively) of the strain rate tensor at every + * point. + * The strain rate is defined as $\varepsilon(\mathbf u)$ in the incompressible + * case and as $\varepsilon(\mathbf u) + * - \tfrac 13 (\textrm{trace}\ \varepsilon(\mathbf u)) \mathbf I$ + * in the compressible case. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class StrainRateTensor + : public DataPostprocessorTensor, + public SimulatorAccess, + public Interface + { + public: + StrainRateTensor (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} +#endif diff --git a/include/aspect/postprocess/visualization/stress.h.bak b/include/aspect/postprocess/visualization/stress.h.bak new file mode 100644 index 00000000000..ae4ea386b81 --- /dev/null +++ b/include/aspect/postprocess/visualization/stress.h.bak @@ -0,0 +1,71 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_stress_h +#define _aspect_postprocess_visualization_stress_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the 3 or 6 independent + * components (in 2d and 3d, respectively) of the stress tensor at every + * point. The stress is defined as $2 \eta (\varepsilon(\mathbf u) + * - \tfrac 13 \textrm{trace}\ \varepsilon(\mathbf u) \mathbf 1) +pI = + * 2\eta (\varepsilon(\mathbf u) - \frac 13 (\nabla \cdot \mathbf u) + * \mathbf I) + pI$. The second term in the parentheses is zero if the + * model is incompressible. + * If elasticity is used, the elastic contribution is being accounted for. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class Stress + : public DataPostprocessorTensor, + public SimulatorAccess, + public Interface + { + public: + /** + * Constructor. + */ + Stress (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/stress_second_invariant.h.bak b/include/aspect/postprocess/visualization/stress_second_invariant.h.bak new file mode 100644 index 00000000000..458e7f4b1e2 --- /dev/null +++ b/include/aspect/postprocess/visualization/stress_second_invariant.h.bak @@ -0,0 +1,67 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_postprocess_visualization_stress_second_invariant_h +#define _aspect_postprocess_visualization_stress_second_invariant_h + +#include +#include + +#include + + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the second moment invariant + * of the deviatoric stress. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class StressSecondInvariant + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + /** + * Constructor. + */ + StressSecondInvariant (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/surface_dynamic_topography.h.bak b/include/aspect/postprocess/visualization/surface_dynamic_topography.h.bak new file mode 100644 index 00000000000..eca7bd7e1bc --- /dev/null +++ b/include/aspect/postprocess/visualization/surface_dynamic_topography.h.bak @@ -0,0 +1,72 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_surface_dynamic_topography_h +#define _aspect_postprocess_visualization_surface_dynamic_topography_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessorScalar that computes a + * variable that represents the dynamic topography, and outputs + * it on all boundary faces. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class SurfaceDynamicTopography + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface, + public SurfaceOnlyVisualization + { + public: + SurfaceDynamicTopography(); + + /** + * Evaluate the dynamic topography for the current cell. + * + * @copydoc DataPostprocessorScalar::evaluate_vector_field() + */ + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + /** + * Register the other postprocessor that we need: DynamicTopography + */ + std::list + required_other_postprocessors() const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/surface_elevation.h.bak b/include/aspect/postprocess/visualization/surface_elevation.h.bak new file mode 100644 index 00000000000..db80cca4cd2 --- /dev/null +++ b/include/aspect/postprocess/visualization/surface_elevation.h.bak @@ -0,0 +1,68 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_surface_elevation_h +#define _aspect_postprocess_visualization_surface_elevation_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessorScalar that computes a + * variable that represents the elevation of points on the ``top'' + * surface relative to the geometry's undeformed state, and outputs + * it on boundary faces. On boundary faces not marked as ``top'', + * this class outputs a zero elevation. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class SurfaceElevation + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface, + public SurfaceOnlyVisualization + { + public: + SurfaceElevation(); + + /** + * Evaluate the dynamic topography for the current cell. + * + * @copydoc DataPostprocessorScalar::evaluate_vector_field() + */ + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/surface_strain_rate_tensor.h.bak b/include/aspect/postprocess/visualization/surface_strain_rate_tensor.h.bak new file mode 100644 index 00000000000..15e5dfbd5c2 --- /dev/null +++ b/include/aspect/postprocess/visualization/surface_strain_rate_tensor.h.bak @@ -0,0 +1,68 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_surface_strain_rate_tensor_h +#define _aspect_postprocess_visualization_surface_strain_rate_tensor_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the 4 or 9 + * components (in 2d and 3d, respectively) of the strain rate tensor at every + * point of the surface of the domain. + * The strain rate is defined as $\varepsilon(\mathbf u)$ in the incompressible + * case and as $\varepsilon(\mathbf u) + * - \tfrac 13 (\textrm{trace}\ \varepsilon(\mathbf u)) \mathbf I$ + * in the compressible case. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class SurfaceStrainRateTensor + : public DataPostprocessorTensor, + public SimulatorAccess, + public Interface, + public SurfaceOnlyVisualization + { + public: + SurfaceStrainRateTensor (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/surface_stress.h.bak b/include/aspect/postprocess/visualization/surface_stress.h.bak new file mode 100644 index 00000000000..878c01d9351 --- /dev/null +++ b/include/aspect/postprocess/visualization/surface_stress.h.bak @@ -0,0 +1,73 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_surface_stress_h +#define _aspect_postprocess_visualization_surface_stress_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the 3 or 6 independent + * components (in 2d and 3d, respectively) of the stress tensor at every + * point of the surface of the domain. + * The stress is defined as $2 \eta (\varepsilon(\mathbf u) + * - \tfrac 13 \textrm{trace}\ \varepsilon(\mathbf u) \mathbf 1) +pI = + * 2\eta (\varepsilon(\mathbf u) - \frac 13 (\nabla \cdot \mathbf u) + * \mathbf I) + pI$. The second term in the parentheses is zero if the + * model is incompressible. If elasticity is used, its contribution + * is accounted for. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class SurfaceStress + : public DataPostprocessorTensor, + public SimulatorAccess, + public Interface, + public SurfaceOnlyVisualization + { + public: + /** + * Constructor. + */ + SurfaceStress (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/temperature_anomaly.h.bak b/include/aspect/postprocess/visualization/temperature_anomaly.h.bak new file mode 100644 index 00000000000..bc00e09d94f --- /dev/null +++ b/include/aspect/postprocess/visualization/temperature_anomaly.h.bak @@ -0,0 +1,93 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_temperature_anomaly_h +#define _aspect_postprocess_visualization_temperature_anomaly_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that outputs the temperature + * anomaly (temperature-depth average of temperature). + */ + template + class TemperatureAnomaly + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + TemperatureAnomaly (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + void + update () override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Number of slices to use when computing depth average of temperature. + */ + unsigned int n_slices; + /** + * Vector of temperature depth average values, padded to include two ghost values + * above and below the surface and bottom of the domain to allow interpolation at + * all depths. + */ + std::vector padded_temperature_depth_average; + /** + * Whether to extrapolate temperatures above/below the first/last depth-average slice + * or, alternatively, interpolate above the center of the first slice using the surface + * temperature or below the last slice using the bottom temperature. + */ + bool extrapolate_surface; + bool extrapolate_bottom; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/vertical_heat_flux.h.bak b/include/aspect/postprocess/visualization/vertical_heat_flux.h.bak new file mode 100644 index 00000000000..d1c00c694db --- /dev/null +++ b/include/aspect/postprocess/visualization/vertical_heat_flux.h.bak @@ -0,0 +1,67 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_vertical_heat_flux_h +#define _aspect_postprocess_visualization_vertical_heat_flux_h + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the density at every point. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class VerticalHeatFlux + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + /** + * Constructor + */ + VerticalHeatFlux (); + + /** + * Evaluate the vertical heat flux for the current cell. + */ + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/volume_of_fluid_values.h.bak b/include/aspect/postprocess/visualization/volume_of_fluid_values.h.bak new file mode 100644 index 00000000000..bd9225431a5 --- /dev/null +++ b/include/aspect/postprocess/visualization/volume_of_fluid_values.h.bak @@ -0,0 +1,116 @@ +/* + Copyright (C) 2016 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_postprocess_visualization_volume_of_fluid_values_h +#define _aspect_postprocess_visualization_volume_of_fluid_values_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * Plugin to output volume fractions and reconstructed interface data + * from the Volume of Fluid Interface Tracking data. + */ + template + class VolumeOfFluidValues + : public DataPostprocessor, + public SimulatorAccess, + public Interface + { + public: + /** + * Standard constructor + */ + VolumeOfFluidValues (); + + /** + * Get the list of names for the components that will be produced by + * this postprocessor + */ + std::vector + get_names () const override; + + /** + * Get the list of component interpretations for the components that + * will be produced by this postprocessor + */ + std::vector + get_data_component_interpretation () const override; + + /** + * Get required update flags + */ + UpdateFlags + get_needed_update_flags () const override; + + /** + * Produce that data based on provided solution data + */ + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Stored list of names for the produced components + */ + std::vector volume_of_fluid_names; + + /** + * Stored list of interpretations for produced components + */ + std::vector interpretations; + + /** + * If true, the data output will include a field that has the + * reconstructed fluid interface as the zero contour + */ + bool include_contour; + + /** + * If true, the data output will include the normal vector for the reconstructed interface + */ + bool include_normal; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/visualization/volumetric_strain_rate.h.bak b/include/aspect/postprocess/visualization/volumetric_strain_rate.h.bak new file mode 100644 index 00000000000..4ceafefbd76 --- /dev/null +++ b/include/aspect/postprocess/visualization/volumetric_strain_rate.h.bak @@ -0,0 +1,62 @@ +/* + Copyright (C) 2017 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_postprocess_volumetric_strain_rate_h +#define _aspect_postprocess_volumetric_strain_rate_h + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + namespace VisualizationPostprocessors + { + /** + * A class derived from DataPostprocessor that takes an output vector + * and computes a variable that represents the volumetric strain rate at every + * point. The volumetric strain rate is defined as the divergence of the velocity + * (or the trace of the strain rate tensor): + * $\nabla\cdot\mathbf u = \textrm{div}\; \mathbf u = \textrm{trace}\; \varepsilon(\mathbf u)$. + * + * The member functions are all implementations of those declared in the + * base class. See there for their meaning. + */ + template + class VolumetricStrainRate + : public DataPostprocessorScalar, + public SimulatorAccess, + public Interface + { + public: + VolumetricStrainRate (); + + void + evaluate_vector_field(const DataPostprocessorInputs::Vector &input_data, + std::vector> &computed_quantities) const override; + }; + } + } +} + +#endif diff --git a/include/aspect/postprocess/volume_of_fluid_statistics.h.bak b/include/aspect/postprocess/volume_of_fluid_statistics.h.bak new file mode 100644 index 00000000000..d7c04b867ff --- /dev/null +++ b/include/aspect/postprocess/volume_of_fluid_statistics.h.bak @@ -0,0 +1,53 @@ + +/* + Copyright (C) 2016 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_postprocess_volume_of_fluid_statistics_h +#define _aspect_postprocess_volume_of_fluid_statistics_h + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + + /** + * A postprocessor that computes some statistics about the volume of fluid fields + * + * @ingroup Postprocessing + */ + template + class VolumeOfFluidStatistics : public Interface, public ::aspect::SimulatorAccess + { + public: + /** + * Evaluate the solution for some velocity statistics. + */ + std::pair + execute (TableHandler &statistics) override; + }; + } +} + + +#endif diff --git a/include/aspect/prescribed_stokes_solution/ascii_data.h.bak b/include/aspect/prescribed_stokes_solution/ascii_data.h.bak new file mode 100644 index 00000000000..c8311aa71be --- /dev/null +++ b/include/aspect/prescribed_stokes_solution/ascii_data.h.bak @@ -0,0 +1,85 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_prescribed_stokes_solution_ascii_data_h +#define _aspect_prescribed_stokes_solution_ascii_data_h + +#include +#include +#include + + +namespace aspect +{ + namespace PrescribedStokesSolution + { + using namespace dealii; + + /** + * A class that implements a prescribed velocity field determined from + * a AsciiData input file. + * + * @ingroup PrescribedStokesSolution + */ + template + class AsciiData : public Utilities::AsciiDataInitial, public Interface + { + public: + /** + * Empty Constructor. + */ + AsciiData (); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + void + initialize () override; + + // avoid -Woverloaded-virtual: + using Utilities::AsciiDataInitial::initialize; + + /** + * For the current class, this function returns value from the text + * files. + */ + void + stokes_solution (const Point &position, Vector &value) const override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + }; + } +} + + +#endif diff --git a/include/aspect/prescribed_stokes_solution/circle.h.bak b/include/aspect/prescribed_stokes_solution/circle.h.bak new file mode 100644 index 00000000000..5e350d14d6c --- /dev/null +++ b/include/aspect/prescribed_stokes_solution/circle.h.bak @@ -0,0 +1,51 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_prescribed_stokes_solution_circle_h +#define _aspect_prescribed_stokes_solution_circle_h + +#include +#include + + +namespace aspect +{ + namespace PrescribedStokesSolution + { + using namespace dealii; + + /** + * A class that implements a circular, divergence-free flow field + * around the origin of the coordinate system. + * + * @ingroup PrescribedStokesSolution + */ + template + class Circle : public Interface, public SimulatorAccess + { + public: + void stokes_solution (const Point &p, Vector &value) const override; + }; + } +} + + +#endif diff --git a/include/aspect/prescribed_stokes_solution/function.h.bak b/include/aspect/prescribed_stokes_solution/function.h.bak new file mode 100644 index 00000000000..355a6eb6eea --- /dev/null +++ b/include/aspect/prescribed_stokes_solution/function.h.bak @@ -0,0 +1,105 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_prescribed_stokes_solution_function_h +#define _aspect_prescribed_stokes_solution_function_h + +#include +#include + +#include + +namespace aspect +{ + namespace PrescribedStokesSolution + { + using namespace dealii; + + /** + * A class that implements velocity and pressure solutions based on a + * functional description provided in the input file. + * + * @ingroup PrescribedStokesSolution + */ + template + class Function : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + Function (); + + /** + * Return the velocity and pressure as a function of position. + */ + void + stokes_solution (const Point &position, Vector &value) const override; + + /** + * A function that is called at the beginning of each time step to + * indicate what the model time is for which the velocity and + * pressure values will next be evaluated. For the current class, + * the function passes to the parsed function what the current time is. + */ + void + update () override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * A function object representing the components of the velocity. + */ + Functions::ParsedFunction prescribed_velocity_function; + /** + * A function object representing the pressure. + */ + Functions::ParsedFunction prescribed_pressure_function; + /** + * A function object representing the fluid pressure (in models with melt transport). + */ + Functions::ParsedFunction prescribed_fluid_pressure_function; + /** + * A function object representing the compaction pressure (in models with melt transport). + */ + Functions::ParsedFunction prescribed_compaction_pressure_function; + /** + * A function object representing the components of the fluid velocity (in models with melt transport). + */ + Functions::ParsedFunction prescribed_fluid_velocity_function; + }; + } +} + + +#endif diff --git a/include/aspect/prescribed_stokes_solution/interface.h.bak b/include/aspect/prescribed_stokes_solution/interface.h.bak new file mode 100644 index 00000000000..6d4f41421fa --- /dev/null +++ b/include/aspect/prescribed_stokes_solution/interface.h.bak @@ -0,0 +1,159 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#ifndef _aspect_prescribed_stokes_solution_interface_h +#define _aspect_prescribed_stokes_solution_interface_h + +#include + +#include +#include + +#include + +namespace aspect +{ + /** + * A namespace in which we define everything that has to do with defining + * the prescribed Stokes solution. + * + * @ingroup PrescribedStokesSolution + */ + namespace PrescribedStokesSolution + { + using namespace dealii; + + /** + * This plugin allows the user to prescribe a Stokes solution and can be + * thought of as velocity and pressure's equivalent of the initial + * conditions plugin. + * + * Note: This can only be used if the nonlinear solver scheme is + * `single Advection, no Stokes'. + * + * @ingroup PrescribedStokesSolution + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Given a position @p p, fill in desired velocity and pressure at + * that point into @p value, which will have dim+1 components. In @p + * value, the velocity components come first, followed by the pressure + * component. + */ + virtual + void stokes_solution (const Point &p, Vector &value) const = 0; + }; + + + + + /** + * Register initial prescribed Stokes solution model so that it can be + * selected from the parameter file. + * + * @param name A string that identifies the prescribed Stokes solution + * model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this prescribed Stokes solution + * model wants to read from input files. + * @param factory_function A pointer to a function that can create an + * object of this prescribed Stokes solution model. + * + * @ingroup PrescribedStokesSolution + */ + template + void + register_prescribed_stokes_solution_model (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * A function that given the name of a model returns a pointer to an + * object that describes it. Ownership of the pointer is transferred to + * the caller. + * + * The model object returned is not yet initialized and has not read its + * runtime parameters yet. + * + * @ingroup PrescribedStokesSolution + */ + template + std::unique_ptr> + create_prescribed_stokes_solution (ParameterHandler &prm); + + + /** + * Declare the runtime parameters of the registered prescribed Stokes + * solution models. + * + * @ingroup PrescribedStokesSolution + */ + template + void + declare_parameters (ParameterHandler &prm); + + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + template + void + write_plugin_graph (std::ostream &output_stream); + + + + /** + * Given a class name, a name, and a description for the parameter file + * for a prescribed Stokes solution model, register it with the functions + * that can declare their parameters and create these objects. + * + * @ingroup PrescribedStokesSolution + */ +#define ASPECT_REGISTER_PRESCRIBED_STOKES_SOLUTION(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_PRESCRIBED_STOKES_SOLUTION_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::PrescribedStokesSolution::register_prescribed_stokes_solution_model<2>, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::PrescribedStokesSolution::register_prescribed_stokes_solution_model<3>, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/simulator.h.bak b/include/aspect/simulator.h.bak new file mode 100644 index 00000000000..0c7fbd1630f --- /dev/null +++ b/include/aspect/simulator.h.bak @@ -0,0 +1,2203 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_simulator_h +#define _aspect_simulator_h + +#include +#include +#include +#include + +DEAL_II_DISABLE_EXTRA_DIAGNOSTICS + +#include + +#include + +#include +#include + +#include +#include +#include + +DEAL_II_ENABLE_EXTRA_DIAGNOSTICS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +namespace aspect +{ + using namespace dealii; + + template + class MeltHandler; + + template + class NewtonHandler; + + template + class StokesMatrixFreeHandler; + + template + class StokesMatrixFreeHandlerImplementation; + + namespace MeshDeformation + { + template + class MeshDeformationHandler; + } + + template + class VolumeOfFluidHandler; + + namespace internal + { + namespace Assembly + { + namespace Scratch + { + template struct StokesPreconditioner; + template struct StokesSystem; + template struct AdvectionSystem; + } + + namespace CopyData + { + template struct StokesPreconditioner; + template struct StokesSystem; + template struct AdvectionSystem; + } + } + } + + namespace Assemblers + { + template class Interface; + template class Manager; + } + + struct DefectCorrectionResiduals + { + double initial_residual; + double velocity_residual; + double pressure_residual; + double residual; + double residual_old; + double switch_initial_residual; + double newton_residual_for_derivative_scaling_factor; + std::pair stokes_residuals; + }; + + /** + * A data structure with all properties relevant to compute angular momentum and rotation. + */ + template + struct RotationProperties + { + RotationProperties() + : + scalar_moment_of_inertia(numbers::signaling_nan()), + scalar_angular_momentum(numbers::signaling_nan()), + scalar_rotation(numbers::signaling_nan()), + tensor_moment_of_inertia(numbers::signaling_nan>()), + tensor_angular_momentum(numbers::signaling_nan>()), + tensor_rotation(numbers::signaling_nan>()) + {}; + + /** + * Scalar properties for the two-dimensional case + * with a fixed rotation axis (z). + */ + double scalar_moment_of_inertia; + double scalar_angular_momentum; + double scalar_rotation; + + /** + * Tensor properties for the three-dimensional case. + */ + SymmetricTensor<2,dim> tensor_moment_of_inertia; + Tensor<1,dim> tensor_angular_momentum; + Tensor<1,dim> tensor_rotation; + }; + + /** + * This is the main class of ASPECT. It implements the overall simulation + * algorithm using the numerical methods discussed in the papers and manuals + * that accompany ASPECT. + * + * @ingroup Simulator + */ + template + class Simulator + { + public: + /** + * Constructor. + * + * @param mpi_communicator The MPI communicator on which this class is + * to work. The class creates a clone of the actual communicator to make + * its communications private from the rest of the world. + * + * @param prm The run-time parameter object from which this class + * obtains its settings. + * + * This function is implemented in + * source/simulator/core.cc. + */ + Simulator (const MPI_Comm mpi_communicator, + ParameterHandler &prm); + + /** + * Destructor. Destroy what needs to be destroyed after waiting for all + * threads that may still be doing something in the background. + */ + ~Simulator (); + + /** + * Declare the run-time parameters this class takes, and call the + * respective declare_parameters functions of the + * namespaces that describe geometries, material models, etc. + * + * @param prm The object in which the run-time parameters are to be + * declared. + * + * This function is implemented in + * source/simulator/parameters.cc. + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * The function that runs the overall algorithm. It contains the loop + * over all time steps as well as the logic of what to do when before + * the loop starts and within the time loop. + * + * This function is implemented in + * source/simulator/core.cc. + */ + void run (); + + /** + * Write a connection graph of all of the plugins we know about, in the + * format that the programs dot and neato understand. This allows for a + * visualization of how all of the plugins that ASPECT knows about are + * interconnected, and connect to other parts of the ASPECT code. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + * + * @param output_stream The stream to write the output to. + */ + void + write_plugin_graph (std::ostream &output_stream) const; + + /** + * Import Nonlinear Solver type. + */ + using NonlinearSolver = typename Parameters::NonlinearSolver; + + /** + * Import nullspace removal type. + */ + using NullspaceRemoval = typename Parameters::NullspaceRemoval; + + + /** + * A structure that is used as an argument to functions that can work on + * both the temperature and the compositional variables and that need to + * be told which one of the two, as well as on which of the + * compositional variables. + */ + struct AdvectionField + { + /** + * An enum indicating whether the identified variable is the + * temperature or one of the compositional fields. + */ + enum FieldType { temperature_field, compositional_field }; + + /** + * A variable indicating whether the identified variable is the + * temperature or one of the compositional fields. + */ + const FieldType field_type; + + /** + * A variable identifying which of the compositional fields is + * selected. This variable is meaningless if the temperature is + * selected. + */ + const unsigned int compositional_variable; + + /** + * Constructor. + * @param field_type Determines whether this variable should select + * the temperature field or a compositional field. + * @param compositional_variable The number of the compositional field + * if the first argument in fact chooses a compositional variable. + * Meaningless if the first argument equals temperature. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + AdvectionField (const FieldType field_type, + const unsigned int compositional_variable = numbers::invalid_unsigned_int); + + /** + * A static function that creates an object identifying the + * temperature. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + static + AdvectionField temperature (); + + /** + * A static function that creates an object identifying given + * compositional field. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + static + AdvectionField composition (const unsigned int compositional_variable); + + /** + * Return whether this object refers to the temperature field. + */ + bool + is_temperature () const; + + /** + * Return whether this object refers to a field discretized by + * discontinuous finite elements. + */ + bool + is_discontinuous (const Introspection &introspection) const; + + /** + * Return the method that is used to solve the advection of this field + * (i.e. 'fem_field', 'particles'). + */ + typename Parameters::AdvectionFieldMethod::Kind + advection_method (const Introspection &introspection) const; + + /** + * Look up the component index for this temperature or compositional + * field. See Introspection::component_indices for more information. + */ + unsigned int component_index(const Introspection &introspection) const; + + /** + * Look up the block index for this temperature or compositional + * field. See Introspection::block_indices for more information. + */ + unsigned int block_index(const Introspection &introspection) const; + + /** + * Look up the block index where the sparsity pattern for this field + * is stored. This can be different than block_index() as several fields + * can use the same pattern (typically in the first compositional field + * if all fields are compatible). See Introspection::block_indices + * for more information. + */ + unsigned int sparsity_pattern_block_index(const Introspection &introspection) const; + + /** + * Returns an index that runs from 0 (temperature field) to n (nth + * compositional field), and uniquely identifies the current advection + * field among the list of all advection fields. Can be used to index + * vectors that contain entries for all advection fields. + */ + unsigned int field_index() const; + + /** + * Look up the base element within the larger composite finite element + * we used for everything, for this temperature or compositional field + * See Introspection::base_elements for more information. + */ + unsigned int base_element(const Introspection &introspection) const; + + /** + * Return the FEValues scalar extractor for this temperature + * or compositional field. + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + FEValuesExtractors::Scalar scalar_extractor(const Introspection &introspection) const; + + /** + * Look up the polynomial degree order for this temperature or compositional + * field. See Introspection::polynomial_degree for more information. + */ + unsigned int polynomial_degree(const Introspection &introspection) const; + }; + + private: + + /** + * A member variable that tracks whether we are completely done + * with initialization and have started the time loop. This + * variable needs to be the first one that is initialized in + * the constructor, so that its value correctly tracks the + * status of the overall object. As a consequence, it has to + * be the first one declared in this class. + * + * The variable is set to @p true just before we start the time + * stepping loop, but may be temporarily reset to @p false + * if, for example, we are during the initial mesh refinement + * steps where we start the time loop, but then go back to + * initialization steps (mesh refinement, interpolation of initial + * conditions, etc.) before re-starting the time loop. + * + * This variable is queried by + * SimulatorAccess::simulator_is_past_initialization(). + */ + bool simulator_is_past_initialization; + + /** + * A class that is empty but that can be used as a member variable and + * whose constructor will be run in the order in which the member + * variables are initialized. Because this class has a constructor that + * takes a function object that it will execute whenever the member + * variable is initialized, this allows running arbitrary actions in + * between member variable initializers, for example if some member + * variable is partially initialized at point A within the member + * variable initializer list, its initialization can only be finalized + * after point B (because it depends on what another member variable + * decides to do), but needs to be finished by point C within the member + * initialization. In such a case, one may have a member variable of the + * current time placed in the list of member variables such that it is + * initialized at point B, and then initialize it using a function + * object that performs the finalization of initialization. + */ + struct IntermediaryConstructorAction + { + IntermediaryConstructorAction (const std::function &action); + }; + + /** + * @name Top-level functions in the overall flow of the numerical + * algorithm + * @{ + */ + + /** + * The function that sets up the DoFHandler objects, It also sets up the + * various partitioners and computes those constraints on the Stokes + * variable and temperature that are the same between all time steps. + * + * This function is implemented in + * source/simulator/core.cc. + */ + void setup_dofs (); + + /** + * This function initializes the variables of the introspection object. + * It is called by setup_dofs() right after distributing degrees of + * freedom since this is when all of the information is available. + * + * This function is implemented in + * source/simulator/core.cc. + */ + void setup_introspection (); + + /** + * A function that is responsible for initializing the + * temperature/compositional field before the first time step. The + * temperature field then serves as the temperature from which the + * velocity is computed during the first time step, and is subsequently + * overwritten by the temperature field one gets by advancing by one + * time step. + * + * This function is implemented in + * source/simulator/initial_conditions.cc. + */ + void set_initial_temperature_and_compositional_fields (); + + /** + * A function that initializes the pressure variable before the first + * time step. It does so by either interpolating (for continuous + * pressure finite elements) or projecting (for discontinuous elements) + * the adiabatic pressure computed from the material model. + * + * Note that the pressure so set is overwritten by the pressure in fact + * computed during the first time step. We need this function, however, + * so that the evaluation of pressure-dependent coefficients (e.g. + * pressure dependent densities or thermal coefficients) during the + * first time step has some useful pressure to start with. + * + * This function is implemented in + * source/simulator/initial_conditions.cc. + */ + void compute_initial_pressure_field (); + + /** + * Fill the given @p constraints with constraints coming from the velocity boundary + * conditions that do not change over time. This function is used by + * setup_dofs(); + */ + void compute_initial_velocity_boundary_constraints (AffineConstraints &constraints); + + /** + * Fill the given @p constraints with constraints coming from the velocity boundary + * conditions that do can change over time. This function is used by + * compute_current_constraints(). + */ + void compute_current_velocity_boundary_constraints (AffineConstraints &constraints); + + /** + * Given the 'constraints' member that contains all constraints that are + * independent of the time (e.g., hanging node constraints, tangential + * flow constraints, etc), copy it over to 'current_constraints' and add + * to the latter all constraints that do depend on time such as + * temperature or velocity Dirichlet boundary conditions. This function + * is therefore called at the beginning of every time step in + * start_timestep(), but also when setting up the initial values. + * + * This function is implemented in + * source/simulator/core.cc. + */ + void compute_current_constraints (); + + /** + * Compute the factor by which we scale the second of + * the Stokes equations (the "pressure scaling factor"). + * We compute the factor by taking the logarithmic + * average of the viscosities we find on the cells in + * this domain and dividing this average by a reference + * length scale provided by the used geometry model. + * + * This function returns the pressure scaling variable. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + double compute_pressure_scaling_factor () const; + + /** + * Do some housekeeping at the beginning of each time step. This + * includes generating some screen output, adding some information to + * the statistics file, and interpolating time-dependent boundary + * conditions specific to this particular time step (the time + * independent boundary conditions, for example for hanging nodes or for + * tangential flow, are computed only once per mesh in setup_dofs()). + * + * This function is implemented in + * source/simulator/core.cc. + */ + void start_timestep (); + + /** + * Do the various steps necessary to assemble and solve the things + * necessary in each time step. + * + * This function is implemented in + * source/simulator/core.cc. + */ + void solve_timestep (); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * If `single Advection, single Stokes' is selected as the nonlinear solver scheme, + * no nonlinear iterations are done, and the temperature, compositional fields and + * Stokes equations are solved exactly once per time step, one after the other. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_single_advection_single_stokes (); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * The `no Advection, iterated Stokes' scheme only solves the Stokes system and + * ignores compositions and the temperature equation (careful, the material + * model must not depend on the temperature; mostly useful for + * Stokes benchmarks). + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_no_advection_iterated_stokes (); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * The `no Advection, single Stokes' scheme only solves the Stokes system and + * ignores compositions and the temperature equation. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_no_advection_single_stokes (); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * The `first timestep only, single Stokes' scheme only solves the Stokes system, + * for the initial timestep. This results in a `steady state' velocity field for + * particle calculations. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_first_timestep_only_single_stokes (); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * The `iterated Advection and Stokes' scheme iterates + * by alternating the solution of the temperature, composition and Stokes systems. + * This is essentially a type of Picard iterations for the whole + * system of equations. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_iterated_advection_and_stokes (); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * The `single Advection, iterated Stokes' scheme solves the temperature and + * composition equations once at the beginning of each time step + * and then iterates out the solution of the Stokes equation using + * Picard iterations. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_single_advection_iterated_stokes (); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * The `no Advection, iterated defect correction Stokes' scheme + * does not solve the temperature and composition equations + * but only iterates out the solution of the Stokes + * equation using Defect Correction (DC) Picard iterations. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_no_advection_iterated_defect_correction_stokes (); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * The `single Advection, iterated defect correction Stokes' scheme + * solves the temperature and composition equations once at the beginning + * of each time step and then iterates out the solution of the Stokes + * equation using Defect Correction (DC) Picard iterations. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_single_advection_iterated_defect_correction_stokes (); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * The `iterated Advection and defect correction Stokes' scheme + * iterates over both the temperature and composition equations + * and the Stokes equations at the same time. The Stokes equation + * is iterated out using the Defect Correction (DC) form of the + * Picard iterations. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_iterated_advection_and_defect_correction_stokes (); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * The `iterated Advection and Newton Stokes' scheme iterates over solving the temperature, + * composition, and Stokes equations just like `iterated Advection and Stokes', but + * for the Stokes system it is able to switch from a defect correction form of + * Picard iterations to Newton iterations after a certain tolerance or + * number of iterations is reached. This can greatly improve the + * convergence rate for particularly nonlinear viscosities. + * + * @param use_newton_iterations Sets whether this function should only use defect + * correction iterations (use_newton_iterations = false) or also use Newton iterations + * (use_newton_iterations = true). + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_iterated_advection_and_newton_stokes (bool use_newton_iterations); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * The `single Advection, iterated Newton Stokes' scheme solves the temperature and + * composition equations once at the beginning of each time step + * and then iterates out the solution of the Stokes equation using Newton iterations. + * For the Stokes system it is able to switch from a defect correction form of + * Picard iterations to Newton iterations after a certain tolerance or + * number of iterations is reached. This can greatly improve the + * convergence rate for particularly nonlinear viscosities. + * + * @param use_newton_iterations Sets whether this function should only use defect + * correction iterations (use_newton_iterations = false) or also use Newton iterations + * (use_newton_iterations = true). + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_single_advection_and_iterated_newton_stokes (bool use_newton_iterations); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * The `single Advection, no Stokes' scheme only solves the temperature and other + * advection systems and instead of solving for the Stokes system, + * a prescribed velocity and pressure is used." + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_single_advection_no_stokes (); + + /** + * This function implements one scheme for the various + * steps necessary to assemble and solve the nonlinear problem. + * + * The `no Advection, no Stokes' scheme skips solving the temperature, + * composition and Stokes equations, which permits to go directly to + * postprocessing after setting up the initial condition. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void solve_no_advection_no_stokes (); + + /** + * Initiate the assembly of the Stokes preconditioner matrix via + * assemble_stokes_preconditioner(), then set up the data structures to + * actually build a preconditioner from this matrix. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void build_stokes_preconditioner (); + + /** + * Initialize the preconditioner for the advection equation of field + * index. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void build_advection_preconditioner (const AdvectionField &advection_field, + aspect::LinearAlgebra::PreconditionILU &preconditioner, + const double diagonal_strengthening); + + /** + * Initiate the assembly of the Stokes matrix and right hand side. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void assemble_stokes_system (); + + /** + * Assemble and solve the temperature equation. + * This function returns the residual after solving. + * + * If the `residual` argument is not a `nullptr`, the function computes + * the residual and puts it into this variable. The function returns + * the current residual divided by the initial residual given as the + * first argument. The two arguments may point to the same variable, + * in which case the function first computes the residual and at + * the end scales that residual by itself, thus returning 1.0. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + double assemble_and_solve_temperature (const double &initial_residual = 0, + double *residual = nullptr); + + /** + * Solve the composition equations with whatever method is selected + * (fields or particles). This function returns the residuals for + * all fields after solving. + * + * If the `residual` argument is not a `nullptr`, the function computes + * the residual and puts it into this variable. The function returns + * the current residual divided by the initial residual given as the + * first argument. The two arguments may point to the same variable, + * in which case the function first computes the residual and at + * the end scales that residual by itself, thus returning 1.0. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + std::vector assemble_and_solve_composition (const std::vector &initial_residual = {}, + std::vector *residual = nullptr); + + /** + * Assemble and solve the Stokes equation. + * This function returns the nonlinear residual after solving. + * + * If the `residual` argument is not a `nullptr`, the function computes + * the residual and puts it into this variable. The function returns + * the current residual divided by the initial residual given as the + * first argument. The two arguments may point to the same variable, + * in which case the function first computes the residual and at + * the end scales that residual by itself, thus returning 1.0. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + double assemble_and_solve_stokes (const double &initial_nonlinear_residual = 0, + double *nonlinear_residual = nullptr); + + /** + * Do one step of the defect correction form of the Stokes equation; + * i.e., assemble and solve the defect correction equations. + * This function takes a structure of DefectCorrectionResiduals which + * contains information about different residuals. The information in + * this structure is updated by this function. The parameter use_picard + * forces the use of the defect correction Picard iteration, if set to 'true' no + * Newton derivatives are added to the matrix. + * + * This function is implemented in + * source/simulator/solver_schemes.cc. + */ + void do_one_defect_correction_Stokes_step(DefectCorrectionResiduals &dcr, + const bool use_picard); + + /** + * Initiate the assembly of one advection matrix and right hand side and + * build a preconditioner for the matrix. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void assemble_advection_system (const AdvectionField &advection_field); + + /** + * Solve one block of the temperature/composition linear system. + * Return the initial nonlinear residual, i.e., if the linear system to + * be solved is $Ax=b$, then return $\|Ax_0-b\|$ where $x_0$ is the + * initial guess for the solution variable and is taken from the + * current_linearization_point member variable. + * + * This function is implemented in + * source/simulator/solver.cc. + */ + double solve_advection (const AdvectionField &advection_field); + + /** + * Interpolate a particular particle property to the solution field. + * + * @deprecated: Use interpolate_particle_property_vector() instead. + */ + DEAL_II_DEPRECATED + void interpolate_particle_properties (const AdvectionField &advection_field); + + /** + * Interpolate the corresponding particle properties into the given + * @p advection_fields solution fields. + */ + void interpolate_particle_properties (const std::vector &advection_fields); + + /** + * Solve the Stokes linear system. + * + * The function returns two pieces of information as a pair of doubles: + * - The initial nonlinear residual, i.e., if the linear system to be + * solved is $Ax_{k+1}=b$, then we use $\|Ax_k-b\|$ where $x_k$ is the + * initial guess for the solution variable and is taken from + * the @p current_linearization_point member variable. For the + * purpose of this function, this residual is computed + * only from the velocity and pressure equations (i.e., for the 2x2 block + * system involving the velocity and pressure variables). A rationale + * for why this number is computed is given below. + * - The final linear residual, i.e., if the linear system to be + * solved is $Ax_{k+1}=b$, then we use $\|Ax_{k+1}-b\|$ where $x_{k+1}$ + * is the solution just computed. If we use a direct solver to compute + * the solution of the linear system, then this linear residual is of + * course zero (or at least quite close to it) and the function just + * returns a zero value without even attempting to compute the actual + * value. On the other hand, if the function uses an iterative solver, + * then the value of the final linear residual is related to the + * tolerance with which we solve the linear system and generally + * indicates how accurately or inaccurately the linear system has been + * solved. + * + * The two values are used in nonlinear solver schemes to assess how + * accurate the solution was before the current solve (for the first + * element of the returned pair) and how accurately the next iteration + * will have to be solved (for the second element of the pair) when using + * the Eisenstat-Walker method. + * + * @note If this function is called from a nonlinear solver -- e.g., the + * `single Advection, iterated Stokes', or the + * `iterated Advection and Stokes' solvers schemes --, then the + * @p current_linearization_point is the solution of the previous + * iteration (or the solution extrapolated from the previous time + * steps, if this is the first nonlinear iteration). Let us call + * this solution $x_k$ as above, where $x$ is a two-component + * block vector that consists of velocity and pressure. This function + * then assumes that we have already built the system matrix $A_k=A(x_k)$ + * and $F_k=F(x_k)$, both linearized around the previous solution. The + * function solves the linear system $A_k x_{k+1} = F_k$ for the + * solution $x_{k+1}$. If the linear system were solved exactly, then + * that would imply that the linear residual + * $\|A_k x_{k+1} - F_k\|$ were zero, or at least small. In other words, + * its size does not tell us anything about how accurately we have + * solved the nonlinear system. On the other hand, the nonlinear + * residual $\|A_k x_k - F_k\|$ tells us something about how + * accurately the previous guess $x_k$ already solved the nonlinear + * system. Consequently, this is what this function returns. (In some + * sense, this is not really what we are interested in: it tells us + * how accurate the solution already was, and if it was already + * pretty accurate, then we may not want to actually solve for + * $x_{k+1}$. But, this would require that this function receives a + * tolerance so that it can bail out early without actually solving + * for $x_{k+1}$ if the tolerance is already reached. This function does + * not actually do that -- in some sense, one may argue that if we have + * already built the matrix and right hand side, we may as well solve + * with them, whether or not the solution was already good. If it + * happens to have been good already, then it will be even better after + * the solve. If it was not good enough yet, then we have to solve + * anyway.) In contrast to all of this, if we are using a Newton + * solver, then $x_{k+1}$ is actually the Newton update + * vector, for which we have no initial guess other than the zero + * vector. In this case, the function simply returns $\|F_k\|$ as the + * first element of the pair, where $F_k=F(x_k)$ is the residual + * vector for the previous solution $x_k$. + * + * This function is implemented in + * source/simulator/solver.cc. + */ + std::pair + solve_stokes (); + + /** + * Solve the Stokes system using a block preconditioner and GMG. + */ + std::pair + solve_stokes_block_gmg (); + + /** + * This function is called at the end of every time step. It runs all + * the postprocessors that have been listed in the input parameter file + * (see the manual) in turn. In particular, this usually includes + * generating graphical output every few time steps. + * + * The function also updates the statistics output file at the end of + * each time step. + * + * This function is implemented in + * source/simulator/core.cc. + */ + void postprocess (); + + /** + * Refine the mesh according to error indicators calculated by + * compute_refinement_criterion(), set up all necessary data structures + * on this new mesh, and interpolate the old solutions onto the new + * mesh. + * + * @param[in] max_grid_level The maximum refinement level of the mesh. + * This is the sum of the initial global refinement and the initial + * adaptive refinement (as provided by the user in the input file) and + * in addition it gets increased by one at each additional refinement + * time. + * + * This function is implemented in + * source/simulator/core.cc. + */ + void refine_mesh (const unsigned int max_grid_level); + + /** + * @} + */ + + /** + * @name Functions used in saving the state of the program and + * restarting from a saved state + * @{ + */ + /** + * Save the state of this program to a set of files in the output + * directory. In reality, however, only some variables are stored (in + * particular the mesh, the solution vectors, etc) whereas others can + * either be re-generated (matrices, DoFHandler objects, etc) or are + * read from the input parameter file. See the manual for more + * information. + * + * This function is implemented in + * source/simulator/checkpoint_restart.cc. + */ + void create_snapshot(); + + /** + * Restore the state of this program from a set of files in the output + * directory. In reality, however, only some variables are stored (in + * particular the mesh, the solution vectors, etc) whereas others can + * either be re-generated (matrices, DoFHandler objects, etc) or are + * read from the input parameter file. See the manual for more + * information. This function only restores those variables that can + * neither be re-generated from other information nor are read from the + * input parameter file. + * + * This function is implemented in + * source/simulator/checkpoint_restart.cc. + */ + void resume_from_snapshot(); + + /** + * Save a number of variables using BOOST serialization mechanism. + * + * This function is implemented in + * source/simulator/checkpoint_restart.cc. + */ + template + void serialize (Archive &ar, const unsigned int version); + /** + * @} + */ + + /** + * @name Functions used in setting up linear systems + * @{ + */ + /** + * Determine which of the components of our finite-element + * system couple to each other. Depending on which equations + * are solved and which solver is used this varies widely. + * + * This function is implemented in + * source/simulator/core.cc. + */ + Table<2,DoFTools::Coupling> + setup_system_matrix_coupling () const; + + /** + * Set up the size and structure of the matrix used to store the + * elements of the linear system. + * + * This function is implemented in + * source/simulator/core.cc. + */ + void setup_system_matrix (const std::vector &system_partitioning); + + /** + * Set up the size and structure of the matrix used to store the + * elements of the matrix that is used to build the + * preconditioner for the system. This matrix is only used for + * the Stokes system, so while it has the size of the whole + * system, it only has entries in the velocity and pressure + * blocks. + * + * This function is implemented in + * source/simulator/core.cc. + */ + void setup_system_preconditioner (const std::vector &system_partitioning); + + /** + * @} + */ + + /** + * @name Functions, classes, and variables used in the assembly of linear systems + * @{ + */ + + /** + * A member variable that stores, for the current simulation, what + * functions need to be called in order to assemble linear systems, + * matrices, and right hand side vectors. + * + * One would probably want this variable to just be a member of type + * Assemblers::Manager, but this requires that + * this type is declared in the current scope, and that would require + * including which we don't want because it's big. + * Consequently, we just store a pointer to such an object, and create + * the object pointed to at the top of set_assemblers(). + */ + std::unique_ptr> assemblers; + + /** + * Determine, based on the run-time parameters of the current simulation, + * which functions need to be called in order to assemble linear systems, + * matrices, and right hand side vectors. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void set_assemblers (); + + /** + * Determine, based on the run-time parameters of the current simulation, + * which functions need to be called in order to assemble linear systems, + * matrices, and right hand side vectors for the advection. This function + * is used by both the default full Stokes solver and the Newton solvers, + * but not by the two-phase flow solver. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void set_advection_assemblers (); + + /** + * Determine, based on the run-time parameters of the current simulation, + * which functions need to be called in order to assemble linear systems, + * matrices, and right hand side vectors for the default full Stokes solver + * i.e. without considering two-phase flow, or Newton solvers. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void set_stokes_assemblers (); + + /** + * Initiate the assembly of the preconditioner for the Stokes system. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void assemble_stokes_preconditioner (); + + /** + * Compute the integrals for the preconditioner for the Stokes system on + * a single cell. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void + local_assemble_stokes_preconditioner (const typename DoFHandler::active_cell_iterator &cell, + internal::Assembly::Scratch::StokesPreconditioner &scratch, + internal::Assembly::CopyData::StokesPreconditioner &data); + + /** + * Copy the contribution to the preconditioner for the Stokes system + * from a single cell into the global matrix that stores these elements. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void + copy_local_to_global_stokes_preconditioner (const internal::Assembly::CopyData::StokesPreconditioner &data); + + /** + * Compute the integrals for the Stokes matrix and right hand side on a + * single cell. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void + local_assemble_stokes_system (const typename DoFHandler::active_cell_iterator &cell, + internal::Assembly::Scratch::StokesSystem &scratch, + internal::Assembly::CopyData::StokesSystem &data); + + /** + * Copy the contribution to the Stokes system from a single cell into + * the global matrix that stores these elements. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void + copy_local_to_global_stokes_system (const internal::Assembly::CopyData::StokesSystem &data); + + /** + * Compute the integrals for one advection matrix and right hand side on + * the faces of a single cell. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void + local_assemble_advection_face_terms(const AdvectionField &advection_field, + const typename DoFHandler::active_cell_iterator &cell, + internal::Assembly::Scratch::AdvectionSystem &scratch, + internal::Assembly::CopyData::AdvectionSystem &data); + /** + * Compute the integrals for one advection matrix and right hand side on + * a single cell. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void + local_assemble_advection_system (const AdvectionField &advection_field, + const Vector &viscosity_per_cell, + const typename DoFHandler::active_cell_iterator &cell, + internal::Assembly::Scratch::AdvectionSystem &scratch, + internal::Assembly::CopyData::AdvectionSystem &data); + + /** + * Copy the contribution to the advection system from a single cell into + * the global matrix that stores these elements. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void + copy_local_to_global_advection_system (const AdvectionField &advection_field, + const internal::Assembly::CopyData::AdvectionSystem &data); + + /** + * @} + */ + + /** + * @name Helper functions + * @{ + */ + /** + * This routine adjusts the second block of the right hand side of a + * Stokes system (containing the term that comes from compressibility, + * so that the system becomes compatible: $0=\int div u = \int g$. The + * vector to adjust is given as the argument of this function. This + * function makes use of the helper vector + * pressure_shape_function_integrals that contains $h_i=(q_i,1)$ with + * the pressure functions $q_i$ and we adjust the right hand side $g$ by + * $h_i \int g / |\Omega|$. + * + * The purpose of this function is described in the second paper on the + * numerical methods in ASPECT. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void make_pressure_rhs_compatible(LinearAlgebra::BlockVector &vector); + + /** + * Fills a vector with the artificial viscosity for the temperature or + * composition on each local cell. + * @param viscosity_per_cell Output vector + * @param advection_field Determines whether this variable should select + * the temperature field or a compositional field. + * @param skip_interior_cells A boolean flag. If set to true the function + * will only compute the artificial viscosity in cells at boundaries. + */ + template + void get_artificial_viscosity (Vector &viscosity_per_cell, + const AdvectionField &advection_field, + const bool skip_interior_cells = false) const; + + /** + * Compute the seismic shear wave speed, Vs anomaly per element. we + * compute the anomaly by computing a smoothed (over 200 km or so) + * laterally averaged temperature profile and associated seismic + * velocity that is then subtracted from the seismic velocity at the + * current pressure temperature conditions + * + * @param values The output vector of depth averaged values. The + * function takes the pre-existing size of this vector as the number of + * depth slices. + */ + void compute_Vs_anomaly(Vector &values) const; + + /** + * Compute the seismic pressure wave speed, Vp anomaly per element. we + * compute the anomaly by computing a smoothed (over 200 km or so) + * laterally averaged temperature profile and associated seismic + * velocity that is then subtracted from the seismic velocity at the + * current pressure temperature conditions + * + * This function is implemented in + * source/simulator/helper_functions.cc. + * + * @param values The output vector of depth averaged values. The + * function takes the pre-existing size of this vector as the number of + * depth slices. + */ + void compute_Vp_anomaly(Vector &values) const; + + /** + * Adjust the pressure variable (which is only determined up to + * a constant by the equations, though its value may enter + * traction boundary conditions) by adding a constant to it in + * such a way that the pressure on the surface or within the + * entire volume has a known average value. The point of this + * function is that the pressure that results from solving the + * linear system may not coincide with what we think of as the + * "physical pressure"; in particular, we typically think of the + * pressure as zero (on average) along the surface because it is + * the sum of the hydrostatic and dynamic pressure, where the + * former is thought of as zero along the surface. This function + * therefore converts from the "mathematical" pressure to the + * "physical" pressure so that all following postprocessing + * steps can use the latter. + * + * In the case of the surface average, whether a face is part of + * the surface is determined by asking whether its depth of its + * midpoint (as determined by the geometry model) is less than + * 1/3*1/sqrt(dim-1)*diameter of the face. For reasonably curved + * boundaries, this rules out side faces that are perpendicular + * to the surface boundary but includes those faces that are + * along the boundary even if the real boundary is curved. + * + * Whether the pressure should be normalized based on the + * surface or volume average is decided by a parameter in the + * input file. + * + * @note This function is called after setting the initial + * pressure field in compute_initial_pressure_field() and at the end + * of solve_stokes(). This makes sense because these are exactly the + * places where the pressure is modified or re-computed. + * + * @return This function returns the pressure adjustment by value. + * This is so that its negative can later be used again in + * denormalize_pressure(). + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + double normalize_pressure(LinearAlgebra::BlockVector &vector) const; + + /** + * Invert the action of the normalize_pressure() function above. This + * means that we move from a pressure that satisfies the pressure + * normalization (e.g., has a zero average pressure, or a zero average + * surface pressure) to one that does not actually satisfy this + * normalization, and this doesn't seem to make sense because we are + * not interested in such a pressure. + * + * Indeed, this function is only called at the very beginning of + * solve_stokes() before we compute the initial (linear) residual + * of the linear system $Ax=b$ that corresponds to the Stokes system, + * where $x$ is the variable for which the pressure is adjusted + * back to the "wrong" form. Because stokes_system() calls + * normalize_pressure() at the end of its operations, no such + * "wrong" pressure ever escapes the realm of solve_stokes(). The + * "wrong" pressure is then used for two purposes in that function: + * (i) To compute the initial Stokes residual, which makes sense + * because it can only be zero (if we solved the same linear system + * twice) if we re-use the exact same pressure as we got from the + * previous solve -- i.e., before we called normalize_pressure() + * at the end of the solve. (ii) To initialize the solution vector + * before calling the GMRES solver, which also makes sense because + * the best guess vector for GMRES is the one that had previously + * come out of GMRES, namely the one on which we later called + * normalize_pressure(). + * + * This function modifies @p vector in-place. In some cases, we need + * locally_relevant values of the pressure. To avoid creating a new vector + * and transferring data, this function uses a second vector with relevant + * dofs (@p relevant_vector) for accessing these pressure values. Both + * @p vector and @p relevant_vector are expected to already contain + * the correct pressure values. + * + * @note The adjustment made in this function is done using the + * negative of the @p pressure_adjustment function argument that + * would typically have been computed and returned by the + * normalize_pressure() function. This value is typically stored in + * the member variable @p last_pressure_normalization_adjustment, + * but the current function doesn't read this variable but instead + * gets the adjustment variable from the given argument. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void denormalize_pressure(const double pressure_adjustment, + LinearAlgebra::BlockVector &vector, + const LinearAlgebra::BlockVector &relevant_vector) const; + + /** + * Apply the bound preserving limiter to the discontinuous Galerkin solutions: + * i.e., given two fixed upper and lower bound [min, max], after applying the limiter, + * the discontinuous Galerkin solution will stay in the prescribed bounds. + * + * This function is implemented in + * source/simulator/limiters.cc. + */ + void apply_BP_limiter_to_dg_solutions (const AdvectionField &advection_field); + + /** + * Apply the WENO limiter to the discontinuous Galerkin solutions. + * WENO is short for Weighted Essentially Non-Oscillatory, which is + * a class of high-resolution schemes used in the numerical solution + * of hyperbolic conservation laws. The basic idea of WENO limiter is + * to replace the solution in troubled cells (cells with oscillation) + * by a polynomial reconstruction that takes the neighbor cells into + * account. The WENO scheme implemented in the program is a simple + * variant proposed by Zhong and Shu, 2013. + * + * This function is implemented in + * source/simulator/limiters.cc. + */ + void apply_WENO_limiter_to_dg_solutions (const AdvectionField &advection_field); + + /** + * Fills a vector with the KXRCF indicator for a given advection field + * on each local cell. The KXRCF indicator is a metric of discontinuity + * for hyperbolic conservation laws. Cells with high KXRCF values are + * identified as "troubled cells" and will be smoothed by the WENO limiter. + * + * This function is implemented in + * source/simulator/limiters.cc. + */ + template + void compute_KXRCF_indicators(Vector &KXRCF_indicators, + const AdvectionField &advection_field) const; + + /** + * Compute the reactions in case of operator splitting: + * Using the current solution vector, this function makes a number of time + * steps determined by the size of the reaction time step, and solves a + * system of coupled ordinary differential equations for the reactions between + * compositional fields and temperature in each of them. To do that, is uses + * the reaction rates outputs from the material and heating models used in + * the computation. The solution vector is then updated with the new values + * of temperature and composition after the reactions. + * + * As the ordinary differential equation in any given point is independent + * from the solution at all other points, we do not have to assemble a matrix, + * but just need to loop over all node locations for the temperature and + * compositional fields and compute the update to the solution. + * + * The function also updates the old solution vectors with the reaction update + * so that the advection time stepping scheme will have the correct field terms + * for the right-hand side when assembling the advection system. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void compute_reactions (); + + /** + * Update the indicated block of the solution vector with the + * corresponding block of the handed over @p distributed_vector. Also + * update reaction_vector with the corresponding block of @p + * distributed_reaction_vector. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void update_solution_vectors_with_reaction_results (const unsigned int block_index, + const LinearAlgebra::BlockVector &distributed_vector, + const LinearAlgebra::BlockVector &distributed_reaction_vector); + + /** + * Initialize the current linearization point vector from the old + * solution vector(s). Depending on the time of the call this + * can be simply a copy of the solution of the last timestep, + * or a linear extrapolation of old and old_old timestep to + * the new timestep. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void initialize_current_linearization_point (); + + /** + * Interpolate material model outputs onto an advection field (temperature + * or composition). For the field identified by the AdvectionField @p adv_field, this function + * asks the material model to fill a MaterialModel::MaterialModelOutputs + * object that has an attached MaterialModel::PrescribedFieldOutputs + * "additional outputs" object (for composition) or an attached + * MaterialModel::PrescribedTemperatureOutputs (for temperature). + * The MaterialModel::MaterialModelInputs + * object passed to the material model then contains the support points of + * the advection field, thereby allowing the outputs to be + * interpolated to the finite element space and consequently into the + * solution vector. + * This is useful for advection fields whose advection mode is set + * to Parameters::AdvectionFieldMethod::prescribed_field or + * Parameters::AdvectionFieldMethod::prescribed_field_with_diffusion. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void interpolate_material_output_into_advection_field (const AdvectionField &adv_field); + + + /** + * Interpolate the given function onto the velocity FE space and write + * it into the given vector. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void interpolate_onto_velocity_system(const TensorFunction<1,dim> &func, + LinearAlgebra::Vector &vec); + + + /** + * Add constraints to the given @p constraints object that are required + * for unique solvability of the velocity block based on the nullspace + * removal settings. + * + * This method will add a zero Dirichlet constraint for the first + * velocity unknown in the domain for each velocity component, which is + * later being processed for translational or linear momentum removal. + * This avoids breakdowns of the linear solvers that otherwise occurred + * in some instances. + * + * @note: Rotational modes are currently not handled and don't appear to + * require constraints so far. + */ + void setup_nullspace_constraints(AffineConstraints &constraints); + + + /** + * Eliminate the nullspace of the velocity in the given vector. Both + * vectors are expected to contain the up to date data. + * + * @param relevant_dst locally relevant vector for the whole FE, will be + * filled at the end. + * @param tmp_distributed_stokes only contains velocity and pressure. + * + * This function is implemented in + * source/simulator/nullspace.cc. + */ + void remove_nullspace(LinearAlgebra::BlockVector &relevant_dst, + LinearAlgebra::BlockVector &tmp_distributed_stokes); + + /** + * Compute the angular momentum and other rotation properties + * of the velocities in the given solution vector. + * + * @param use_constant_density determines whether to use a constant + * density (which corresponds to computing a net rotation instead of net + * angular momentum). + * @param solution Solution vector to compute the properties for. + * @param limit_to_top_faces allows to only compute the net angular momentum + * (or net rotation) of the top surface. + * + * This function is implemented in + * source/simulator/nullspace.cc. + */ + RotationProperties + compute_net_angular_momentum(const bool use_constant_density, + const LinearAlgebra::BlockVector &solution, + const bool limit_to_top_faces = false) const; + + /** + * Remove the angular momentum of the given vector + * + * @param use_constant_density determines whether to use a constant + * density (which corresponds to removing a net rotation instead of net + * angular momentum). + * @param relevant_dst locally relevant vector for the whole FE, will be + * filled at the end. + * @param tmp_distributed_stokes only contains velocity and pressure. + * @param limit_to_top_faces allows to only remove the net angular momentum + * (or net rotation) of the top surface. This can be useful to compare surface + * motions against plate reconstructions in no net rotation reference frames. + * + * This function is implemented in + * source/simulator/nullspace.cc. + */ + void remove_net_angular_momentum( const bool use_constant_density, + LinearAlgebra::BlockVector &relevant_dst, + LinearAlgebra::BlockVector &tmp_distributed_stokes, + const bool limit_to_top_faces = false); + + /** + * Offset the boundary id of all faces located on an outflow boundary + * by a fixed value given by the input parameter @p boundary_id_offset. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void replace_outflow_boundary_ids(const unsigned int boundary_id_offset); + + /** + * Undo the offset of the boundary ids done in replace_outflow_boundary_ids + * by resetting all boundary ids to their original value. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void restore_outflow_boundary_ids(const unsigned int boundary_id_offset); + + /** + * Remove the linear momentum of the given vector + * + * @param use_constant_density determines whether to use a constant + * density (which corresponds to removing a net translation instead of + * net linear momentum). + * @param relevant_dst locally relevant vector for the whole FE, will be + * filled at the end. + * @param tmp_distributed_stokes only contains velocity and pressure. + * + * This function is implemented in + * source/simulator/nullspace.cc. + */ + void remove_net_linear_momentum( const bool use_constant_density, + LinearAlgebra::BlockVector &relevant_dst, + LinearAlgebra::BlockVector &tmp_distributed_stokes); + + /** + * Compute the maximal velocity throughout the domain. This is needed to + * compute the size of the time step. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + double get_maximal_velocity (const LinearAlgebra::BlockVector &solution) const; + + /** + * Compute the variation (i.e., the difference between maximal and + * minimal value) of the entropy $(T-\bar T)^2$ where $\bar T$ is the + * average temperature throughout the domain given as argument to this + * function. + * + * This function is used in computing the artificial diffusion + * stabilization term. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + double get_entropy_variation (const double average_field, + const AdvectionField &advection_field) const; + + /** + * Compute the minimal and maximal temperature throughout the domain from + * a solution vector extrapolated from the previous time steps. This is + * needed to compute the artificial diffusion stabilization terms. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + std::pair + get_extrapolated_advection_field_range (const AdvectionField &advection_field) const; + + /** + * Exchange coarsen/refinement flags set between processors so that + * we have the correct settings on all ghost cells. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + * + */ + void exchange_refinement_flags(); + + + /** + * Check if timing output should be written in this timestep, and if so + * write it. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + * + */ + void maybe_write_timing_output () const; + + /** + * Check if a checkpoint should be written in this timestep. If so create + * one. Returns whether a checkpoint was written. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + bool maybe_write_checkpoint (const time_t last_checkpoint_time, + const bool force_writing_checkpoint); + + /** + * Check if we should do an initial refinement cycle in this timestep. + * This will only be checked in timestep 0, afterwards the variable + * pre_refinement_step variable is invalidated, and this function will + * return without doing refinement. + * An initial refinement cycle is different from a regular one, + * because time is not increased. Instead the same timestep is solved + * using the new mesh. + * Therefore, only output timing information and postprocessor output + * if required in the input file. But always output statistics (to have + * a history of the number of cells in the statistics file). + * This function returns whether an initial refinement was done. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + bool maybe_do_initial_refinement (const unsigned int max_refinement_level); + + /** + * Check if refinement is requested in this timestep. If so: Refine mesh. + * The @p max_refinement_level might be increased from this time on + * if this is an additional refinement cycle. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void maybe_refine_mesh (const double new_time_step, + unsigned int &max_refinement_level); + + /** + * Advance the current time by the given @p step_size and update the + * solution vectors as needed. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void advance_time (const double step_size); + + /** + * Compute the artificial diffusion coefficient value on a cell given + * the values and gradients of the solution passed as arguments. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + double + compute_viscosity(internal::Assembly::Scratch::AdvectionSystem &scratch, + const double global_u_infty, + const double global_field_variation, + const double average_field, + const double global_entropy_variation, + const double cell_diameter, + const AdvectionField &advection_field) const; + + /** + * Compute the residual of one advection equation to be used for the + * artificial diffusion coefficient value on a cell given the values and + * gradients of the solution passed as arguments. + * + * This function is implemented in + * source/simulator/assembly.cc. + */ + void + compute_advection_system_residual(internal::Assembly::Scratch::AdvectionSystem &scratch, + const double average_field, + const AdvectionField &advection_field, + double &max_residual, + double &max_velocity, + double &max_density, + double &max_specific_heat, + double &conductivity) const; + + /** + * Return whether the Stokes matrix depends on the values of the + * solution at the previous time step. This is the case is the + * coefficients that appear in the matrix (i.e., the viscosity and, in + * the case of a compressible model, the density) depend on the + * solution. + * + * This function exists to ensure that the Stokes matrix is rebuilt in + * time steps where it may have changed, while we want to save the + * effort of rebuilding it whenever we don't need to. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + bool + stokes_matrix_depends_on_solution () const; + + /** + * Return whether to the best of our knowledge the A block of the + * Stokes system is symmetric. This is the case for most models, except + * if additional non-symmetric terms are added by special assemblers + * (e.g., the free surface stabilization term). + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + bool + stokes_A_block_is_symmetric () const; + + /** + * This function checks that the user-selected formulations of the + * equations are consistent with the other inputs. If an incorrect + * selection is detected it throws an exception. It for example assures that + * correct heating terms are selected, and the material model supports + * the selection of the mass conservation formulation (e.g. incompressible)). + * If the parameter 'parameters.formulation' is set to 'custom' + * it only ensures very basic consistency. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void + check_consistency_of_formulation (); + + /** + * This function checks if the default solver and/or material + * averaging were selected and if so, determines the appropriate + * solver and/or averaging option. + */ + void + select_default_solver_and_averaging (); + + /** + * This function checks that the user-selected boundary conditions do not + * contain contradictions. If an incorrect selection is detected it + * throws an exception. This for example assures that not both velocity + * and traction boundary conditions are prescribed at the same boundary, + * and that no boundary temperatures are prescribed at a periodic boundary. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void + check_consistency_of_boundary_conditions () const; + + /** + * Computes the initial Newton residual. + */ + double + compute_initial_newton_residual (const LinearAlgebra::BlockVector &linearized_stokes_initial_guess); + + /** + * This function computes the Eisenstat Walker linear tolerance used for the Newton iterations + * in the `iterated Advection and Newton Stokes' and `single Advection, iterated Newton Stokes' solver schemes. + * The Eisenstat and Walker (1996) method is used for determining the linear tolerance of + * the iteration after the first iteration. The paper gives two preferred choices of computing + * this tolerance. Both choices are implemented here with the suggested parameter values and + * safeguards. + */ + double + compute_Eisenstat_Walker_linear_tolerance(const bool EisenstatWalkerChoiceOne, + const double maximum_linear_stokes_solver_tolerance, + const double linear_stokes_solver_tolerance, + const double stokes_residual, + const double newton_residual, + const double newton_residual_old); + + /** + * This function is called at the end of each time step and writes the + * statistics object that contains data like the current time, the + * number of linear solver iterations, and whatever the postprocessors + * have generated, to disk. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + void output_statistics(); + + /** + * This routine computes the initial (nonlinear) Stokes residual that is + * needed as a convergence criterion in models with solver schemes that do + * nonlinear iterations. We calculate it in the same way as the tolerance for the linear + * solver, using the norm of the pressure RHS for the pressure part and a + * residual with zero velocity for the velocity part to get the part of + * the RHS not balanced by the static pressure. + * + * This function is implemented in + * source/simulator/helper_functions.cc. + */ + double + compute_initial_stokes_residual(); + + /** + * @} + */ + + /** + * @name Variables that have to do with input, output, parallel + * communication and interfacing with other parts of the program. + * @{ + */ + Parameters parameters; + + /** + * Unique pointer for an instance of the MeltHandler. This way, + * if we do not need the machinery for doing melt stuff, we do + * not even allocate it. + */ + std::unique_ptr> melt_handler; + + /** + * Unique pointer for an instance of the NewtonHandler. This way, + * if we do not need the machinery for doing Newton stuff, we do + * not even allocate it. + */ + std::unique_ptr> newton_handler; + + SimulatorSignals signals; + + const IntermediaryConstructorAction post_signal_creation; + + /** + * Unique pointer for an instance of the VolumeOfFluidHandler. This way, + * if we do not need the machinery for doing volume_of_fluid stuff, we do + * not even allocate it. + * + * Located here due to needing signals access + */ + std::unique_ptr> volume_of_fluid_handler; + + Introspection introspection; + + + MPI_Comm mpi_communicator; + + /** + * This stream will log into the file output/log.txt (used automatically + * by pcout). + */ + std::ofstream log_file_stream; + + using TeeDevice = boost::iostreams::tee_device; + using TeeStream = boost::iostreams::stream; + + TeeDevice iostream_tee_device; + TeeStream iostream_tee_stream; + + /** + * Output stream for logging information. Will only output on processor + * 0. + */ + ConditionalOStream pcout; + + /** + * An object that stores a bunch of statistics such as the number of + * linear solver iterations, the time corresponding to each time step, + * etc, as well as whatever the various postprocessors want to put into + * it. + * + * This variable is written to disk after every time step, by the + * Simulator::output_statistics() function. + */ + TableHandler statistics; + + /** + * The following two variables keep track which parts of the statistics + * object have already been written. This is because the TableHandler + * class has no way to keep track what it has already written, and so + * we can not just append the last row of the table to the output + * file. Rather, we keep track how many bytes we already wrote, + * and a hash of what they contained, and if these so-many bytes have + * not changed between the previous and current write operation, then + * we only open the file in 'append' mode to add the new bytes from the + * last row. If what we would write now has changed from what we wrote + * back then in the first so-many bytes (e.g., because column widths of + * the table have changed), then we just replace the previous file by + * the current table contents in their entirety. + */ + std::size_t statistics_last_write_size; + std::size_t statistics_last_hash; + + mutable TimerOutput computing_timer; + + /** + * A timer used to track the current wall time since the + * last snapshot (or since the program started). + */ + Timer wall_timer; + + /** + * The total wall time that has elapsed up to the last snapshot + * that was created. + */ + double total_walltime_until_last_snapshot; + + /** + * In output_statistics(), where we output the statistics object above, + * we do the actual writing on a separate thread. This variable is the + * handle we get for this thread so that we can wait for it to finish, + * either if we want to write the statistics object for the next thread, + * or if we want to terminate altogether. + */ + std::thread output_statistics_thread; + + /** + * @} + */ + + /** + * @name Variables that describe the physical setup of the problem + * @{ + */ + const std::unique_ptr> initial_topography_model; + const std::unique_ptr> geometry_model; + const IntermediaryConstructorAction post_geometry_model_creation_action; + const std::unique_ptr> material_model; + const std::unique_ptr> gravity_model; + BoundaryTemperature::Manager boundary_temperature_manager; + BoundaryComposition::Manager boundary_composition_manager; + const std::unique_ptr> prescribed_stokes_solution; + + /** + * The following two variables are pointers to objects that describe + * the initial temperature and composition values. The Simulator + * class itself releases these pointers once they are no longer + * needed, somewhere during the first time step once it is known + * that they are no longer needed. However, plugins can have their + * own shared pointers to these objects, and the lifetime of the + * objects pointed to is then until the last of these plugins + * gets deleted. + */ + std::shared_ptr> initial_temperature_manager; + std::shared_ptr> initial_composition_manager; + + const std::unique_ptr> adiabatic_conditions; +#ifdef ASPECT_WITH_WORLD_BUILDER + /** + * A pointer to the WorldBuilder object. Like the + * `initial_temperature_manager` and + * `initial_composition_manager` objects above, the Simulator + * object itself releases this pointer at the end of the + * initialization process (right after releasing the + * two mentioned initial condition objects). If a part of + * the plugin system still needs the world builder object + * after this point, it needs to keep its own shared pointer + * to it. + */ + std::shared_ptr world_builder; +#endif + BoundaryVelocity::Manager boundary_velocity_manager; + BoundaryTraction::Manager boundary_traction_manager; + const std::unique_ptr> boundary_heat_flux; + + /** + * The world holding the particles + */ + std::vector>> particle_worlds; + + /** + * @} + */ + /** + * @name Variables that describe the time discretization + * @{ + */ + double time; + double time_step; + double old_time_step; + unsigned int timestep_number; + unsigned int pre_refinement_step; + unsigned int nonlinear_iteration; + /** + * @} + */ + + /** + * @name Variables related to simulation time stepping + * @{ + */ + TimeStepping::Manager time_stepping_manager; + /** + * @} + */ + + /** + * @name Variables for doing lateral averaging + * @{ + */ + LateralAveraging lateral_averaging; + /** + * @} + */ + + /** + * @name Variables that describe the spatial discretization + * @{ + */ + parallel::distributed::Triangulation triangulation; + double global_Omega_diameter; + double global_volume; + + MeshRefinement::Manager mesh_refinement_manager; + HeatingModel::Manager heating_model_manager; + + /** + * Pointer to the Mapping object used by the finite elements when + * going from the reference cell to the cell in the computational + * domain. We use a pointer since different mapping objects may + * be useful. In particular, when the mesh is deformable we use + * a MappingQ1Eulerian object to describe the mesh deformation, + * swapping it in for the original MappingQ or MappingCartesian object. + */ + std::unique_ptr> mapping; + + const FESystem finite_element; + + DoFHandler dof_handler; + + Postprocess::Manager postprocess_manager; + + /** + * Constraint objects. The first of these describes all constraints that + * are not time dependent (e.g., hanging nodes, no-normal-flux + * constraints), whereas the second one is initialized at the top of + * every time step by copying from the first and then adding to it + * constraints that are time dependent (e.g., time dependent velocity or + * temperature boundary conditions). + * + * 'constraints' is computed in setup_dofs(), 'current_constraints' is + * done in compute_current_constraints(). + */ + AffineConstraints constraints; + AffineConstraints current_constraints; + + /** + * A place to store the latest correction computed by normalize_pressure(). + * We store this so we can undo the correction in denormalize_pressure(). + */ + double last_pressure_normalization_adjustment; + + /** + * Scaling factor for the pressure as explained in the + * Kronbichler/Heister/Bangerth paper to ensure that the linear system + * that results from the Stokes equations is well conditioned. + */ + double pressure_scaling; + + /** + * A variable that determines whether we need to do the correction of + * the Stokes right hand side vector to ensure that the average + * divergence is zero. This is necessary for compressible models, but + * only if there are no in/outflow boundaries. + */ + bool do_pressure_rhs_compatibility_modification; + + /** + * @} + */ + + + /** + * @name Variables that describe the linear systems and solution vectors + * @{ + */ + + /** + * An object that contains the entries of the system matrix. It + * has a size equal to the total number of degrees of freedom, + * but since we typically do not solve for all variables at + * once, the content of the matrix at any given time is only + * appropriate for the part of the system we are currently + * solving. + */ + LinearAlgebra::BlockSparseMatrix system_matrix; + + /** + * This vector is used for the weighted BFBT preconditioner. It + * stores the inverted lumped velocity mass matrix. + */ + LinearAlgebra::BlockVector inverse_lumped_mass_matrix; + + /** + * An object that contains the entries of preconditioner + * matrices for the system matrix. It has a size equal to the + * total number of degrees of freedom, but is only used for the + * Stokes system (that's the only part of the system where we + * use a matrix for preconditioning that is different from the + * matrix we solve). Consequently, the blocks in rows and + * columns corresponding to temperature or compositional fields + * are left empty when building the sparsity pattern of this + * matrix in the Simulator::setup_system_preconditioner() + * function. + */ + LinearAlgebra::BlockSparseMatrix system_preconditioner_matrix; + + LinearAlgebra::BlockVector solution; + LinearAlgebra::BlockVector old_solution; + LinearAlgebra::BlockVector old_old_solution; + LinearAlgebra::BlockVector system_rhs; + + LinearAlgebra::BlockVector current_linearization_point; + + // only used if is_compressible() + LinearAlgebra::BlockVector pressure_shape_function_integrals; + + // only used if operator split is enabled + LinearAlgebra::BlockVector operator_split_reaction_vector; + + + + std::unique_ptr Amg_preconditioner; + std::unique_ptr Mp_preconditioner; + + bool rebuild_sparsity_and_matrices; + bool rebuild_stokes_matrix; + bool assemble_newton_stokes_matrix; + bool assemble_newton_stokes_system; + bool rebuild_stokes_preconditioner; + + /** + * @} + */ + + private: + + /** + * Unique pointer for an instance of the MeshDeformationHandler. this way, + * if we do not need the machinery for doing mesh deformation stuff, we do + * not even allocate it. + */ + std::unique_ptr> mesh_deformation; + + /** + * Unique pointer for the matrix-free Stokes solver + */ + std::unique_ptr> stokes_matrix_free; + + friend class boost::serialization::access; + friend class SimulatorAccess; + friend class MeshDeformation::MeshDeformationHandler; // MeshDeformationHandler needs access to the internals of the Simulator + friend class VolumeOfFluidHandler; // VolumeOfFluidHandler needs access to the internals of the Simulator + friend class StokesMatrixFreeHandler; + template + friend class StokesMatrixFreeHandlerImplementation; + friend struct Parameters; + }; +} + + +#endif diff --git a/include/aspect/simulator/assemblers/advection.h.bak b/include/aspect/simulator/assemblers/advection.h.bak new file mode 100644 index 00000000000..cfc5a5edd10 --- /dev/null +++ b/include/aspect/simulator/assemblers/advection.h.bak @@ -0,0 +1,136 @@ +/* + Copyright (C) 2017 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + +#ifndef _aspect_simulator_assemblers_advection_h +#define _aspect_simulator_assemblers_advection_h + + +#include +#include + +namespace aspect +{ + namespace Assemblers + { + /** + * This class assembles the terms for the matrix and right-hand-side of the advection + * equation for the current cell. + */ + template + class AdvectionSystem : public Assemblers::Interface, public Assemblers::AdvectionStabilizationInterface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + + std::vector + compute_residual(internal::Assembly::Scratch::ScratchBase &scratch_base) const override; + }; + + template + class DarcySystem : public Assemblers::Interface, public Assemblers::AdvectionStabilizationInterface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + + std::vector + compute_residual(internal::Assembly::Scratch::ScratchBase &scratch_base) const override; + + void + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const override; + }; + + /** + * This class assembles the terms for the matrix and right-hand-side equation for the + * current cell in case we only want to solve the diffusion equation. + */ + template + class DiffusionSystem : public Assemblers::Interface, public Assemblers::AdvectionStabilizationInterface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + + std::vector + compute_residual(internal::Assembly::Scratch::ScratchBase &scratch_base) const override; + + virtual + std::vector + advection_prefactors(internal::Assembly::Scratch::ScratchBase &scratch_base) const override; + + virtual + std::vector + diffusion_prefactors(internal::Assembly::Scratch::ScratchBase &scratch_base) const override; + }; + + /** + * This class assembles the face terms for the right-hand-side of the + * advection equation for a face at the boundary of the domain where + * Neumann boundary conditions are used (which allow to prescribe a heat flux). + */ + template + class AdvectionSystemBoundaryHeatFlux : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class assembles the face terms for the matrix and right-hand-side of + * the discontinuous advection equation for a face at the boundary of the domain. + */ + template + class AdvectionSystemBoundaryFace : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class assembles the face terms for the matrix and right-hand-side of + * the discontinuous advection equation for a face in the interior of the domain. + */ + template + class AdvectionSystemInteriorFace : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + } +} + + +#endif diff --git a/include/aspect/simulator/assemblers/interface.h.bak b/include/aspect/simulator/assemblers/interface.h.bak new file mode 100644 index 00000000000..fa918170c0e --- /dev/null +++ b/include/aspect/simulator/assemblers/interface.h.bak @@ -0,0 +1,818 @@ +/* + Copyright (C) 2017 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_simulator_assemblers_interface_h +#define _aspect_simulator_assemblers_interface_h + +#include +#include +#include + +#include + +namespace aspect +{ + using namespace dealii; + + template + class Simulator; + + struct AdvectionField; + + /** + * A namespace that is used for internal scratch objects, i.e. objects that define + * the inputs and outputs for the individual assembler objects. The different classes + * are provided for the different systems of equations, and the inputs are filled + * by the local_assemble_... functions in assembly.cc, + * before being handed over to the assemblers. + */ + namespace internal + { + namespace Assembly + { + namespace Scratch + { + /** + * Scratch objects are used to store information about a cell that is + * necessary for assembling matrix and right hand side terms for this + * cell. The ScratchBase class acts as a empty base class for + * individual scratch objects for the different equations. + */ + template + struct ScratchBase + { + ScratchBase() + : + cell(), + face_number(numbers::invalid_unsigned_int) + {} + + ScratchBase(const ScratchBase &scratch) + : + cell(scratch.cell), + face_number(scratch.face_number) + {} + + virtual ~ScratchBase () = default; + + /** + * Cell object on which we currently operate. + */ + typename DoFHandler::active_cell_iterator cell; + + /** + * The number of the face object with respect to the current + * cell on which we operate. If we currently + * operate on a cell, this member is set to + * numbers::invalid_unsigned_int. + */ + unsigned face_number; + }; + + /** + * A scratch object to store all necessary information to assemble + * the Stokes preconditioner terms. + */ + template + struct StokesPreconditioner: public ScratchBase + { + StokesPreconditioner (const FiniteElement &finite_element, + const Quadrature &quadrature, + const Mapping &mapping, + const UpdateFlags update_flags, + const unsigned int n_compositional_fields, + const unsigned int stokes_dofs_per_cell, + const bool add_compaction_pressure, + const bool rebuild_matrix, + const bool use_bfbt); + StokesPreconditioner (const StokesPreconditioner &scratch); + + ~StokesPreconditioner () override; + + FEValues finite_element_values; + + void reinit (const typename DoFHandler::active_cell_iterator &cell_ref); + + std::vector local_dof_indices; + std::vector dof_component_indices; + std::vector> grads_phi_u; + std::vector div_phi_u; + std::vector phi_p; + std::vector> phi_u; + std::vector phi_p_c; + std::vector> grad_phi_p; + + /** + * Material model inputs and outputs computed at the current + * linearization point. + */ + MaterialModel::MaterialModelInputs material_model_inputs; + MaterialModel::MaterialModelOutputs material_model_outputs; + + /** + * Whether the Stokes matrix should be rebuild during this + * assembly. If the matrix does not change, assembling the right + * hand side is sufficient. + */ + const bool rebuild_stokes_matrix; + }; + + + + /** + * A scratch object to store all necessary information to assemble + * the terms in the Stokes equations. + * We derive the StokesSystem scratch class from the + * StokesPreconditioner class, because all the objects that + * are necessary for the assembly of the preconditioner are also + * needed for the actual system matrix and right hand side, plus some + * extra data that we need for the time stepping and traction boundaries + * on the right hand side. + */ + template + struct StokesSystem : public StokesPreconditioner + { + StokesSystem (const FiniteElement &finite_element, + const Mapping &mapping, + const Quadrature &quadrature, + const Quadrature &face_quadrature, + const UpdateFlags update_flags, + const UpdateFlags face_update_flags, + const unsigned int n_compositional_fields, + const unsigned int stokes_dofs_per_cell, + const bool add_compaction_pressure, + const bool use_reference_density_profile, + const bool rebuild_stokes_matrix, + const bool rebuild_newton_stokes_matrix, + const bool use_bfbt); + + StokesSystem (const StokesSystem &scratch); + + FEFaceValues face_finite_element_values; + + using StokesPreconditioner::reinit; + + void reinit (const typename DoFHandler::active_cell_iterator &cell_ref, + const unsigned face_number_ref); + + std::vector> phi_u; + std::vector> velocity_values; + std::vector velocity_divergence; + std::vector> temperature_gradients; + + /** + * Material model inputs and outputs computed at the current + * linearization point. + * + * In contrast to the variables above, the following two + * variables are used in the assembly at quadrature points + * on faces, not on cells. + */ + MaterialModel::MaterialModelInputs face_material_model_inputs; + MaterialModel::MaterialModelOutputs face_material_model_outputs; + + /** + * In some approximations of the Stokes equations the density used + * for the mass conservation (/continuity) equation is some form + * of reference density, while the density used for calculating + * the buoyancy force is the full density. In case such a formulation + * is used the reference density (and its derivative in depth + * direction) is queried from the adiabatic conditions plugin + * and is stored in these variables. + */ + std::vector reference_densities; + std::vector reference_densities_depth_derivative; + + /** + * Whether the Newton solver Stokes matrix should be rebuild during + * this assembly. If the matrix does not change, assembling the right + * hand side is sufficient. + */ + const bool rebuild_newton_stokes_matrix; + }; + + + + /** + * A scratch object to store all necessary information to assemble + * the terms in the advection equations. + */ + template + struct AdvectionSystem: public ScratchBase + { + AdvectionSystem (const FiniteElement &finite_element, + const FiniteElement &advection_element, + const Mapping &mapping, + const Quadrature &quadrature, + const Quadrature &face_quadrature, + const UpdateFlags update_flags, + const UpdateFlags face_update_flags, + const unsigned int n_compositional_fields, + const typename Simulator::AdvectionField &field); + AdvectionSystem (const AdvectionSystem &scratch); + + FEValues finite_element_values; + + void reinit (const typename DoFHandler::active_cell_iterator &cell_ref); + + std::unique_ptr> face_finite_element_values; + std::unique_ptr> neighbor_face_finite_element_values; + std::unique_ptr> subface_finite_element_values; + + std::vector local_dof_indices; + + /** + * Variables describing the values and gradients of the + * shape functions at the quadrature points, as they are + * used in the advection assembly function. note that the sizes + * of these arrays are equal to the number of shape functions + * corresponding to the currently advected field (and not all of the + * existing fields), and that they are also correspondingly indexed. + */ + std::vector phi_field; + std::vector> grad_phi_field; + std::vector laplacian_phi_field; + std::vector face_phi_field; + std::vector> face_grad_phi_field; + std::vector neighbor_face_phi_field; + std::vector> neighbor_face_grad_phi_field; + + std::vector> old_velocity_values; + std::vector> old_old_velocity_values; + + std::vector old_pressure; + std::vector old_old_pressure; + std::vector> old_pressure_gradients; + std::vector> old_old_pressure_gradients; + + std::vector> old_strain_rates; + std::vector> old_old_strain_rates; + + std::vector old_temperature_values; + std::vector old_old_temperature_values; + + std::vector old_field_values; + std::vector old_old_field_values; + std::vector> old_field_grads; + std::vector> old_old_field_grads; + std::vector old_field_laplacians; + std::vector old_old_field_laplacians; + + std::vector> old_composition_values; + std::vector> old_old_composition_values; + + std::vector current_temperature_values; + std::vector> current_velocity_values; + std::vector> face_current_velocity_values; + std::vector> mesh_velocity_values; + std::vector> face_mesh_velocity_values; + + std::vector> current_strain_rates; + std::vector> current_composition_values; + std::vector current_velocity_divergences; + + /** + * Material model inputs and outputs computed at the current + * linearization point. + */ + MaterialModel::MaterialModelInputs material_model_inputs; + MaterialModel::MaterialModelOutputs material_model_outputs; + + MaterialModel::MaterialModelInputs face_material_model_inputs; + MaterialModel::MaterialModelOutputs face_material_model_outputs; + + MaterialModel::MaterialModelInputs neighbor_face_material_model_inputs; + MaterialModel::MaterialModelOutputs neighbor_face_material_model_outputs; + + /** + * Heating model outputs computed at the quadrature points of the + * current cell at the time of the current linearization point. + * As explained in the class documentation of + * HeatingModel::HeatingModelOutputs each term contains the sum of all + * enabled heating mechanism contributions. + */ + HeatingModel::HeatingModelOutputs heating_model_outputs; + HeatingModel::HeatingModelOutputs face_heating_model_outputs; + HeatingModel::HeatingModelOutputs neighbor_face_heating_model_outputs; + + /** + * This pointer contains a struct that can be used to identify the + * advection field that is currently assembled. It can be used to + * determine between temperature and the available compositional + * fields. See the documentation of the AdvectionField class for + * more details. + */ + const typename Simulator::AdvectionField *advection_field; + + /** + * The amount of entropy viscosity that should be applied to the + * current cell to stabilize the solution of the advection system. + */ + double artificial_viscosity; + }; + } + + + + /** + * The CopyData arrays are similar to the Scratch arrays except they are + * meant as containers for the output of assembler objects. They provide a + * constructor and some data objects for local matrix, local vectors and + * the relation between local and global degrees of freedom (a.k.a. + * local_dof_indices). After all assemblers are finished + * the objects contain the local contributions of a particular cell to + * the global matrix and right hand side. This copy data object is then + * handed over to one of the copy_local_to_global... + * functions in assembly.cc that copy their content to the global matrix + * and right hand side vector. + */ + namespace CopyData + { + /** + * The base class is empty and only allows us to hand over pointers + * or references of a generic type and later cast them to their actual + * derived class. + */ + template + struct CopyDataBase + { + virtual ~CopyDataBase () = default; + }; + + /** + * The Stokes preconditioner object only requires the bare minimum of + * copy data objects. Matrix contributions and degrees of freedom this + * cell corresponds to. + */ + template + struct StokesPreconditioner: public CopyDataBase + { + StokesPreconditioner (const unsigned int stokes_dofs_per_cell); + + StokesPreconditioner (const StokesPreconditioner &data); + + ~StokesPreconditioner () override = default; + StokesPreconditioner &operator= (const StokesPreconditioner &data) = default; + + FullMatrix local_matrix; + Vector local_inverse_lumped_mass_matrix; + std::vector local_dof_indices; + + /** + * Extract the values listed in @p all_dof_indices only if + * it corresponds to the Stokes component and copy it to the variable + * local_dof_indices declared above in the same class as this function + */ + void extract_stokes_dof_indices(const std::vector &all_dof_indices, + const Introspection &introspection, + const FiniteElement &finite_element); + }; + + /** + * Similar to the scratch object the Stokes system requires all + * data from the Stokes preconditioner copy data class, plus some + * extras like the right hand side contribution. + */ + template + struct StokesSystem : public StokesPreconditioner + { + StokesSystem (const unsigned int stokes_dofs_per_cell, + const bool do_pressure_rhs_compatibility_modification); + StokesSystem (const StokesSystem &data); + + ~StokesSystem () override = default; + StokesSystem &operator= (const StokesSystem &data) = default; + + Vector local_rhs; + Vector local_pressure_shape_function_integrals; + }; + + /** + * Additionally to the Stokes system the Advection system copy data + * object also needs to keep track of contributions across faces + * (mostly for discontinuous elements that contain DG terms). + */ + template + struct AdvectionSystem: public CopyDataBase + { + /** + * Constructor. + * + * @param finite_element The element that describes the field for + * which we are trying to assemble a linear system. Not + * the global finite element. + * @param field_is_discontinuous If true, the field is a DG element. + */ + AdvectionSystem (const FiniteElement &finite_element, + const bool field_is_discontinuous); + + /** + * Local contributions to the global matrix + * that correspond only to the variables listed in local_dof_indices + */ + FullMatrix local_matrix; + + /** + * Local contributions to the global matrix from the face terms in the + * discontinuous Galerkin method. These arrays are of a length sufficient + * to hold one matrix for each possible face or subface of the cell. + * The discontinuous Galerkin bilinear form contains terms arising from + * internal (to the cell) values and external (to the cell) values. + * `_int_ext` and `_ext_int` hold the terms arising from the pairing + * between a cell and its neighbor, while `_ext_ext` is the pairing + * of the neighbor's dofs with themselves. In the continuous + * Galerkin case, these are unused, and set to size zero. + */ + std::vector> local_matrices_int_ext; + std::vector> local_matrices_ext_int; + std::vector> local_matrices_ext_ext; + + /** + * Local contributions to the right hand side + * that correspond only to the variables listed in local_dof_indices + */ + Vector local_rhs; + + /** + * Denotes which face matrices have actually been assembled in the DG field + * assembly. Entries for matrices not used (for example, those corresponding + * to non-existent subfaces; or faces being assembled by the neighboring cell) + * are set to false. + */ + std::vector assembled_matrices; + + /** + * Indices of those degrees of freedom that actually correspond + * to the temperature or compositional field. since this structure + * is used to represent just contributions to the advection + * systems, there will be no contributions to other parts of the + * system and consequently, we do not need to list here indices + * that correspond to velocity or pressure degrees (or, in fact + * any other variable outside the block we are currently considering) + */ + std::vector local_dof_indices; + + /** + * Indices of the degrees of freedom corresponding to the temperature + * or composition field on all possible neighboring cells. This is used + * in the discontinuous Galerkin method. The outer array has a + * length sufficient to hold one element for each possible face + * and sub-face of the current cell. The object is not used + * and has size zero if in the continuous Galerkin case. + */ + std::vector> neighbor_dof_indices; + }; + } + } + } + + /** + * A namespace for the definition of assemblers for the various terms in the + * linear systems ASPECT solves. + */ + namespace Assemblers + { + + /** + * For a reference cell (which is typically obtained by asking the finite + * element to be used), determine how many interface matrices are needed. + * Since interface matrices are needed for as many neighbors as each + * cell can have, this is the number of faces for the given reference cell + * times the number of children each of these faces can have. This + * accommodates the fact that the neighbors of a cell can all be refined, + * though they can only be refined once. + */ + unsigned int + n_interface_matrices (const ReferenceCell &reference_cell); + + /** + * For a given reference cell, and a given face we are currently + * assembling on, return which element of an array of size + * `n_interface_matrices(reference_cell)` to use. + */ + unsigned int + nth_interface_matrix (const ReferenceCell &reference_cell, + const unsigned int face); + + /** + * For a given reference cell, and a given face and sub-face we are + * currently assembling on, return which element of an array of size + * `n_interface_matrices(reference_cell)` to use. + */ + unsigned int + nth_interface_matrix (const ReferenceCell &reference_cell, + const unsigned int face, + const unsigned int sub_face); + + /** + * A base class for objects that implement assembly + * operations. + * + * The point of this class is primarily so that we can store + * pointers to such objects in a list. The objects are created + * in Simulator::set_assemblers() and destroyed in the destructor of + * the Simulator object. Derived classes of this base class usually + * handle groups of terms in the equations that are + * logically connected (such as all terms in the Stokes equations that + * appear independent on the selected compressibility formulation). This + * way selecting a certain set of assembler objects effectively controls + * which equation is solved. + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Execute this assembler object. This function performs the primary work + * of an assembler. More precisely, it uses information for the current + * cell that is stored in @p scratch (like the material properties on + * this cell and the position of quadrature points) and computes the + * matrix and right hand side contributions for a set of terms for + * the given cell. These contributions are stored in @p data. Note, that + * the data in @p scratch and @p data is shared between all active + * assemblers so that each assembler should only add contributions to + * @p data, not overwrite entries in the matrix. After all assemblers + * have finished, the final content of @p data is distributed into the + * global matrix and right hand side vector. + */ + virtual + void + execute(internal::Assembly::Scratch::ScratchBase &scratch, + internal::Assembly::CopyData::CopyDataBase &data) const = 0; + + /** + * This function gets called if a MaterialModelOutputs is created + * and allows the assembler to attach AdditionalOutputs. The + * function might be called more than once for a + * MaterialModelOutput, so it is recommended to check if + * get_additional_output() returns an instance before adding a new + * one to the additional_outputs vector. By default this function does + * not create additional outputs. + * + * Material models, through functions derived from + * MaterialModel::Interface::evaluate(), put their computed material + * parameters into a structure of type MaterialModel::MaterialModelOutputs. + * By default, material models will compute those parameters that + * correspond to the member variables of that structure. However, + * there are situations where parts of the simulator need additional + * pieces of information; a typical example would be the use of a + * Newton scheme that also requires the computation of derivatives + * of material parameters with respect to pressure, temperature, and + * possibly other variables. + * + * The computation of such additional information is controlled by + * the presence of a collection of pointers in + * MaterialModel::MaterialModelOutputs that point to additional + * objects. Whether or not one needs these additional objects depends + * on what assemblers are selected, or what postprocessing one + * wants to compute. For the purpose of assembly, the current + * function creates the additional objects (such as the one that stores + * derivatives) and adds pointers to them to the collection, based on + * what this assembler class requires. This function is always called + * before the material model is evaluated and execute() is called. + * This ensures the additional material model output is available when + * execute() is called. + */ + virtual + void + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &) const; + + /** + * A required function for objects that implement the assembly of terms + * in an equation that requires the computation of residuals + * (in particular the advection equation in ASPECT). + * Just like the assemblers itself, the residual + * that we use to compute the necessary entropy viscosity depend on the + * equation (i.e. which terms are actually included in the + * equation). Thus different objects compute different residuals (i.e. + * the residual for a melt advection equation looks different from the + * residual for a passive compositional field). + * For assemblers for the Stokes system, an implementation of this + * function is not necessary. + */ + virtual + std::vector + compute_residual(internal::Assembly::Scratch::ScratchBase &) const; + }; + + + + /** + * A base class for objects that implement assembly + * operations for advection-diffusion problems. + * + * This class implements functions that provide information + * for stabilization mechanisms. + */ + template + class AdvectionStabilizationInterface + { + public: + virtual ~AdvectionStabilizationInterface (); + + /** + * This function returns a representative prefactor for the advection + * term of the equation for each quadrature point of the current cell. + * In the non-dimensional case this is simply 1.0, but for other + * quantities like temperature it is computed using physical units + * (like density and specific heat capacity). + * This information is useful for algorithms that depend on the + * magnitude of individual terms, like stabilization methods. + */ + virtual + std::vector + advection_prefactors(internal::Assembly::Scratch::ScratchBase &scratch_base) const; + + /** + * This function returns a representative conductivity for the + * diffusion part of the equation for each quadrature point of the + * current cell. For the pure advection case this factor is 0.0, but + * for other quantities like temperature it is + * computed using physical units (like thermal conductivity). This + * information is useful for algorithms depending on the magnitude of + * individual terms, like stabilization methods. + */ + virtual + std::vector + diffusion_prefactors(internal::Assembly::Scratch::ScratchBase &scratch_base) const; + }; + + + + /** + * A class that owns member variables representing + * all assemblers that need to be called when + * assembling right hand side vectors, matrices, or complete linear + * systems. We use this approach in order to support the following + * cases: + * - Assembling different formulations: When assembling either the + * full equations or only the Boussinesq approximation (to give just + * two examples), one needs different terms. This could be achieved + * using a large number of switch or if + * statements in the code, or one could encapsulate each equation + * or approximation into a collection of assemblers for this particular + * purpose. The approach chosen here in essence allows the + * implementation of each set of equations in its own scope, and we + * then just need to store a pointer to the object that + * assembles the Stokes system (for example) for the selected + * approximation. The pointer to this function is stored in the + * appropriate member variable of this class. + * - Sometimes, we want to assemble a number of terms that build on + * each other. An example is the addition of free boundary terms + * to the Stokes matrix. Rather than having to "know" in one + * place about all of the terms that need to be assembled, + * we simply add the function that computes these terms as + * another object to the appropriate set of assemblers declared + * in this class. + */ + template + class Manager + { + public: + + /** + * Reset the state of the manager and remove all Assemblers. + */ + void reset (); + + /** + * A vector of pointers containing all assemblers for the Stokes preconditioner. + * These assemblers are called once per cell. + */ + std::vector>> stokes_preconditioner; + + /** + * A vector of pointers containing all assemblers that compute + * cell contributions for the Stokes system. + * These assemblers are called once per cell. + */ + std::vector>> stokes_system; + + /** + * A vector of pointers containing all assemblers that compute face + * contributions for the Stokes system. These assemblers are called + * once per face at a boundary with the properly initialized inputs, + * therefore they allow terms that only exist on boundary faces (e.g. + * traction boundary conditions). + */ + std::vector>> stokes_system_on_boundary_face; + + /** + * A vector of vectors of pointers containing a list of all assemblers + * for each individual advection system. + * These assemblers are called once per cell. + */ + std::vector>>> advection_system; + + /** + * A vector of vectors of pointers containing a list of all assemblers + * for the individual advection systems that compute face contributions + * at boundaries. These assemblers are called once per boundary face with + * the properly initialized inputs, therefore they allow terms that only + * exist on boundary faces (e.g. flux boundary conditions). + */ + std::vector>>> advection_system_on_boundary_face; + + /** + * A vector of vectors of pointers containing a list of all assemblers + * for the individual advection systems that compute face contributions + * on faces between cells. These assemblers are called once per interior + * face with the properly initialized inputs, therefore they allow terms + * that only exist on interior faces (e.g. DG penalty terms). + */ + std::vector>>> advection_system_on_interior_face; + + /** + * A structure that describes what information an assembler function + * (listed as one of the assembler objects above) may need to operate. + * + * There are a number of pieces of information that are always + * assumed to be needed. For example, the Stokes and advection + * assemblers will always need to have access to the material + * model outputs. But the Stokes assembler may or may not need + * access to material model outputs for quadrature points on faces. + * + * These properties are all preset in a conservative way + * (i.e., disabled) in the constructor of this class, but can + * be enabled in Simulator::set_assemblers() when adding + * individual assemblers. Functions such as + * Simulator::local_assemble_stokes_preconditioner(), + * Simulator::local_assemble_stokes_system() will then query + * these flags to determine whether something has to be + * initialized for at least one of the assemblers they call. + */ + struct Properties + { + /** + * Constructor. Disable all properties as described in the + * class documentation. + */ + Properties (); + + /** + * Whether or not at least one of the active assembler objects for + * a certain equation requires the initialization and re-computation + * of a MaterialModelOutputs object for each face. This + * property is only relevant to assemblers that operate on + * faces. + */ + bool need_face_material_model_data; + + /** + * Whether or not at least one of the active assembler objects for + * a certain equation requires the evaluation of the FEFaceValues + * object. This is different from need_face_material_model_data, + * because an assembler might assemble terms that do not require + * material model outputs. + */ + bool need_face_finite_element_evaluation; + + /** + * Whether or not at least one of the active assembler objects for + * a certain equation requires the computation of the viscosity. + */ + bool need_viscosity; + + /** + * A list of FEValues UpdateFlags that are necessary for + * a given operation. Assembler objects may add to this list + * as necessary; it will be initialized with a set of + * "default" flags that will always be set. + */ + UpdateFlags needed_update_flags; + }; + + /** + * Lists of properties for the various equations we want to assemble. + * These property lists are set in Simulator::set_assemblers() + * where we add individual functions to the vectors of assembler + * objects above. + */ + Properties stokes_preconditioner_assembler_properties; + Properties stokes_system_assembler_properties; + Properties stokes_system_assembler_on_boundary_face_properties; + std::vector advection_system_assembler_properties; + std::vector advection_system_assembler_on_face_properties; + }; + } +} + + +#endif diff --git a/include/aspect/simulator/assemblers/stokes.h.bak b/include/aspect/simulator/assemblers/stokes.h.bak new file mode 100644 index 00000000000..6ffe27fd8f3 --- /dev/null +++ b/include/aspect/simulator/assemblers/stokes.h.bak @@ -0,0 +1,224 @@ +/* + Copyright (C) 2017 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + +#ifndef _aspect_simulator_assemblers_stokes_h +#define _aspect_simulator_assemblers_stokes_h + + +#include +#include + +namespace aspect +{ + namespace Assemblers + { + /** + * A class containing the functions to assemble the Stokes preconditioner. + */ + template + class StokesPreconditioner : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * A class containing the functions to assemble the compressible adjustment + * to the Stokes preconditioner. + */ + template + class StokesCompressiblePreconditioner : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class assembles the terms for the matrix and right-hand-side of the incompressible + * Stokes equation for the current cell. + */ + template + class StokesIncompressibleTerms : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + + /** + * Create AdditionalMaterialOutputsStokesRHS if we need to do so. + */ + void create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const override; + }; + + /** + * This class assembles the term that arises in the viscosity term of Stokes matrix for + * compressible models, because the divergence of the velocity is not longer zero. + */ + template + class StokesCompressibleStrainRateViscosityTerm : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class assembles the compressibility term of the Stokes equation + * that is caused by the compressibility in the mass conservation equation. + * It uses an approximation that involves the reference density profile, and + * includes this term explicitly in the right-hand side vector to preserve + * the symmetry of the matrix. + * This class approximates this term as + * $- \nabla \cdot \mathbf{u} = \frac{1}{\rho^{\ast}} \frac{\partial rho}{\partial z} \frac{\mathbf{g}}{||\mathbf{g}||} \cdot \mathbf{u}$ + */ + template + class StokesReferenceDensityCompressibilityTerm : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class assembles the compressibility term of the Stokes equation + * that is caused by the compressibility in the mass conservation equation. + * It uses an approximation that involves the reference density profile, and + * includes this term implicitly in the matrix, + * which is therefore not longer symmetric. + * This class approximates this term as + * $ - \nabla \cdot \mathbf{u} - \frac{1}{\rho^{\ast}} \frac{\partial rho{^\ast}}{\partial z} \frac{\mathbf{g}}{||\mathbf{g}||} \cdot \mathbf{u} = 0$ + */ + template + class StokesImplicitReferenceDensityCompressibilityTerm : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class assembles the right-hand-side term of the Stokes equation + * that is caused by the compressibility in the mass conservation equation. + * This class approximates this term as + * $ - \nabla \cdot \mathbf{u} = \kappa \rho \mathbf{g} \cdot \mathbf{u}$ + * where $\kappa$ is the compressibility provided by the material model, + * which is frequently computed as + * $\kappa = \frac{1}{\rho} \frac{\partial rho}{\partial p}$. + */ + template + class StokesIsentropicCompressionTerm : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class assembles the right-hand-side term of the Stokes equation + * that is caused by the variable density in the mass conservation equation. + * This class approximates this term as + * $ - \nabla \cdot \mathbf{u} = \frac{1}{\rho} \frac{\partial \rho}{\partial t} + \frac{1}{\rho} \nabla \rho \cdot \mathbf{u}$ + * where the right-hand side velocity is explicitly taken from the last timestep, + * and the density is taken from a compositional field of the type 'density'. + */ + template + class StokesProjectedDensityFieldTerm : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch, + internal::Assembly::CopyData::CopyDataBase &data) const override; + }; + + + /** + * This class assembles the right-hand-side term of the Stokes equation + * that is caused by the compression based on the changes in (hydrostatic) + * pressure and temperature in the mass conservation equation. + * + * This class approximates this term as + * $ -\nabla \cdot \mathbf{u} = \left( \kappa \rho \textbf{g} - \alpha \nabla T \right) \cdot \textbf{u}$ + * + * where $\frac{1}{\rho} \frac{\partial \rho}{\partial p} = \kappa$ is the compressibility, + * $- \frac{1}{\rho}\frac{\partial \rho}{\partial T} = \alpha$ is the thermal expansion coefficient, + * and both are defined in the material model. + */ + template + class StokesHydrostaticCompressionTerm : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class assembles the right-hand-side terms that are used to weakly + * prescribe the boundary tractions. + */ + template + class StokesBoundaryTraction : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + + /** + * This class computes the local pressure shape function integrals that + * are later used to make the Stokes equations compatible to its right hand + * side. For more information why this is necessary see Section 3.2.2 of + * Heister et al. (2017), "High Accuracy Mantle Convection Simulation + * through Modern Numerical Methods. II: Realistic Models and Problems." + */ + template + class StokesPressureRHSCompatibilityModification : public Assemblers::Interface, + public SimulatorAccess + { + public: + void + execute(internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const override; + }; + } +} + + +#endif diff --git a/include/aspect/simulator_access.h.bak b/include/aspect/simulator_access.h.bak new file mode 100644 index 00000000000..999a22a6980 --- /dev/null +++ b/include/aspect/simulator_access.h.bak @@ -0,0 +1,1002 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_simulator_access_h +#define _aspect_simulator_access_h + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace WorldBuilder +{ + class World; +} + +namespace aspect +{ + using namespace dealii; + + // forward declarations: + template class Simulator; + template struct SimulatorSignals; + template class LateralAveraging; + template struct RotationProperties; + + namespace GravityModel + { + template class Interface; + } + + namespace HeatingModel + { + template class Manager; + } + + namespace MaterialModel + { + template class Interface; + } + + namespace InitialTemperature + { + template class Manager; + template class Interface; + } + + namespace BoundaryTemperature + { + template class Manager; + template class Interface; + } + + namespace BoundaryHeatFlux + { + template class Interface; + } + + namespace BoundaryComposition + { + template class Manager; + template class Interface; + } + + namespace BoundaryTraction + { + template class Manager; + template class Interface; + } + + namespace BoundaryVelocity + { + template class Manager; + template class Interface; + } + + namespace InitialComposition + { + template class Manager; + template class Interface; + } + + namespace InitialTopographyModel + { + template class Interface; + } + + namespace MeshRefinement + { + template class Manager; + } + + namespace AdiabaticConditions + { + template class Interface; + } + + namespace Postprocess + { + template class Manager; + } + + template class MeltHandler; + template class VolumeOfFluidHandler; + + namespace MeshDeformation + { + template class MeshDeformationHandler; + } + + template class NewtonHandler; + + template class StokesMatrixFreeHandler; + + namespace Particle + { + template class World; + } + + namespace TimeStepping + { + template class Manager; + } + + /** + * SimulatorAccess is a base class for different plugins like postprocessors. + * It provides access to the various variables of the main class that + * plugins may want to use in their evaluations, such as solution vectors, + * the current time, time step sizes, material models, or the triangulations + * and DoFHandlers that correspond to solutions. + * + * This class is the interface between plugins and the main simulator class. + * Using this insulation layer, the plugins need not know anything about the + * internal details of the simulation class. + * + * Every Postprocessor is required to derive from SimulatorAccess. It is + * optional for other plugins like MaterialModel, GravityModel, etc.. + * + * Since the functions providing access to details of the simulator class + * are meant to be used only by derived classes of this class (rather than + * becoming part of the public interface of these classes), the functions of + * this class are made @p protected. + * + * @ingroup Simulator + */ + template + class SimulatorAccess + { + public: + /** + * Default constructor. Initialize the SimulatorAccess object without + * a reference to a particular Simulator object. You will later have + * to call initialize() to provide this reference to the Simulator + * object. + */ + SimulatorAccess (); + + /** + * Create a SimulatorAccess object that is already initialized for + * a particular Simulator. + */ + SimulatorAccess (const Simulator &simulator_object); + + /** + * Destructor. Does nothing but is virtual so that derived classes + * destructors are also virtual. + */ + virtual ~SimulatorAccess () = default; + + /** + * Initialize this class for a given simulator. This function is marked + * as virtual so that derived classes can do something upon + * initialization as well, for example look up and cache data; derived + * classes should call this function from the base class as well, + * however. + * + * @param simulator_object A reference to the main simulator object. + */ + virtual void initialize_simulator (const Simulator &simulator_object); + + /** @name Accessing variables that identify overall properties of the simulator */ + /** @{ */ + + /** + * Return a reference to an introspection object that describes overall + * properties of the simulator. In particular, it provides symbolic + * names for extractors and component masks for each variable, etc, and + * thereby reduces the need for implicit knowledge throughout the code + * base. + */ + const Introspection & + introspection () const; + + /** + * Return a reference to the Simulator itself. Note that you can not + * access any members or functions of the Simulator. This function + * exists so that any class with SimulatorAccess can create other + * objects with SimulatorAccess (because initializing them requires a + * reference to the Simulator). + */ + const Simulator & + get_simulator () const; + + /** + * Return a reference to the parameters object that describes all run-time + * parameters used in the current simulation. + */ + const Parameters & + get_parameters () const; + + /** + * Get Access to the structure containing the signals of the simulator. + */ + SimulatorSignals & + get_signals() const; + + /** + * Return the MPI communicator for this simulation. + */ + MPI_Comm + get_mpi_communicator () const; + + /** + * Return the timer object for this simulation. Since the timer is + * mutable in the Simulator class, this allows plugins to define their + * own sections in the timer to measure the time spent in sections of + * their code. + */ + TimerOutput & + get_computing_timer () const; + + /** + * Return a reference to the stream object that only outputs something + * on one processor in a parallel program and simply ignores output put + * into it on all other processors. + */ + const ConditionalOStream & + get_pcout () const; + + /** + * Return the current simulation time in seconds. + */ + double get_time () const; + + /** + * Return the size of the current time step. + */ + double + get_timestep () const; + + /** + * Return the size of the last time step. + */ + double + get_old_timestep () const; + + /** + * Return the current number of a time step. + */ + unsigned int + get_timestep_number () const; + + /** + * Return a reference to the manager of the time stepping strategies. + * This can then be used, for example, to check whether a checkpoint needs to + * be made upon termination. + */ + const TimeStepping::Manager & + get_timestepping_manager() const; + + /** + * Return the current nonlinear iteration number of a time step. + */ + unsigned int + get_nonlinear_iteration () const; + + /** + * Return a reference to the triangulation in use by the simulator + * object. + */ + const parallel::distributed::Triangulation & + get_triangulation () const; + + /** + * Return the global volume of the computational domain. + */ + double + get_volume () const; + + /** + * Return a reference to the mapping used to describe the boundary of + * the domain. + */ + const Mapping & + get_mapping () const; + + /** + * Return the directory specified in the input parameter file to be the + * place where output files are to be placed. The string is terminated + * by a directory separator (i.e., '/'). + */ + std::string + get_output_directory () const; + + /** + * Return whether we use the adiabatic heating term. + */ + bool + include_adiabatic_heating () const; + + /** + * Return whether we use the latent heat term. + */ + bool + include_latent_heat () const; + + /** + * Return whether we solve the equations for melt transport. + */ + bool + include_melt_transport () const; + + /** + * Return the stokes velocity degree. + */ + int + get_stokes_velocity_degree () const; + + /** + * Return the adiabatic surface temperature. + */ + double + get_adiabatic_surface_temperature () const; + + /** + * Return the adiabatic surface pressure. + */ + double + get_surface_pressure () const; + + /** + * Return whether things like velocities should be converted from the + * seconds in the MKS system to years. The value of this flag is set by + * the corresponding entry in the input parameter file. + */ + bool + convert_output_to_years () const; + + /** + * Return the number of the current pre refinement step. + * This can be useful for plugins that want to function differently in + * the initial adaptive refinements and later on. + * This will be not initialized before Simulator::run() is called. + * It iterates upward from 0 to parameters.initial_adaptive_refinement + * during the initial adaptive refinement steps, and equals + * std::numeric_limits::max() afterwards. + */ + unsigned int + get_pre_refinement_step () const; + + /** + * Return the number of compositional fields specified in the input + * parameter file that will be advected along with the flow field. + */ + unsigned int + n_compositional_fields () const; + + /** + * Return the simulation end time in seconds. + */ + double + get_end_time () const; + + /** + * Compute the error indicators in the same way they are normally used + * for mesh refinement. The mesh is not refined when doing so, but the + * indicators can be used when generating graphical output to check why + * mesh refinement is proceeding as it is. + */ + void + get_refinement_criteria(Vector &estimated_error_per_cell) const; + + /** + * Returns the entropy viscosity on each locally owned cell as it is + * used to stabilize the temperature equation. + * + * @param viscosity_per_cell Output vector with as many entries as + * active cells. Each entry corresponding to a locally owned active + * cell index will contain the artificial viscosity for this cell. + * @param skip_interior_cells A boolean flag. If set to true the function + * will only compute the artificial viscosity in cells at boundaries. + */ + void + get_artificial_viscosity(Vector &viscosity_per_cell, + const bool skip_interior_cells = false) const; + + /** + * Returns the entropy viscosity on each locally owned cell as it is + * used to stabilize the composition equation. + */ + void + get_artificial_viscosity_composition(Vector &viscosity_per_cell, + const unsigned int compositional_variable) const; + + /** + * Compute the KXRCF indicator on each locally owned cell for a specific + * advection field. + */ + void + compute_KXRCF_indicators(Vector &KXRCF_indicators, + const unsigned int field_index) const; + /** @} */ + + + /** @name Accessing variables that identify the solution of the problem */ + /** @{ */ + + /** + * Return a reference to the vector that has the current linearization + * point of the entire system, i.e. the velocity and pressure variables + * as well as the temperature and compositional fields. This vector is + * associated with the DoFHandler object returned by get_dof_handler(). + * This vector is only different from the one returned by get_solution() + * during the solver phase. + * + * @note In general the vector is a distributed vector; however, it + * contains ghost elements for all locally relevant degrees of freedom. + */ + const LinearAlgebra::BlockVector & + get_current_linearization_point () const; + + /** + * Return a reference to the vector that has the current solution of the + * entire system, i.e. the velocity and pressure variables as well as + * the temperature and compositional fields. + * This vector is associated with the DoFHandler object returned by + * get_dof_handler(). + * + * @note In general the vector is a distributed vector; however, it + * contains ghost elements for all locally relevant degrees of freedom. + */ + const LinearAlgebra::BlockVector & + get_solution () const; + + /** + * Return a reference to the vector that has the solution of the entire + * system at the previous time step. This vector is associated with the + * DoFHandler object returned by get_stokes_dof_handler(). + * + * @note In general the vector is a distributed vector; however, it + * contains ghost elements for all locally relevant degrees of freedom. + */ + const LinearAlgebra::BlockVector & + get_old_solution () const; + + /** + * Return a reference to the vector that has the solution of the entire + * system at the second-to-last time step. This vector is associated with the + * DoFHandler object returned by get_stokes_dof_handler(). + * + * @note In general the vector is a distributed vector; however, it + * contains ghost elements for all locally relevant degrees of freedom. + */ + const LinearAlgebra::BlockVector & + get_old_old_solution () const; + + /** + * Return a reference to the vector that has the reactions computed by the + * operator splitting scheme in the current time step. + * + * @note In general the vector is a distributed vector; however, it + * contains ghost elements for all locally relevant degrees of freedom. + */ + const LinearAlgebra::BlockVector & + get_reaction_vector () const; + + /** + * Return a reference to the vector that has the mesh velocity for + * simulations with mesh deformation. + * + * @note In general the vector is a distributed vector; however, it + * contains ghost elements for all locally relevant degrees of freedom. + */ + const LinearAlgebra::BlockVector & + get_mesh_velocity () const; + + /** + * Return a reference to the DoFHandler that is used to discretize the + * variables at the current time step. + */ + const DoFHandler & + get_dof_handler () const; + + /** + * Return a reference to the finite element that is + * used to discretize the variables at the current time step. + * This is the finite element for the entire, coupled problem, i.e., + * it contains sub-elements for velocity, pressure, temperature and all + * other variables in this problem (e.g., compositional variables, if + * used in this simulation). + */ + const FiniteElement & + get_fe () const; + + /** + * Return a reference to the system matrix at the current time step. + */ + const LinearAlgebra::BlockSparseMatrix & + get_system_matrix () const; + + /** + * Return a reference to the system preconditioner matrix at the current time step. + */ + const LinearAlgebra::BlockSparseMatrix & + get_system_preconditioner_matrix () const; + + /** @} */ + + + /** @name Accessing variables that identify aspects of the simulation */ + /** @{ */ + + /** + * Return a pointer to the material model to access functions like + * density(). + */ + const MaterialModel::Interface & + get_material_model () const; + + /** + * Return a pointer to the gravity model description. + */ + const GravityModel::Interface & + get_gravity_model () const; + + /** + * Return a pointer to the initial topography model. + */ + const InitialTopographyModel::Interface & + get_initial_topography_model () const; + + /** + * Return a pointer to the geometry model. + */ + const GeometryModel::Interface & + get_geometry_model () const; + + + /** + * Return a pointer to the object that describes the adiabatic + * conditions. + */ + const AdiabaticConditions::Interface & + get_adiabatic_conditions () const; + + /** + * Return whether the current model has a boundary temperature object + * set. This is useful because a simulation does not actually have to + * declare any boundary temperature model, for example if all + * boundaries are insulating. In such cases, there is no + * boundary temperature model that can provide, for example, + * a minimal and maximal temperature on the boundary. + */ + bool has_boundary_temperature () const; + + /** + * Return an reference to the manager of the boundary temperature models. + * This can then, for example, be used to get the names of the initial temperature + * models used in a computation, or to compute the initial temperature + * for a given position. + */ + const BoundaryTemperature::Manager & + get_boundary_temperature_manager () const; + + /** + * Return a reference to the object that describes heat flux + * boundary conditions. + */ + const BoundaryHeatFlux::Interface & + get_boundary_heat_flux () const; + + /** + * Return whether the current model has a boundary composition object + * set. This is useful because a simulation does not actually have to + * declare any boundary composition model, for example if all + * boundaries are reflecting. In such cases, there is no + * boundary composition model. + */ + bool has_boundary_composition () const; + + /** + * Return an reference to the manager of the boundary composition models. + * This can then, for example, be used to get the names of the boundary composition + * models used in a computation, or to compute the boundary composition + * for a given position. + */ + const BoundaryComposition::Manager & + get_boundary_composition_manager () const; + + /** + * Return an reference to the manager of the boundary traction models. + * This can then, for example, be used to get the names of the boundary traction + * models used in a computation, or to compute the boundary traction + * for a given position. + */ + const BoundaryTraction::Manager & + get_boundary_traction_manager () const; + + /** + * Return a reference to the manager of the initial temperature models. + * This can then, for example, be used to get the names of the initial temperature + * models used in a computation, or to compute the initial temperature + * for a given position. + * + * While the Simulator class creates a shared pointer to an initial + * temperature manager before the first time step, it releases + * the pointer once it no longer needs access to the initial + * compositions. As a consequence, you can only call this function + * during the first time step. + * + * If the Simulator's shared pointer were the only + * one that points to the initial temperature manager object, that + * would also destroy the object pointed to. However, plugin classes + * can have member variables that are *also* shared pointers to + * these manager objects, and if you initialize such a shared + * pointer from the result of this function -- typically in the + * `initialize()` function of a plugin class -- then the Simulator + * giving up its shared pointer does not actually destroy the + * manager object but extends its lifetime until the last plugin + * that has a pointer to it is destroyed itself. As a consequence, + * if you need access to the initial temperature in a plugin, you + * will need to keep a shared pointer to it around for as long + * as you need it. + */ + std::shared_ptr> + get_initial_temperature_manager_pointer () const; + + /** + * Return a reference to the manager of the initial temperature model. + * This can then, for example, be used to get the names of the initial temperature + * models used in a computation. + * + * While the Simulator class creates a shared pointer to an initial + * temperature manager before the first time step, it releases + * the pointer once it no longer needs access to the initial + * temperature. As a consequence, you can only call this function + * during the first time step. If a plugin needs access to the initial + * temperature at a later time, it has to store its own shared + * pointer to that object, and that is what can be achieved using + * the get_initial_temperature_manager_pointer() function above. + */ + const InitialTemperature::Manager & + get_initial_temperature_manager () const; + + /** + * Return a pointer to the manager of the initial composition model. + * This can then, for example, be used to get the names of the initial composition + * models used in a computation. + * + * While the Simulator class creates a shared pointer to an initial + * composition manager before the first time step, it releases + * the pointer once it no longer needs access to the initial + * compositions. As a consequence, you can only call this function + * during the first time step. + * + * If the Simulator's shared pointer were the only + * one that points to the initial composition manager object, that + * would also destroy the object pointed to. However, plugin classes + * can have member variables that are *also* shared pointers to + * these manager objects, and if you initialize such a shared + * pointer from the result of this function -- typically in the + * `initialize()` function of a plugin class -- then the Simulator + * giving up its shared pointer does not actually destroy the + * manager object but extends its lifetime until the last plugin + * that has a pointer to it is destroyed itself. As a consequence, + * if you need access to the initial compositions in a plugin, you + * will need to keep a shared pointer to it around for as long + * as you need it. + */ + std::shared_ptr> + get_initial_composition_manager_pointer () const; + + /** + * Return a reference to the manager of the initial composition model. + * This can then, for example, be used to get the names of the initial composition + * models used in a computation. + * + * While the Simulator class creates a shared pointer to an initial + * composition manager before the first time step, it releases + * the pointer once it no longer needs access to the initial + * compositions. As a consequence, you can only call this function + * during the first time step. If a plugin needs access to the initial + * composition at a later time, it has to store its own shared + * pointer to that object, and that is what can be achieved using + * the get_initial_composition_manager_pointer() function above. + */ + const InitialComposition::Manager & + get_initial_composition_manager () const; + + /** + * Return a set of boundary indicators that describes which of the + * boundaries have a fixed temperature. + */ + const std::set & + get_fixed_temperature_boundary_indicators () const; + + /** + * Return a set of boundary indicators that describes which of the + * boundaries have a fixed heat flux. + */ + const std::set & + get_fixed_heat_flux_boundary_indicators () const; + + /** + * Return a set of boundary indicators that describes which of the + * boundaries have a fixed composition. + */ + const std::set & + get_fixed_composition_boundary_indicators () const; + + /** + * Return a set of boundary indicators that describes which of the + * boundaries have a mesh deformation boundary condition. Note that + * it does not specify which boundaries have which mesh deformation + * condition, only which boundaries have a mesh deformation condition. + */ + const std::set & + get_mesh_deformation_boundary_indicators () const; + + /** + * Return an reference to the manager of the boundary velocity models. + * This can then, for example, be used to get the names of the boundary velocity + * models used in a computation, or to compute the boundary velocity + * for a given position. + */ + const BoundaryVelocity::Manager & + get_boundary_velocity_manager () const; + + /** + * Return a pointer to the manager of the heating model. + * This can then, for example, be used to get the names of the heating models + * used in a computation. + */ + const HeatingModel::Manager & + get_heating_model_manager () const; + + /** + * Return a reference to the manager of the mesh refinement strategies. + * this can then, for example, be used to get the names of the active refinement + * strategies for such purposes as confirming that a particular one has + * been included. + */ + const MeshRefinement::Manager & + get_mesh_refinement_manager () const; + + /** + * Return a reference to the melt handler. + */ + const MeltHandler & + get_melt_handler () const; + + /** + * Return a reference to the VolumeOfFluid handler. + */ + const VolumeOfFluidHandler & + get_volume_of_fluid_handler () const; + + /** + * Return a reference to the Newton handler that controls the Newton + * iteration to resolve nonlinearities. + */ + const NewtonHandler & + get_newton_handler () const; + +#ifdef ASPECT_WITH_WORLD_BUILDER + /** + * Return a reference to the world builder that controls the setup of + * initial conditions. + * + * This call will only succeed if ASPECT was configured to use + * the WorldBuilder. + * + * While the Simulator class creates a shared pointer to a + * WorldBuilder object before the first time step, it releases + * the pointer once it no longer needs access to the initial + * conditions. As a consequence, you can only call this function + * during the first time step. If a plugin needs access to the object + * so returned at a later time, it has to store its own shared + * pointer to that object, and that is what can be achieved using + * the get_world_builder_pointer() function below. + */ + const WorldBuilder::World & + get_world_builder () const; + + /** + * This function is to get_world_builder() what + * get_initial_temperature_manager_pointer() is to + * the get_initial_temperature_manager() function: It returns a + * shared pointer so that objects that still need access to the + * WorldBuilder object after the Simulator class has released + * it, can extend the lifetime of the object pointed to by + * keeping a shared pointer to it. + */ + std::shared_ptr + get_world_builder_pointer () const; +#endif + /** + * Return a reference to the mesh deformation handler. This function will + * throw an exception if mesh deformation is not activated. + */ + const MeshDeformation::MeshDeformationHandler & + get_mesh_deformation_handler () const; + + /** + * Return a reference to the lateral averaging object owned + * by the simulator, which can be used to query lateral averages + * of various quantities at depth slices. + */ + const LateralAveraging & + get_lateral_averaging () const; + + /** + * Return a pointer to the object that describes the DoF + * constraints for the time step we are currently solving. + */ + const AffineConstraints & + get_current_constraints () const; + + /** + * Return whether the Simulator object has been completely initialized + * and has started to run its time stepping loop. + * + * This function is useful to determine in a plugin whether some + * of the information one can query about the Simulator can be trusted + * because it has already been set up completely. For example, + * while the Simulator is being + * set up, plugins may already have access to it via the current + * SimulatorAccess object, but data such as the current time, the + * time step number, etc, may all still be in a state that is not + * reliable since it may not have been initialized at that time. (As + * an example, at the very beginning of the Simulator object's existence, + * the time step number is set to numbers::invalid_unsigned_int, and + * only when the time step loop is started is it set to a valid + * value). Similar examples are that at some point the Simulator + * sets the solution vector to the correct size, but only at a later + * time (though before the time stepping starts), the *contents* of + * the solution vector are set based on the initial conditions + * specified in the input file. + * + * Only when this function returns @p true is all of the information + * returned by the SimulatorAccess object reliable and correct. + * + * @note This function returns @p true starting with the moment where the + * Simulator starts the time stepping loop. However, it may + * temporarily revert to returning @p false if, for example, + * the Simulator does the initial mesh refinement steps where + * it starts the time loop, but then goes back to + * initialization steps (mesh refinement, interpolation of initial + * conditions, etc.) before re-starting the time loop. + */ + bool simulator_is_past_initialization () const; + + /** + * Return the value used for rescaling the pressure in the linear + * solver. + */ + double + get_pressure_scaling () const; + + /** + * Return whether we need to apply a compatibility modification + * to the pressure right hand side. See documentation of + * Simulator::do_pressure_rhs_compatibility_modification for more + * information. + */ + bool + pressure_rhs_needs_compatibility_modification() const; + + /** + * Return whether the model uses a prescribed Stokes solution. + */ + bool + model_has_prescribed_stokes_solution () const; + + /** + * A convenience function that copies the values of the compositional + * fields at the quadrature point q given as input parameter to the + * output vector composition_values_at_q_point. + */ + static + void + get_composition_values_at_q_point (const std::vector> &composition_values, + const unsigned int q, + std::vector &composition_values_at_q_point); + + /** + * Return a writable reference to the statistics object into which + * you can store additional data that then shows up in the + * output_dir/statistics file. + * + * Postprocessor objects get a reference to this object automatically + * when called, but other plugins may not. They do not usually + * produce output anyway, but through this function they can still + * record information as necessary. + * @return + */ + TableHandler &get_statistics_object() const; + + /** + * Return a reference to the melt handler. + */ + const Postprocess::Manager & + get_postprocess_manager () const; + + /** + * Returns whether there is at least one particle world. + */ + unsigned int + n_particle_worlds() const; + + /** + * Returns a const reference to a single particle world, in case anyone + * wants to query something about particles. + */ + const Particle::World & + get_particle_world(const unsigned int particle_world_index) const; + + /** + * Returns a reference to a single particle world, in case anyone wants to + * change something within the particle world. Use with care, usually + * you want to only let the functions within the particle subsystem + * change member variables of the particle world. + */ + Particle::World & + get_particle_world(const unsigned int particle_world_index); + + /** + * Return true if using the block GMG Stokes solver. + */ + bool is_stokes_matrix_free(); + + /** + * Return a reference to the StokesMatrixFreeHandler that controls the + * matrix-free Stokes solver. + */ + const StokesMatrixFreeHandler & + get_stokes_matrix_free () const; + + /** + * Compute the angular momentum and other rotation properties + * of the velocities in the given solution vector. + * + * @param use_constant_density determines whether to use a constant + * density (which corresponds to computing a net rotation instead of net + * angular momentum). + * @param solution Solution vector to compute the properties for. + * @param limit_to_top_faces allows to only compute the net angular momentum + * (or net rotation) of the top surface. + */ + RotationProperties + compute_net_angular_momentum(const bool use_constant_density, + const LinearAlgebra::BlockVector &solution, + const bool limit_to_top_faces = false) const; + + /** @} */ + + private: + /** + * A pointer to the simulator object to which we want to get access. + */ + const Simulator *simulator; + }; +} + + +#endif diff --git a/include/aspect/simulator_signals.h.bak b/include/aspect/simulator_signals.h.bak new file mode 100644 index 00000000000..dea23bd94be --- /dev/null +++ b/include/aspect/simulator_signals.h.bak @@ -0,0 +1,420 @@ +/* + Copyright (C) 2015 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_simulator_signals_h +#define _aspect_simulator_signals_h + +#include +#include +#include + +#include +#include + +#include + +namespace aspect +{ + namespace Assemblers + { + template + class Manager; + + template + class Interface; + } + + /** + * A class that collects the definition of signals that can be triggered + * at different points in a computation. A signal is in essence an event + * that is triggered whenever the program passes a certain point in a + * computation. Parties interested in any of these signals can attach + * "slots" to a signal. A slot is, in essence, a function that is called + * whenever the signal is triggered. Multiple slots (or none) can be + * attached to the same signal. To be as general as possible, slots are + * not actually just pointers to functions, but std::function objects + * that have a certain signature. Consequently, they can have much more + * complicated types than just function pointers, such as objects with + * an operator() or lambda functions. + * + * The documentation of each of the signals below indicates when + * exactly it is called. + * + * @ingroup Simulator + */ + template + struct SimulatorSignals + { + /** + * A signal that is called before the list of finite element variables is + * used to construct the Introspection class. + * + * The functions (slots) that can attach to this signal need to + * take one argument: A std::vector of VariableDeclaration + * representing the collection of finite element variables, + * that can be modified and will be used to construct the + * final finite element system later. + */ + boost::signals2::signal> &)> + edit_finite_element_variables; + + /** + * A signal that is called before setting up the initial conditions. + * + * The functions (slots) that can attach to this signal need to take one + * argument: A SimulatorAccess object that describes the simulator. + */ + boost::signals2::signal &)> pre_set_initial_state; + + /** + * A signal that is called after setting up the initial conditions. + * + * The functions (slots) that can attach to this signal need to take one + * argument: A SimulatorAccess object that describes the simulator. + */ + boost::signals2::signal &)> post_set_initial_state; + + /** + * A signal that is called at the beginning of each time step. + * + * The functions (slots) that can attach to this signal need to take one + * argument: A SimulatorAccess object that describes the simulator. + */ + boost::signals2::signal &)> start_timestep; + + /** + * A signal that is called at the end of setting up the + * constraints for the current time step. This allows to add + * more constraints on degrees of freedom, for example to fix + * the velocity at certain points. + * + * The functions (slots) that can attach to this signal need to + * take two arguments: A SimulatorAccess object that + * describes the simulator to act on, and an (output) + * argument that indicates the constraints to be computed. + */ + boost::signals2::signal &, + AffineConstraints &)> post_constraints_creation; + + /** + * A signal that is called at the start of setup_dofs(). This allows for + * editing of the parameters struct on the fly (such as changing boundary + * conditions) to give ASPECT different behavior in mid-run than it + * otherwise would have. + * + * The functions that connect to this signal must take two arguments, a + * SimulatorAccess object that describes the simulator, and an object of + * type aspect::Parameters, which is the current parameters object + * that the simulator is working with. + */ + boost::signals2::signal &, + Parameters ¶meters)> edit_parameters_pre_setup_dofs; + + /** + * A signal that is called before every mesh_refinement. This signal + * allows for registering functions that store data that is related to + * mesh cells and needs to be transferred with the cells during the + * repartitioning. + * + * The functions that connect to this signal must take a reference to a + * parallel::distributed::Triangulation object as argument. This argument + * will point to the triangulation used by the Simulator class. + */ + boost::signals2::signal &)> pre_refinement_store_user_data; + + /** + * A signal that is called after every mesh_refinement. This signal + * allows for registering functions that load data related to mesh cells + * and that was transferred with the cells during the repartitioning. + * + * The functions that connect to this signal must take a reference to a + * parallel::distributed::Triangulation object as argument. This argument + * will point to the triangulation used by the Simulator class. + */ + boost::signals2::signal &)> post_refinement_load_user_data; + + /** + * A signal that is called before the computation of tangential boundary + * conditions for which normal vectors are needed, i.e. calls to the + * compute_no_normal_flux_constraints function for both the + * velocity variable in the main simulator and the mesh velocity + * variable in models with mesh deformation. + * + * The functions that connect to this signal must take a reference + * to a parallel::distributed::Triangulation object as + * argument. This argument will point to the triangulation used by + * the Simulator class. + */ + boost::signals2::signal &)> pre_compute_no_normal_flux_constraints; + + /** + * A signal that is called after the computation of tangential boundary + * conditions for which normal vectors are needed, i.e. calls to the + * compute_no_normal_flux_constraints function for both the + * velocity variable in the main simulator and the mesh velocity + * variable in models with mesh deformation. + * + * The functions that connect to this signal must take a reference + * to a parallel::distributed::Triangulation object as + * argument. This argument will point to the triangulation used by + * the Simulator class. + */ + boost::signals2::signal &)> post_compute_no_normal_flux_constraints; + + /** + * A signal that is called before the creation of every checkpoint. This + * signal allows for registering functions that store data related to mesh + * cells. + * + * The functions that connect to this signal must take a reference to a + * parallel::distributed::Triangulation object as argument. This argument + * will point to the triangulation used by the Simulator class. + */ + boost::signals2::signal &)> pre_checkpoint_store_user_data; + + /** + * A signal that is called after resuming from a checkpoint. This signal + * allows for registering functions that load data related to mesh cells + * that was previously stored in the checkpoint. Note that before calling + * Triangulation::notify_ready_to_unpack() the function needs to call + * register_attach_data() with the appropriate arguments to restore the + * state of the triangulation. + * + * The functions that connect to this signal must take a reference to a + * parallel::distributed::Triangulation object as argument. This argument + * will point to the triangulation used by the Simulator class. + */ + boost::signals2::signal &)> post_resume_load_user_data; + + /** + * This signal is called whenever the pressure scaling is computed, see + * Simulator::compute_pressure_scaling_factor(), and allows inspection + * and/or modification of the computed factor. + * + * The argument @p pressure_scaling contains the computed pressure scaling (the ratio + * of the reference viscosity @p reference_viscosity computed by averaging + * the viscosity in the domain and the length scale @p length_scale reported + * by the geometry model). The return value of this functions will replace + * the computed value, therefore no changes are made if you return the value + * @p pressure_scaling. + */ + boost::signals2::signal modify_pressure_scaling; + + /** + * A signal that is called at the beginning of the program. It + * gives user extensions the ability to declare additional + * parameters via the provided argument. User extensions connected to + * this signal will likely also want to connect to the + * parse_additional_parameters signal. + * + * The first argument to functions that connect to this signal + * denotes the dimension in which ASPECT will be run. Functions + * connected to this signal can declare additional runtime + * parameters in the second argument. + */ + static boost::signals2::signal declare_additional_parameters; + + /** + * A signal that is called at the beginning of the program, after reading + * the input file. It gives user extensions the ability to read additional + * parameters from the provided argument. The first argument indicates an + * object that represents all of the other parameters (that have already + * been parsed at this point). + * + * User extensions connected to this signal will likely also want to + * connect to the declare_additional_parameters signal. + */ + static boost::signals2::signal &, + ParameterHandler &)> parse_additional_parameters; + + /** + * A signal that is triggered when the iterative Stokes solver (either + * matrix-based or matrix-free) is done. The signal is not called when + * using a direct solver because the kind of information passed on by this + * signal does not exist when using a direct solver. + * + * Arguments to this signal are a reference to the SimulatorAccess, the number of + * preconditioner inner solver iterations for the $S$ and $A$ block of the + * system, and two information objects that contain information + * about the success of the solve, the number of outer GMRES iterations + * and the residual history for the cheap and expensive solver phase. + */ + boost::signals2::signal &, + const unsigned int number_S_iterations, + const unsigned int number_A_iterations, + const SolverControl &solver_control_cheap, + const SolverControl &solver_control_expensive)> post_stokes_solver; + + /** + * A signal that is triggered when the iterative advection solver is done. + * Arguments are a reference to the SimulatorAccess, a bool indicating + * whether the temperature field or a compositional field was solved, + * a composition index that describes which compositional field + * was solved, and an information object that contains information + * about the number of iterations and history of residuals. + */ + boost::signals2::signal &, + const bool solved_temperature_field, + const unsigned int compositional_index, + const SolverControl &solver_control)> post_advection_solver; + + /** + * A signal that is triggered when the nonlinear solver scheme is done. + * The signal parameter is an object that contains information + * about the final state (failure/success), number of + * iterations and history of residuals of the nonlinear solver. + * If there is no nonlinear solver (only a single solve), the + * SolverControl object will report a successful state, a single iteration + * and a remaining residual of zero. + */ + boost::signals2::signal post_nonlinear_solver; + + /** + * A signal that is triggered when ARKode is done solving an ODE. + * Arguments are a reference to the SimulatorAccess and + * an iteration count describing how many iterations ARKode required + * to solve the ODE. + */ + boost::signals2::signal &, + const unsigned int iteration_count)> post_ARKode_solve; + + /** + * A signal that is triggered when mesh deformation has occurred. + * The arguments to this signal is a reference to the SimulatorAccess + * object. + */ + boost::signals2::signal &)> post_mesh_deformation; + + /** + * A signal that is triggered at the end of the set_assemblers() function that + * allows modification of the assembly objects active in this simulation. + */ + boost::signals2::signal &, + aspect::Assemblers::Manager &)> + set_assemblers; + + /** + * A signal that is called before the build_patches() function is called during + * the creation of the visualization output. This signal + * allows for registering functions that take a DataOut object and can for example + * be used to select only certain cells of the mesh to be built into patches through + * calling the DataOut member function set_cell_selection(). + */ + boost::signals2::signal &)> pre_data_out_build_patches; + }; + + + // Explain to the compiler that we instantiate this class elsewhere, along + // with its static members. This is necessary to avoid warnings by some + // compilers. + extern template struct SimulatorSignals<2>; + extern template + boost::signals2::signal + SimulatorSignals<2>::declare_additional_parameters; + extern template + boost::signals2::signal &, ParameterHandler &)> + SimulatorSignals<2>::parse_additional_parameters; + + extern template struct SimulatorSignals<3>; + extern template + boost::signals2::signal + SimulatorSignals<3>::declare_additional_parameters; + extern template + boost::signals2::signal &, ParameterHandler &)> + SimulatorSignals<3>::parse_additional_parameters; + + + namespace internals + { + /** + * A namespace for some internal functions that have to do with how plugins + * can register their slots with signals. + */ + namespace SimulatorSignals + { + /** + * Two functions that (in 2d and 3d) put a user-provided function onto a list + * of functions that the Simulator object will later go through when + * letting plugins connect their slots to signals. + */ + void register_connector_function_2d (const std::function &)> &connector); + void register_connector_function_3d (const std::function &)> &connector); + + /** + * A function that is called by the Simulator object and that goes + * through the list (with the corresponding dimension) created by the + * previous pair of functions and call each of the user-provided + * connector functions to let them register their slots with the + * corresponding signals. + */ + template + void call_connector_functions (aspect::SimulatorSignals &signals); + } + } + + + /** + * A macro that is used in user-provided plugins to register a function that + * is called at the beginning of a simulation by a Simulator object. When called, + * the provided function will receive a SimulatorSignals object that contains + * signals to which one can subscribe. + * + * For technical reasons, the macro takes two arguments denoting functions for the + * 2d and 3d cases. These can, for example, be the names of 2d and 3d + * instantiations of the same template function. + */ +#define ASPECT_REGISTER_SIGNALS_CONNECTOR(connector_function_2d,connector_function_3d) \ + namespace ASPECT_REGISTER_SIGNALS_CONNECTOR \ + { \ + struct dummy_do_register \ + { \ + dummy_do_register () \ + { \ + aspect::internals::SimulatorSignals::register_connector_function_2d (connector_function_2d); \ + aspect::internals::SimulatorSignals::register_connector_function_3d (connector_function_3d); \ + } \ + } dummy_variable; \ + } + + + /** + * A macro that is used to register a function that can be used to connect user + * extension functions to the parameter-related signals declared in SimulatorSignals. + * + * In essence, this function simply registers a (global) function that is called + * at the beginning of the program and that can be used to connect parameter + * declaration and parsing functions to the signals listed above. + */ +#define ASPECT_REGISTER_SIGNALS_PARAMETER_CONNECTOR(connector_function) \ + namespace ASPECT_REGISTER_SIGNALS_PARAMETER_CONNECTOR_ ## connector_function \ + { \ + struct dummy_do_register_ ## connector_function \ + { \ + dummy_do_register_ ## connector_function () \ + { \ + connector_function (); \ + } \ + } dummy_variable_ ## classname; \ + } + +} +#endif diff --git a/include/aspect/stokes_matrix_free.h.bak b/include/aspect/stokes_matrix_free.h.bak new file mode 100644 index 00000000000..e90f857cc4a --- /dev/null +++ b/include/aspect/stokes_matrix_free.h.bak @@ -0,0 +1,702 @@ +/* + Copyright (C) 2018 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_stokes_matrix_free_h +#define _aspect_stokes_matrix_free_h + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/** + * Typedef for the number type for the multigrid operators. Can be either float or double. + */ +using GMGNumberType = double; + +namespace aspect +{ + using namespace dealii; + + namespace internal + { + /** + * Matrix-free operators must use deal.II defined vectors, while the rest of the ASPECT + * software is based on Trilinos vectors. Here we define functions which copy between the + * vector types. + */ + namespace ChangeVectorTypes + { + void import(TrilinosWrappers::MPI::Vector &out, + const dealii::LinearAlgebra::ReadWriteVector &rwv, + const VectorOperation::values operation); + + void copy(TrilinosWrappers::MPI::Vector &out, + const dealii::LinearAlgebra::distributed::Vector &in); + + void copy(dealii::LinearAlgebra::distributed::Vector &out, + const TrilinosWrappers::MPI::Vector &in); + + void copy(TrilinosWrappers::MPI::BlockVector &out, + const dealii::LinearAlgebra::distributed::BlockVector &in); + + void copy(dealii::LinearAlgebra::distributed::BlockVector &out, + const TrilinosWrappers::MPI::BlockVector &in); + } + } + + /** + * This namespace contains all matrix-free operators used in the Stokes solver. + */ + namespace MatrixFreeStokesOperators + { + + /** + * This struct stores the data for the current linear operator that is required to perform + * matrix-vector products. + * + * The members of type Table<2, VectorizedArray> contain values + * of type X, grouped by cell batch using the VectorizedArray. The + * table is indexed by the index of the cell batch and quadrature + * point index. In other words, you can access the value by + * table(cell_batch_index, q_index)[cell_index] + */ + template + struct OperatorCellData + { + /** + * Information on the compressibility of the flow. + */ + bool is_compressible; + + /** + * Pressure scaling constant. + */ + double pressure_scaling; + + /** + * If true, Newton terms are part of the operator. + */ + bool enable_newton_derivatives; + + /** + * Symmetrize the Newton system when it's true (i.e., the + * stabilization is symmetric or SPD). + */ + bool symmetrize_newton_system; + + /** + * If true, apply the stabilization on free surface faces. + */ + bool apply_stabilization_free_surface_faces; + + /** + * Table which stores viscosity values for each cell. + * + * If the second dimension is of size 1, the viscosity is + * assumed to be constant per cell. + */ + Table<2, VectorizedArray> viscosity; + + /** + * Table which stores the strain rate for each cell to be used + * for the Newton terms. + */ + Table<2, SymmetricTensor<2, dim, VectorizedArray>> strain_rate_table; + + /** + * Table which stores the product of the following three + * variables: viscosity derivative with respect to pressure, + * the Newton derivative scaling factor, and the averaging weight. + */ + Table<2, VectorizedArray> newton_factor_wrt_pressure_table; + + /** + * Table which stores the product of the following four + * variables: viscosity derivative with respect to strain rate, + * newton derivative scaling factor, alpha, and the averaging + * weight. Here alpha is the spd factor when the stabilization + * is PD or SPD, otherwise, it is 1. + */ + Table<2, SymmetricTensor<2, dim, VectorizedArray>> + newton_factor_wrt_strain_rate_table; + + /** + * Table which stores the product of the pressure perturbation + * and the normalized gravity. The size is n_face_boundary * n_face_q_points, + * but only those on the free surface are computed and stored. + */ + Table<2, Tensor<1, dim, VectorizedArray>> free_surface_stabilization_term_table; + + /** + * Boundary indicators of those boundaries with a free surface. + */ + std::set free_surface_boundary_indicators; + + /** + * Determine an estimate for the memory consumption (in bytes) of this + * object. + */ + std::size_t + memory_consumption() const; + + /** + * Reset the object and free all memory + */ + void clear(); + }; + + /** + * Operator for the entire Stokes block. + */ + template + class StokesOperator + : public MatrixFreeOperators::Base> + { + public: + + /** + * Constructor. + */ + StokesOperator (); + + /** + * Reset object. + */ + void clear () override; + + /** + * Pass in a reference to the problem data. + */ + void set_cell_data (const OperatorCellData &data); + + /** + * Computes the diagonal of the matrix. Since matrix-free operators have not access + * to matrix elements, we must apply the matrix-free operator to the unit vectors to + * recover the diagonal. + */ + void compute_diagonal () override; + + private: + + /** + * Performs the application of the matrix-free operator. This function is called by + * vmult() functions MatrixFreeOperators::Base. + */ + void apply_add (dealii::LinearAlgebra::distributed::BlockVector &dst, + const dealii::LinearAlgebra::distributed::BlockVector &src) const override; + + /** + * Defines the application of the cell matrix. + */ + void local_apply (const dealii::MatrixFree &data, + dealii::LinearAlgebra::distributed::BlockVector &dst, + const dealii::LinearAlgebra::distributed::BlockVector &src, + const std::pair &cell_range) const; + + /** + * This function doesn't do anything, it's created to use the matrixfree loop. + */ + void local_apply_face (const dealii::MatrixFree &data, + dealii::LinearAlgebra::distributed::BlockVector &dst, + const dealii::LinearAlgebra::distributed::BlockVector &src, + const std::pair &face_range) const; + + /** + * Apply the stabilization on free surface faces. + */ + void local_apply_boundary_face (const dealii::MatrixFree &data, + dealii::LinearAlgebra::distributed::BlockVector &dst, + const dealii::LinearAlgebra::distributed::BlockVector &src, + const std::pair &face_range) const; + + /** + * A pointer to the current cell data that contains viscosity and other required parameters per cell. + */ + const OperatorCellData *cell_data; + }; + + /** + * Operator for the pressure mass matrix used in the block preconditioner + */ + template + class MassMatrixOperator + : public MatrixFreeOperators::Base> + { + public: + + /** + * Constructor + */ + MassMatrixOperator (); + + /** + * Reset the object. + */ + void clear () override; + + /** + * Pass in a reference to the problem data. + */ + void set_cell_data (const OperatorCellData &data); + + /** + * Computes the diagonal of the matrix. Since matrix-free operators have not access + * to matrix elements, we must apply the matrix-free operator to the unit vectors to + * recover the diagonal. + */ + void compute_diagonal () override; + + private: + + /** + * Performs the application of the matrix-free operator. This function is called by + * vmult() functions MatrixFreeOperators::Base. + */ + void apply_add (dealii::LinearAlgebra::distributed::Vector &dst, + const dealii::LinearAlgebra::distributed::Vector &src) const override; + + /** + * Defines the application of the cell matrix. + */ + void local_apply (const dealii::MatrixFree &data, + dealii::LinearAlgebra::distributed::Vector &dst, + const dealii::LinearAlgebra::distributed::Vector &src, + const std::pair &cell_range) const; + + + /** + * Computes the diagonal contribution from a cell matrix. + */ + void local_compute_diagonal (const MatrixFree &data, + dealii::LinearAlgebra::distributed::Vector &dst, + const unsigned int &dummy, + const std::pair &cell_range) const; + + /** + * A pointer to the current cell data that contains viscosity and other required parameters per cell. + */ + const OperatorCellData *cell_data; + }; + + /** + * Operator for the A block of the Stokes matrix. The same class is used for both + * active and level mesh operators. + */ + template + class ABlockOperator + : public MatrixFreeOperators::Base> + { + public: + + /** + * Constructor + */ + ABlockOperator (); + + /** + * Reset the operator. + */ + void clear () override; + + /** + * Pass in a reference to the problem data. + */ + void set_cell_data (const OperatorCellData &data); + + /** + * Computes the diagonal of the matrix. Since matrix-free operators have not access + * to matrix elements, we must apply the matrix-free operator to the unit vectors to + * recover the diagonal. + */ + void compute_diagonal () override; + + /** + * Manually set the diagonal inside the matrix-free object. This function is needed + * when using tangential constraints as the function compute_diagonal() cannot handle + * non-Dirichlet boundary conditions. + */ + void set_diagonal (const dealii::LinearAlgebra::distributed::Vector &diag); + + private: + /** + * Defines the inner-most operator on a single cell batch with + * the loop over quadrature points. + */ + void inner_cell_operation(FEEvaluation &velocity) const; + + /** + * Defines the operation on a single cell batch including + * load/store and calls inner_cell_operation(). + */ + void cell_operation(FEEvaluation &velocity) const; + + /** + * Performs the application of the matrix-free operator. This + * function is called by vmult() functions + * MatrixFreeOperators::Base. + */ + void apply_add (dealii::LinearAlgebra::distributed::Vector &dst, + const dealii::LinearAlgebra::distributed::Vector &src) const override; + + /** + * Defines the application of the cell matrix. + */ + void local_apply (const dealii::MatrixFree &data, + dealii::LinearAlgebra::distributed::Vector &dst, + const dealii::LinearAlgebra::distributed::Vector &src, + const std::pair &cell_range) const; + + /** + * A pointer to the current cell data that contains viscosity and other required parameters per cell. + */ + const OperatorCellData *cell_data; + }; + } + + /** + * Base class for the matrix free GMG solver for the Stokes system. The + * actual implementation is found inside StokesMatrixFreeHandlerImplementation below. + */ + template + class StokesMatrixFreeHandler + { + public: + /** + * virtual Destructor. + */ + virtual ~StokesMatrixFreeHandler() = default; + + /** + * Solves the Stokes linear system matrix-free. This is called + * by Simulator::solve_stokes(). + */ + virtual std::pair solve()=0; + + /** + * Allocates and sets up the members of the StokesMatrixFreeHandler. This + * is called by Simulator::setup_dofs() + */ + virtual void setup_dofs()=0; + + /** + * Perform various tasks to update the linear system to solve + * for. Note that we are not assembling a matrix (as this is a + * matrix-free algorithm), but we are evaluating the material + * model and storing the information necessary for a later call + * to solve(). + */ + virtual void assemble()=0; + + /** + * Computes and sets the diagonal for both the mass matrix + * operator and the A-block operators on each level for the + * purpose of smoothing inside the multigrid v-cycle. + */ + virtual void build_preconditioner()=0; + + /** + * Declare parameters. + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * Return a reference to the DoFHandler that is used for velocity in + * the block GMG solver. + */ + virtual const DoFHandler & + get_dof_handler_v () const = 0; + + /** + * Return a reference to the DoFHandler that is used for pressure in + * the block GMG solver. + */ + virtual const DoFHandler & + get_dof_handler_p () const = 0; + + /** + * Return a reference to the DoFHandler that is used for the coefficient + * projection in the block GMG solver. + */ + virtual const DoFHandler & + get_dof_handler_projection () const = 0; + + /** + * Return a pointer to the object that describes the velocity DoF + * constraints for the block GMG Stokes solver. + */ + virtual const AffineConstraints & + get_constraints_v () const = 0; + + /** + * Return a pointer to the object that describes the pressure DoF + * constraints for the block GMG Stokes solver. + */ + virtual const AffineConstraints & + get_constraints_p () const = 0; + + /** + * Return a pointer to the MGTransfer object used for the A block + * of the block GMG Stokes solver. + */ + virtual const MGTransferMF & + get_mg_transfer_A () const = 0; + + /** + * Return a pointer to the MGTransfer object used for the Schur + * complement block of the block GMG Stokes solver. + */ + virtual const MGTransferMF & + get_mg_transfer_S () const = 0; + + /** + * Return the memory consumption in bytes that are used to store + * equation data like viscosity to be able to apply the operators. + */ + virtual std::size_t get_cell_data_memory_consumption() const = 0; + }; + + /** + * Main class of the Matrix-free method. Here are all the functions for + * setup, assembly and solving the Stokes system. + * + * We need to derive from StokesMatrixFreeHandler to be able to introduce a + * second template argument for the degree of the Stokes finite + * element. This way, the main simulator does not need to know about the + * degree by using a pointer to the base class and we can pick the desired + * velocity degree at runtime. + */ + template + class StokesMatrixFreeHandlerImplementation: public StokesMatrixFreeHandler + { + public: + /** + * Initialize this class, allowing it to read in + * relevant parameters as well as giving it a reference to the + * Simulator that owns it, since it needs to make fairly extensive + * changes to the internals of the simulator. + */ + StokesMatrixFreeHandlerImplementation(Simulator &, ParameterHandler &prm); + + /** + * Destructor. + */ + ~StokesMatrixFreeHandlerImplementation() override = default; + + /** + * Solves the Stokes linear system matrix-free. This is called + * by Simulator::solve_stokes(). + */ + std::pair solve() override; + + /** + * Allocates and sets up the members of the StokesMatrixFreeHandler. This + * is called by Simulator::setup_dofs() + */ + void setup_dofs() override; + + /** + * Perform various tasks to update the linear system to solve + * for. Note that we are not assembling a matrix (as this is a + * matrix-free algorithm), but we are evaluating the material + * model and storing the information necessary for a later call + * to solve(). + */ + void assemble() override; + + /** + * Computes and sets the diagonal for both the mass matrix operator and the A-block + * operators on each level for the purpose of smoothing inside the multigrid v-cycle. + */ + void build_preconditioner() override; + + /** + * Declare parameters. (No actual parameters at the moment). + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * Return a reference to the DoFHandler that is used for velocity in + * the block GMG solver. + */ + const DoFHandler & + get_dof_handler_v () const override; + + /** + * Return a reference to the DoFHandler that is used for pressure in + * the block GMG solver. + */ + const DoFHandler & + get_dof_handler_p () const override; + + /** + * Return a reference to the DoFHandler that is used for the coefficient + * projection in the block GMG solver. + */ + const DoFHandler & + get_dof_handler_projection () const override; + + /** + * Return a pointer to the object that describes the velocity DoF + * constraints for the block GMG Stokes solver. + */ + const AffineConstraints & + get_constraints_v () const override; + + /** + * Return a pointer to the object that describes the pressure DoF + * constraints for the block GMG Stokes solver. + */ + const AffineConstraints & + get_constraints_p () const override; + + /** + * Return a pointer to the MGTransfer object used for the A block + * of the block GMG Stokes solver. + */ + const MGTransferMF & + get_mg_transfer_A () const override; + + /** + * Return a pointer to the MGTransfer object used for the Schur + * complement block of the block GMG Stokes solver. + */ + const MGTransferMF & + get_mg_transfer_S () const override; + + + /** + * Return the memory consumption in bytes that are used to store + * equation data like viscosity to be able to apply the operators. + */ + std::size_t get_cell_data_memory_consumption() const override; + + private: + /** + * Parse parameters. + */ + void parse_parameters (ParameterHandler &prm); + + /** + * Evaluate the MaterialModel to query information like the viscosity and + * project this viscosity to the multigrid hierarchy. Also queries + * other parameters like pressure scaling. + */ + void evaluate_material_model(); + + /** + * Add correction to system RHS for non-zero boundary condition. See description in + * StokesMatrixFreeHandler::correct_stokes_rhs() for more information. + */ + void correct_stokes_rhs(); + + + Simulator ∼ + + bool print_details; + + /** + * If true, it will time the key components of this matrix-free implementation, such as + * vmult of different matrices, solver IDR with the cheap preconditioner, etc. + */ + bool do_timings; + + /** + * The max/min of the evaluated viscosities. + */ + double minimum_viscosity; + double maximum_viscosity; + + DoFHandler dof_handler_v; + DoFHandler dof_handler_p; + DoFHandler dof_handler_projection; + + FESystem fe_v; + FESystem fe_p; + FESystem fe_projection; + + /** + * Store the data for the Stokes operator (viscosity, etc.) for the active cells. + */ + MatrixFreeStokesOperators::OperatorCellData active_cell_data; + + /** + * Store the data for the Stokes operator (viscosity, etc.) for each multigrid level. + */ + MGLevelObject> level_cell_data; + + using StokesMatrixType = MatrixFreeStokesOperators::StokesOperator; + using SchurComplementMatrixType = MatrixFreeStokesOperators::MassMatrixOperator; + using ABlockMatrixType = MatrixFreeStokesOperators::ABlockOperator; + + using GMGSchurComplementMatrixType = MatrixFreeStokesOperators::MassMatrixOperator; + using GMGABlockMatrixType = MatrixFreeStokesOperators::ABlockOperator; + + StokesMatrixType stokes_matrix; + ABlockMatrixType A_block_matrix; + SchurComplementMatrixType Schur_complement_block_matrix; + + AffineConstraints constraints_v; + AffineConstraints constraints_p; + + MGLevelObject mg_matrices_A_block; + MGLevelObject mg_matrices_Schur_complement; + + MGConstrainedDoFs mg_constrained_dofs_A_block; + MGConstrainedDoFs mg_constrained_dofs_Schur_complement; + MGConstrainedDoFs mg_constrained_dofs_projection; + + MGTransferMF mg_transfer_A_block; + MGTransferMF mg_transfer_Schur_complement; + + std::vector>> matrix_free_objects; + }; +} + + +#endif diff --git a/include/aspect/structured_data.h.bak b/include/aspect/structured_data.h.bak new file mode 100644 index 00000000000..cc569e1c2a2 --- /dev/null +++ b/include/aspect/structured_data.h.bak @@ -0,0 +1,778 @@ +/* + Copyright (C) 2014 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_structured_data_h +#define _aspect_structured_data_h + +#include +#include + +#include + +namespace aspect +{ + namespace Utilities + { + using namespace dealii; + + /** + * StructuredDataLookup (formerly AsciiDataLookup) represents structured + * data that can be read from files including in ascii format. + * + * For ascii files the files need to be formatted as follows: + * Note the required format of the input data: The first lines may contain + * any number of comments if they begin with '#', but one of these lines + * needs to contain the number of grid points in each dimension as for + * example '# POINTS: 3 3'. The comments can optionally be followed by a + * single line, which does not start with '#', containing the names of + * the data columns. + * The order of the following data columns has to be + * 'coordinates data' with @p dim coordinate columns and @p components + * data columns. Note that the data in the input files need to be sorted + * in a specific order: the first coordinate needs to ascend first, + * followed by the second and so on in order to assign the correct data to + * the prescribed coordinates. The coordinates do not need to be + * equidistant. + */ + template + class StructuredDataLookup + { + public: + /** + * Constructor that explicitly prescribes the number of data columns + * in the data file. If a list of data components is provided in the + * data file it is checked that the length of this list is consistent + * with this number of components. This constructor is mostly provided + * for backwards compatibility. Not prescribing the number of components + * and instead reading them from the input file allows for more + * flexible files. + */ + StructuredDataLookup(const unsigned int n_components, + const double scale_factor); + + /** + * This constructor relies on the list of column names at the beginning + * of the model file to determine the number of data components, + * therefore when using this constructor it is necessary to provide + * this list in the first uncommented line of the data file. + */ + explicit StructuredDataLookup(const double scale_factor); + + /** + * Replace the data stored in this class by the data given to this function. + * + * @note This is a manual way to fill the data. Consider load_file() if your data + * is stored in a txt/csv file. + * + * The data consists of @p n_components (implicitly given by the size of @p column_names) + * specified at @p coordinate_values[d] points in each of the dim coordinate directions @p d. + * + * The data in @p data_table consists of a Table for each of the @p n_components components. + * + * The `coordinate_values` and `data_table` arguments are rvalue references, + * and the function will move the data so provided into another storage + * location. In other words, after the call, the variables passed as the + * second and third arguments may be empty or otherwise altered. + * + * This class + * is able to share data between processes located on the same + * machine if the last argument `root_process` is + * set to anything other than `numbers::invalid_unsigned_int`. Then only the + * indicated root process within the given MPI communicator needs to + * pass in valid arguments whereas on all other processes the values + * of `column_names`, `coordinate_values`, and `data_table` are + * ignored. Instead, the indicated root process will make sure that + * the other processes obtain valid data, for example by sharing + * data tables in shared memory spaces. This reduces both the + * computational effort in reading data from disk and parsing it on + * all processes, and can vastly reduce the amount of memory required + * on machines where many processor cores have access to shared memory + * resources. + * + * If `root_process` equals `numbers::invalid_unsigned_int`, then + * every process needs to pass data for all arguments and the + * `mpi_communicator` argument is ignored. + */ + void reinit(const std::vector &column_names, + std::vector> &&coordinate_values, + std::vector> &&data_table, + const MPI_Comm mpi_communicator = MPI_COMM_SELF, + const unsigned int root_process = numbers::invalid_unsigned_int); + + /** + * Loads a data text file replacing the current data. + * + * Throws an exception if the file does not + * exist, if the data file format is incorrect, or if the file data + * like the number and names of columns change (if this class contains + * existing data for example when used with a collection of ascii files + * changing over the simulation time). + * + * This function supports normal text / ASCII files that can optionally + * be compressed using .gz. If the given filename is a URL and libDAB + * support is enabled, the data is downloaded and parsed from the ASCII + * data received. + * + * This function uses the given MPI communicator to only load the data on + * rank 0 and broadcasting the information to all other ranks. + */ + void + load_ascii(const std::string &filename, + const MPI_Comm communicator); + + /** + * Fill the current object with data read from a NetCDF file + * with filename @p filename. This call will fail if ASPECT is not + * configured with NetCDF support. + * + * @p data_column_names specifies the list of data columns to load (in the specified order). If + * an empty vector is passed, all columns will be loaded. + */ + void + load_netcdf(const std::string &filename, const std::vector &data_column_names = {}); + + + /** + * Loads data from a file replacing the current data. + * + * Throws an exception if the file does not + * exist, if the data file format is incorrect, or if the file data + * like the number and names of columns change (if this class contains + * existing data for example when used with a collection of ascii files + * changing over the simulation time). + * + * The following formats are currently supported: + * - ASCII files (typically ending in .txt) + * - gzip compressed ASCII files (ending in .gz) + * - URLs starting with "http" (handled by libDAB) + */ + void + load_file(const std::string &filename, + const MPI_Comm communicator); + + /** + * Returns the computed data (velocity, temperature, etc. - according + * to the used plugin) in Cartesian coordinates. + * + * @param position The current position to compute the data (velocity, + * temperature, etc.) + * @param component The index (starting at 0) of the data column to be + * returned. The index is therefore less than the number of data + * columns in the data file (or specified in the constructor). + */ + double + get_data(const Point &position, + const unsigned int component) const; + + /** + * Returns the gradient of the function based on the bilinear + * interpolation of the data (velocity, temperature, etc. - according + * to the used plugin) in Cartesian coordinates. + * + * @param position The current position to compute the data (velocity, + * temperature, etc.) + * @param component The index of the data column to be returned. + */ + Tensor<1,dim> + get_gradients(const Point &position, + const unsigned int component); + + /** + * Returns a vector that contains the names of all data columns in the + * order of their appearance in the data file (and their order in the + * memory data table). Returns an empty vector if no names are provided + * or the file is not read in yet. + */ + std::vector + get_column_names() const; + + /** + * Returns whether the stored coordinates are equidistant. If + * coordinates are equidistant the lookup is more efficient. Returns + * false if no coordinates are loaded at the moment. + */ + bool + has_equidistant_coordinates() const; + + /** + * Returns the coordinates of the interpolation points at which data is + * stored. This function can be used to determine the number of data + * points in each of the coordinate directions, or to query + * data only at exactly the positions at which they are available (avoiding + * interpolation). + * + * @param dimension The spatial direction for which to return the data + * coordinates, e.g. 0 for $x$-direction, 1 for $y$-direction, or equivalent + * values if your data coordinates are other dimensions such as + * temperature, pressure. + */ + const std::vector & + get_interpolation_point_coordinates(const unsigned int dimension) const; + + /** + * Returns the column index of a column with the given name + * @p column_name. Throws an exception if no such + * column exists or no names were provided in the file. + */ + unsigned int + get_column_index_from_name(const std::string &column_name) const; + + /** + * Returns a string that contains the name of the column with index + * @p column_index. Throws an exception if no such + * column exists or no name was provided in the file. + */ + std::string + get_column_name_from_index(const unsigned int column_index) const; + + /** + * Return the maximum value of the component values. + */ + double get_maximum_component_value(const unsigned int component) const; + + private: + /** + * The number of data components read in (=columns in the data file). + */ + unsigned int n_components; + + /** + * The names of the data components in the columns of the read file. + * Does not contain any strings if none are provided in the first + * uncommented line of the file. + */ + std::vector data_component_names; + + /** + * Interpolation functions to access the data. + * Either InterpolatedUniformGridData or InterpolatedTensorProductGridData; + * the type is determined from the grid specified in the data file. + */ + std::vector>> data; + + /** + * The coordinate values in each direction as specified in the data file. + */ + std::array,dim> coordinate_values; + + /** + * The maximum value of each component + */ + std::vector maximum_component_value; + + /** + * Number of points in the data grid as specified in the data file. + */ + TableIndices table_points; + + /** + * Scales the data boundary condition by a scalar factor. Can be used + * to transform the unit of the data. + */ + const double scale_factor; + + /** + * Stores whether the coordinate values are equidistant or not, + * this determines the type of data function stored. + */ + bool coordinate_values_are_equidistant; + + /** + * Computes the table indices given the size @p sizes of the + * entry with index @p idx. + */ + TableIndices + compute_table_indices(const TableIndices &sizes, const std::size_t idx) const; + + }; + + /** + * AsciDataBase is a generic plugin used for declaring and reading the + * parameters from the parameter file. + */ + template + class AsciiDataBase + { + public: + /** + * Constructor + */ + AsciiDataBase(); + + /** + * Declare the parameters all derived classes take from input files. + */ + static + void + declare_parameters (ParameterHandler &prm, + const std::string &default_directory, + const std::string &default_filename, + const std::string &subsection_name = "Ascii data model"); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm, + const std::string &subsection_name = "Ascii data model"); + + /** + * Directory in which the data files are present. + */ + std::string data_directory; + + /** + * Filename of data file. The file names can contain the specifiers %s + * and/or %c (in this order), meaning the name of the boundary and the + * number of the data file time step. + */ + std::string data_file_name; + + /** + * Scale the data by a scalar factor. Can be used to transform the + * unit of the data (if they are not specified in SI units (m/s or + * m/yr depending on the "Use years in output instead of seconds" + * parameter). + */ + double scale_factor; + }; + + /** + * A base class that implements boundary conditions determined from a + * AsciiData input file. + */ + template + class AsciiDataBoundary : public Utilities::AsciiDataBase, public SimulatorAccess + { + public: + /** + * Constructor + */ + AsciiDataBoundary(); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + virtual + void + initialize (const std::set &boundary_ids, + const unsigned int components); + + /** + * A function that is called at the beginning of each time step. For + * the current plugin, this function loads the next data files if + * necessary and outputs a warning if the end of the set of data files + * is reached. + */ + void + update(); + + /** + * Returns the data component at the given position. + */ + double + get_data_component (const types::boundary_id boundary_indicator, + const Point &position, + const unsigned int component) const; + + /** + * Returns the maximum value of the given data component. + */ + double + get_maximum_component_value (const types::boundary_id boundary_indicator, + const unsigned int component) const; + + /** + * Return the gradients of the parameters from the parameter file. + */ + Tensor<1,dim-1> + vector_gradient(const types::boundary_id boundary_indicator, + const Point &p, + const unsigned int component) const; + + /** + * Declare the parameters all derived classes take from input files. + * + * @param prm The parameter handler in which the parameters are declared. + * @param default_directory The default value for the data directory parameter. + * @param default_filename The default value for the filename parameter. + * @param subsection_name The name of the parameter file subsection all + * parameters will be declared in. The function will enter this subsection, + * declare all parameters, then leave this subsection, to return @p prm in + * the same subsection it was in before. + * @param declare_time_dependent_parameters Whether to declare the parameter + * that are only needed for time dependent AsciiDataBoundary objects. If + * the caller already knows time dependence is not supported for the current + * application, disabling this parameter avoids introducing these parameters + * to the parameter handler. + */ + static + void + declare_parameters (ParameterHandler &prm, + const std::string &default_directory, + const std::string &default_filename, + const std::string &subsection_name = "Ascii data model", + const bool declare_time_dependent_parameters = true); + + /** + * Read the parameters from the parameter file. + * + * @param prm The parameter handler from which the parameters are parsed. + * @param subsection_name The name of the parameter file subsection all + * parameters will be parsed from. The function will enter this subsection, + * parse all parameters, then leave this subsection, to return @p prm in + * the same subsection it was in before. + * @param parse_time_dependent_parameters Whether to parse the parameter + * that are only needed for time dependent AsciiDataBoundary objects. This + * parameter always needs to be set to the same value that was handed over + * to declare_parameters(). + */ + void + parse_parameters (ParameterHandler &prm, + const std::string &subsection_name = "Ascii data model", + const bool parse_time_dependent_parameters = true); + + protected: + /** + * A variable that stores the currently used data file of a series. It + * gets updated if necessary by update(). + */ + int current_file_number; + + /** + * Number of the first data file to be loaded when the model time is + * larger than 'First data file model time'. + */ + int first_data_file_number; + + /** + * In some cases the boundary files are not numbered in increasing but + * in decreasing order (e.g. 'Ma BP'). If this flag is set to 'True' + * the plugin will first load the file with the number 'First data + * file number' and decrease the file number during the model run. + */ + bool decreasing_file_order; + + /** + * Time in model units (depends on other model inputs) between two + * data files. + */ + double data_file_time_step; + + /** + * Weight between data file n and n+1 while the current time is + * between the two values t(n) and t(n+1). + */ + double time_weight; + + /** + * State whether we have time_dependent boundary conditions. Switched + * off after finding no more data files to suppress attempts to read + * in new files. + */ + bool time_dependent; + + /** + * Map between the boundary id and an object that reads and processes + * data we get from text files. + */ + std::map>> lookups; + + /** + * Map between the boundary id and the old data objects. + */ + std::map>> old_lookups; + + /** + * Handles the update of the data in lookup. + */ + void + update_data (const types::boundary_id boundary_id, + const bool reload_both_files); + + /** + * Handles settings and user notification in case the time-dependent + * part of the boundary condition is over. + */ + void + end_time_dependence (); + + /** + * Create a filename out of the name template. + */ + std::string + create_filename (const int filenumber, + const types::boundary_id boundary_id) const; + }; + + + + /** + * A base class that implements initial conditions determined from a + * AsciiData input file. + */ + template + class AsciiDataInitial : public Utilities::AsciiDataBase, public SimulatorAccess + { + public: + /** + * Constructor + */ + AsciiDataInitial(); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + virtual + void + initialize (const unsigned int components); + + + /** + * Returns the data component at the given position. + */ + double + get_data_component (const Point &position, + const unsigned int component) const; + + /** + * Declare the parameters all derived classes take from input files. + */ + static + void + declare_parameters (ParameterHandler &prm, + const std::string &default_directory, + const std::string &default_filename, + const std::string &subsection_name = "Ascii data model"); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm, + const std::string &subsection_name = "Ascii data model"); + + protected: + /** + * Pointer to an object that reads and processes data we get from text + * files. + */ + std::unique_ptr> lookup; + + /** + * Pointer to an object that reads and processes data we get from text + * files if the current model is a slice of the input file (e.g. a 2D + * model and a 3D data file). + */ + std::unique_ptr> slice_lookup; + + /** + * Whether to use a dataset that has the same spatial dimensions as + * the model or not. If true only a 2D slice of a 3D dataset is used. + */ + bool slice_data; + + /** + * The matrix that describes the rotation by which a 2D model + * needs to be transformed to a plane that contains the origin and + * the two prescribed points given in the input. + */ + Tensor<2,3> rotation_matrix; + }; + + + /** + * A base class that implements conditions determined from a + * layered AsciiData input file. + */ + template + class AsciiDataLayered : public Utilities::AsciiDataBase, public SimulatorAccess + { + public: + /** + * Constructor + */ + AsciiDataLayered(); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + virtual + void + initialize (const unsigned int components); + + + /** + * Returns the data component at the given position. + */ + double + get_data_component (const Point &position, + const unsigned int component) const; + + + /** + * Declare the parameters all derived classes take from input files. + */ + static + void + declare_parameters (ParameterHandler &prm, + const std::string &default_directory, + const std::string &default_filename, + const std::string &subsection_name = "Ascii data model"); + + /** + * Read the parameters from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm, + const std::string &subsection_name = "Ascii data model"); + + protected: + /** + * Pointer to an object that reads and processes data we get from text + * files. + */ + std::vector>> lookups; + + private: + + /** + * Directory in which the data files are present. + */ + std::string data_directory; + + /** + * Filenames of data files. + */ + std::vector data_file_names; + + /** + * Number of layer boundaries in the model. + */ + unsigned int number_of_layer_boundaries; + + /** + * Interpolation scheme for profile averaging. + */ + std::string interpolation_scheme; + + + }; + + + /** + * A base class that reads in a data profile and provides its values. + */ + template + class AsciiDataProfile : public Utilities::AsciiDataBase + { + public: + /** + * Constructor + */ + AsciiDataProfile(); + + /** + * Initialization function. This function is called once at the + * beginning of the program. Checks preconditions. + */ + virtual + void + initialize (const MPI_Comm communicator); + + + /** + * Returns the data component at the given position. + */ + double + get_data_component (const Point<1> &position, + const unsigned int component) const; + + /** + * Returns a vector that contains the names of all data columns in the + * order of their appearance in the data file (and their order in the + * memory data table). Returns an empty vector if no names are provided + * or the file is not read in yet. + */ + std::vector + get_column_names() const; + + /** + * Returns the coordinates of the interpolation points at which data is + * stored. This function can be used to determine the number of data + * points in each of the coordinate directions, or to query + * data only at exactly the positions at which they are available (avoiding + * interpolation). + * + * Because this class represents a one-dimensional profile, the returned + * values correspond to the values of the sole coordinate of the + * interpolation points, in contrast to the + * StructuredDataLookup::get_interpolation_point_coordinates() + * function that takes an integer argument indicating which coordinate + * is to be selected. + */ + const std::vector & + get_interpolation_point_coordinates() const; + + /** + * Returns the column index of a column with the given name + * @p column_name. Throws an exception if no such + * column exists or no names were provided in the file. + */ + unsigned int + get_column_index_from_name(const std::string &column_name) const; + + /** + * Returns the column index of a column with the given name + * @p column_name. Returns an invalid unsigned int if no such + * column exists or no names were provided in the file. + */ + unsigned int + maybe_get_column_index_from_name(const std::string &column_name) const; + + /** + * Returns a string that contains the name of the column with index + * @p column_index. Returns an empty string if no such + * column exists or no name was provided in the file. + */ + std::string + get_column_name_from_index(const unsigned int column_index) const; + protected: + /** + * Pointer to an object that reads and processes data we get from text + * files. + */ + std::unique_ptr> lookup; + }; + + + + template + using AsciiDataLookup DEAL_II_DEPRECATED = StructuredDataLookup; + } +} + +#endif diff --git a/include/aspect/termination_criteria/end_step.h.bak b/include/aspect/termination_criteria/end_step.h.bak new file mode 100644 index 00000000000..24b3e0570af --- /dev/null +++ b/include/aspect/termination_criteria/end_step.h.bak @@ -0,0 +1,70 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#ifndef _aspect_termination_criteria_end_step_h +#define _aspect_termination_criteria_end_step_h + +#include +#include + +namespace aspect +{ + namespace TerminationCriteria + { + + /** + * A class that terminates the simulation when a specified end timestep is + * reached. + * + * @ingroup TerminationCriteria + */ + template + class EndStep : public Interface, public SimulatorAccess + { + public: + /** + * Evaluate this termination criterion. + * + * @return Whether to terminate the simulation (true) or continue + * (false). + */ + bool + execute () override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + unsigned int end_step; + }; + } +} + +#endif diff --git a/include/aspect/termination_criteria/end_time.h.bak b/include/aspect/termination_criteria/end_time.h.bak new file mode 100644 index 00000000000..9205bdae7d7 --- /dev/null +++ b/include/aspect/termination_criteria/end_time.h.bak @@ -0,0 +1,77 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_termination_criteria_end_time_h +#define _aspect_termination_criteria_end_time_h + +#include +#include + +namespace aspect +{ + namespace TerminationCriteria + { + + /** + * A class that terminates the simulation when a specified end time is + * reached. + * + * @ingroup TerminationCriteria + */ + template + class EndTime : public Interface, public SimulatorAccess + { + public: + + /** + * Check this termination criterion and possibly reduce time step size + */ + double check_for_last_time_step (const double time_step) const override; + + /** + * Evaluate this termination criterion. + * + * @return Whether to terminate the simulation (true) or continue + * (false). + */ + bool + execute () override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + double end_time; + }; + } +} + +#endif diff --git a/include/aspect/termination_criteria/end_walltime.h.bak b/include/aspect/termination_criteria/end_walltime.h.bak new file mode 100644 index 00000000000..c8c1076cf1b --- /dev/null +++ b/include/aspect/termination_criteria/end_walltime.h.bak @@ -0,0 +1,84 @@ +/* + Copyright (C) 2011 - 2019- 2018 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#ifndef _aspect_termination_criteria_end_walltime_h +#define _aspect_termination_criteria_end_walltime_h + +#include +#include + +namespace aspect +{ + namespace TerminationCriteria + { + + /** + * A class that terminates the simulation when a specified end time is + * reached. + * + * @ingroup TerminationCriteria + */ + template + class EndWalltime : public Interface, public SimulatorAccess + { + public: + + /** + * Evaluate this termination criterion. + * + * @return Whether to terminate the simulation (true) or continue + * (false). + */ + bool + execute () override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The maximum walltime duration in seconds. The program will be terminated + * once this value is reached. + */ + unsigned int walltime_duration; + + /** + * The start_walltime is not stored into checkpoint, so it will get reset at restart. + * Make start_walltime as a static variable that it gets initialized pretty much + * right away as the program starts, rather than several seconds in once we get + * to creating the plugin. It gives better estimate of the actual start time. + */ + static std::time_t start_walltime; + }; + } +} + +#endif diff --git a/include/aspect/termination_criteria/interface.h.bak b/include/aspect/termination_criteria/interface.h.bak new file mode 100644 index 00000000000..8306819eab6 --- /dev/null +++ b/include/aspect/termination_criteria/interface.h.bak @@ -0,0 +1,244 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_termination_criteria_interface_h +#define _aspect_termination_criteria_interface_h + +#include +#include + +#include +#include +#include + + +namespace aspect +{ + using namespace dealii; + + template class Simulator; + + + /** + * A namespace for everything to do with determining criteria for + * terminating the simulation gracefully. This does not include termination + * due to errors. + * + * @ingroup TerminationCriteria + */ + namespace TerminationCriteria + { + + /** + * This class declares the public interface of termination criteria + * plugins. These plugins must implement a function that can be called + * each time step to determine if specific criteria have been met that + * mean the simulation should be ended gracefully. + * + * Access to the data of the simulator is granted by the @p protected + * member functions of the SimulatorAccess class, i.e., classes + * implementing this interface will in general want to derive from both + * this Interface class as well as from the SimulatorAccess class if they + * need to find out about the state of the simulation. + * + * @ingroup TerminationCriteria + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Execute evaluation of the termination criterion. + * + * @return Whether to terminate the simulation (true) or continue + * (false). + * + * @note For some kinds of termination plugins, it may be difficult to + * ensure that all processors come to the same conclusion. An example + * is one that terminates the simulation after a certain amount of CPU + * time has expired, and this may be different from MPI process to MPI + * process. To avoid difficult to deal with situations, the plugin + * manager only requires that a single processor returns + * true for a given plugin to record that the plugin + * wants to terminate the simulation, even if the other processors + * return false. + */ + virtual + bool + execute () = 0; + + /** + * Check for last time step and if so reduce the time step to user + * specified end time + * + * @return Reduced or current time step size + * + * @note A reduced time step size may be returned for the last time + * step. For all other time steps, the current time step size + * (provided as argument) will be returned. The returned time step + * size will be greater than zero, and less than or equal to the given + * argument put into this function. + */ + virtual double check_for_last_time_step (const double time_step) const; + }; + + + + + + + /** + * A class that manages all objects that provide functionality to specify + * termination criteria. + * + * @ingroup TerminationCriteria + */ + template + class Manager : public Plugins::ManagerBase>, public SimulatorAccess + { + public: + /** + * Execute all of the termination criteria objects that have been + * requested in the input file. + * + * The function returns a bool indicating whether the simulation should be + * terminated. + * + * To avoid undefined situations, this function only requires that a + * single processor's termination request comes back positive for a + * given plugin. In other words, for each plugin selected, not all + * processors need to return the same value: if only one of the says + * that the simulation should be terminated, then this is enough. + */ + virtual + bool + execute () const; + + /** + * Check all of the termination criteria objects that have been + * requested in the input file for criteria regarding last time step + * and if so get the minimum of these values. + * + * @return Reduced or current time step size + * + * @note A reduced time step size may be returned for the last time + * step. For all other time steps, the current time step size + * (provided as argument) will be returned. The returned time step + * size will be greater than zero, and less than or equal to the given + * argument put into this function. + */ + double check_for_last_time_step (const double time_step) const; + + /** + * Declare the parameters of all known termination criteria plugins, + * as well as of ones this class has itself. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * This determines which termination criteria objects will be created; + * then let these objects read their parameters as well. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * A function that is used to register termination criteria objects in + * such a way that the Manager can deal with all of them without + * having to know them by name. This allows the files in which + * individual plugins are implement to register these plugins, rather + * than also having to modify the Manager class by adding the new + * termination criteria class. + * + * @param name The name under which this plugin is to be called in + * parameter files. + * @param description A text description of what this model does and + * that will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that + * declares the parameters for this plugin. + * @param factory_function A pointer to a function that creates such a + * termination criterion object and returns a pointer to it. + */ + static + void + register_termination_criterion (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + /** + * Exception. + */ + DeclException1 (ExcTerminationCriteriaNameNotFound, + std::string, + << "Could not find entry <" + << arg1 + << "> among the names of registered termination criteria objects."); + private: + /** + * A list of names corresponding to the termination criteria in the + * termination_objects. + */ + std::list termination_obj_names; + }; + + + + /** + * Given a class name, a name, and a description for the parameter file + * for a termination criterion object, register it with the + * aspect::TerminationCriteria::Manager class. + * + * @ingroup TerminationCriteria + */ +#define ASPECT_REGISTER_TERMINATION_CRITERION(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_TERMINATION_CRITERION_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::TerminationCriteria::Manager<2>::register_termination_criterion, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::TerminationCriteria::Manager<3>::register_termination_criterion, \ + name, description); \ + } + } +} + + +#endif diff --git a/include/aspect/termination_criteria/steady_heat_flux.h.bak b/include/aspect/termination_criteria/steady_heat_flux.h.bak new file mode 100644 index 00000000000..88f3cd3d782 --- /dev/null +++ b/include/aspect/termination_criteria/steady_heat_flux.h.bak @@ -0,0 +1,94 @@ +/* + Copyright (C) 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_termination_criteria_steady_heat_flux_h +#define _aspect_termination_criteria_steady_heat_flux_h + +#include +#include +#include + +namespace aspect +{ + namespace TerminationCriteria + { + /** + * A class that implements a termination criterion based on the steady state + * of the average heat flux. + * + * @ingroup TerminationCriteria + */ + template + class SteadyHeatFlux : public Interface, public SimulatorAccess + { + public: + /** + * Evaluate this termination criterion. + * + * @return Whether to terminate the simulation (true) or continue + * (false). + */ + bool + execute () override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The minimum length of simulation time that the system + * should be in steady state before termination. + */ + double necessary_time_in_steady_state; + + /** + * The maximum relative deviation of the heat flux in recent + * simulation time for the system to be considered in steady state. + */ + double allowed_relative_deviation; + + /** + * A set of boundary ids on which the average heat flux will be + * computed. + */ + std::set boundary_indicators; + + /** + * A list of pairs (time, heat flux) that we have computed at + * previous time steps. This is used to determine when we have reached + * steady state. + */ + std::list> time_heat_flux; + }; + } +} + +#endif diff --git a/include/aspect/termination_criteria/steady_rms_velocity.h.bak b/include/aspect/termination_criteria/steady_rms_velocity.h.bak new file mode 100644 index 00000000000..00a23c9e132 --- /dev/null +++ b/include/aspect/termination_criteria/steady_rms_velocity.h.bak @@ -0,0 +1,79 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_termination_criteria_steady_rms_velocity_h +#define _aspect_termination_criteria_steady_rms_velocity_h + +#include +#include + +namespace aspect +{ + namespace TerminationCriteria + { + + /** + * A class that implements a termination criterion based on steady state + * of the root mean square of the velocity field. + * + * @ingroup TerminationCriteria + */ + template + class SteadyRMSVelocity : public Interface, public SimulatorAccess + { + public: + /** + * Evaluate this termination criterion. + * + * @return Whether to terminate the simulation (true) or continue + * (false). + */ + bool + execute () override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + double time_length; + double relative_deviation; + + /** + * A list of pairs (time, rms_velocity) that we have computed at + * previous time steps. This is used to determine when we have reached + * steady state. + */ + std::list> time_rmsvel; + }; + } +} + +#endif diff --git a/include/aspect/termination_criteria/steady_temperature.h.bak b/include/aspect/termination_criteria/steady_temperature.h.bak new file mode 100644 index 00000000000..922df3795ab --- /dev/null +++ b/include/aspect/termination_criteria/steady_temperature.h.bak @@ -0,0 +1,78 @@ +/* + Copyright (C) 2019 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_termination_criteria_steady_temperature_h +#define _aspect_termination_criteria_steady_temperature_h + +#include +#include + +namespace aspect +{ + namespace TerminationCriteria + { + /** + * A class that implements a termination criterion based on the steady state + * of the average temperature. + * + * @ingroup TerminationCriteria + */ + template + class SteadyTemperature : public Interface, public SimulatorAccess + { + public: + /** + * Evaluate this termination criterion. + * + * @return Whether to terminate the simulation (true) or continue + * (false). + */ + bool + execute () override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + double necessary_time_in_steady_state; + double allowed_relative_deviation; + + /** + * A list of pairs (time, temperature) that we have computed at + * previous time steps. This is used to determine when we have reached + * steady state. + */ + std::list> time_temperature; + }; + } +} + +#endif diff --git a/include/aspect/termination_criteria/user_request.h.bak b/include/aspect/termination_criteria/user_request.h.bak new file mode 100644 index 00000000000..245ad1926e3 --- /dev/null +++ b/include/aspect/termination_criteria/user_request.h.bak @@ -0,0 +1,72 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_termination_criteria_user_request_h +#define _aspect_termination_criteria_user_request_h + +#include +#include + +namespace aspect +{ + namespace TerminationCriteria + { + + /** + * A class that terminates the simulation when a specified file appears in + * the working directory. This allows the user to gracefully exit the + * simulation at any time. + * + * @ingroup TerminationCriteria + */ + template + class UserRequest : public Interface, public SimulatorAccess + { + public: + /** + * Evaluate this termination criterion. + * + * @return Whether to terminate the simulation (true) or continue + * (false). + */ + bool + execute () override; + + /** + * Declare the parameters this class takes through input files. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void + parse_parameters (ParameterHandler &prm) override; + + private: + std::string filename_to_test; + }; + } +} + +#endif diff --git a/include/aspect/time_stepping/conduction_time_step.h.bak b/include/aspect/time_stepping/conduction_time_step.h.bak new file mode 100644 index 00000000000..38101bca10e --- /dev/null +++ b/include/aspect/time_stepping/conduction_time_step.h.bak @@ -0,0 +1,61 @@ +/* + Copyright (C) 2018 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_time_stepping_conduction_time_step_h +#define _aspect_time_stepping_conduction_time_step_h + +#include + + +namespace aspect +{ + namespace TimeStepping + { + using namespace dealii; + + /** + * Compute the conduction time step based on the current solution and + * return this as the time step. + * + * @ingroup TimeStepping + */ + template + class ConductionTimeStep : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + ConductionTimeStep () = default; + + + /** + * @copydoc aspect::TimeStepping::Interface::execute() + */ + double + execute() override; + + }; + } +} + + +#endif diff --git a/include/aspect/time_stepping/convection_time_step.h.bak b/include/aspect/time_stepping/convection_time_step.h.bak new file mode 100644 index 00000000000..fa18a9032e2 --- /dev/null +++ b/include/aspect/time_stepping/convection_time_step.h.bak @@ -0,0 +1,62 @@ +/* + Copyright (C) 2014 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_time_stepping_convection_time_step_h +#define _aspect_time_stepping_convection_time_step_h + +#include + + +namespace aspect +{ + namespace TimeStepping + { + using namespace dealii; + + /** + * Compute the convection time step based on the current solution and + * return it. + * + * @ingroup TimeStepping + */ + template + class ConvectionTimeStep : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + ConvectionTimeStep () = default; + + + /** + * @copydoc aspect::TimeStepping::Interface::execute() + */ + double + execute() override; + + private: + }; + } +} + + +#endif diff --git a/include/aspect/time_stepping/function.h.bak b/include/aspect/time_stepping/function.h.bak new file mode 100644 index 00000000000..0a1608f0674 --- /dev/null +++ b/include/aspect/time_stepping/function.h.bak @@ -0,0 +1,72 @@ +/* + Copyright (C) 2018 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_time_stepping_function_h +#define _aspect_time_stepping_function_h + +#include +#include + +namespace aspect +{ + namespace TimeStepping + { + using namespace dealii; + + /** + * A class that implements a time stepping plugin on a function + * description provided in the input file. + * + * @ingroup TimeStepping + */ + template + class Function : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + Function () = default; + + /** + * The main execute() function. + */ + double + execute() override; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * The function object. + */ + Functions::ParsedFunction<1> function; + }; + } +} + + +#endif diff --git a/include/aspect/time_stepping/interface.h.bak b/include/aspect/time_stepping/interface.h.bak new file mode 100644 index 00000000000..a59a5728341 --- /dev/null +++ b/include/aspect/time_stepping/interface.h.bak @@ -0,0 +1,284 @@ +/* + Copyright (C) 2019 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#ifndef _aspect_time_stepping_interface_h +#define _aspect_time_stepping_interface_h + +#include +#include +#include + +namespace aspect +{ + using namespace dealii; + + /** + * A namespace containing all class related to the time stepping plugin system. + */ + namespace TimeStepping + { + + /** + * This enum describes the possible reactions by the time stepping plugins after the + * computation of each time step. + * + * Note: the ordering of the options is crucial, as the Manager will use the minimum + * of the values given by all active plugins as the reaction to take. This means the + * first entry has highest priority. + */ + enum class Reaction + { + /** + * Initiate mesh refinement and go back in time to repeat the last timestep. + */ + refine_and_repeat_step, + /** + * Go back in time to repeat the last timestep. + */ + repeat_step, + /** + * Initiate mesh refinement and continue to the next timestep. + */ + refine_and_advance, + /** + * Continue to the next timestep. The default action to take. + */ + advance + }; + + /** + * Information passed to Interface::determine_reaction with information + * about the time step. + */ + struct TimeStepInfo + { + /** + * The proposed time step size for the next step as computed by querying + * plugins and applying other logic. + */ + double next_time_step_size; + + /** + * If true, a termination criterion decided to shorten the time step + * size. + */ + bool reduced_by_termination_plugin; + }; + + /** + * A base class for parameterizations of the time stepping models. + * + * @ingroup TimeStepping + */ + template + class Interface : public Plugins::InterfaceBase + { + public: + /** + * Execute the logic of the plugin. + * + * This is called after every time step to determine + * a) What to do (advance, repeat, etc.), see the Reaction enum. + * b) What timestep size to use. + * + */ + virtual + double + execute() = 0; + + /** + * Determine what we want with the simulation to happen next: advance, + * repeat, refinement, etc.. The second return value is the time step + * size to take in case the plugin requests a repeated time step. + * + * The argument @p info contains information like the step size that + * would be taken in this time step (determined as the minimum of the + * return value of execute() from all plugins). + * + * The default implementation of this function will always advance + * to the next time step. + */ + virtual + std::pair + determine_reaction(const TimeStepInfo &info); + }; + + + /** + * A class to handle computation of the next time step (as desired by the user) and + * checking if the simulation is finished. + */ + template + class Manager : public Plugins::ManagerBase>, public SimulatorAccess + { + public: + /** + * Override initialize_simulator() so that we can also initialize the contained + * termination_manager. + */ + void initialize_simulator (const Simulator &simulator_object) override; + + + /** + * Update the current state and determine what needs to happen based on the + * last computed solution (see functions below). This computes the size of + * the next time step potentially taking into account the current solution + * (convection time step, conduction time step), settings from parameters, + * and termination criteria (to hit the end time exactly). + */ + void + update() override; + + /** + * Return the next step size as computed from update(). + */ + double get_next_time_step_size() const; + + /** + * If true, a plugin requested to redo the last computed time step. Updated + * when calling update(). + */ + bool should_repeat_time_step() const; + + /** + * If true, execute a mesh refinement step now (potentially before repeating + * the current time step). + */ + bool should_refine_mesh() const; + + /** + * If true, the simulator should perform a checkpoint before terminating. + */ + bool need_checkpoint_on_terminate() const; + + /** + * Check if the simulation is ready to terminate successfully. + */ + bool should_simulation_terminate_now() const; + + /** + * Declare the parameters of all known termination criteria plugins, + * as well as of ones this class has itself. + */ + static + void + declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + * This determines which termination criteria objects will be created; + * then let these objects read their parameters as well. + */ + void + parse_parameters (ParameterHandler &prm) override; + + /** + * For the current plugin subsystem, write a connection graph of all of the + * plugins we know about, in the format that the + * programs dot and neato understand. This allows for a visualization of + * how all of the plugins that ASPECT knows about are interconnected, and + * connect to other parts of the ASPECT code. + * + * @param output_stream The stream to write the output to. + */ + static + void + write_plugin_graph (std::ostream &output_stream); + + + /** + * A function that is used to register time stepping model objects in such + * a way that the Manager can deal with all of them without having to + * know them by name. This allows the files in which individual + * plugins are implemented to register these plugins, rather than also + * having to modify the Manager class by adding the new plugin class. + * + * @param name A string that identifies the model + * @param description A text description of what this model does and that + * will be listed in the documentation of the parameter file. + * @param declare_parameters_function A pointer to a function that can be + * used to declare the parameters that this model wants to read + * from input files. + * @param factory_function A pointer to a function that can create an + * object of this model. + * + * @ingroup TimeStepping + */ + static + void + register_time_stepping_model (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()); + + private: + + /** + * The current Reaction computed by update(). + */ + Reaction current_reaction; + + /** + * The next time step size computed by update(). + */ + double next_time_step_size; + + /** + * The minimum time step size specified by the user (in seconds). + */ + double minimum_time_step_size; + + /** + * Whether to do a final checkpoint before termination. This is + * specified in the parameters. + */ + bool do_checkpoint_on_terminate; + + /** + * The termination manager keeps track of the termination plugins and we use + * it to determine the time_step size in the final time step. + */ + TerminationCriteria::Manager termination_manager; + }; + + /** + * Given a class name, a name, and a description for the parameter file, register it with the + * aspect::TimeStepping::Manager class. + * + * @ingroup TimeStepping + */ +#define ASPECT_REGISTER_TIME_STEPPING_MODEL(classname,name,description) \ + template class classname<2>; \ + template class classname<3>; \ + namespace ASPECT_REGISTER_TIME_STEPPING_MODEL_ ## classname \ + { \ + aspect::internal::Plugins::RegisterHelper,classname<2>> \ + dummy_ ## classname ## _2d (&aspect::TimeStepping::Manager<2>::register_time_stepping_model, \ + name, description); \ + aspect::internal::Plugins::RegisterHelper,classname<3>> \ + dummy_ ## classname ## _3d (&aspect::TimeStepping::Manager<3>::register_time_stepping_model, \ + name, description); \ + } + + } +} + +#endif diff --git a/include/aspect/time_stepping/repeat_on_cutback.h.bak b/include/aspect/time_stepping/repeat_on_cutback.h.bak new file mode 100644 index 00000000000..624e2b90cea --- /dev/null +++ b/include/aspect/time_stepping/repeat_on_cutback.h.bak @@ -0,0 +1,85 @@ +/* + Copyright (C) 2018 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_time_stepping_repeat_on_cutback_h +#define _aspect_time_stepping_repeat_on_cutback_h + +#include + +namespace aspect +{ + namespace TimeStepping + { + using namespace dealii; + + /** + * A class that implements a time stepping plugin to repeat a time step if the + * next time step is significantly smaller than the last step. + * + * @ingroup TimeStepping + */ + template + class RepeatOnCutback : public Interface, public SimulatorAccess + { + public: + /** + * Constructor. + */ + RepeatOnCutback () = default; + + /** + * @copydoc aspect::TimeStepping::Interface::execute() + */ + double + execute() override; + + /** + * The main execute() function. + */ + std::pair + determine_reaction(const TimeStepInfo &info) override; + + static + void + declare_parameters (ParameterHandler &prm); + + void + parse_parameters (ParameterHandler &prm) override; + + private: + /** + * Parameter to determine how much smaller the time step should be + * repeated as. + */ + double cut_back_amount; + + /** + * Parameter that controls when to repeat a time step. If the newly + * computed step size is smaller than the last step size multiplied by + * this factor, the step is repeated. + */ + double repeat_threshold; + }; + } +} + + +#endif diff --git a/include/aspect/utilities.h.bak b/include/aspect/utilities.h.bak new file mode 100644 index 00000000000..68ed43c9d5b --- /dev/null +++ b/include/aspect/utilities.h.bak @@ -0,0 +1,1392 @@ +/* + Copyright (C) 2014 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#ifndef _aspect_utilities_h +#define _aspect_utilities_h + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +namespace aspect +{ + template class SimulatorAccess; + + namespace GeometryModel + { + template class Interface; + } + + /** + * A namespace for utility functions that might be used in many different + * places to prevent code duplication. + */ + namespace Utilities + { + using namespace dealii; + using namespace dealii::Utilities; + + + /** + * Given an array @p values, consider three cases: + * - If it has size @p N, return the original array. + * - If it has size one, return an array of size @p N where all + * elements are equal to the one element of @p value. + * - If it has any other size, throw an exception that uses + * @p id_text as an identifying string. + * + * This function is typically used for parameter lists that can either + * contain different values for each of a set of objects (e.g., for + * each compositional field), or contain a single value that is then + * used for each object. + */ + template + std::vector + possibly_extend_from_1_to_N (const std::vector &values, + const unsigned int N, + const std::string &id_text); + + namespace MapParsing + { + /** + * A struct that bundles all the available options for + * parse_map_to_double_array(). + */ + struct Options + { + /* A list of valid key names that are allowed + * to appear in the map. If this list is empty + * it is assumed to be equal to the list of + * required keys. If this list is longer than + * list_of_required_keys, every key that is + * allowed but not required will be ignored when + * parsing the map. + */ + std::vector list_of_allowed_keys; + + /* A list of valid key names that are required + * to appear in the map. Only these keys will be + * parsed into the map structure and the order of + * these keys determines the order of entries + * in the output vector. + */ + std::vector list_of_required_keys; + + /* + * A name that identifies the type of input property (e.g. 'density', 'viscosity') + * that is being parsed by this function. This name is used in generating + * error messages if the map does not conform to the expected format. + */ + std::string property_name; + + /* + * If true, allow multiple values + * for each key. If false only allow a single value per key. In either + * case each key is only allowed to appear once. Multiple values + * for a key are delimited by a "|" character, as in + * "key1: value1|value2|value3, key2: value1|value2". + */ + bool allow_multiple_values_per_key; + + /* + * Whether to allow for some keys in list_of_required_keys to be + * not set to any values, i.e. they do not appear at all. + * This also allows a completely empty map. + */ + bool allow_missing_keys; + + /* + * Whether to store the number of values + * per key in n_values_per_key while creating + * the map. This vector can be later accessed + * and used (for example) to check that subsequent calls to + * parse other input parameters have the same + * structure. + */ + bool store_values_per_key; + + /* + * Whether to check the number of values + * per key in the map against values stored + * in n_values_per_key. This allows to + * check that subsequent calls to + * parse other input parameters have the same + * structure. + */ + bool check_values_per_key; + + /* + * A vector of unsigned + * integers that is used by store_values_per_key and + * check_values_per_key to either store the current map + * structure or check the map structure against an existing + * map. This parameter is only used if either of these + * two parameters are set to true + */ + std::vector n_values_per_key; + + /** + * Delete the default constructor, because we want to ensure that + * at least the required options are always set. + */ + Options() = delete; + + /** + * A constructor for options that only sets the required + * parameters and leaves all other parameters at their default values. + * By default the @p list_of_required_keys will be used as both + * the list of allowed and list of required keys. In other words + * exactly these keys and no other keys are allowed to appear + * in the input and all of the keys have to be specified and will + * be included in the output. For a documentation of the parameters + * see the documentation of the member variables of this class. + */ + Options(const std::vector &list_of_required_keys, + const std::string &property_name) + : + list_of_allowed_keys(list_of_required_keys), + list_of_required_keys(list_of_required_keys), + property_name(property_name), + allow_multiple_values_per_key(false), + allow_missing_keys(false), + store_values_per_key(false), + check_values_per_key(false), + n_values_per_key() + {} + }; + + /** + * This function takes a string argument that is interpreted as a map + * of the form "key1 : value1, key2 : value2, etc", and then parses + * it to return a vector of these values. The parsing and output + * is controlled by @p options, which provides control over which keys + * (and how many) are allowed and required, whether multiple values + * per keys are allowed, whether the structure of the map is recorded + * while parsing, or checked against an existing structure and some other + * options. See the documentation of MapParsing::Options for available + * settings. + * + * @param[in] input_string The string representation of the map + * to be parsed. + * @param[in] options An object of type MapParsing::Options() that contains + * the parsing options that are considered by this function. See the + * documentation of Options() for the available settings. + * + * @return A vector of values that are parsed from the @p input_string according + * to the provided @p options and is sorted according to the member variable + * list_of_required_keys inside @p options. + * If multiple values per key are allowed, the vector contains first all + * values for key 1, then all values for key 2 and so forth. Using the + * n_values_per_key vector inside @p options allows the caller to + * associate entries in the returned vector with specific keys. + */ + std::vector + parse_map_to_double_array(const std::string &input_string, + Options &options); + } + + /** + * This function takes a string argument that is interpreted as a map + * of the form "key1 : value1, key2 : value2, etc", and then parses + * it to return a vector of these values where the values are ordered + * in the same order as a given set of keys. If @p allow_multiple_values_per_key + * is set to 'true' it also allows entries of the form + * "key1: value1|value2|value3, etc", in which case the returned + * vector will have more entries than the provided + * @p list_of_keys. + * + * This function also considers a number of special cases: + * - If the input string consists of only a comma separated + * set of values "value1, value2, value3, ..." (i.e., without + * the "keyx :" part), then the input string is interpreted + * as if it had had the form "key1 : value1, key2 : value2, ..." + * where "key1", "key2", ... are exactly the keys provided by the + * @p list_of_keys in the same order as provided. In this situation, + * if a background field is required, the background value is + * assigned to the first element of the output vector. This form only + * allows a single value per key. + * - Whether or not a background field is required depends on + * @p expects_background_field. Requiring a background field + * inserts "background" into the @p list_of_keys as the first entry + * in the list. Some calling functions (like some material models) + * require values for background fields, while others may not + * need background values. + * - Two special keys are recognized: + * all --> Assign the associated value to all fields. + * Only one key is allowed in this case. + * background --> Assign associated value to the background. + * + * @param[in] key_value_map The string representation of the map + * to be parsed. + * @param[in] list_of_keys A list of N valid key names that are allowed + * to appear in the map. The order of these keys determines the order + * of values that are returned by this function. + * @param[in] expects_background_field If true, expect N+1 values and allow + * setting of the background using the key "background". + * @param[in] property_name A name that identifies the type of property + * that is being parsed by this function and that is used in generating + * error messages if the map does not conform to the expected format. + * @param [in] allow_multiple_values_per_key If true allow having multiple values + * for each key. If false only allow a single value per key. In either + * case each key is only allowed to appear once. + * @param [in,out] n_values_per_key A pointer to a vector of unsigned + * integers. If no pointer is handed over nothing happens. If a pointer + * to an empty vector is handed over, the vector + * is resized with as many components as + * keys (+1 if there is a background field). Each value then stores + * how many values were found for this key. The sum over all + * entries is the length of the return value of this function. + * If a pointer to an existing vector with one or more entries is + * handed over (e.g. a n_values_per_key vector created by a + * previous call to this function) then this vector is used as + * expected structure of the input parameter, and it is checked that + * @p key_value_map fulfills this structure. This can be used to assert + * that several input parameters prescribe the same number of values + * to each key. + * @param [in] allow_missing_keys Whether to allow that some keys are + * not set to any values, i.e. they do not appear at all in the + * @p key_value_map. This also allows a completely empty map. + * + * @return A vector of values that are parsed from the map, provided + * in the order in which the keys appear in the @p list_of_keys argument. + * If multiple values per key are allowed, the vector contains first all + * values for key 1, then all values for key 2 and so forth. Using the + * @p n_values_per_key vector allows the caller to associate entries in the + * returned vector with specific keys. + * + * @deprecated: This function is deprecated in favor of the more general + * Utilities::MapParsing::parse_map_to_double_array() function. Please + * use the other function instead. + */ + std::vector + parse_map_to_double_array (const std::string &key_value_map, + const std::vector &list_of_keys, + const bool expects_background_field, + const std::string &property_name, + const bool allow_multiple_values_per_key = false, + const std::unique_ptr> &n_values_per_key = nullptr, + const bool allow_missing_keys = false); + + /** + * This function takes a string argument that is assumed to represent + * an input table, in which each row is separated by + * semicolons, and each column separated by commas. The function + * returns the parsed entries as a table. In addition this function + * utilizes the possibly_extend_from_1_to_N() function to accept + * inputs with only a single column/row, which will be extended + * to @p n_rows or @p n_columns respectively, to allow abbreviating + * the input string (e.g. you can provide a single value instead of + * n_rows by n_columns identical values). This function can for example + * be used by material models to read densities for different + * compositions and different phases for each composition. + */ + template + Table<2,T> + parse_input_table (const std::string &input_string, + const unsigned int n_rows, + const unsigned int n_columns, + const std::string &property_name); + + /** + * Given a vector @p var_declarations expand any entries of the form + * vector(str) or tensor(str) to sublists with component names of the form + * str_x, str_y, str_z or str_xx, str_xy... for the correct dimension + * value. + * + * This function is to be used for expanding lists of variable names where + * one or more such variable is actually intended to be a list of + * components. + * + * Returns the generated list of variable names + */ + template + std::vector + expand_dimensional_variable_names (const std::vector &var_declarations); + + /** + * Returns an IndexSet that contains all locally active DoFs that belong to + * the given component_mask. + * + * This function should be moved into deal.II at some point. + */ + template + IndexSet extract_locally_active_dofs_with_component(const DoFHandler &dof_handler, + const ComponentMask &component_mask); + + /** + * This function retrieves the unit support points (in the unit cell) for the current element. + * The DGP element used when 'set Use locally conservative discretization = true' does not + * have support points. If these elements are in use, a fictitious support point at the cell + * center is returned for each shape function that corresponds to the pressure variable, + * whereas the support points for the velocity are correct. The fictitious points don't matter + * because we only use this function when interpolating the velocity variable, and ignore the + * evaluation at the pressure support points. + */ + template + std::vector> get_unit_support_points(const SimulatorAccess &simulator_access); + + + + /** + * Given a point @p point, find out if any of the MPI + * processes own the cell in which this point lies. If + * not, the point lies outside the @p triangulation. + */ + template + bool + point_is_in_triangulation(const Mapping &mapping, + const parallel::distributed::Triangulation &triangulation, + const Point &point, + const MPI_Comm mpi_communicator); + + + namespace Coordinates + { + + /** + * Returns distance from the Earth's center, latitude and longitude from a + * given ECEF Cartesian coordinates that account for ellipsoidal shape of + * the Earth with WGS84 parameters. + */ + template + std::array + WGS84_coordinates(const dealii::Point &position); + + /** + * Returns spherical coordinates of a Cartesian point. If `dim==3`, then + * the returned array contains the three values radius, phi, and theta + * (polar angle). In other words, the two angles correspond to longitude + * and *colatitude* (instead of latitude). If `dim==2`, then theta is omitted. + * The longitude Phi is always considered in the interval $[0,2\pi]$. Note + * that that implies that input files that use spherical coordinates also + * have to provide data using this convention, rather than providing their + * data from $-\pi$ (=180 degrees west) to $+\pi$ (=180 degrees east). + */ + template + std::array + cartesian_to_spherical_coordinates(const dealii::Point &position); + + /** + * Return the Cartesian point of a spherical position defined by radius, + * phi and theta (polar angle). If the dimension is set to 2 theta is + * omitted. + */ + template + dealii::Point + spherical_to_cartesian_coordinates(const std::array &scoord); + + /** + * Given a vector defined in the radius, phi and theta directions, return + * a vector defined in Cartesian coordinates. If the dimension is set to 2 + * theta is omitted. Position is given as a Point in Cartesian coordinates. + */ + template + Tensor<1,dim> + spherical_to_cartesian_vector(const Tensor<1,dim> &spherical_vector, + const dealii::Point &position); + + + /** + * Returns ellipsoidal coordinates of a Cartesian point. The returned array + * is filled with phi, theta and radius. + * + */ + template + std::array + cartesian_to_ellipsoidal_coordinates(const dealii::Point<3> &position, + const double semi_major_axis_a, + const double eccentricity); + + /** + * Return the Cartesian point of a ellipsoidal position defined by phi, + * theta and radius. + */ + template + dealii::Point<3> + ellipsoidal_to_cartesian_coordinates(const std::array &phi_theta_d, + const double semi_major_axis_a, + const double eccentricity); + + + /** + * A function that takes a string representation of the name of a + * coordinate system (as represented by the CoordinateSystem enum) + * and returns the corresponding value. + */ + CoordinateSystem + string_to_coordinate_system (const std::string &); + } + + + /** + * Given a 2d point and a list of points which form a polygon, computes if the point + * falls within the polygon. + */ + template + bool + polygon_contains_point(const std::vector> &point_list, + const dealii::Point<2> &point); + + /** + * Given a 2d point and a list of points which form a polygon, compute the smallest + * distance of the point to the polygon. The sign is negative for points outside of + * the polygon and positive for points inside the polygon. + */ + template + double + signed_distance_to_polygon(const std::vector> &point_list, + const dealii::Point<2> &point); + + + /** + * Given a 2d point and a list of two points that define a line, compute the smallest + * distance of the point to the line segment. When the point's perpendicular + * base does not lie on the line segment, the smallest distance to the segment's end + * points is calculated. + */ + double + distance_to_line(const std::array,2> &point_list, + const dealii::Point<2> &point); + + /** + * Given a vector @p v in @p dim dimensional space, return a set + * of (dim-1) vectors that are orthogonal to @p v and to each + * other. The length of each of these vectors equals that of the original + * vector @p v to ensure that the resulting set of vectors + * represents a well-conditioned basis. + */ + template + std::array,dim-1> + orthogonal_vectors (const Tensor<1,dim> &v); + + /** + * A function that returns the corresponding euler angles for a + * rotation described by rotation axis and angle. + */ + Tensor<2,3> + rotation_matrix_from_axis (const Tensor<1,3> &rotation_axis, + const double rotation_angle); + + /** + * Compute the 3d rotation matrix that describes the rotation of a + * plane defined by the two points @p point_one and @p point_two + * onto the x-y-plane in a way that the vector from the origin to + * point_one points into the (0,1,0) direction after the rotation. + */ + Tensor<2,3> + compute_rotation_matrix_for_slice (const Tensor<1,3> &point_one, + const Tensor<1,3> &point_two); + + /** + * A function for evaluating real spherical harmonics. It takes the degree (l) + * and the order (m) of the spherical harmonic, where $l \geq 0$ and $0 \leq m \leq l$. + * It also takes the colatitude (theta) and longitude (phi), which are in + * radians. + * + * There are an unfortunate number of normalization conventions in existence + * for spherical harmonics. Here we use fully normalized spherical harmonics + * including the Condon-Shortley phase. This corresponds to the definitions + * given in equations B.72 and B.99-B.102 in Dahlen and Tromp (1998, ISBN: 9780691001241). + * The functional form of the real spherical harmonic is given by + * + * \f[ + * Y_{lm}(\theta, \phi) = \sqrt{2} X_{l \left| m \right| }(\theta) \cos m \phi \qquad \mathrm{if} \qquad -l \le m < 0 + * \f] + * \f[ + * Y_{lm}(\theta, \phi) = X_{l 0 }(\theta) \qquad \mathrm{if} \qquad m = 0 + * \f] + * \f[ + * Y_{lm}(\theta, \phi) = \sqrt{2} X_{lm}(\theta) \sin m \phi \qquad \mathrm{if} \qquad 0< m \le m + * \f] + * where $X_{lm}( \theta )$ is an associated Legendre function. + * + * In practice it is often convenient to compute the sine ($-l \le m < 0$) and cosine ($0 < m \le l$) + * variants of the real spherical harmonic at the same time. That is the approach taken + * here, where we return a pair of numbers, the first corresponding the cosine part and the + * second corresponding to the sine part. Given this, it is no longer necessary to distinguish + * between positive and negative $m$, so this function only accepts $ m \ge 0$. + * For $m = 0$, there is only one part, which is stored in the first entry of the pair. + * + * @note This function uses the Boost spherical harmonics implementation internally, + * which is not designed for very high order (> 100) spherical harmonics computation. + * If you use spherical harmonics of a high order be sure to confirm the accuracy first. + * For more information, see: + * http://www.boost.org/doc/libs/1_49_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/sf_poly/sph_harm.html + */ + std::pair real_spherical_harmonic( unsigned int l, // degree + unsigned int m, // order + double theta, // colatitude (radians) + double phi ); // longitude (radians) + + /** + * A struct to enable numerical output with a comma as thousands separator + */ + struct ThousandSep : std::numpunct + { + protected: + char do_thousands_sep() const override + { + return ','; + } + + std::string do_grouping() const override + { + return "\003"; // groups of 3 digits (this string is in octal format) + } + + }; + + /** + * Checks whether a file named @p filename exists and is readable. + * + * Note: This function performs file access on all MPI ranks that + * call it. Only use this function if + * the file access is performed on all MPI ranks + * and on a reasonably fast file system. + * + * @return True if the file exists and is readable on all MPI ranks + * that call this function. + * @param filename File to check existence + */ + bool fexists(const std::string &filename); + + /** + * Check whether a file named @p filename exists and is readable + * on MPI rank 0. Then, broadcast the result to all MPI ranks. + * + * Note that in contrast to the other fexists() function, this function + * only checks for the existence of the file on a single process. + * This is useful to avoid overloading the file system and is sufficient + * if the subsequent file access is also only performed on MPI rank 0. + * + * @return True if the file exists and is readable on MPI rank 0. + * @param filename File to check existence + * @param comm MPI communicator to use. + */ + bool fexists(const std::string &filename, + const MPI_Comm comm); + + /** + * Checks to see if the user is trying to use data from a url. + * + * @param filename File to check + */ + bool filename_is_url(const std::string &filename); + + /** + * Reads the content of the ascii file @p filename on process 0 and + * distributes the content by MPI_Bcast to all processes. The function + * returns the content of the file on all processes. The purpose of this + * function is to reduce parallel file access to a single file access on + * process 0. + * + * @param [in] filename The name of the ascii file to load. If the + * file name ends in `.gz`, then the function assumes that the file + * has been compressed using gzip; it then reads and uncompresses the file + * before distributing it. If the file name is a URL (starting with either + * `http://`, `https://`, or `file://`), and if ASPECT has been configured + * with libDAP, then the file is read from that location via libDAP + * and the returned string is an ASCII data representation of what was + * obtained this way. + * @param [in] comm The MPI communicator in which the content is + * distributed. + * @return A string which contains the data in @p filename. + */ + std::string + read_and_distribute_file_content(const std::string &filename, + const MPI_Comm comm); + + /** + * Collect the content of @p file_content using MPI_Gather to process 0. + * Then write the content to the file @p filename on process 0. + * The purpose of this function is to reduce parallel file access to + * process 0. Note that this function assumes that the content from + * all processes fits into the memory of process 0. + * + * @param [in] filename The name of the file to write. + * @param [in] file_content The content that should be written to file. + * @param [in] comm The MPI communicator from which the content is + * collected. + */ + void + collect_and_write_file_content(const std::string &filename, + const std::string &file_content, + const MPI_Comm comm); + + /** + * Creates a path as if created by the shell command "mkdir -p", therefore + * generating directories from the highest to the lowest level if they are + * not already existing. + * + * @param pathname String that contains the path to create. '/' is used as + * directory separator. + * @param mode Permissions (mode bits) of the created directories. See the + * documentation of the chmod() command for more information. + * @return The function returns the error value of the last mkdir call + * inside. It returns zero on success. See the man page of mkdir() for + * more information. + */ + int + mkdirp(std::string pathname, const mode_t mode = 0755); + + /** + * Create directory @p pathname, optionally printing a message. + * + * @param pathname String that contains path to create. '/' is used as + * directory separator. + * @param comm MPI communicator, used to limit creation of directory to + * processor 0. + * @param silent Print a nicely formatted message on processor 0 if set + * to true. + */ + void create_directory(const std::string &pathname, + const MPI_Comm comm, + bool silent); + + /** + * A namespace defining the cubic spline interpolation that can be used + * between different spherical layers in the mantle. + */ + namespace tk + { + /** + * Class for cubic spline interpolation + */ + class spline + { + public: + /** + * Initialize the spline. + * + * @param x X coordinates of interpolation points. + * @param y Values in the interpolation points. + * @param cubic_spline Whether to construct a cubic spline or just do linear interpolation + * @param monotone_spline Whether the cubic spline should be a monotone cubic spline. + * Requires cubic_spline to be set to true. + */ + void set_points(const std::vector &x, + const std::vector &y, + const bool cubic_spline = true, + const bool monotone_spline = false); + /** + * Evaluate spline at point @p x. + */ + double operator() (double x) const; + + private: + /** + * x coordinates of points + */ + std::vector m_x; + + /** + * interpolation parameters + * \[ + * f(x) = a*(x-x_i)^3 + b*(x-x_i)^2 + c*(x-x_i) + y_i + * \] + */ + std::vector m_a, m_b, m_c, m_y; + }; + } + + /** + * Extract the compositional values at a single quadrature point with + * index @p q from @p composition_values, which is indexed by + * compositional index and quadrature point, and write them into @p + * composition_values_at_q_point. In other words, + * this extracts @p composition_values[i][q] for all @p i. + */ + inline + void + extract_composition_values_at_q_point (const std::vector> &composition_values, + const unsigned int q, + std::vector &composition_values_at_q_point); + + /** + * Replace the string \$ASPECT_SOURCE_DIR in @p location by the current + * source directory of ASPECT and return the resulting string. + */ + std::string + expand_ASPECT_SOURCE_DIR (const std::string &location); + + /** + * Given a string @p s, return it in the form ' ("s")' if nonempty. + * Otherwise just return the empty string itself. + */ + std::string parenthesize_if_nonempty (const std::string &s); + + /** + * Given a string @p s, convert it to a boolean value. + */ + bool + string_to_bool(const std::string &s); + + /** + * Given a vector of strings @p s, convert it to a vector of boolean values. + */ + std::vector + string_to_bool(const std::vector &s); + + /** + * Given a string @p s, convert it to an unsigned int. + */ + unsigned int + string_to_unsigned_int(const std::string &s); + + /** + * Given a vector of strings @p s, convert it to a vector of unsigned int values. + */ + std::vector + string_to_unsigned_int(const std::vector &s); + + /** + * Returns if a vector of strings @p strings only contains unique + * entries. + */ + bool has_unique_entries (const std::vector &strings); + + + + /** + * This function computes the weighted average $\bar y$ of $y_i$ for a weighted p norm. This + * leads for a general p to: + * $\bar y = \left(\frac{\sum_{i=1}^k w_i y_i^p}{\sum_{i=1}^k w_i}\right)^{\frac{1}{p}}$. + * When p = 0 we take the geometric average: + * $\bar y = \exp\left(\frac{\sum_{i=1}^k w_i \log\left(y_i\right)}{\sum_{i=1}^k w_i}\right)$, + * and when $p \le -1000$ or $p \ge 1000$ we take the minimum and maximum norm respectively. + * This means that the smallest and largest value is respectively taken taken. + * + * This function has been set up to be very tolerant to strange values, such as negative weights. + * The only things we require in for the general p is that the sum of the weights and the sum of + * the weights times the values to the power p may not be smaller or equal to zero. Furthermore, + * when a value is zero, the exponent is smaller then one and the correspondent weight is non-zero, + * this corresponds to no resistance in a parallel system. This means that this 'path' will be followed, + * and we return zero. + * + * The implemented special cases (which are minimum (p <= -1000), harmonic average (p = -1), geometric + * average (p = 0), arithmetic average (p = 1), quadratic average (RMS) (p = 2), cubic average (p = 3) + * and maximum (p >= 1000) ) is, except for the harmonic and quadratic averages even more tolerant of + * negative values, because they only require the sum of weights to be non-zero. + */ + double weighted_p_norm_average (const std::vector &weights, + const std::vector &values, + const double p); + + + /** + * This function computes the derivative ($\frac{\partial\bar y}{\partial x}$) of an average + * of the values $y_i(x)$ with regard to $x$, using $\frac{\partial y_i(x)}{\partial x}$. + * This leads for a general p to: + * $\frac{\partial\bar y}{\partial x} = + * \frac{1}{p}\left(\frac{\sum_{i=1}^k w_i y_i^p}{\sum_{i=1}^k w_i}\right)^{\frac{1}{p}-1} + * \frac{\sum_{i=1}^k w_i p y_i^{p-1} y'_i}{\sum_{i=1}^k w_i}$. + * When p = 0 we take the geometric average as a reference, which results in: + * $\frac{\partial\bar y}{\partial x} = + * \exp\left(\frac{\sum_{i=1}^k w_i \log\left(y_i\right)}{\sum_{i=1}^k w_i}\right) + * \frac{\sum_{i=1}^k\frac{w_i y'_i}{y_i}}{\sum_{i=1}^k w_i}$ + * and when $p \le -1000$ or $p \ge 1000$ we take the min and max norm respectively. + * This means that the derivative is taken which has the min/max value. + * + * This function has, like the function weighted_p_norm_average been set up to be very tolerant to + * strange values, such as negative weights. The only things we require in for the general p is that + * the sum of the weights and the sum of the weights times the values to the power p may not be smaller + * or equal to zero. Furthermore, when a value is zero, the exponent is smaller then one and the + * correspondent weight is non-zero, this corresponds to no resistance in a parallel system. This means + * that this 'path' will be followed, and we return the corresponding derivative. + * + * The implemented special cases (which are minimum (p <= -1000), harmonic average (p = -1), geometric + * average (p = 0), arithmetic average (p = 1), and maximum (p >= 1000) ) is, except for the harmonic + * average even more tolerant of negative values, because they only require the sum of weights to be non-zero. + */ + template + T derivative_of_weighted_p_norm_average (const double averaged_parameter, + const std::vector &weights, + const std::vector &values, + const std::vector &derivatives, + const double p); + /** + * This function computes a factor which can be used to make sure that the + * Jacobian remains positive definite. + * + * The goal of this function is to find a factor $\alpha$ so that + * $2\eta(\varepsilon(\mathbf u)) I \otimes I + \alpha\left[a \otimes b + b \otimes a\right]$ remains a + * positive definite rank-4 tensor (i.e., a positive definite operator mapping + * rank-2 tensors to rank-2 tensors). By definition, the whole operator + * is symmetric. In the definition above, $a=\varepsilon(\mathbf u)$ is the @p strain_rate + * and $b=\frac{\partial\eta(\varepsilon(\mathbf u),p)}{\partial \varepsilon}$ is the derivative of the viscosity + * with respect to the strain rate and is given by @p dviscosities_dstrain_rate. Since the viscosity $\eta$ + * must be positive, there is always a value of $\alpha$ (possibly small) so that the result is a positive + * definite operator. In the best case, we want to choose $\alpha=1$ because that corresponds to the full Newton step, + * and so the function never returns anything larger than one. + * + * One can do some algebra to determine what the optimal factor is. We did + * this in the Newton paper (Fraters et al., Geophysical Journal + * International, 2019) where we derived a factor of + * $\frac{2\eta(\varepsilon(\mathbf u))}{\left[1-\frac{b:a}{\|a\| \|b\|} \right]^2\|a\|\|b\|}$, + * which we reset to a maximum of one, and if it is smaller then one, + * a safety_factor scales the value to make sure that 1-alpha won't get to + * close to zero. However, as later pointed out by Yimin Jin, the computation + * is wrong, see https://github.com/geodynamics/aspect/issues/5555. Instead, + * the function now computes the factor as + * $(2 \eta) / (a:b + b:a)$, again capped at a maximal value of 1, + * and using a safety factor from below. + * + * In practice, $a$ and $b$ are almost always parallel to each other, + * and $a:b + b:a = 2a:b$, in which case one can drop the factor + * of $2$ everywhere in the computations. + */ + template + double compute_spd_factor(const double eta, + const SymmetricTensor<2,dim> &strain_rate, + const SymmetricTensor<2,dim> &dviscosities_dstrain_rate, + const double SPD_safety_factor); + + /** + * Converts an array of size dim to a Point of size dim. + */ + template + Point convert_array_to_point(const std::array &array); + + /** + * Converts a Point of size dim to an array of size dim. + */ + template + std::array convert_point_to_array(const Point &point); + + /** + * A class that represents a binary operator between two doubles. The type of + * operation is specified on construction time, and can be checked later + * by using the operator ==. The operator () executes the operation on two + * double parameters and returns the result. This class is helpful for + * user specified operations that are not known at compile time. + */ + class Operator + { + public: + /** + * An enum of supported operations. + */ + enum operation + { + uninitialized, + add, + subtract, + minimum, + maximum, + replace_if_valid + }; + + /** + * The default constructor creates an invalid operation that will fail + * if ever executed. + */ + Operator(); + + /** + * Construct the selected operator. + */ + Operator(const operation op); + + /** + * Execute the selected operation with the given parameters and + * return the result. + */ + double operator() (const double x, const double y) const; + + /** + * Return the comparison result between the current operation and + * the one provided as argument. + */ + bool operator== (const operation op) const; + + private: + /** + * The selected operation of this object. + */ + operation op; + }; + + /** + * Create a vector of operator objects out of a list of strings. Each + * entry in the list must match one of the allowed operations. + */ + std::vector create_model_operator_list(const std::vector &operator_names); + + /** + * Create a string of model operators for use in declare_parameters + */ + const std::string get_model_operator_options(); + + /** + * A function that returns a SymmetricTensor, whose entries are zero, except for + * the k'th component, which is set to one. If k is not on the main diagonal the + * resulting tensor is symmetrized. + */ + template + SymmetricTensor<2,dim> nth_basis_for_symmetric_tensors (const unsigned int k); + + /** + * A class that represents a point in a chosen coordinate system. + */ + template + class NaturalCoordinate + { + public: + /** + * Constructor based on providing the geometry model as a pointer. + */ + NaturalCoordinate(Point &position, + const GeometryModel::Interface &geometry_model); + + /** + * Constructor based on providing the coordinates and associated + * coordinate system. + */ + NaturalCoordinate(const std::array &coord, + const Utilities::Coordinates::CoordinateSystem &coord_system); + + /** + * Returns the coordinates in the given coordinate system, which may + * not be Cartesian. + */ + std::array &get_coordinates(); + + /** + * Returns the coordinates in the given coordinate system, which may + * not be Cartesian. + */ + const std::array &get_coordinates() const; + + /** + * The coordinate that represents the 'surface' directions in the + * chosen coordinate system. + */ + std::array get_surface_coordinates() const; + + /** + * The coordinate that represents the 'depth' direction in the chosen + * coordinate system. + */ + double get_depth_coordinate() const; + + private: + /** + * An enum which stores the coordinate system of this natural + * point + */ + Utilities::Coordinates::CoordinateSystem coordinate_system; + + /** + * An array which stores the coordinates in the coordinates system + */ + std::array coordinates; + }; + + + /** + * Compute the cellwise projection of component @p component_index of @p function to the finite element space + * described by @p dof_handler. + * + * @param[in] mapping The mapping object to use. + * @param[in] dof_handler The DoFHandler the describes the finite element space to + * project into and that corresponds to @p vec_result. + * @param[in] component_index The component index of the @p dof_handler for which + * the projection is being performed. This component should be described by + * a DG finite element. + * @param[in] quadrature The quadrature formula to use to evaluate @p function on each cell. + * @param[in] function The function to project into the finite element space. + * This function should store the value of the function at the points described + * by the 2nd argument into the 3rd argument as an std::vector + * of size quadrature.size(). + * @param[out] vec_result The output vector where the projected function will be + * stored in. + */ + template + void + project_cellwise(const Mapping &mapping, + const DoFHandler &dof_handler, + const unsigned int component_index, + const Quadrature &quadrature, + const std::function::active_cell_iterator &, + const std::vector> &, + std::vector &)> &function, + VectorType &vec_result); + + /** + * Throw an exception that a linear solver failed with some helpful information for the user. + * This function is needed because we have multiple solvers that all require similar treatment + * and we would like to keep the output consistent. If the optional parameter + * @p output_filename is given, the solver history is additionally written to this file. + * + * @p solver_name A name that identifies the solver and appears in the error message. + * @p function_name The name of the function that used the solver (to identify where in the code + * a solver failed). + * @p solver_controls One or more solver controls that describe the history of the solver(s) + * that failed. The reason the function takes multiple controls is we sometimes use + * multi-stage solvers, e.g. we try a cheap solver first, and use an expensive solver if the + * cheap solver fails. + * @p exc The exception that was thrown by the solver when it failed, containing additional + * information about what happened. + * @p mpi_communicator The MPI Communicator of the problem. + * @p output_filename An optional file name into which (if present) the solver history will + * be written. + * + * @return This function never returns normally. It always exits via an exception, either + * of type ExcMessage (on rank 0 of the parallel computation) or QuietException (on all + * other ranks). + */ + void throw_linear_solver_failure_exception(const std::string &solver_name, + const std::string &function_name, + const std::vector &solver_controls, + const std::exception &exc, + const MPI_Comm mpi_communicator, + const std::string &output_filename = ""); + + /** + * Conversion object where one can provide a function that returns + * a tensor for the velocity at a given point and it returns something + * that matches the dealii::Function interface with a number of output + * components equal to the number of components of the finite element + * in use. + */ + template + class VectorFunctionFromVelocityFunctionObject : public Function + { + public: + /** + * Given a function object that takes a Point and returns a Tensor<1,dim>, + * convert this into an object that matches the Function@ + * interface. + * + * @param n_components total number of components of the finite element system. + * @param function_object The function that will form one component + * of the resulting Function object. + */ + VectorFunctionFromVelocityFunctionObject (const unsigned int n_components, + const std::function (const Point &)> &function_object); + + /** + * Return the value of the + * function at the given + * point. Returns the value the + * function given to the constructor + * produces for this point. + */ + double value (const Point &p, + const unsigned int component = 0) const override; + + /** + * Return all components of a + * vector-valued function at a + * given point. + * + * values shall have the right + * size beforehand, + * i.e. #n_components. + */ + void vector_value (const Point &p, + Vector &values) const override; + + private: + /** + * The function object which we call when this class's value() or + * value_list() functions are called. + */ + const std::function (const Point &)> function_object; + }; + + /** + * Create and return a permutation vector which can be used by the + * apply_permutation() function to put the vector in sorted order. + * + * @param vector vector to sort + */ + template + inline + std::vector + compute_sorting_permutation(const std::vector &vector); + + /** + * Applies a permutation vector to another vector and return the resulting vector. + * + * @param vector vector to sort + * @param permutation_vector The permutation vector used to sort the input vector. + * @return The permuted input vector. + */ + template + inline + std::vector + apply_permutation( + const std::vector &vector, + const std::vector &permutation_vector); + + /** + * Get volume weighted rotation matrices, using random draws to convert + * to a discrete number of orientations, weighted by volume. + * The input is a vector of volume fractions and a vector of rotation matrices. + * The vectors need to have the same length. + * + * @param volume_fractions a vector of doubles representing the volume fraction of each grain + * @param rotation_matrices a vector of 2nd order 3D tensors representing the rotation matrix of each grain + * @param n_output_matrices The number of rotation matrices which are output by this function. This can be + * different from the number of entries in the volume fraction and rotation matrices vectors. + * @param random_number_generator a reference to a mt19937 random number generator. + */ + std::vector> + rotation_matrices_random_draw_volume_weighting(const std::vector &volume_fractions, + const std::vector> &rotation_matrices, + const unsigned int n_output_matrices, + std::mt19937 &random_number_generator); + + /** + * Wraps angle between 0 and 360 degrees. + */ + double wrap_angle(const double angle); + + /** + * Compute Z-X-Z Euler angles (https://en.wikipedia.org/wiki/Euler_angles) from rotation matrix. + * The Z-X-Z indicates the order of axis rotations to generate the Euler angles. + */ + std::array zxz_euler_angles_from_rotation_matrix(const Tensor<2,3> &rotation_matrix); + + /** + * Compute rotation matrix from Z-X-Z Euler angles (https://en.wikipedia.org/wiki/Euler_angles) + * The Z-X-Z indicates the order of axis axis rotations to generate the Euler angles. + */ + Tensor<2,3> zxz_euler_angles_to_rotation_matrix(const double phi1, + const double theta, + const double phi2); + + } +} + + +// inline implementations: +#ifndef DOXYGEN +namespace aspect +{ + namespace Utilities + { + + template + inline + std::vector + possibly_extend_from_1_to_N (const std::vector &values, + const unsigned int N, + const std::string &id_text) + { + if (values.size() == 1) + { + return std::vector (N, values[0]); + } + else if (values.size() == N) + { + return values; + } + else + { + // Non-specified behavior + AssertThrow(false, + ExcMessage("Length of " + id_text + " list must be " + + "either one or " + Utilities::to_string(N) + + ". Currently it is " + Utilities::to_string(values.size()) + ".")); + } + + // This should never happen, but return an empty vector so the compiler + // will be happy + return std::vector (); + } + + inline + void + extract_composition_values_at_q_point (const std::vector> &composition_values, + const unsigned int q, + std::vector &composition_values_at_q_point) + { + Assert(q 0, + ExcInternalError()); + + for (unsigned int k=0; k < composition_values_at_q_point.size(); ++k) + { + Assert(composition_values[k].size() == composition_values_at_q_point.size(), + ExcInternalError()); + composition_values_at_q_point[k] = composition_values[k][q]; + } + } + + template + inline + std::vector + compute_sorting_permutation(const std::vector &vector) + { + std::vector p(vector.size()); + std::iota(p.begin(), p.end(), 0); + std::sort(p.begin(), p.end(), + [&](std::size_t i, std::size_t j) + { + return vector[i] < vector[j]; + }); + return p; + } + + template + inline + std::vector + apply_permutation( + const std::vector &vector, + const std::vector &permutation_vector) + { + std::vector sorted_vec(vector.size()); + std::transform(permutation_vector.begin(), permutation_vector.end(), sorted_vec.begin(), + [&](std::size_t i) + { + return vector[i]; + }); + return sorted_vec; + } + + /** + * Contains utility functions related to tensors. + */ + namespace Tensors + { + /** + * Convert a series of doubles to a SymmetricTensor of the same size. + * The input is expected to be ordered according to the + * SymmetricTensor::unrolled_to_component_indices() function. + */ + template + inline + SymmetricTensor<2,dim> + to_symmetric_tensor(const Iterator begin, + const Iterator end) + { + AssertDimension(std::distance(begin, end), (SymmetricTensor<2,dim>::n_independent_components)); + (void) end; + + SymmetricTensor<2,dim> output; + + Iterator next = begin; + for (unsigned int i=0; i < SymmetricTensor<2,dim>::n_independent_components; ++i, ++next) + output[SymmetricTensor<2,dim>::unrolled_to_component_indices(i)] = *next; + + return output; + } + + /** + * Unroll a SymmetricTensor into a series of doubles. The output is ordered + * according to the SymmetricTensor::unrolled_to_component_indices() function. + */ + template + inline + void + unroll_symmetric_tensor_into_array(const SymmetricTensor<2,dim> &tensor, + const Iterator begin, + const Iterator end) + { + AssertDimension(std::distance(begin, end), (SymmetricTensor<2,dim>::n_independent_components)); + (void) end; + + Iterator next = begin; + for (unsigned int i=0; i < SymmetricTensor<2,dim>::n_independent_components; ++i, ++next) + *next = tensor[SymmetricTensor<2,dim>::unrolled_to_component_indices(i)]; + } + + /** + * Rotate a 3D 4th order tensor representing the full stiffnexx matrix using a 3D 2nd order rotation tensor + */ + SymmetricTensor<4,3> + rotate_full_stiffness_tensor(const Tensor<2,3> &rotation_tensor, const SymmetricTensor<4,3> &input_tensor); + + /** + * Rotate a 6x6 voigt stiffness matrix using a 2nd order Voigt stiffness tensor. + * See https://en.wikipedia.org/wiki/Voigt_notation for more info on the Voigt notation. + */ + SymmetricTensor<2,6> + rotate_voigt_stiffness_matrix(const Tensor<2,3> &rotation_tensor, const SymmetricTensor<2,6> &input_tensor); + + /** + * Transform a 4th order full stiffness tensor into a 6x6 Voigt stiffness matrix. + * See https://en.wikipedia.org/wiki/Voigt_notation for more info on the Voigt notation. + */ + SymmetricTensor<2,6> + to_voigt_stiffness_matrix(const SymmetricTensor<4,3> &input_tensor); + + /** + * Transform a 6x6 Voigt stiffness matrix into a 4th order full stiffness tensor. + * See https://en.wikipedia.org/wiki/Voigt_notation for more info on the Voigt notation. + */ + SymmetricTensor<4,3> + to_full_stiffness_tensor(const SymmetricTensor<2,6> &input_tensor); + + /** + * Form a 21D voigt stiffness vector from a 6x6 Voigt stiffness matrix. + * See https://en.wikipedia.org/wiki/Voigt_notation for more info on the Voigt notation. + */ + Tensor<1,21> + to_voigt_stiffness_vector(const SymmetricTensor<2,6> &input_tensor); + + /** + * Form a 21D voigt stiffness vector from a 6x6 Voigt stiffness matrix. + * See https://en.wikipedia.org/wiki/Voigt_notation for more info on the Voigt notation. + */ + SymmetricTensor<2,6> + to_voigt_stiffness_matrix(const Tensor<1,21> &input_tensor); + + /** + * Transform a 4th order full stiffness tensor into a 21D Voigt stiffness vector. + * See https://en.wikipedia.org/wiki/Voigt_notation for more info on the Voigt notation. + */ + Tensor<1,21> + to_voigt_stiffness_vector(const SymmetricTensor<4,3> &input); + + + /** + * Return the Levi-Civita tensor, also called a permutation or "totally antisymmetric" tensor. + * See https://en.wikipedia.org/wiki/Levi-Civita_symbol for a definition. + */ + template + const Tensor &levi_civita(); + + // Declare the existence of a specialization: + template <> + const Tensor<3,3> &levi_civita<3>(); + } + + } +} +#endif + +#endif diff --git a/include/aspect/volume_of_fluid/assembly.h b/include/aspect/volume_of_fluid/assembly.h index bc212c798e2..fb46191c864 100644 --- a/include/aspect/volume_of_fluid/assembly.h +++ b/include/aspect/volume_of_fluid/assembly.h @@ -18,8 +18,8 @@ . */ -#ifndef _aspect_volume_of_fluid_assembly_h -#define _aspect_volume_of_fluid_assembly_h +#ifndef _aspect_volume_of_fluid_simulator/assemblers/interface.h +#define _aspect_volume_of_fluid_simulator/assemblers/interface.h #include #include diff --git a/include/aspect/volume_of_fluid/assembly.h.bak b/include/aspect/volume_of_fluid/assembly.h.bak new file mode 100644 index 00000000000..bc212c798e2 --- /dev/null +++ b/include/aspect/volume_of_fluid/assembly.h.bak @@ -0,0 +1,231 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . + */ + +#ifndef _aspect_volume_of_fluid_assembly_h +#define _aspect_volume_of_fluid_assembly_h + +#include +#include + +#include + +namespace aspect +{ + using namespace dealii; + + template + class Simulator; + + template + struct VolumeOfFluidField; + + namespace internal + { + namespace Assembly + { + namespace Scratch + { + /** + * Standard scratch data structure for matrix assembly + */ + template + struct VolumeOfFluidSystem + { + VolumeOfFluidSystem (const FiniteElement &finite_element, + const FiniteElement &volume_of_fluid_element, + const Mapping &mapping, + const Quadrature &quadrature, + const Quadrature &face_quadrature); + + VolumeOfFluidSystem (const VolumeOfFluidSystem &scratch); + + /** + * Add a defaulted assignment operator because relying on it + * implicitly is deprecated. + */ + VolumeOfFluidSystem &operator=(const VolumeOfFluidSystem &) = default; + + FEValues finite_element_values; + FEValues neighbor_finite_element_values; + FEFaceValues face_finite_element_values; + FEFaceValues neighbor_face_finite_element_values; + FESubfaceValues subface_finite_element_values; + + std::vector local_dof_indices; + + // Field for exact cell volume (needed in some of the face flux calculations) + double volume; + + /** + * Variables describing the values of the shape functions at the + * quadrature points, as they are used in the advection assembly + * function. note that the sizes of these arrays are equal to the + * number of shape functions corresponding to a single VolumeOfFluid field (and + * not of all VolumeOfFluid fields!), and that they are also correspondingly + * indexed. + */ + std::vector phi_field; + std::vector face_phi_field; + + std::vector old_field_values; + /* Vector for interface normal in the unit cell */ + std::vector> cell_i_n_values; + /* "Distance" from cell center to interface as d value for the interface in the form $\vec{n}\cdot\vec{x}=d$ */ + std::vector cell_i_d_values; + + std::vector> face_current_velocity_values; + std::vector> face_old_velocity_values; + std::vector> face_old_old_velocity_values; + + std::vector neighbor_old_values; + /* Vector for interface normal in the unit cell */ + std::vector> neighbor_i_n_values; + /* "Distance" from cell center to interface as d value for the interface in the form $\vec{n}\cdot\vec{x}=d$ */ + std::vector neighbor_i_d_values; + }; + } + + namespace CopyData + { + /** + * Standard copy data structure for matrix assembly + */ + template + struct VolumeOfFluidSystem + { + /** + * Constructor. + * @param finite_element The element that describes the field for which we + * are trying to assemble a linear system. Not the global finite + * element. + */ + VolumeOfFluidSystem(const FiniteElement &finite_element); + VolumeOfFluidSystem(const VolumeOfFluidSystem &data); + + /** + * Add a defaulted assignment operator because relying on it + * implicitly is deprecated. + */ + VolumeOfFluidSystem &operator=(const VolumeOfFluidSystem &) = default; + + /** + * Local contributions to the global matrix and right hand side + * that correspond only to the variables listed in local_dof_indices + */ + FullMatrix local_matrix; + Vector local_rhs; + + /** + * Local contributions to the global rhs from the face terms in the + * discontinuous Galerkin interpretation of the VolumeOfFluid method. + * + * The array has a length sufficient to hold one element for each + * possible face and sub-face of a cell. + */ + std::vector> local_face_rhs; + std::vector> local_face_matrices_ext_ext; + + /** + * Denotes which face's rhs have actually been assembled in the DG + * field assembly. Entries not used (for example, those corresponding + * to non-existent subfaces; or faces being assembled by the + * neighboring cell) are set to false. + * + * The array has a length sufficient to hold one element for each + * possible face and sub-face of a cell. + */ + std::vector face_contributions_mask; + + /** + * Indices of those degrees of freedom that actually correspond to + * the volume_of_fluid field. Since this structure is used to represent just + * contributions to the volume_of_fluid systems, there will be no contributions + * to other parts of the system and consequently, we do not need to + * list here indices that correspond to velocity or pressure degrees + * (or, in fact any other variable outside the block we are currently + * considering) + */ + std::vector local_dof_indices; + + /** + * Indices of the degrees of freedom corresponding to the volume_of_fluid field + * on all possible neighboring cells. This is used in the + * discontinuous Galerkin interpretation of the VolumeOfFluid method. + * + * The array has a length sufficient to hold one element for each + * possible face and sub-face of a cell. + */ + std::vector> neighbor_dof_indices; + }; + } + } + } + + namespace Assemblers + { + + /** + * Class to hold VolumeOfFluid assembly logic, as analogous to that used in the main simulator. + */ + template + class VolumeOfFluidAssembler : public SimulatorAccess + { + public: + /** + * Do setup and assembly on internal quadrature points and dispatch to + * other functions for face assembly + */ + void local_assemble_volume_of_fluid_system (const VolumeOfFluidField &field, + const unsigned int calc_dir, + const bool update_from_old, + const typename DoFHandler::active_cell_iterator &cell, + internal::Assembly::Scratch::VolumeOfFluidSystem &scratch, + internal::Assembly::CopyData::VolumeOfFluidSystem &data) const; + + /** + * Do assembly for cell faces on the boundary + */ + void local_assemble_boundary_face_volume_of_fluid_system (const VolumeOfFluidField &field, + const bool update_from_old, + const typename DoFHandler::active_cell_iterator &cell, + const unsigned int face_no, + internal::Assembly::Scratch::VolumeOfFluidSystem &scratch, + internal::Assembly::CopyData::VolumeOfFluidSystem &data) const; + + /** + * Function for assembling face fluxes for VolumeOfFluid system. + */ + void local_assemble_internal_face_volume_of_fluid_system (const VolumeOfFluidField &field, + const bool update_from_old, + const typename DoFHandler::active_cell_iterator &cell, + const unsigned int face_no, + internal::Assembly::Scratch::VolumeOfFluidSystem &scratch, + internal::Assembly::CopyData::VolumeOfFluidSystem &data) const; + + /** + * Set volume fraction threshold for use in assembly + */ + void set_volume_fraction_threshold(const double value); + }; + } +} + + +#endif diff --git a/include/aspect/volume_of_fluid/field.h.bak b/include/aspect/volume_of_fluid/field.h.bak new file mode 100644 index 00000000000..da88e97ec28 --- /dev/null +++ b/include/aspect/volume_of_fluid/field.h.bak @@ -0,0 +1,96 @@ +/* + Copyright (C) 2016 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + +#ifndef _aspect_volume_of_fluid_field_h +#define _aspect_volume_of_fluid_field_h + +#include + +using namespace dealii; + +namespace aspect +{ + namespace VolumeOfFluid + { + /** + * A structure that contains enum values that identify type of input data + * to allow robust use of sub-mesh scale input that remain valid over + * multiple mesh sizes. + */ + struct VolumeOfFluidInputType + { + enum Kind + { + /** + * Input data is a value between 0 and 1 at all points. + */ + composition, + /** + * Input data is an interface defined by a signed distance level set + * with positive value indicating fluid presence. IE the function has + * gradient 1 almost everywhere, is positive where the fluid is, and is + * zero on the fluid interface + */ + level_set + }; + }; + } + + /** + * Structure to package the relevant data (both state and cached) in a single + * location for access. + */ + template + struct VolumeOfFluidField + { + /** + * Initialize the structure with FEVariables to hold the required + * information that must be available on all cells. + */ + VolumeOfFluidField(const FEVariable &volume_fraction, + const FEVariable &reconstruction, + const FEVariable &level_set, + const unsigned int composition_index); + + /** + * Field to hold the current volume fraction. + */ + const FEVariable &volume_fraction; + + /** + * Field to hold the cached interface reconstruction. + */ + const FEVariable &reconstruction; + + /** + * Field to expose reconstructed interface as a zero-contour to output in + * visualization plugin. + */ + const FEVariable &level_set; + + /** + * Field index of the associated composition field + */ + const unsigned int composition_index; + + }; +} + +#endif diff --git a/include/aspect/volume_of_fluid/handler.h b/include/aspect/volume_of_fluid/handler.h index 56be01c21f6..8e741060777 100644 --- a/include/aspect/volume_of_fluid/handler.h +++ b/include/aspect/volume_of_fluid/handler.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include diff --git a/include/aspect/volume_of_fluid/handler.h.bak b/include/aspect/volume_of_fluid/handler.h.bak new file mode 100644 index 00000000000..56be01c21f6 --- /dev/null +++ b/include/aspect/volume_of_fluid/handler.h.bak @@ -0,0 +1,226 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + +#ifndef _aspect_volume_of_fluid_handler_h +#define _aspect_volume_of_fluid_handler_h + +#include +#include +#include +#include + +#include + +using namespace dealii; + +namespace aspect +{ + /** + * A member class that isolates the functions and variables that deal + * with the Volume of Fluid implementation. If Volume of Fluid interface + * tracking is not active, there is no instantiation of this class at + * all. + */ + template + class VolumeOfFluidHandler : public SimulatorAccess + { + public: + /** + * Standard initial constructor + */ + VolumeOfFluidHandler(Simulator &simulator, ParameterHandler &prm); + + /** + * Add the Volume of Fluid field declaration to the list to be included + * in the solution vector. + */ + void edit_finite_element_variables (std::vector> &vars); + + /** + * Declare the parameters this class takes through input files. + */ + static + void declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters this class declares from the parameter file. + */ + void parse_parameters (ParameterHandler &prm); + + /** + * Get the number of volume of fluid fields in current model + */ + unsigned int get_n_fields() const; + + /** + * Get the name of volume of fluid field with index i + */ + const std::string name_for_field_index(unsigned int i) const; + + /** + * Get the structure containing the variable locations for the volume of + * fluid field with index i. + */ + const VolumeOfFluidField &field_struct_for_field_index(unsigned int i) const; + + /** + * Get threshold for volume fraction + */ + double get_volume_fraction_threshold() const; + + /** + * Get the local index (within vof fields) for the named composition/volume of fluid field + */ + unsigned int field_index_for_name(const std::string &fieldname) const; + + /** + * Do necessary internal initialization that is dependent on having the + * simulator and Finite Element initialized. + */ + void initialize (ParameterHandler &prm); + + /** + * Do initialization routine for all volume of fluid fields + */ + void set_initial_volume_fractions (); + + /** + * Initialize specified field based on a composition field initial condition + */ + void initialize_from_composition_field (const VolumeOfFluidField &field); + + /** + * Initialize specified field based on a level set initial condition + */ + void initialize_from_level_set (const VolumeOfFluidField &field); + + /** + * Do interface reconstruction for specified field and cache result in solution vector + */ + void update_volume_of_fluid_normals (const VolumeOfFluidField &field, + LinearAlgebra::BlockVector &solution); + + /** + * Use current interface reconstruction to produce a composition field + * approximation that is bilinear on the unit cell and write that field + * to the specified AdvectionField + */ + void update_volume_of_fluid_composition (const typename Simulator::AdvectionField &composition_field, + const VolumeOfFluidField &volume_of_fluid_field, + LinearAlgebra::BlockVector &solution); + + /** + * Do single timestep update, includes logic for doing Strang split update + */ + void do_volume_of_fluid_update (const typename Simulator::AdvectionField &advection_field); + + /** + * Assemble matrix and RHS for the specified field and dimension + * (calculation_dim). If update_from_old_solution is true, the initial + * values for this update step are in old_solution, otherwise the values + * in solution are used. This allows a clean restart of the split update + * from the last timestep if necessary without requiring the overhead of + * copying the data. + */ + void assemble_volume_of_fluid_system (const VolumeOfFluidField &field, + const unsigned int calculation_dim, + const bool update_from_old_solution); + + /** + * Solve the diagonal matrix assembled in assemble_volume_of_fluid_system for the + * specified field. + */ + void solve_volume_of_fluid_system (const VolumeOfFluidField &field); + + + private: + /** + * Parent simulator + */ + Simulator ∼ + + /** + * Function to copy assembled data to final system. Requires access to + * the full matrix, so must be in this class. + */ + void copy_local_to_global_volume_of_fluid_system (const internal::Assembly::CopyData::VolumeOfFluidSystem &data); + + /** + * Assembler object used for doing the matrix and RHS assembly + */ + Assemblers::VolumeOfFluidAssembler assembler; + + /** + * Number of volume of fluid fields to calculate for + */ + unsigned int n_volume_of_fluid_fields; + + /** + * Structures containing the locations of the associated state data for + * each volume of fluid field. + */ + std::vector> data; + + /** + * Volume fraction threshold for the reconstruction and advection + * algorithms indicating minimum relevant volume fraction. + */ + double volume_fraction_threshold; + + /** + * Tolerance to use for the Newton iteration in the reconstruction step + */ + static constexpr double volume_of_fluid_reconstruct_epsilon = 1e-13; + + /** + * Tolerance to use for the matrix solve in the timestep update + */ + double volume_of_fluid_solver_tolerance; + + /** + * Number of samples in each dimension to use during the Volume of Fluid + * initialization, for a total of $n_init_samples^dim$ points sampled + */ + unsigned int n_init_samples; + + /** + * Vector of human readable names for the volume of fluid fields, + * obtained from the associated composition field name + */ + std::vector volume_of_fluid_field_names; + + /** + * Map relating the index of a Volume of Fluid based composition field to the index of the corresponding Volume of Fluid field. + */ + std::map volume_of_fluid_composition_map_index; + + /** + * Methods to use when initializing the volume of fluid fields. Must be + * held here as all access to the actual methods for composition + * initialization is handled by the manager. + */ + std::vector initialization_data_type; + + friend class Simulator; + }; + +} + +#endif diff --git a/include/aspect/volume_of_fluid/utilities.h.bak b/include/aspect/volume_of_fluid/utilities.h.bak new file mode 100644 index 00000000000..bb04f2a64d4 --- /dev/null +++ b/include/aspect/volume_of_fluid/utilities.h.bak @@ -0,0 +1,171 @@ +/* + Copyright (C) 2016 - 2020-2018 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . + */ + +#ifndef _aspect_volume_of_fluid_utilities_h +#define _aspect_volume_of_fluid_utilities_h + +#include + +#include + +namespace aspect +{ + namespace VolumeOfFluid + { + namespace Utilities + { + using namespace dealii; + + /** + * Function to calculate volume fraction contained by indicator function + * H(d-normal*(x'-x_{cen}')) on the [0, 1]^dim unit cell where x_{cen} is + * the unit cell center. + * + * Currently only works assuming constant Jacobian determinant. + */ + double compute_fluid_fraction (const Tensor<1, 2> normal, + const double d); + double compute_fluid_fraction (const Tensor<1, 3> normal, + const double d); + + /** + * Function to calculate required value of d to obtain given volume + * fraction for indicator function H(d-normal*(x'-x_{cen}')) on the [0, + * 1]^dim unit cell where x_{cen} is the unit cell center. + * + * Currently only works assuming constant Jacobian determinant. + */ + double compute_interface_location (const Tensor<1, 2> normal, + const double volume_fraction); + double compute_interface_location (const Tensor<1, 3> normal, + const double volume_fraction); + + /** + * Obtain values at points for a polynomial function that is equivalent to + * the Heaviside function $H(d-normal*xhat)$ on the unit cell when + * integrated against polynomials of up to the specified degree. + * + * Currently works for degree <=1 + * + * @param degree Maximum degree for exact integration + * @param normal Interface normal vector, pointed away from the included region + * @param d Interface parameter specifying location of interface in unit cell + * @param points Locations to evaluate the constructed polynomial + * @param values Values of the constructed polynomial at the specified points + */ + void xFEM_Heaviside(const unsigned int degree, + const Tensor<1, 2> normal, + const double d, + const std::vector> &points, + std::vector &values); + void xFEM_Heaviside(const unsigned int degree, + const Tensor<1, 3> normal, + const double d, + const std::vector> &points, + std::vector &values); + + /** + * Obtain values at points for a polynomial function that is equivalent to + * the function $\frac{d}{dd}H(d-normal*xhat)$ on the unit cell when + * integrated against polynomials of up to the specified degree. + * + * Currently works for degree <=1 + * + * @param degree Maximum degree for exact integration + * @param normal Interface normal vector, pointed away from the included region + * @param d Interface parameter specifying location of interface in unit cell + * @param points Locations to evaluate the constructed polynomial + * @param values Values of the constructed polynomial at the specified points + */ + void xFEM_Heaviside_derivative_d(const unsigned int degree, + const Tensor<1, 2> normal, + const double d, + const std::vector> &points, + std::vector &values); + void xFEM_Heaviside_derivative_d(const unsigned int degree, + const Tensor<1, 3> normal, + const double d, + const std::vector> &points, + std::vector &values); + + + /** + * Function to do Newton iteration calculation of correct d for a given + * normal to get volume_fraction from xFEM_Heaviside integrated against the given + * weights. + * + * @param degree Maximum degree for exact integration + * @param normal Interface normal vector, pointed away from the included region + * @param volume_fraction Cell volume fraction in physical space - used for target value for integration + * @param vol Cell volume in physical space - used for target value for integration + * @param epsilon Tolerance for Newton iteration + * @param points Quadrature points to use for update + * @param weights JxW values to use for quadrature + */ + template + double compute_interface_location_newton(const unsigned int degree, + const Tensor<1, dim, double> normal, + const double volume_fraction, + const double vol, + const double epsilon, + const std::vector> &points, + const std::vector &weights); + + /** + * Function to calculate volume contained by indicator function + * $H(d-normal*(x'-x_{cen}'))$ on the $[0, 1]^dim$ unit cell where + * $x_{cen}$ is the unit cell center, using a polynomial mapping of + * degree up to "degree". + * + * @param degree Maximum degree for exact integration + * @param normal Interface normal vector, pointed away from the included region + * @param d Interface parameter specifying location of interface in unit cell by distance from cell center + * @param points Quadrature points to use for update + * @param weights JxW values to use for quadrature + */ + template + double compute_fluid_volume(const unsigned int degree, + const Tensor<1, dim, double> normal, + const double d, + const std::vector> &points, + const std::vector &weights); + + /** + * Function to calculate flux volume fraction based on a method of + * characteristics approximation of the interface on the cell's face over + * the timestep. Calculation assumes an approximation to the interface of the form + * $H(d-normal*(x'-x_{face center})-time_direction_derivative*t')$ where + * $t'$ is in terms of a "unit timestep". + * + * @param compute_direction Dimension of unit cell we are currently computing along + * @param time_direction_derivative Approximated gradient in time for the "level set" describing the interface. + * @param interface_normal_in_cell The normal vector for the current interface reconstruction in the computing cell. + * @param d_at_face_center The correct d value to for the interface description on the face we are computing for. + */ + template + double calculate_volume_flux (const unsigned int compute_direction, + const double time_direction_derivative, + const Tensor<1, dim, double> interface_normal_in_cell, + const double d_at_face_center); + } + } +} + +#endif diff --git a/source/adiabatic_conditions/ascii_data.cc.bak b/source/adiabatic_conditions/ascii_data.cc.bak new file mode 100644 index 00000000000..b472abd43b3 --- /dev/null +++ b/source/adiabatic_conditions/ascii_data.cc.bak @@ -0,0 +1,168 @@ +/* + Copyright (C) 2016 - 2018 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include + + +namespace aspect +{ + namespace AdiabaticConditions + { + template + AsciiData::AsciiData() + : + initialized(false), + temperature_index(numbers::invalid_unsigned_int), + pressure_index(numbers::invalid_unsigned_int), + density_index(numbers::invalid_unsigned_int) + {} + + + + template + void + AsciiData::initialize () + { + if (initialized) + return; + + this->initialize(this->get_mpi_communicator()); + temperature_index = this->get_column_index_from_name("temperature"); + pressure_index = this->get_column_index_from_name("pressure"); + density_index = this->get_column_index_from_name("density"); + + initialized = true; + } + + + + template + bool + AsciiData::is_initialized() const + { + return initialized; + } + + + + template + double AsciiData::pressure (const Point &p) const + { + const double depth = this->get_geometry_model().depth(p); + return this->get_data_component(Point<1>(depth),pressure_index); + } + + + + template + double AsciiData::temperature (const Point &p) const + { + const double depth = this->get_geometry_model().depth(p); + return this->get_data_component(Point<1>(depth),temperature_index); + } + + + + template + double AsciiData::density (const Point &p) const + { + const double depth = this->get_geometry_model().depth(p); + return this->get_data_component(Point<1>(depth),density_index); + } + + + + template + double AsciiData::density_derivative (const Point &p) const + { + const double depth = this->get_geometry_model().depth(p); + const double eps = std::sqrt(std::numeric_limits::epsilon()) * this->get_geometry_model().maximal_depth(); + return (this->get_data_component(Point<1>(depth+eps),density_index) + - + this->get_data_component(Point<1>(depth),density_index)) + / + eps; + } + + + + template + void + AsciiData::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Adiabatic conditions model"); + { + Utilities::AsciiDataBase::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/tests/adiabatic-conditions/ascii-data/test/", + ""); + } + prm.leave_subsection(); + } + + + + template + void + AsciiData::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Adiabatic conditions model"); + { + Utilities::AsciiDataBase::parse_parameters(prm); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace AdiabaticConditions + { + ASPECT_REGISTER_ADIABATIC_CONDITIONS_MODEL(AsciiData, + "ascii data", + "A model in which the adiabatic profile is " + "read from a file that describes the reference " + "state. Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of points in the reference state as " + "for example `# POINTS: 3'. " + "Following the comment lines there has to be a single line " + "containing the names of all data columns, separated by arbitrarily " + "many spaces. Column names are not allowed to contain spaces. " + "The file can contain unnecessary columns, but for this plugin it " + "needs to at least provide columns named `temperature', `pressure', " + "and `density'. " + "Note that the data lines in the file need to be sorted in order " + "of increasing depth from 0 to the maximal depth in the model " + "domain. Points in the model that are outside of the provided " + "depth range will be assigned the maximum or minimum depth values, " + "respectively. Points do not need to be equidistant, " + "but the computation of properties is optimized in speed " + "if they are.") + } +} diff --git a/source/adiabatic_conditions/compute_entropy_profile.cc.bak b/source/adiabatic_conditions/compute_entropy_profile.cc.bak new file mode 100644 index 00000000000..ab2f7a072ad --- /dev/null +++ b/source/adiabatic_conditions/compute_entropy_profile.cc.bak @@ -0,0 +1,315 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include + + +namespace aspect +{ + namespace AdiabaticConditions + { + template + ComputeEntropyProfile::ComputeEntropyProfile() + : + initialized(false) + {} + + + + template + void + ComputeEntropyProfile::initialize() + { + if (initialized) + return; + + temperatures.resize(n_points, numbers::signaling_nan()); + pressures.resize(n_points, numbers::signaling_nan()); + densities.resize(n_points, numbers::signaling_nan()); + + delta_z = this->get_geometry_model().maximal_depth() / (n_points-1); + + MaterialModel::MaterialModelInputs in(1, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(1, this->n_compositional_fields()); + this->get_material_model().create_additional_named_outputs (out); + + MaterialModel::PrescribedTemperatureOutputs *prescribed_temperature_out + = out.template get_additional_output>(); + + // check if the material model computes prescribed temperature outputs + AssertThrow(prescribed_temperature_out != nullptr, + ExcMessage("The material model you use does not provide " + "PrescribedTemperatureOutputs, which is required " + "for this adiabatic conditions plugin.")); + + const std::vector entropy_indices = this->introspection().get_indices_for_fields_of_type(CompositionalFieldDescription::entropy); + // TODO : need to make it work for more than one field + AssertThrow(entropy_indices.size() >= 1, + ExcMessage("The 'compute entropy' adiabatic conditions plugin " + "requires at least one field of type 'entropy'.")); + + // Constant properties on the reference profile + // We only need the material model to compute the density + in.requested_properties = MaterialModel::MaterialProperties::density | MaterialModel::MaterialProperties::additional_outputs; + in.velocity[0] = Tensor <1,dim> (); + // The entropy along an adiabat is constant (equals the surface entropy) + // When there is more than one entropy field, we use the background field to compute the adiabatic profile + // TODO : provide more ways to specify compositional fields like in compute_profile.cc + for (unsigned int i=0; i < this->n_compositional_fields(); ++i) + in.composition[0][i] = 0; + + in.composition[0][entropy_indices[0]] = surface_entropy; + + // Check whether gravity is pointing up / out or down / in. In the normal case it should + // point down / in and therefore gravity should be positive, leading to increasing + // adiabatic pressures and temperatures with depth. In some cases it will point up / out + // (e.g. for backward advection), in which case the pressures and temperatures should + // decrease with depth and therefore gravity has to be negative in the following equations. + const Tensor <1,dim> g = this->get_gravity_model().gravity_vector(this->get_geometry_model().representative_point(0)); + const Point point_surf = this->get_geometry_model().representative_point(0); + const Point point_bot = this->get_geometry_model().representative_point(this->get_geometry_model().maximal_depth()); + const int gravity_direction = (g * (point_bot - point_surf) >= 0) ? + 1 : + -1; + + // now integrate downward using the explicit Euler method for simplicity + // + // note: p'(z) = rho(p,T) * |g| + // T(z) = look up for reference entropy and current p(z) + for (unsigned int i=0; iget_surface_pressure(); + } + else + { + // use material properties calculated at i-1 + const double density = out.densities[0]; + // get the magnitude of gravity. we assume + // that gravity always points along the depth direction. this + // may not strictly be true always but is likely a good enough + // approximation here. + const double gravity = gravity_direction * this->get_gravity_model().gravity_vector(in.position[0]).norm(); + + pressures[i] = pressures[i-1] + density * gravity * delta_z; + } + + const double z = static_cast(i)/static_cast(n_points-1)*this->get_geometry_model().maximal_depth(); + const Point representative_point = this->get_geometry_model().representative_point (z); + + in.position[0] = representative_point; + in.pressure[0] = pressures[i]; + this->get_material_model().evaluate(in, out); + + densities[i] = out.densities[0]; + temperatures[i] = prescribed_temperature_out->prescribed_temperature_outputs[0]; + } + + if (gravity_direction == 1 && this->get_surface_pressure() >= 0) + { + Assert (*std::min_element (pressures.begin(), pressures.end()) >= + -std::numeric_limits::epsilon() * pressures.size(), + ExcMessage("Adiabatic ComputeProfile encountered a negative pressure of " + + dealii::Utilities::to_string(*std::min_element (pressures.begin(), pressures.end())))); + } + else if (gravity_direction == -1 && this->get_surface_pressure() <= 0) + { + Assert (*std::max_element (pressures.begin(), pressures.end()) <= + std::numeric_limits::epsilon() * pressures.size(), + ExcMessage("Adiabatic ComputeProfile encountered a positive pressure of " + + dealii::Utilities::to_string(*std::max_element (pressures.begin(), pressures.end())))); + } + + Assert (*std::min_element (temperatures.begin(), temperatures.end()) >= + -std::numeric_limits::epsilon() * temperatures.size(), + ExcMessage("Adiabatic ComputeProfile encountered a negative temperature.")); + + + initialized = true; + } + + + + template + bool + ComputeEntropyProfile::is_initialized() const + { + return initialized; + } + + + + template + double ComputeEntropyProfile::pressure (const Point &p) const + { + return get_property(p,pressures); + } + + + + template + double ComputeEntropyProfile::temperature (const Point &p) const + { + return get_property(p,temperatures); + } + + + + template + double ComputeEntropyProfile::density (const Point &p) const + { + return get_property(p,densities); + } + + + + template + double ComputeEntropyProfile::density_derivative (const Point &p) const + { + const double z = this->get_geometry_model().depth(p); + + if (z >= this->get_geometry_model().maximal_depth()) + { + Assert (z <= this->get_geometry_model().maximal_depth() + delta_z, + ExcInternalError()); + return (densities.back() - densities[densities.size()-2]) / delta_z; + } + + if (z < 0) + { + Assert (z >= -delta_z, ExcInternalError()); + return (densities[1] - densities.front()) / delta_z; + } + + // if z/delta_z is within [k-eps, k+eps] of a whole number k, round it down to k-1 + const unsigned int i = static_cast((z/delta_z) * (1. - 2. * std::numeric_limits::epsilon())); + Assert (i < densities.size() - 1, ExcInternalError()); + + return (densities[i+1]-densities[i])/delta_z; + } + + + + template + double ComputeEntropyProfile::get_property (const Point &p, + const std::vector &property) const + { + const double z = this->get_geometry_model().depth(p); + + if (z >= this->get_geometry_model().maximal_depth()) + { + Assert (z <= this->get_geometry_model().maximal_depth() + delta_z, + ExcInternalError()); + return property.back(); + } + + if (z <= 0) + { + Assert (z >= -delta_z, ExcInternalError()); + return property.front(); + } + + const double floating_index = z/delta_z; + const unsigned int i = static_cast(floating_index); + + // If p is close to an existing value use that one. This prevents + // asking for values at i+1 while initializing i+1 (when p is at the + // depth of index i). + if (std::abs(floating_index-std::floor(floating_index+0.5)) < 1e-6) + return property[i]; + + Assert (i+1 < property.size(), ExcInternalError()); + + // now do the linear interpolation + const double d = floating_index - i; + Assert ((d>=0) && (d<=1), ExcInternalError()); + + return d*property[i+1] + (1.-d)*property[i]; + } + + + + + template + void + ComputeEntropyProfile::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Adiabatic conditions model"); + { + prm.enter_subsection("Compute entropy profile"); + { + prm.declare_entry ("Number of points", "1000", + Patterns::Integer (5), + "The number of points we use to compute the adiabatic " + "profile. The higher the number of points, the more accurate " + "the downward integration from the adiabatic surface " + "conditions will be."); + + prm.declare_entry ("Surface entropy", "0", + Patterns::Double(), + "The surface entropy for the profile."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + ComputeEntropyProfile::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Adiabatic conditions model"); + { + prm.enter_subsection("Compute entropy profile"); + { + n_points = prm.get_integer ("Number of points"); + surface_entropy = prm.get_double ("Surface entropy"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace AdiabaticConditions + { + ASPECT_REGISTER_ADIABATIC_CONDITIONS_MODEL(ComputeEntropyProfile, + "compute entropy profile", + "A model in which the adiabatic profile is " + "calculated by solving the hydrostatic equations for " + "pressure and entropy in depth. " + "Of course the entropy along an adiabat is constant. " + "This plugin requires the material model to provide an " + "additional output object of type PrescribedTemperatureOutputs. " + "It also requires that there is a compositional field of type " + "'entropy' that represents the entropy of the material.") + } +} diff --git a/source/adiabatic_conditions/compute_profile.cc.bak b/source/adiabatic_conditions/compute_profile.cc.bak new file mode 100644 index 00000000000..5ef8d23bc22 --- /dev/null +++ b/source/adiabatic_conditions/compute_profile.cc.bak @@ -0,0 +1,427 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + +#include + + +namespace aspect +{ + namespace AdiabaticConditions + { + template + ComputeProfile::ComputeProfile() + : + initialized(false), + surface_condition_function(2) + {} + + + + template + void + ComputeProfile::update() + { + if (use_surface_condition_function) + { + initialized = false; + surface_condition_function.set_time(this->get_time()); + initialize(); + } + } + + + template + void + ComputeProfile::initialize() + { + if (initialized) + return; + + // The simulator only keeps the initial conditions around for + // the first time step. As a consequence, we have to save a + // shared pointer to that object ourselves the first time we get + // here. + if ((reference_composition == initial_composition) + && + (initial_composition_manager == nullptr)) + initial_composition_manager = this->get_initial_composition_manager_pointer(); + + temperatures.resize(n_points, numbers::signaling_nan()); + pressures.resize(n_points, numbers::signaling_nan()); + densities.resize(n_points, numbers::signaling_nan()); + + delta_z = this->get_geometry_model().maximal_depth() / (n_points-1); + + MaterialModel::MaterialModelInputs in(1, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(1, this->n_compositional_fields()); + + // Constant properties on the reference profile + in.requested_properties = MaterialModel::MaterialProperties::equation_of_state_properties; + in.velocity[0] = Tensor <1,dim> (); + + // Check whether gravity is pointing up / out or down / in. In the normal case it should + // point down / in and therefore gravity should be positive, leading to increasing + // adiabatic pressures and temperatures with depth. In some cases it will point up / out + // (e.g. for backward advection), in which case the pressures and temperatures should + // decrease with depth and therefore gravity has to be negative in the following equations. + const Tensor <1,dim> g = this->get_gravity_model().gravity_vector(this->get_geometry_model().representative_point(0)); + const Point point_surf = this->get_geometry_model().representative_point(0); + const Point point_bot = this->get_geometry_model().representative_point(this->get_geometry_model().maximal_depth()); + const int gravity_direction = (g * (point_bot - point_surf) >= 0) ? + 1 : + -1; + + // now integrate downward using the explicit Euler method for simplicity + // + // note: p'(z) = rho(p,T) * |g| + // T'(z) = alpha |g| T / C_p + for (unsigned int i=0; iget_surface_pressure(); + temperatures[0] = this->get_adiabatic_surface_temperature(); + } + else + { + pressures[0] = surface_condition_function.value(Point<1>(0.0),0); + temperatures[0] = surface_condition_function.value(Point<1>(0.0),1); + } + } + else + { + // use material properties calculated at i-1 + const double density = out.densities[0]; + const double alpha = out.thermal_expansion_coefficients[0]; + // Handle the case that cp is zero (happens in simple Stokes test problems like sol_cx). By setting + // 1/cp = 0.0 we will have a constant temperature profile with depth. + const double one_over_cp = (out.specific_heat[0]>0.0) ? 1.0/out.specific_heat[0] : 0.0; + // get the magnitude of gravity. we assume + // that gravity always points along the depth direction. this + // may not strictly be true always but is likely a good enough + // approximation here. + const double gravity = gravity_direction * this->get_gravity_model().gravity_vector(in.position[0]).norm(); + + pressures[i] = pressures[i-1] + density * gravity * delta_z; + temperatures[i] = (this->include_adiabatic_heating()) + ? + temperatures[i-1] * (1 + alpha * gravity * delta_z * one_over_cp) + : + temperatures[0]; + } + + const double z = static_cast(i)/static_cast(n_points-1)*this->get_geometry_model().maximal_depth(); + const Point representative_point = this->get_geometry_model().representative_point (z); + const Tensor <1,dim> g = this->get_gravity_model().gravity_vector(representative_point); + + in.position[0] = representative_point; + in.temperature[0] = temperatures[i]; + in.pressure[0] = pressures[i]; + + // we approximate the pressure gradient by extrapolating the values + // from the two points above + if (i>0) + in.pressure_gradient[0] = g/(g.norm() != 0.0 ? g.norm() : 1.0) + * (pressures[i] - pressures[i-1]) / delta_z; + else + in.pressure_gradient[0] = Tensor <1,dim> (); + + if (reference_composition == initial_composition) + for (unsigned int c=0; cn_compositional_fields(); ++c) + in.composition[0][c] = initial_composition_manager->initial_composition(representative_point, c); + else if (reference_composition == reference_function) + { + const double depth = this->get_geometry_model().depth(representative_point); + const Point<1> p(depth); + for (unsigned int c=0; cn_compositional_fields(); ++c) + in.composition[0][c] = composition_function->value(p, c); + } + else + AssertThrow(false,ExcNotImplemented()); + + this->get_material_model().evaluate(in, out); + + densities[i] = out.densities[0]; + } + + if (gravity_direction == 1 && this->get_surface_pressure() >= 0) + { + Assert (*std::min_element (pressures.begin(), pressures.end()) >= + -std::numeric_limits::epsilon() * pressures.size(), + ExcMessage("Adiabatic ComputeProfile encountered a negative pressure of " + + dealii::Utilities::to_string(*std::min_element (pressures.begin(), pressures.end())))); + } + else if (gravity_direction == -1 && this->get_surface_pressure() <= 0) + { + Assert (*std::max_element (pressures.begin(), pressures.end()) <= + std::numeric_limits::epsilon() * pressures.size(), + ExcMessage("Adiabatic ComputeProfile encountered a positive pressure of " + + dealii::Utilities::to_string(*std::max_element (pressures.begin(), pressures.end())))); + } + + Assert (*std::min_element (temperatures.begin(), temperatures.end()) >= + -std::numeric_limits::epsilon() * temperatures.size(), + ExcMessage("Adiabatic ComputeProfile encountered a negative temperature.")); + + + initialized = true; + } + + + + template + bool + ComputeProfile::is_initialized() const + { + return initialized; + } + + + + template + double ComputeProfile::pressure (const Point &p) const + { + return get_property(p,pressures); + } + + + + template + double ComputeProfile::temperature (const Point &p) const + { + return get_property(p,temperatures); + } + + + + template + double ComputeProfile::density (const Point &p) const + { + return get_property(p,densities); + } + + + + template + double ComputeProfile::density_derivative (const Point &p) const + { + const double z = this->get_geometry_model().depth(p); + + if (z >= this->get_geometry_model().maximal_depth()) + { + Assert (z <= this->get_geometry_model().maximal_depth() + delta_z, + ExcInternalError()); + return (densities.back() - densities[densities.size()-2]) / delta_z; + } + + if (z < 0) + { + Assert (z >= -delta_z, ExcInternalError()); + return (densities[1] - densities.front()) / delta_z; + } + + // if z/delta_z is within [k-eps, k+eps] of a whole number k, round it down to k-1 + const unsigned int i = static_cast((z/delta_z) * (1. - 2. * std::numeric_limits::epsilon())); + Assert (i < densities.size() - 1, ExcInternalError()); + + return (densities[i+1]-densities[i])/delta_z; + } + + + + template + double ComputeProfile::get_property (const Point &p, + const std::vector &property) const + { + const double z = this->get_geometry_model().depth(p); + + if (z >= this->get_geometry_model().maximal_depth()) + { + Assert (z <= this->get_geometry_model().maximal_depth() + delta_z, + ExcInternalError()); + return property.back(); + } + + if (z <= 0) + { + Assert (z >= -delta_z, ExcInternalError()); + return property.front(); + } + + const double floating_index = z/delta_z; + const unsigned int i = static_cast(floating_index); + + // If p is close to an existing value use that one. This prevents + // asking for values at i+1 while initializing i+1 (when p is at the + // depth of index i). + if (std::abs(floating_index-std::floor(floating_index+0.5)) < 1e-6) + return property[i]; + + Assert (i+1 < property.size(), ExcInternalError()); + + // now do the linear interpolation + const double d = floating_index - i; + Assert ((d>=0) && (d<=1), ExcInternalError()); + + return d*property[i+1] + (1.-d)*property[i]; + } + + + + + template + void + ComputeProfile::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Adiabatic conditions model"); + { + prm.enter_subsection("Compute profile"); + { + Functions::ParsedFunction<1>::declare_parameters (prm, 1); + prm.declare_entry("Composition reference profile","initial composition", + Patterns::Selection("initial composition|function"), + "Select how the reference profile for composition " + "is computed. This profile is used to evaluate the " + "material model, when computing the pressure and " + "temperature profile."); + prm.declare_entry ("Number of points", "1000", + Patterns::Integer (5), + "The number of points we use to compute the adiabatic " + "profile. The higher the number of points, the more accurate " + "the downward integration from the adiabatic surface " + "temperature will be."); + prm.declare_entry ("Use surface condition function", "false", + Patterns::Bool(), + "Whether to use the 'Surface condition function' to determine surface " + "conditions, or the 'Adiabatic surface temperature' and 'Surface pressure' " + "parameters. If this is set to true the reference profile is updated " + "every timestep. The function expression of the function should be " + "independent of space, but can depend on time 't'. The function must " + "return two components, the first one being reference surface pressure, " + "the second one being reference surface temperature."); + + prm.enter_subsection("Surface condition function"); + { + Functions::ParsedFunction<1>::declare_parameters (prm, 2); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + ComputeProfile::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Adiabatic conditions model"); + { + prm.enter_subsection("Compute profile"); + { + const std::string composition_profile = prm.get("Composition reference profile"); + + if (composition_profile == "initial composition") + reference_composition = initial_composition; + else if (composition_profile == "function") + reference_composition = reference_function; + else + AssertThrow(false, ExcNotImplemented()); + + if ((this->n_compositional_fields() > 0) && (reference_composition == reference_function)) + { + composition_function + = std::make_unique>(this->n_compositional_fields()); + try + { + composition_function->parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Adiabatic conditions model.compute profile'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + } + + n_points = prm.get_integer ("Number of points"); + use_surface_condition_function = prm.get_bool("Use surface condition function"); + if (use_surface_condition_function) + { + prm.enter_subsection("Surface condition function"); + try + { + surface_condition_function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Adiabatic conditions model.Initial profile.Surface condition function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + prm.leave_subsection(); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace AdiabaticConditions + { + ASPECT_REGISTER_ADIABATIC_CONDITIONS_MODEL(ComputeProfile, + "compute profile", + "A model in which the adiabatic profile is " + "calculated by solving the hydrostatic equations for " + "pressure and temperature in depth. " + "The gravity is assumed to be in depth direction " + "and the composition is either given by the initial " + "composition at reference points or computed " + "as a reference depth-function. " + "All material parameters are computed by the " + "material model plugin. The surface conditions are " + "either constant or changing over time as prescribed " + "by a user-provided function.") + } +} diff --git a/source/adiabatic_conditions/function.cc.bak b/source/adiabatic_conditions/function.cc.bak new file mode 100644 index 00000000000..ddad051d8b6 --- /dev/null +++ b/source/adiabatic_conditions/function.cc.bak @@ -0,0 +1,148 @@ +/* + Copyright (C) 2016 - 2017 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +namespace aspect +{ + namespace AdiabaticConditions + { + template + Function::Function() + : function (3) + {} + + template + void + Function::initialize() + { + } + + template + bool + Function::is_initialized() const + { + return true; + } + + + + template + double Function::pressure (const Point &p) const + { + const double z = this->get_geometry_model().depth(p); + return function.value(Point<1>(z), 1); + } + + + + template + double Function::temperature (const Point &p) const + { + const double z = this->get_geometry_model().depth(p); + return function.value(Point<1>(z), 0); + } + + template + double Function::density (const Point &p) const + { + const double z = this->get_geometry_model().depth(p); + return function.value(Point<1>(z), 2); + } + + + + template + double Function::density_derivative (const Point &p) const + { + // TODO: better eps or make it a user input + const double z = this->get_geometry_model().depth(p); + const double z2 = z + (1.e6 * std::numeric_limits::epsilon()) + * this->get_geometry_model().maximal_depth(); + return (function.value(Point<1>(z), 2) + - function.value(Point<1>(z2), 2))/(z-z2); + } + + template + void + Function::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Adiabatic conditions model"); + { + prm.enter_subsection("Function"); + Functions::ParsedFunction<1>::declare_parameters (prm, 3); + prm.declare_entry("Function expression","0.0; 0.0; 1.0", + Patterns::Anything(), + "Expression for the adiabatic temperature, " + "pressure, and density separated by " + "semicolons as a function of `depth'."); + prm.declare_entry("Variable names","depth"); + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + Function::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Adiabatic conditions model"); + { + prm.enter_subsection("Function"); + try + { + function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Adiabatic conditions model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + + +// explicit instantiations +namespace aspect +{ + namespace AdiabaticConditions + { + ASPECT_REGISTER_ADIABATIC_CONDITIONS_MODEL(Function, + "function", + "A model in which the adiabatic profile is " + "specified by a user defined function. The " + "supplied function has to contain " + "temperature, pressure, and density as a function " + "of depth in this order.") + } +} diff --git a/source/adiabatic_conditions/interface.cc.bak b/source/adiabatic_conditions/interface.cc.bak new file mode 100644 index 00000000000..05619b509a0 --- /dev/null +++ b/source/adiabatic_conditions/interface.cc.bak @@ -0,0 +1,222 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + +#include + + +namespace aspect +{ + namespace AdiabaticConditions + { + template + void Interface::get_adiabatic_temperature_profile(std::vector &values) const + { + const unsigned int num_slices = values.size(); + const double max_depth = this->get_geometry_model().maximal_depth(); + AssertThrow(num_slices > 1, ExcInternalError()); + + for (unsigned int n = 0 ; n < num_slices; ++n) + { + const double depth = n * max_depth / (num_slices-1); + const Point p = this->get_geometry_model().representative_point(depth); + values[n] = temperature(p); + } + } + + + template + void Interface::get_adiabatic_pressure_profile(std::vector &values) const + { + const unsigned int num_slices = values.size(); + const double max_depth = this->get_geometry_model().maximal_depth(); + AssertThrow(num_slices > 1, ExcInternalError()); + + for (unsigned int n = 0 ; n < num_slices; ++n) + { + const double depth = n * max_depth / (num_slices-1); + const Point p = this->get_geometry_model().representative_point(depth); + values[n] = pressure(p); + } + } + + template + void Interface::get_adiabatic_density_profile(std::vector &values) const + { + const unsigned int num_slices = values.size(); + const double max_depth = this->get_geometry_model().maximal_depth(); + AssertThrow(num_slices > 1, ExcInternalError()); + + for (unsigned int n = 0 ; n < num_slices; ++n) + { + const double depth = n * max_depth / (num_slices-1); + const Point p = this->get_geometry_model().representative_point(depth); + values[n] = density(p); + } + } + + template + void Interface::get_adiabatic_density_derivative_profile(std::vector &values) const + { + const unsigned int num_slices = values.size(); + const double max_depth = this->get_geometry_model().maximal_depth(); + AssertThrow(num_slices > 1, ExcInternalError()); + + for (unsigned int n = 0 ; n < num_slices; ++n) + { + const double depth = n * max_depth / (num_slices-1); + const Point p = this->get_geometry_model().representative_point(depth); + values[n] = density_derivative(p); + } + } + + +// -------------------------------- Deal with registering models and automating +// -------------------------------- their setup and selection at run time + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + register_adiabatic_conditions (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + template + std::unique_ptr> + create_adiabatic_conditions (ParameterHandler &prm) + { + std::string model_name; + prm.enter_subsection ("Adiabatic conditions model"); + { + model_name = prm.get ("Model name"); + } + prm.leave_subsection (); + + std::unique_ptr>plugin = std::get(registered_plugins).create_plugin (model_name, + "Adiabatic Conditions model::Model name"); + + return plugin; + + } + + + + template + void + declare_parameters (ParameterHandler &prm) + { + // declare the entry in the parameter file + prm.enter_subsection ("Adiabatic conditions model"); + { + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + + prm.declare_entry ("Model name", "compute profile", + Patterns::Selection (pattern_of_names), + "Select one of the following models:\n\n" + + + std::get(registered_plugins).get_description_string()); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + template + void + write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Adiabatic conditions interface", + out); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace AdiabaticConditions + { +#define INSTANTIATE(dim) \ + template class Interface; \ + \ + template \ + void \ + register_adiabatic_conditions (const std::string &, \ + const std::string &, \ + void ( *) (ParameterHandler &), \ + std::unique_ptr>( *) ()); \ + \ + template \ + void \ + declare_parameters (ParameterHandler &); \ + \ + template \ + void \ + write_plugin_graph (std::ostream &); \ + \ + template \ + std::unique_ptr> \ + create_adiabatic_conditions (ParameterHandler &prm); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/boundary_composition/ascii_data.cc.bak b/source/boundary_composition/ascii_data.cc.bak new file mode 100644 index 00000000000..69c9d179284 --- /dev/null +++ b/source/boundary_composition/ascii_data.cc.bak @@ -0,0 +1,131 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include + +#include + + +namespace aspect +{ + namespace BoundaryComposition + { + template + AsciiData::AsciiData () + = default; + + template + void + AsciiData::initialize () + { + Utilities::AsciiDataBoundary::initialize(this->get_fixed_composition_boundary_indicators(), + this->n_compositional_fields()); + } + + + template + void + AsciiData::update () + { + Interface::update (); + + Utilities::AsciiDataBoundary::update(); + } + + + template + double + AsciiData:: + boundary_composition (const types::boundary_id boundary_indicator, + const Point &position, + const unsigned int compositional_field) const + { + return Utilities::AsciiDataBoundary::get_data_component(boundary_indicator, + position, + compositional_field); + } + + template + void + AsciiData::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary composition model"); + { + Utilities::AsciiDataBoundary::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/boundary-composition/ascii-data/test/", + "box_2d_%s.%d.txt"); + } + prm.leave_subsection(); + } + + + template + void + AsciiData::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary composition model"); + { + Utilities::AsciiDataBoundary::parse_parameters(prm); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryComposition + { + ASPECT_REGISTER_BOUNDARY_COMPOSITION_MODEL(AsciiData, + "ascii data", + "Implementation of a model in which the boundary " + "composition is derived from files containing data " + "in ascii format. Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example `# POINTS: 3 3'. " + "The order of the data columns " + "has to be `x', `composition1', `composition2', " + "etc. in a 2d model and " + "`x', `y', `composition1', `composition2', " + "etc., in a 3d model, according " + "to the number of compositional fields, which means that " + "there has to be a single column " + "for every composition in the model. " + "Note that the data in the input " + "files need to be sorted in a specific order: " + "the first coordinate needs to ascend first, " + "followed by the second in order to " + "assign the correct data to the prescribed coordinates." + "If you use a spherical model, " + "then the assumed grid changes. `x' will be replaced by " + "the radial distance of the point to the bottom of the model, " + "`y' by the azimuth angle and `z' by the polar angle measured " + "positive from the north pole. The grid will be assumed to be " + "a latitude-longitude grid. Note that the order " + "of spherical coordinates is `r', `phi', `theta' " + "and not `r', `theta', `phi', since this allows " + "for dimension independent expressions.") + } +} diff --git a/source/boundary_composition/box.cc.bak b/source/boundary_composition/box.cc.bak new file mode 100644 index 00000000000..1dd7d357f1e --- /dev/null +++ b/source/boundary_composition/box.cc.bak @@ -0,0 +1,180 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace BoundaryComposition + { +// ------------------------------ Box ------------------- + + template + double + Box:: + boundary_composition (const types::boundary_id boundary_indicator, + const Point &/*position*/, + const unsigned int compositional_field) const + { + Assert (boundary_indicator<2*dim, ExcMessage ("The given boundary indicator needs to be less than 2*dimension..")); + return composition_values[boundary_indicator][compositional_field]; + } + + template + void + Box::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary composition model"); + { + prm.enter_subsection("Box"); + { + prm.declare_entry ("Left composition", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the left boundary (at minimal $x$-value). This list must have as many " + "entries as there are compositional fields. Units: none."); + prm.declare_entry ("Right composition", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the right boundary (at maximal $x$-value). This list must have as many " + "entries as there are compositional fields. Units: none."); + prm.declare_entry ("Bottom composition", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the bottom boundary (at minimal $y$-value in 2d, or minimal " + "$z$-value in 3d). This list must have as many " + "entries as there are compositional fields. Units: none."); + prm.declare_entry ("Top composition", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the top boundary (at maximal $y$-value in 2d, or maximal " + "$z$-value in 3d). This list must have as many " + "entries as there are compositional fields. Units: none."); + if (dim==3) + { + prm.declare_entry ("Front composition", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the front boundary (at minimum $y$-value). This list must have as many " + "entries as there are compositional fields. Units: none."); + prm.declare_entry ("Back composition", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the back boundary (at maximum $y$-value). This list must have as many " + "entries as there are compositional fields. Units: none."); + } + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + Box::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary composition model"); + { + prm.enter_subsection("Box"); + { + switch (dim) + { + case 2: + composition_values[0] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Left composition"))); + composition_values[1] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Right composition"))); + composition_values[2] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Bottom composition"))); + composition_values[3] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Top composition"))); + break; + + case 3: + composition_values[0] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Left composition"))); + composition_values[1] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Right composition"))); + composition_values[2] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Front composition"))); + composition_values[3] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Back composition"))); + composition_values[4] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Bottom composition"))); + composition_values[5] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Top composition"))); + break; + + default: + Assert (false, ExcNotImplemented()); + } + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + + template + void + Box::initialize() + { + // verify that the geometry is a box since only for this geometry + // do we know for sure what boundary indicators it uses and what they mean + AssertThrow (Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage ("This boundary model is only implemented if the geometry is " + "a box.")); + + // Verify that each of the lists for boundary values + // has the requisite number of elements if it is in the set + // of prescribed boundary indicators. + for (unsigned int f=0; f<2*dim; ++f) + if (this->get_boundary_composition_manager().get_fixed_composition_boundary_indicators().count(f) != 0) + AssertThrow (composition_values[f].size() == this->n_compositional_fields(), + ExcMessage (std::string("The specification of boundary composition values for the `box' model " + "requires as many values on each face of the box as there are compositional " + "fields. However, for face ") + + + Utilities::int_to_string(f) + + + ", the input file specifies " + + + Utilities::int_to_string(composition_values[f].size()) + + + " values even though there are " + + + Utilities::int_to_string(this->n_compositional_fields()) + + + " compositional fields.")); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryComposition + { + ASPECT_REGISTER_BOUNDARY_COMPOSITION_MODEL(Box, + "box", + "A model in which the composition is chosen constant on " + "the sides of a box which are selected by the parameters " + "Left/Right/Top/Bottom/Front/Back composition") + } +} diff --git a/source/boundary_composition/function.cc.bak b/source/boundary_composition/function.cc.bak new file mode 100644 index 00000000000..2c8a172dc51 --- /dev/null +++ b/source/boundary_composition/function.cc.bak @@ -0,0 +1,146 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include +#include +#include + +namespace aspect +{ + namespace BoundaryComposition + { + + template + double + Function:: + boundary_composition (const types::boundary_id /*boundary_indicator*/, + const Point &position, + const unsigned int compositional_field) const + { + const Utilities::NaturalCoordinate point = + this->get_geometry_model().cartesian_to_other_coordinates(position, coordinate_system); + return function->value(Utilities::convert_array_to_point(point.get_coordinates()), compositional_field); + } + + + template + void + Function::update() + { + // we get time passed as seconds (always) but may want + // to reinterpret it in years + if (this->convert_output_to_years()) + function->set_time (this->get_time() / year_in_seconds); + else + function->set_time (this->get_time()); + } + + + + template + void + Function::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary composition model"); + { + prm.enter_subsection("Function"); + { + prm.declare_entry ("Coordinate system", "cartesian", + Patterns::Selection ("cartesian|spherical|depth"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are 'cartesian', 'spherical', and 'depth'. " + "'spherical' coordinates are interpreted as r,phi " + "or r,phi,theta in 2d/3d respectively with theta " + "being the polar angle. 'depth' will create a " + "function, in which only the first parameter is " + "non-zero, which is interpreted to be the depth of " + "the point."); + + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + Function::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary composition model"); + { + prm.enter_subsection("Function"); + { + coordinate_system = ::aspect::Utilities::Coordinates::string_to_coordinate_system(prm.get("Coordinate system")); + + try + { + function + = std::make_unique>(this->n_compositional_fields()); + function->parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Boundary composition model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryComposition + { + ASPECT_REGISTER_BOUNDARY_COMPOSITION_MODEL(Function, + "function", + "Implementation of a model in which the boundary " + "composition is given in terms of an explicit formula " + "that is elaborated in the parameters in section " + "``Boundary composition model|Function''. " + "\n\n" + "Since the symbol $t$ indicating time " + "may appear in the formulas for the prescribed " + "composition, it is interpreted as having units " + "seconds unless the global input parameter ``Use " + "years in output instead of seconds'' is set, in " + "which case we interpret the formula expressions " + "as having units year." + "\n\n" + "The format of these " + "functions follows the syntax understood by the " + "muparser library, see " + "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") + } +} diff --git a/source/boundary_composition/initial_composition.cc.bak b/source/boundary_composition/initial_composition.cc.bak new file mode 100644 index 00000000000..1e96a2d761f --- /dev/null +++ b/source/boundary_composition/initial_composition.cc.bak @@ -0,0 +1,135 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + + +namespace aspect +{ + namespace BoundaryComposition + { +// ------------------------------ InitialComposition ------------------- + + template + void + InitialComposition::initialize() + { + // Make sure we keep track of the initial composition manager and + // that it continues to live beyond the time when the simulator + // class releases its pointer to it. + initial_composition = this->get_initial_composition_manager_pointer(); + } + + + + template + double + InitialComposition:: + boundary_composition (const types::boundary_id /*boundary_indicator*/, + const Point &position, + const unsigned int compositional_field) const + { + return initial_composition->initial_composition(position, compositional_field); + } + + + template + double + InitialComposition:: + minimal_composition (const std::set &) const + { + return min_composition; + } + + + + template + double + InitialComposition:: + maximal_composition (const std::set &) const + { + return max_composition; + } + + + + template + void + InitialComposition::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary composition model"); + { + prm.enter_subsection("Initial composition"); + { + prm.declare_entry ("Minimal composition", "0.", + Patterns::Double (), + "Minimal composition. Units: none."); + prm.declare_entry ("Maximal composition", "1.", + Patterns::Double (), + "Maximal composition. Units: none."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + InitialComposition::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary composition model"); + { + prm.enter_subsection("Initial composition"); + { + min_composition = prm.get_double ("Minimal composition"); + max_composition = prm.get_double ("Maximal composition"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryComposition + { + ASPECT_REGISTER_BOUNDARY_COMPOSITION_MODEL(InitialComposition, + "initial composition", + "A model in which the composition at the boundary " + "is chosen to be the same as given in the initial " + "conditions." + "\n\n" + "Because this class simply takes what the initial " + "composition had described, this class can not " + "know certain pieces of information such as the " + "minimal and maximal composition on the boundary. " + "For operations that require this, for example in " + "post-processing, this boundary composition model " + "must therefore be told what the minimal and " + "maximal values on the boundary are. This is done " + "using parameters set in section ``Boundary composition model/Initial composition''.") + } +} diff --git a/source/boundary_composition/interface.cc.bak b/source/boundary_composition/interface.cc.bak new file mode 100644 index 00000000000..91719a1e34f --- /dev/null +++ b/source/boundary_composition/interface.cc.bak @@ -0,0 +1,376 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + +#include +#include +#include + +#include + + +namespace aspect +{ + namespace BoundaryComposition + { + // ------------------------------ Manager ----------------------------- + // -------------------------------- Deal with registering boundary_composition models and automating + // -------------------------------- their setup and selection at run time + + template + Manager::~Manager() + = default; + + + + template + void + Manager::update () + { + for (auto &p : this->plugin_objects) + p->update(); + } + + + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + template + void + Manager::register_boundary_composition (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + template + void + Manager::parse_parameters (ParameterHandler &prm) + { + // find out which plugins are requested and the various other + // parameters we declare here + prm.enter_subsection ("Boundary composition model"); + { + model_names + = Utilities::split_string_list(prm.get("List of model names")); + + AssertThrow(Utilities::has_unique_entries(model_names), + ExcMessage("The list of strings for the parameter " + "'Boundary composition model/List of model names' contains entries more than once. " + "This is not allowed. Please check your parameter file.")); + + const std::string model_name = prm.get ("Model name"); + + AssertThrow (model_name == "unspecified" || model_names.size() == 0, + ExcMessage ("The parameter 'Model name' is only used for reasons" + "of backwards compatibility and can not be used together with " + "the new functionality 'List of model names'. Please add your " + "boundary composition model to the list instead.")); + + if (!(model_name == "unspecified")) + model_names.push_back(model_name); + + // create operator list + std::vector model_operator_names = + Utilities::possibly_extend_from_1_to_N (Utilities::split_string_list(prm.get("List of model operators")), + model_names.size(), + "List of model operators"); + model_operators = Utilities::create_model_operator_list(model_operator_names); + + try + { + const std::vector x_fixed_composition_boundary_indicators + = this->get_geometry_model().translate_symbolic_boundary_names_to_ids (Utilities::split_string_list + (prm.get ("Fixed composition boundary indicators"))); + fixed_composition_boundary_indicators + = std::set (x_fixed_composition_boundary_indicators.begin(), + x_fixed_composition_boundary_indicators.end()); + + // If model names have been set, but no boundaries on which to use them, + // ignore the set values, do not create objects that are never used. + if (fixed_composition_boundary_indicators.size() == 0) + { + model_names.clear(); + model_operators.clear(); + } + } + catch (const std::string &error) + { + AssertThrow (false, ExcMessage ("While parsing the entry , there was an error. Specifically, " + "the conversion function complained as follows:\n\n" + + error)); + } + + if (prm.get ("Allow fixed composition on outflow boundaries") == "true") + allow_fixed_composition_on_outflow_boundaries = true; + else if (prm.get ("Allow fixed composition on outflow boundaries") == "false") + allow_fixed_composition_on_outflow_boundaries = false; + else if (prm.get ("Allow fixed composition on outflow boundaries") == "false for models without melt") + allow_fixed_composition_on_outflow_boundaries = this->get_parameters().include_melt_transport; + else + AssertThrow(false, ExcMessage("'Allow fixed composition on outflow boundaries' " + "must be set to 'true' or 'false', or to its default value.")); + } + prm.leave_subsection (); + + // go through the list, create objects and let them parse + // their own parameters + for (auto &model_name : model_names) + { + // create boundary composition objects + this->plugin_objects.push_back (std::unique_ptr> + (std::get(registered_plugins) + .create_plugin (model_name, + "Boundary composition::Model names"))); + + if (SimulatorAccess *sim = dynamic_cast*>(this->plugin_objects.back().get())) + sim->initialize_simulator (this->get_simulator()); + + this->plugin_objects.back()->parse_parameters (prm); + this->plugin_objects.back()->initialize (); + } + } + + + + template + double + Manager::boundary_composition (const types::boundary_id boundary_indicator, + const Point &position, + const unsigned int compositional_field) const + { + double composition = 0.0; + + auto p = this->plugin_objects.begin(); + for (unsigned int i=0; iplugin_objects.size(); ++p, ++i) + composition = model_operators[i](composition, + (*p)->boundary_composition(boundary_indicator, + position, + compositional_field)); + + return composition; + } + + + + template + const std::vector & + Manager::get_active_boundary_composition_names () const + { + return model_names; + } + + + template + const std::list>> & + Manager::get_active_boundary_composition_conditions () const + { + return this->plugin_objects; + } + + + + template + const std::set & + Manager::get_fixed_composition_boundary_indicators() const + { + return fixed_composition_boundary_indicators; + } + + + + template + bool + Manager::allows_fixed_composition_on_outflow_boundaries() const + { + return allow_fixed_composition_on_outflow_boundaries; + } + + + + template + void + Manager::declare_parameters (ParameterHandler &prm) + { + // declare the entry in the parameter file + prm.enter_subsection ("Boundary composition model"); + { + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + + prm.declare_entry("List of model names", + "", + Patterns::MultipleSelection(pattern_of_names), + "A comma-separated list of boundary composition models that " + "will be used to initialize the composition. " + "These plugins are loaded in the order given, and modify the " + "existing composition field via the operators listed " + "in 'List of model operators'.\n\n" + "The following boundary composition models are available:\n\n" + + + std::get(registered_plugins).get_description_string()); + + prm.declare_entry("List of model operators", "add", + Patterns::MultipleSelection(Utilities::get_model_operator_options()), + "A comma-separated list of operators that " + "will be used to append the listed composition models onto " + "the previous models. If only one operator is given, " + "the same operator is applied to all models."); + + prm.declare_entry ("Model name", "unspecified", + Patterns::Selection (pattern_of_names+"|unspecified"), + "Select one of the following models:\n\n" + + + std::get(registered_plugins).get_description_string() + + "\n\n" + + "\\textbf{Warning}: This parameter provides an old and " + "deprecated way of specifying " + "boundary composition models and shouldn't be used. " + "Please use 'List of model names' instead."); + + prm.declare_entry ("Fixed composition boundary indicators", "", + Patterns::List (Patterns::Anything()), + "A comma separated list of names denoting those boundaries " + "on which the composition is fixed and described by the " + "boundary composition object selected in its own section " + "of this input file. All boundary indicators used by the geometry " + "but not explicitly listed here will end up with no-flux " + "(insulating) boundary conditions." + "\n\n" + "The names of the boundaries listed here can either be " + "numbers (in which case they correspond to the numerical " + "boundary indicators assigned by the geometry object), or they " + "can correspond to any of the symbolic names the geometry object " + "may have provided for each part of the boundary. You may want " + "to compare this with the documentation of the geometry model you " + "use in your model." + "\n\n" + "This parameter only describes which boundaries have a fixed " + "composition, but not what composition should hold on these " + "boundaries. The latter piece of information needs to be " + "implemented in a plugin in the BoundaryComposition " + "group, unless an existing implementation in this group " + "already provides what you want."); + prm.declare_entry ("Allow fixed composition on outflow boundaries", "false for models without melt", + Patterns::Selection("true|false|false for models without melt"), + "When the composition is fixed on a given boundary as determined " + "by the list of 'Fixed composition boundary indicators', there " + "might be parts of the boundary where material flows out and " + "one may want to prescribe the composition only on those parts of " + "the boundary where there is inflow. This parameter determines " + "if compositions are only prescribed at these inflow parts of the " + "boundary (if false) or everywhere on a given boundary, independent " + "of the flow direction (if true). By default, this parameter is set " + "to false, except in models with melt transport (see below). " + "Note that in this context, `fixed' refers to the fact that these " + "are the boundary indicators where Dirichlet boundary conditions are " + "applied, and does not imply that the boundary composition is " + "time-independent. " + "\n\n" + "Mathematically speaking, the compositional fields satisfy an " + "advection equation that has no diffusion. For this equation, one " + "can only impose Dirichlet boundary conditions (i.e., prescribe a " + "fixed compositional field value at the boundary) at those boundaries " + "where material flows in. This would correspond to the ``false'' " + "setting of this parameter, which is correspondingly the default. " + "On the other hand, on a finite dimensional discretization such as " + "the one one obtains from the finite element method, it is possible " + "to also prescribe values on outflow boundaries, even though this may " + "make no physical sense. This would then correspond to the ``true'' " + "setting of this parameter. Note however that this parameter is only " + "taken into account for the continuous field method and is not " + "applied to the Discontinuous Galerkin (DG) field method. " + "\n\n" + "A warning for models with melt transport: In models with fluid flow, " + "some compositional fields (in particular the porosity) might be " + "transported with the fluid velocity, and would need to set the " + "constraints based on the fluid velocity. However, this is currently " + "not possible, because we reuse the same matrix for all compositional " + "fields, and therefore can not use different constraints for different " + "fields. Consequently, we set this parameter to true by default in " + "models where melt transport is enabled. Be aware that if you change " + "this default setting, you will not use the melt velocity, but the solid " + "velocity to determine on which parts of the boundaries there is outflow."); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + Manager::write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Boundary composition interface", + out); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace BoundaryComposition + { +#define INSTANTIATE(dim) \ + template class Interface; \ + template class Manager; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/boundary_composition/spherical_constant.cc.bak b/source/boundary_composition/spherical_constant.cc.bak new file mode 100644 index 00000000000..7c9694813d0 --- /dev/null +++ b/source/boundary_composition/spherical_constant.cc.bak @@ -0,0 +1,143 @@ +/* + Copyright (C) 2011 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include + + +namespace aspect +{ + namespace BoundaryComposition + { + template + void + SphericalConstant:: + initialize () + { + // verify that the geometry is supported by this plugin + AssertThrow ( Plugins::plugin_type_matches>(this->get_geometry_model()) || + Plugins::plugin_type_matches>(this->get_geometry_model()) || + Plugins::plugin_type_matches>(this->get_geometry_model()) || + Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage ("This boundary model is only implemented if the geometry is " + "one of the spherical geometries.")); + + // no inner boundary in a full sphere + if (Plugins::plugin_type_matches>(this->get_geometry_model())) + inner_boundary_indicator = numbers::invalid_unsigned_int; + else + inner_boundary_indicator = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); + + outer_boundary_indicator = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + + } + + + + template + double + SphericalConstant:: + boundary_composition (const types::boundary_id boundary_indicator, + const Point &/*position*/, + const unsigned int compositional_field) const + { + if (boundary_indicator == outer_boundary_indicator) + return outer_composition[compositional_field]; + else if (boundary_indicator == inner_boundary_indicator) + return inner_composition[compositional_field]; + else + AssertThrow (false, + ExcMessage ("Unknown boundary indicator for geometry model. " + "The given boundary should be ``top'' or ``bottom''.")); + + return numbers::signaling_nan(); + } + + + + template + void + SphericalConstant::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary composition model"); + { + prm.enter_subsection("Spherical constant"); + { + prm.declare_entry ("Outer composition", "0.", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the top boundary (at maximal radius). This list must have " + "one entry or as many entries as there are compositional fields. " + "Units: none."); + prm.declare_entry ("Inner composition", "1.", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the bottom boundary (at minimal radius). This list must have " + "one entry or as many entries as there are compositional fields. " + "Units: none."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + SphericalConstant::parse_parameters (ParameterHandler &prm) + { + const unsigned int n_compositional_fields = this->n_compositional_fields(); + + prm.enter_subsection("Boundary composition model"); + { + prm.enter_subsection("Spherical constant"); + { + inner_composition = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Inner composition"))), + n_compositional_fields, + "Inner boundary composition values"); + + outer_composition = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Outer composition"))), + n_compositional_fields, + "Outer boundary composition values"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryComposition + { + ASPECT_REGISTER_BOUNDARY_COMPOSITION_MODEL(SphericalConstant, + "spherical constant", + "A model in which the composition is chosen constant on " + "the inner and outer boundaries of a sphere, spherical " + "shell, chunk or ellipsoidal chunk. " + "Parameters are read from subsection 'Spherical constant'.") + } +} diff --git a/source/boundary_composition/two_merged_boxes.cc.bak b/source/boundary_composition/two_merged_boxes.cc.bak new file mode 100644 index 00000000000..78ab9d5119e --- /dev/null +++ b/source/boundary_composition/two_merged_boxes.cc.bak @@ -0,0 +1,207 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace BoundaryComposition + { + + template + double + TwoMergedBoxes:: + boundary_composition (const types::boundary_id boundary_indicator, + const Point &/*position*/, + const unsigned int compositional_field) const + { + Assert (boundary_indicator<2*dim+2*(dim-1), ExcMessage ("The given boundary indicator needs to be less than 2*dimension+2*(dim-1).")); + + return composition_values[boundary_indicator][compositional_field]; + } + + template + void + TwoMergedBoxes::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary composition model"); + { + prm.enter_subsection("Box with lithosphere boundary indicators"); + { + prm.declare_entry ("Left composition", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the left boundary (at minimal $x$-value). This list must have as many " + "entries as there are compositional fields. Units: none."); + prm.declare_entry ("Right composition", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the right boundary (at maximal $x$-value). This list must have as many " + "entries as there are compositional fields. Units: none."); + prm.declare_entry ("Left composition lithosphere", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the left boundary (at minimal $x$-value). This list must have as many " + "entries as there are compositional fields. Units: none."); + prm.declare_entry ("Right composition lithosphere", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the right boundary (at maximal $x$-value). This list must have as many " + "entries as there are compositional fields. Units: none."); + prm.declare_entry ("Bottom composition", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the bottom boundary (at minimal $y$-value in 2d, or minimal " + "$z$-value in 3d). This list must have as many " + "entries as there are compositional fields. Units: none."); + prm.declare_entry ("Top composition", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the top boundary (at maximal $y$-value in 2d, or maximal " + "$z$-value in 3d). This list must have as many " + "entries as there are compositional fields. Units: none."); + if (dim==3) + { + prm.declare_entry ("Front composition", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the front boundary (at minimal $y$-value). This list must have as many " + "entries as there are compositional fields. Units: none."); + prm.declare_entry ("Back composition", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the back boundary (at maximal $y$-value). This list must have as many " + "entries as there are compositional fields. Units: none."); + prm.declare_entry ("Front composition lithosphere", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the front lithosphere boundary (at minimal $y$-value). This list must have as many " + "entries as there are compositional fields. Units: none."); + prm.declare_entry ("Back composition lithosphere", "", + Patterns::List(Patterns::Double ()), + "A comma separated list of composition boundary values " + "at the back lithosphere boundary (at maximal $y$-value). This list must have as many " + "entries as there are compositional fields. Units: none."); + } + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + TwoMergedBoxes::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary composition model"); + { + prm.enter_subsection("Box with lithosphere boundary indicators"); + { + switch (dim) + { + case 2: + composition_values[0] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Left composition"))); + composition_values[1] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Right composition"))); + composition_values[2] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Bottom composition"))); + composition_values[3] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Top composition"))); + composition_values[4] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Left composition lithosphere"))); + composition_values[5] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Right composition lithosphere"))); + break; + + case 3: + composition_values[0] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Left composition"))); + composition_values[1] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Right composition"))); + composition_values[2] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Front composition"))); + composition_values[3] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Back composition"))); + composition_values[4] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Bottom composition"))); + composition_values[5] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Top composition"))); + composition_values[6] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Left composition lithosphere"))); + composition_values[7] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Right composition lithosphere"))); + composition_values[8] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Front composition lithosphere"))); + composition_values[9] = Utilities::string_to_double(Utilities::split_string_list(prm.get ("Back composition lithosphere"))); + break; + + default: + Assert (false, ExcNotImplemented()); + } + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + + template + void + TwoMergedBoxes::initialize() + { + // verify that the geometry is a box since only for this geometry + // do we know for sure what boundary indicators it uses and what they mean + AssertThrow (Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage ("This boundary model is only useful if the geometry is " + "a box with additional lithosphere boundary indicators.")); + + // verify that each of the lists for boundary values + // has the requisite number of elements + for (unsigned int f=0; f<2*dim+2*(dim-1); ++f) + AssertThrow (composition_values[f].size() == this->n_compositional_fields(), + ExcMessage (std::string("The specification of boundary composition values for the `box with " + "lithosphere boundary indicators' model " + "requires as many values for each boundary indicator the box as there " + "are compositional " + "fields. However, for boundary indicator ") + + + Utilities::int_to_string(f) + + + ", the input file specifies " + + + Utilities::int_to_string(composition_values[f].size()) + + + " values even though there are " + + + Utilities::int_to_string(this->n_compositional_fields()) + + + " compositional fields.")); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryComposition + { + ASPECT_REGISTER_BOUNDARY_COMPOSITION_MODEL(TwoMergedBoxes, + "box with lithosphere boundary indicators", + "A model in which the composition is chosen constant on " + "all the sides of a box. Additional boundary indicators " + "are added to the lithospheric parts of the vertical boundaries. " + "This model is to be used with the 'Two Merged Boxes' Geometry Model.") + } +} diff --git a/source/boundary_fluid_pressure/density.cc.bak b/source/boundary_fluid_pressure/density.cc.bak new file mode 100644 index 00000000000..c22e157c99f --- /dev/null +++ b/source/boundary_fluid_pressure/density.cc.bak @@ -0,0 +1,154 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include + + +namespace aspect +{ + namespace BoundaryFluidPressure + { + + template + void + Density:: + fluid_pressure_gradient ( + const types::boundary_id /*boundary_indicator*/, + const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + const std::vector> &normal_vectors, + std::vector &fluid_pressure_gradient_outputs + ) const + { + const MaterialModel::MeltOutputs *melt_outputs = material_model_outputs.template get_additional_output>(); + Assert(melt_outputs!=nullptr, ExcMessage("Error, MeltOutputs are missing in fluid_pressure_gradient()")); + for (unsigned int q=0; q gravity = this->get_gravity_model().gravity_vector(material_model_inputs.position[q]); + + switch (density_formulation) + { + case DensityFormulation::solid_density: + { + fluid_pressure_gradient_outputs[q] = (material_model_outputs.densities[q] * gravity) * normal_vectors[q]; + break; + } + + case DensityFormulation::fluid_density: + { + fluid_pressure_gradient_outputs[q] = (melt_outputs->fluid_densities[q] * gravity) * normal_vectors[q]; + break; + } + + case DensityFormulation::average_density: + { + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + const double phi = material_model_inputs.composition[q][porosity_idx]; + fluid_pressure_gradient_outputs[q] = ((1.0 - phi) * material_model_outputs.densities[q] * gravity + + phi * melt_outputs->fluid_densities[q] * gravity) + * normal_vectors[q]; + break; + } + + default: + Assert (false, ExcNotImplemented()); + } + } + } + + template + void + Density::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary fluid pressure model"); + { + prm.enter_subsection("Density"); + { + prm.declare_entry ("Density formulation", "solid density", + Patterns::Selection ("solid density|fluid density|average density"), + "The density formulation used to compute the fluid pressure gradient " + "at the model boundary." + "\n\n" + "`solid density' prescribes the gradient of the fluid pressure as " + "solid density times gravity (which is the lithostatic " + "pressure) and leads to approximately the same pressure in " + "the melt as in the solid, so that fluid is only flowing " + "in or out due to differences in dynamic pressure." + "\n\n" + "`fluid density' prescribes the gradient of the fluid pressure as " + "fluid density times gravity and causes melt to flow in " + "with the same velocity as inflowing solid material, " + "or no melt flowing in or out if the solid velocity " + "normal to the boundary is zero." + "\n\n" + "'average density' prescribes the gradient of the fluid pressure as " + "the averaged fluid and solid density times gravity " + "(which is a better approximation for the lithostatic " + "pressure than just the solid density) and leads to approximately the same pressure in " + "the melt as in the solid, so that fluid is only flowing " + "in or out due to differences in dynamic pressure."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + Density::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary fluid pressure model"); + { + prm.enter_subsection("Density"); + { + if (prm.get ("Density formulation") == "solid density") + density_formulation = DensityFormulation::solid_density; + else if (prm.get ("Density formulation") == "fluid density") + density_formulation = DensityFormulation::fluid_density; + else if (prm.get ("Density formulation") == "average density") + density_formulation = DensityFormulation::average_density; + else + AssertThrow (false, ExcNotImplemented()); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryFluidPressure + { + ASPECT_REGISTER_BOUNDARY_FLUID_PRESSURE_MODEL(Density, + "density", + "A plugin that prescribes the fluid pressure gradient at " + "the boundary based on fluid/solid density from the material " + "model.") + } +} diff --git a/source/boundary_fluid_pressure/interface.cc.bak b/source/boundary_fluid_pressure/interface.cc.bak new file mode 100644 index 00000000000..f14832e9278 --- /dev/null +++ b/source/boundary_fluid_pressure/interface.cc.bak @@ -0,0 +1,155 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + +#include + + +namespace aspect +{ + namespace BoundaryFluidPressure + { +// -------------------------------- Deal with registering models and automating +// -------------------------------- their setup and selection at run time + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + register_boundary_fluid_pressure (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + template + std::unique_ptr> + create_boundary_fluid_pressure (ParameterHandler &prm) + { + std::string model_name; + prm.enter_subsection ("Boundary fluid pressure model"); + { + model_name = prm.get ("Plugin name"); + } + prm.leave_subsection (); + + return std::get(registered_plugins).create_plugin (model_name, + "Boundary fluid pressure model::Plugin name"); + } + + + + template + void + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Boundary fluid pressure model"); + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + prm.declare_entry ("Plugin name", "density", + Patterns::Selection (pattern_of_names), + "Select one of the following plugins:\n\n" + + + std::get(registered_plugins).get_description_string()); + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Boundary fluid pressure interface", + out); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace BoundaryFluidPressure + { +#define INSTANTIATE(dim) \ + template class Interface; \ + \ + template \ + void \ + register_boundary_fluid_pressure (const std::string &, \ + const std::string &, \ + void ( *) (ParameterHandler &), \ + std::unique_ptr>( *) ()); \ + \ + template \ + void \ + declare_parameters (ParameterHandler &); \ + \ + template \ + void \ + write_plugin_graph (std::ostream &); \ + \ + template \ + std::unique_ptr> \ + create_boundary_fluid_pressure (ParameterHandler &prm); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/boundary_heat_flux/function.cc.bak b/source/boundary_heat_flux/function.cc.bak new file mode 100644 index 00000000000..3d7e49fc576 --- /dev/null +++ b/source/boundary_heat_flux/function.cc.bak @@ -0,0 +1,179 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + +namespace aspect +{ + namespace BoundaryHeatFlux + { + template + std::vector> + Function:: + heat_flux (const types::boundary_id /*boundary_indicator*/, + const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &/*material_model_outputs*/, + const std::vector> &normal_vectors) const + { + const unsigned int n_evaluation_points = material_model_inputs.n_evaluation_points(); + std::vector> heat_flux(normal_vectors); + + for (unsigned int i=0; i position = material_model_inputs.position[i]; + if (coordinate_system == Utilities::Coordinates::cartesian) + { + heat_flux[i] *= boundary_heat_flux_function.value(position); + } + else if (coordinate_system == Utilities::Coordinates::spherical) + { + const std::array spherical_coordinates = + aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(position); + Point point; + + for (unsigned int d=0; dget_geometry_model().depth(position); + Point point; + point(0) = depth; + + heat_flux[i] *= boundary_heat_flux_function.value(point); + } + else + { + AssertThrow(false, ExcNotImplemented()); + } + } + + return heat_flux; + } + + + template + void + Function::update() + { + // we get time passed as seconds (always) but may want + // to reinterpret it in years + if (this->convert_output_to_years()) + boundary_heat_flux_function.set_time (this->get_time() / year_in_seconds); + else + boundary_heat_flux_function.set_time (this->get_time()); + } + + + template + void + Function::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary heat flux model"); + { + prm.enter_subsection("Function"); + { + prm.declare_entry ("Coordinate system", "cartesian", + Patterns::Selection ("cartesian|spherical|depth"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `cartesian', `spherical', and `depth'. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle. `depth' " + "will create a function, in which only the first " + "parameter is non-zero, which is interpreted to " + "be the depth of the point."); + + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + Function::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary heat flux model"); + { + prm.enter_subsection("Function"); + { + coordinate_system = Utilities::Coordinates::string_to_coordinate_system(prm.get("Coordinate system")); + } + try + { + boundary_heat_flux_function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Boundary heat flux model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryHeatFlux + { + ASPECT_REGISTER_BOUNDARY_HEAT_FLUX_MODEL(Function, + "function", + "Implementation of a model in which the boundary " + "heat flux is given in terms of an explicit formula " + "that is elaborated in the parameters in section " + "``Boundary heat flux model|Function''. The format of these " + "functions follows the syntax understood by the " + "muparser library, see " + "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`." + "\n\n" + "The formula you describe in the mentioned " + "section is a scalar value for the heat flux that is assumed " + "to be the flux normal to the boundary, and that has the unit " + "W/(m$^2$) (in 3d) or W/m (in 2d). Negative fluxes are " + "interpreted as the flow of heat into the domain, and positive " + "fluxes are interpreted as heat flowing out of the domain." + "\n\n" + "The symbol $t$ indicating time that " + "may appear in the formulas for the prescribed " + "heat flux is interpreted as having units " + "seconds unless the global parameter ``Use " + "years in output instead of seconds'' has " + "been set.") + } +} diff --git a/source/boundary_heat_flux/interface.cc.bak b/source/boundary_heat_flux/interface.cc.bak new file mode 100644 index 00000000000..db736384b2a --- /dev/null +++ b/source/boundary_heat_flux/interface.cc.bak @@ -0,0 +1,155 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + +#include + + +namespace aspect +{ + namespace BoundaryHeatFlux + { +// -------------------------------- Deal with registering models and automating +// -------------------------------- their setup and selection at run time + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + register_boundary_heat_flux (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + template + std::unique_ptr> + create_boundary_heat_flux (ParameterHandler &prm) + { + std::string model_name; + prm.enter_subsection ("Boundary heat flux model"); + { + model_name = prm.get ("Model name"); + } + prm.leave_subsection (); + + return std::get(registered_plugins).create_plugin (model_name, + "Boundary heat flux model::Model name"); + } + + + + template + void + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Boundary heat flux model"); + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + prm.declare_entry ("Model name", "function", + Patterns::Selection (pattern_of_names), + "Select one of the following plugins:\n\n" + + + std::get(registered_plugins).get_description_string()); + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Boundary heat flux interface", + out); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace BoundaryHeatFlux + { +#define INSTANTIATE(dim) \ + template class Interface; \ + \ + template \ + void \ + register_boundary_heat_flux (const std::string &, \ + const std::string &, \ + void ( *) (ParameterHandler &), \ + std::unique_ptr>( *) ()); \ + \ + template \ + void \ + declare_parameters (ParameterHandler &); \ + \ + template \ + void \ + write_plugin_graph (std::ostream &); \ + \ + template \ + std::unique_ptr> \ + create_boundary_heat_flux (ParameterHandler &prm); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/boundary_temperature/ascii_data.cc.bak b/source/boundary_temperature/ascii_data.cc.bak new file mode 100644 index 00000000000..5e3737ed89f --- /dev/null +++ b/source/boundary_temperature/ascii_data.cc.bak @@ -0,0 +1,144 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include + +#include + + + +namespace aspect +{ + namespace BoundaryTemperature + { + template + AsciiData::AsciiData () + = default; + + + template + void + AsciiData::initialize () + { + Utilities::AsciiDataBoundary::initialize(this->get_fixed_temperature_boundary_indicators(), + 1); + } + + + template + void + AsciiData::update () + { + Interface::update (); + Utilities::AsciiDataBoundary::update(); + } + + + template + double + AsciiData::boundary_temperature (const types::boundary_id boundary_indicator, + const Point &position) const + { + return Utilities::AsciiDataBoundary::get_data_component(boundary_indicator, + position, + 0); + } + + + template + double + AsciiData::minimal_temperature (const std::set &) const + { + return 0; + } + + + template + double + AsciiData::maximal_temperature (const std::set &) const + { + return 0; + } + + + template + void + AsciiData::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + Utilities::AsciiDataBoundary::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/boundary-temperature/ascii-data/test/", + "box_2d_%s.%d.txt"); + } + prm.leave_subsection(); + } + + + template + void + AsciiData::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + Utilities::AsciiDataBoundary::parse_parameters(prm); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryTemperature + { + ASPECT_REGISTER_BOUNDARY_TEMPERATURE_MODEL(AsciiData, + "ascii data", + "Implementation of a model in which the boundary " + "data is derived from files containing data " + "in ascii format. Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example `# POINTS: 3 3'. " + "The order of the data columns " + "has to be `x', `Temperature [K]' in a 2d model and " + " `x', `y', `Temperature [K]' in a 3d model, which means that " + "there has to be a single column " + "containing the temperature. " + "Note that the data in the input " + "files need to be sorted in a specific order: " + "the first coordinate needs to ascend first, " + "followed by the second in order to " + "assign the correct data to the prescribed coordinates. " + "If you use a spherical model, " + "then the assumed grid changes. `x' will be replaced by " + "the radial distance of the point to the bottom of the model, " + "`y' by the azimuth angle and `z' by the polar angle measured " + "positive from the north pole. The grid will be assumed to be " + "a latitude-longitude grid. Note that the order " + "of spherical coordinates is `r', `phi', `theta' " + "and not `r', `theta', `phi', since this allows " + "for dimension independent expressions.") + } +} diff --git a/source/boundary_temperature/box.cc.bak b/source/boundary_temperature/box.cc.bak new file mode 100644 index 00000000000..f1899243c66 --- /dev/null +++ b/source/boundary_temperature/box.cc.bak @@ -0,0 +1,173 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace BoundaryTemperature + { +// ------------------------------ Box ------------------- + + template + double + Box:: + boundary_temperature (const types::boundary_id boundary_indicator, + const Point &/*position*/) const + { + Assert (boundary_indicator<2*dim, ExcMessage ("Given boundary indicator needs to be less than 2*dimension.")); + return temperature_[boundary_indicator]; + } + + + template + double + Box:: + minimal_temperature (const std::set &fixed_boundary_ids) const + { + if (fixed_boundary_ids.empty()) + return *std::min_element(temperature_, temperature_+2*dim); + else + { + double min = maximal_temperature(fixed_boundary_ids); + for (const auto id : fixed_boundary_ids) + min = std::min(min,temperature_[id]); + return min; + } + } + + + + template + double + Box:: + maximal_temperature (const std::set &fixed_boundary_ids) const + { + if (fixed_boundary_ids.empty()) + return *std::max_element(temperature_, temperature_+2*dim); + else + { + double max = std::numeric_limits::lowest(); + for (const auto id : fixed_boundary_ids) + max = std::max(max,temperature_[id]); + return max; + } + } + + template + void + Box::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Box"); + { + prm.declare_entry ("Left temperature", "1.", + Patterns::Double (), + "Temperature at the left boundary (at minimal $x$-value). Units: \\si{\\kelvin}."); + prm.declare_entry ("Right temperature", "0.", + Patterns::Double (), + "Temperature at the right boundary (at maximal $x$-value). Units: \\si{\\kelvin}."); + prm.declare_entry ("Bottom temperature", "0.", + Patterns::Double (), + "Temperature at the bottom boundary (at minimal $z$-value). Units: \\si{\\kelvin}."); + prm.declare_entry ("Top temperature", "0.", + Patterns::Double (), + "Temperature at the top boundary (at maximal $x$-value). Units: \\si{\\kelvin}."); + if (dim==3) + { + prm.declare_entry ("Front temperature", "0.", + Patterns::Double (), + "Temperature at the front boundary (at minimal $y$-value). Units: \\si{\\kelvin}."); + prm.declare_entry ("Back temperature", "0.", + Patterns::Double (), + "Temperature at the back boundary (at maximal $y$-value). Units: \\si{\\kelvin}."); + } + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + Box::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Box"); + { + switch (dim) + { + case 2: + temperature_[0] = prm.get_double ("Left temperature"); + temperature_[1] = prm.get_double ("Right temperature"); + temperature_[2] = prm.get_double ("Bottom temperature"); + temperature_[3] = prm.get_double ("Top temperature"); + break; + + case 3: + temperature_[0] = prm.get_double ("Left temperature"); + temperature_[1] = prm.get_double ("Right temperature"); + temperature_[2] = prm.get_double ("Front temperature"); + temperature_[3] = prm.get_double ("Back temperature"); + temperature_[4] = prm.get_double ("Bottom temperature"); + temperature_[5] = prm.get_double ("Top temperature"); + break; + + default: + Assert (false, ExcNotImplemented()); + } + + // verify that the geometry is a box since only for this geometry + // do we know for sure what boundary indicators it uses and what they mean + AssertThrow (Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage ("This boundary model is only implemented if the geometry is " + "a box.")); + + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryTemperature + { + ASPECT_REGISTER_BOUNDARY_TEMPERATURE_MODEL(Box, + "box", + "A model in which the temperature is chosen constant on " + "the sides of a box which are selected by the parameters " + "Left/Right/Top/Bottom/Front/Back temperature") + } +} diff --git a/source/boundary_temperature/constant.cc.bak b/source/boundary_temperature/constant.cc.bak new file mode 100644 index 00000000000..442eee8a480 --- /dev/null +++ b/source/boundary_temperature/constant.cc.bak @@ -0,0 +1,189 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include + +#include + + +namespace aspect +{ + namespace BoundaryTemperature + { +// ------------------------------ Constant ------------------- + + template + double + Constant:: + boundary_temperature (const types::boundary_id boundary_indicator, + const Point &/*position*/) const + { + const std::map::const_iterator it = boundary_temperatures.find(boundary_indicator); + if (it != boundary_temperatures.end()) + return it->second; + else + { + Assert (false, + ExcMessage ("Unknown boundary indicator with number <" + Utilities::int_to_string(boundary_indicator) + ">. " + "You may not have specified the temperature for this boundary indicator " + "in the input file.")); + return numbers::signaling_nan(); + } + } + + + template + double + Constant:: + minimal_temperature (const std::set &) const + { + std::map::const_iterator it = boundary_temperatures.begin(); + double min = it->second; + ++it; + + for ( ; it != boundary_temperatures.end(); ++it) + if ( it->second < min ) + min = it->second; + + return min; + } + + + + template + double + Constant:: + maximal_temperature (const std::set &) const + { + std::map::const_iterator it = boundary_temperatures.begin(); + double max = it->second; + ++it; + + for ( ; it != boundary_temperatures.end(); ++it) + if ( it->second > max ) + max = it->second; + + return max; + } + + + + template + void + Constant::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Constant"); + { + prm.declare_entry ("Boundary indicator to temperature mappings", "", + Patterns::Map (Patterns::Anything(), + Patterns::Double()), + "A comma separated list of mappings between boundary " + "indicators and the temperature associated with the " + "boundary indicators. The format for this list is " + "``indicator1 : value1, indicator2 : value2, ...'', " + "where each indicator is a valid boundary indicator " + "(either a number or the symbolic name of a boundary as provided " + "by the geometry model) " + "and each value is the temperature of that boundary." ); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + Constant::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Constant"); + { + // get the list of mappings + const std::vector x_boundary_temperatures + = Utilities::split_string_list(prm.get ("Boundary indicator to temperature mappings")); + + + for (const auto &boundary_id_string : x_boundary_temperatures) + { + // each entry has the format (white space is optional): + // : + const std::vector parts = Utilities::split_string_list (boundary_id_string, ':'); + + AssertThrow (parts.size() == 2, + ExcMessage (std::string("Invalid entry trying to describe boundary " + "temperatures. Each entry needs to have the form " + ", " + "but there is an entry of the form <") + boundary_id_string + ">")); + + types::boundary_id boundary_id; + try + { + boundary_id + = this->get_geometry_model().translate_symbolic_boundary_name_to_id (parts[0]); + } + catch (const std::string &error) + { + AssertThrow (false, ExcMessage ("While parsing the entry , " + "there was an error. Specifically, " + "the conversion function complained as follows:\n\n" + + error)); + } + + AssertThrow((this->get_fixed_temperature_boundary_indicators().find(boundary_id) != this->get_fixed_temperature_boundary_indicators().end()), + ExcMessage ("You have indicated a temperature mapping for " + "boundary indicator " + parts[0] + ", but that " + "indicator isn't in the " + "list of Fixed temperature boundary indicators.")); + + AssertThrow (boundary_temperatures.find(boundary_id) == boundary_temperatures.end(), + ExcMessage ("Boundary indicator <" + Utilities::int_to_string(boundary_id) + + "> appears more than once in the list of indicators " + "for constant temperature boundary conditions.")); + + boundary_temperatures[boundary_id] = Utilities::string_to_double (parts[1]); + } + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryTemperature + { + ASPECT_REGISTER_BOUNDARY_TEMPERATURE_MODEL(Constant, + "constant", + "A model in which the temperature is chosen constant on " + "a given boundary indicator. Parameters are read from the " + "subsection 'Constant'.") + } +} diff --git a/source/boundary_temperature/dynamic_core.cc.bak b/source/boundary_temperature/dynamic_core.cc.bak new file mode 100644 index 00000000000..f38bbbae653 --- /dev/null +++ b/source/boundary_temperature/dynamic_core.cc.bak @@ -0,0 +1,986 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace BoundaryTemperature + { + + template + double + DynamicCore:: + boundary_temperature (const types::boundary_id boundary_indicator, + const Point &/*location*/) const + { + switch (boundary_indicator) + { + case 0: + return inner_temperature; + case 1: + return outer_temperature; + default: + Assert (false, ExcMessage ("Unknown boundary indicator.")); + return std::numeric_limits::quiet_NaN(); + } + } + + + template + double + DynamicCore:: + minimal_temperature (const std::set &/*fixed_boundary_ids*/) const + { + return std::min (inner_temperature, outer_temperature); + } + + + + template + double + DynamicCore:: + maximal_temperature (const std::set &/*fixed_boundary_ids*/) const + { + return std::max (inner_temperature, outer_temperature); + } + + + + template + void + DynamicCore::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Dynamic core"); + { + prm.declare_entry ("Outer temperature", "0.", + Patterns::Double (), + "Temperature at the outer boundary (lithosphere water/air). Units: \\si{\\kelvin}."); + prm.declare_entry ("Inner temperature", "6000.", + Patterns::Double (), + "Temperature at the inner boundary (core mantle boundary) at the " + "beginning. Units: \\si{\\kelvin}."); + prm.declare_entry ("dT over dt", "0.", + Patterns::Double (), + "Initial CMB temperature changing rate. " + "Units: \\si{\\kelvin}/year."); + prm.declare_entry ("dR over dt", "0.", + Patterns::Double (), + "Initial inner core radius changing rate. " + "Units: \\si{\\kilo\\meter}/year."); + prm.declare_entry ("dX over dt", "0.", + Patterns::Double (), + "Initial light composition changing rate. " + "Units: 1/year."); + prm.declare_entry ("Core density", "12.5e3", + Patterns::Double (), + "Density of the core. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Gravity acceleration", "9.8", + Patterns::Double (), + "Gravitation acceleration at CMB. " + "Units: \\si{\\meter\\per\\second\\squared}."); + prm.declare_entry ("CMB pressure", "0.14e12", + Patterns::Double (), + "Pressure at CMB. Units: \\si{\\pascal}."); + prm.declare_entry ("Initial light composition", "0.01", + Patterns::Double (0.), + "Initial light composition (eg. S,O) concentration " + "in weight fraction."); + prm.declare_entry ("Max iteration", "30000", + Patterns::Integer (0), + "The max iterations for nonlinear core energy solver."); + prm.declare_entry ("Core heat capacity", "840.", + Patterns::Double (0.), + "Heat capacity of the core. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("K0", "4.111e11", + Patterns::Double (0.), + "Core compressibility at zero pressure. " + "See \\cite{NPB+04} for more details."); + prm.declare_entry ("Rho0", "7.019e3", + Patterns::Double (0.), + "Core density at zero pressure. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}. " + "See \\cite{NPB+04} for more details."); + prm.declare_entry ("Alpha", "1.35e-5", + Patterns::Double (0.), + "Core thermal expansivity. Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Lh", "750e3", + Patterns::Double (0.), + "The latent heat of core freeze. " + "Units: \\si{\\joule\\per\\kilogram}."); + prm.declare_entry ("Rh","-27.7e6", + Patterns::Double (), + "The heat of reaction. " + "Units: \\si{\\joule\\per\\kilogram}."); + prm.declare_entry ("Beta composition", "1.1", + Patterns::Double (0.), + "Compositional expansion coefficient $Beta_c$. " + "See \\cite{NPB+04} for more details."); + prm.declare_entry ("Delta","0.5", + Patterns::Double (0., 1.), + "Partition coefficient of the light element."); + prm.declare_entry ("Core conductivity", "60.", + Patterns::Double (0.), + "Core heat conductivity $k_c$. Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.enter_subsection("Geotherm parameters"); + { + prm.declare_entry ("Tm0","1695.", + Patterns::Double (0.), + "Melting curve (\\cite{NPB+04} eq. (40)) parameter Tm0. Units: \\si{\\kelvin}."); + prm.declare_entry ("Tm1","10.9", + Patterns::Double (), + "Melting curve (\\cite{NPB+04} eq. (40)) parameter Tm1. " + "Units: \\si{\\per\\tera\\pascal}."); + prm.declare_entry ("Tm2","-8.0", + Patterns::Double (), + "Melting curve (\\cite{NPB+04} eq. (40)) parameter Tm2. " + "Units: \\si{\\per\\tera\\pascal\\squared}."); + prm.declare_entry ("Theta","0.11", + Patterns::Double (), + "Melting curve (\\cite{NPB+04} eq. (40)) parameter Theta."); + prm.declare_entry ("Composition dependency","true", + Patterns::Bool (), + "If melting curve dependent on composition."); + prm.declare_entry ("Use BW11","false", + Patterns::Bool (), + "If using the Fe-FeS system solidus from Buono \\& Walker (2011) instead."); + } + prm.leave_subsection (); + + prm.enter_subsection("Radioactive heat source"); + { + prm.declare_entry ("Number of radioactive heating elements","0", + Patterns::Integer (0), + "Number of different radioactive heating elements in core"); + prm.declare_entry ("Heating rates","", + Patterns::List (Patterns::Double ()), + "Heating rates of different elements (W/kg)"); + prm.declare_entry ("Half life times","", + Patterns::List (Patterns::Double ()), + "Half decay times of different elements (Ga)"); + prm.declare_entry ("Initial concentrations","", + Patterns::List (Patterns::Double ()), + "Initial concentrations of different elements (ppm)"); + } + prm.leave_subsection (); + + prm.enter_subsection("Other energy source"); + { + prm.declare_entry ("File name","", + Patterns::Anything(), + "Data file name for other energy source into the core. " + "The 'other energy source' is used for external core energy source." + "For example if someone want to test the early lunar core powered by precession " + "(Dwyer, C. A., et al. (2011). A long-lived lunar dynamo driven by continuous mechanical stirring. Nature 479(7372): 212-214.)" + "Format [Time(Gyr) Energy rate(W)]"); + } + prm.leave_subsection (); + + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + DynamicCore::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Dynamic core"); + { + // verify that the geometry is in fact a spherical shell since only + // for this geometry do we know for sure what boundary indicators it + // uses and what they mean + AssertThrow (Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage ("This boundary model is only implemented if the geometry is " + "a spherical shell.")); + + inner_temperature = prm.get_double ("Inner temperature"); + outer_temperature = prm.get_double ("Outer temperature"); + init_dT_dt = prm.get_double ("dT over dt") / year_in_seconds; + init_dR_dt = prm.get_double ("dR over dt") / year_in_seconds * 1.e3; + init_dX_dt = prm.get_double ("dX over dt") / year_in_seconds; + Rho_cen = prm.get_double ("Core density"); + g = prm.get_double ("Gravity acceleration"); + P_CMB = prm.get_double ("CMB pressure"); + X_init = prm.get_double ("Initial light composition"); + max_steps = prm.get_integer ("Max iteration"); + Cp = prm.get_double ("Core heat capacity"); + CpRho = Cp*Rho_cen; + + //\cite{NPB+04} + K0 = prm.get_double ("K0"); + Alpha = prm.get_double ("Alpha"); + Rho_0 = prm.get_double ("Rho0"); + Lh = prm.get_double ("Lh"); + Beta_c = prm.get_double ("Beta composition"); + k_c = prm.get_double ("Core conductivity"); + Delta = prm.get_double ("Delta"); + Rh = prm.get_double ("Rh"); + + prm.enter_subsection("Geotherm parameters"); + { + Tm0 = prm.get_double ("Tm0"); + Tm1 = prm.get_double ("Tm1"); + Tm2 = prm.get_double ("Tm2"); + Theta = prm.get_double ("Theta"); + composition_dependency + = prm.get_bool("Composition dependency"); + use_bw11 = prm.get_bool("Use BW11"); + } + prm.leave_subsection (); + + prm.enter_subsection("Radioactive heat source"); + { + n_radioheating_elements = prm.get_integer ("Number of radioactive heating elements"); + heating_rate = Utilities::string_to_double + (Utilities::split_string_list + (prm.get("Heating rates"))); + AssertThrow(n_radioheating_elements==heating_rate.size(), + ExcMessage("Number of heating rate entities does not match " + "the number of radioactive elements.")); + half_life = Utilities::string_to_double + (Utilities::split_string_list + (prm.get("Half life times"))); + AssertThrow(n_radioheating_elements==half_life.size(), + ExcMessage("Number of half life time entities does not match " + "the number of radioactive elements.")); + initial_concentration = Utilities::string_to_double + (Utilities::split_string_list + (prm.get("Initial concentrations"))); + AssertThrow(n_radioheating_elements==initial_concentration.size(), + ExcMessage("Number of initial concentration entities does not match " + "the number of radioactive elements.")); + } + prm.leave_subsection (); + + prm.enter_subsection("Other energy source"); + { + name_OES = prm.get("File name"); + } + prm.leave_subsection (); + + L=sqrt(3*K0*(log(Rho_cen/Rho_0)+1)/(2*M_PI*constants::big_g*Rho_0*Rho_cen)); + D=sqrt(3*Cp/(2*M_PI*Alpha*Rho_cen*constants::big_g)); + + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + template + void + DynamicCore::read_data_OES() + { + data_OES.clear(); + if (name_OES.size()==0) + return; + std::istringstream in(Utilities::read_and_distribute_file_content(name_OES, + this->get_mpi_communicator())); + if (in.good()) + { + str_data_OES data_read; + std::string line; + while (!in.eof()) + { + std::getline(in, line); + if (sscanf(line.data(), "%le\t%le\n", &data_read.t, &data_read.w)==2) + data_OES.push_back(data_read); + } + } + if (data_OES.size()!=0) + this->get_pcout() << "Other energy source is in use ( " + << data_OES.size() + << " data points is read)." + << std::endl; + } + + template + double + DynamicCore::get_OES(double t) const + { + // The core evolution is quite slow, so the time units used here is billion years. + t/=1.e9*year_in_seconds; + double w=0.; + for (unsigned i=1; i=data_OES[i-1].t && t + DynamicCore::DynamicCore() + { + is_first_call = true; + core_data.is_initialized = false; + } + + template + double + DynamicCore::get_initial_Ri(double T) + { + double r0=0., + r1=Rc; + double dT0=get_T(T,r0)-get_solidus(get_X(r0),get_Pressure(r0)), + dT1=get_T(T,r1)-get_solidus(get_X(r1),get_Pressure(r1)); + if (dT0<=0. && dT1<=0.) + return Rc; + if (dT0>=0. && dT1>=0.) + return 0.; + for (int i=0; i0 && dT1<0) + { + // Snowing core + AssertThrow(false, ExcMessage("[Dynamic core] You had a 'Snowing Core' (i.e., core is freezing from CMB), " + "the treatment is not available at the moment.")); + } + return (r0+r1)/2.; + } + + template + bool + DynamicCore::solve_time_step(double &X, double &T, double &R) + { + // Well solving the change in core-mantle boundary temperature T, inner core radius R, and + // light component (e.g. S, O, Si) composition X, the following relations has to be respected: + // 1. At the inner core boundary the adiabatic temperature should be equal to solidus temperature + // 2. The following energy production rate should be balanced in core: + // Heat flux at core-mantle boundary Q + // Specific heat Qs*dT/dt + // Radioactive heating Qr + // Gravitational contribution Qg*dR/dt + // Latent heat Ql*dR/dt + // So that Q+Qs*dT/dt+Qr+Qg*dR/dt*Ql*dR/dt=0 + // 3. The light component composition X depends on inner core radius (See function get_X() ), + // and core solidus may dependent on X as well + // This becomes a small nonlinear problem. Directly iterate through the above three system doesn't + // converge well. Alternatively we solve the inner core radius by bisection method. + + int steps=1; + double R_0,R_1,R_2; + // dT is the temperature difference between adiabatic and solidus at + // inner-outer core boundary. If dT=0 then we found our solution. + double dT0,dT1,dT2; + R_0 = 0.; + R_1 = core_data.Ri; + R_2 = Rc; + dT0 = get_dT(R_0); + dT1 = get_dT(R_1); + dT2 = get_dT(R_2); + + if (dT0 >= 0. && dT2 >= 0.) + { + // Fully molten core + R_1 = R_0; + dT1 = 0; + } + else if (dT2 <= 0. && dT0 <= 0. ) + { + //Completely solid core + R_1 = R_2; + dT1 = 0; + } + else while (!(dT1==0 || steps>max_steps)) + { + // If solution is out of the interval, then something is wrong. + if (dT0*dT2>0) + { + this->get_pcout()<<"Step: "<0.) + { + // Normal solution + return true; + } + else if (dT0>0. && dT2<0.) + { + // Snowing core solution + return false; + } + else + { + // No solution found. + this->get_pcout()<<"[Dynamic core] Step: "< + double + DynamicCore::get_Tc(double r) const + { + // Using all Q values from last step. + // Qs & Qr is constant, while Qg & Ql depends on inner core radius Ri + // TODO: Use mid-point value for Q values. + return core_data.Ti - ( (core_data.Q + core_data.Qr + core_data.Q_OES) * core_data.dt + + (core_data.Qg + core_data.Ql)*(r-core_data.Ri) + ) / core_data.Qs; + } + + template + double + DynamicCore::get_Ts(double r) const + { + return get_solidus(get_X(r),get_Pressure(r)); + } + + + template + double + DynamicCore::get_dT(double r) const + { + return get_T(get_Tc(r),r) - get_Ts(r); + } + + template + void + DynamicCore::update_core_data() + { + get_specific_heating(core_data.Ti,core_data.Qs,core_data.Es); + get_radio_heating(core_data.Ti,core_data.Qr,core_data.Er); + get_gravity_heating(core_data.Ti,core_data.Ri,core_data.Xi,core_data.Qg,core_data.Eg); + get_adiabatic_heating(core_data.Ti,core_data.Ek,core_data.Qk); + get_latent_heating(core_data.Ti,core_data.Ri,core_data.El,core_data.Ql); + get_heat_solution(core_data.Ti,core_data.Ri,core_data.Xi,core_data.Eh); + } + + template + const internal::CoreData & + DynamicCore::get_core_data() const + { + return core_data; + } + + template + double + DynamicCore::get_solidus(double X,double p) const + { + if (use_bw11) + { + // Change from weight percent to mole percent. + double x,x0=32./88.; + if (X + double + DynamicCore::get_X(double r) const + { + double xi_3=pow(r/Rc,3); + return X_init/(1-xi_3+Delta*xi_3); + } + + template + void + DynamicCore::update() + { + core_data.dt = this->get_timestep(); + core_data.H = get_radioheating_rate(); + + // It's a bit tricky here. + // Didn't use the initialize() function instead because the postprocess is initialized after boundary temperature. + // It is not available at the time initialize() function of boundary temperature is called. + if (is_first_call==true) + { + AssertThrow(this->get_postprocess_manager().template has_matching_postprocessor>(), + ExcMessage ("Dynamic core boundary condition has to work with dynamic core statistics postprocessor.")); + + const Postprocess::CoreStatistics &core_statistics + = this->get_postprocess_manager().template get_matching_postprocessor>(); + // The restart data is stored in 'core statistics' postprocessor. + // If restart from checkpoint, extract data from there. + core_data = core_statistics.get_core_data(); + + // Read data of other energy source + read_data_OES(); + + const GeometryModel::SphericalShell &spherical_shell_geometry = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + Rc=spherical_shell_geometry.inner_radius(); + Mc=get_Mass(Rc); + P_Core=get_Pressure(0); + + // If the material model is incompressible, we have to get correction for the real core temperature + if (this->get_adiabatic_conditions().is_initialized() && !this->get_material_model().is_compressible()) + { + Point p1; + p1(0) = spherical_shell_geometry.inner_radius(); + dTa = this->get_adiabatic_conditions().temperature(p1) + - this->get_adiabatic_surface_temperature(); + } + else + dTa = 0.; + + // Setup initial core data from prm input. + // If resumed from checkpoint, core_data is read from postprocess instead of set from prm file. + // (The boundary_temperature doesn't seem to support restart/resume, the data has to passed and + // stored in the postprocessor 'core statistics') + if (!core_data.is_initialized) + { + core_data.Ti=inner_temperature + dTa; + core_data.Ri = get_initial_Ri(core_data.Ti); + core_data.Xi = get_X(core_data.Ri); + + core_data.Q=0.; + core_data.dt=0.; + core_data.dT_dt=init_dT_dt; + core_data.dR_dt=init_dR_dt; + core_data.dX_dt=init_dX_dt; + update_core_data(); + core_data.is_initialized = true; + std::stringstream output; + output<get_pcout() << output.str(); + } + is_first_call = false; + } + + // Calculate core mantle boundary heat flow + { + const Quadrature &quadrature_formula = this->introspection().face_quadratures.temperature; + FEFaceValues fe_face_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_gradients | update_values | + update_normal_vectors | + update_quadrature_points | update_JxW_values); + + std::vector> temperature_gradients (quadrature_formula.size()); + std::vector> composition_values (this->n_compositional_fields(),std::vector (quadrature_formula.size())); + + //std::map local_boundary_fluxes; + double local_CMB_flux = 0.; + double local_CMB_area = 0.; + + types::boundary_id CMB_id = 0; + + typename MaterialModel::Interface::MaterialModelInputs in(fe_face_values.n_quadrature_points, this->n_compositional_fields()); + typename MaterialModel::Interface::MaterialModelOutputs out(fe_face_values.n_quadrature_points, this->n_compositional_fields()); + // Do not request viscosity or reaction rates + in.requested_properties = MaterialModel::MaterialProperties::equation_of_state_properties | + MaterialModel::MaterialProperties::thermal_conductivity; + + // for every surface face on which it makes sense to compute a + // heat flux and that is owned by this processor, + // integrate the normal heat flux given by the formula + // j = - k * n . grad T + // + // for the spherical shell geometry, note that for the inner boundary, + // the normal vector points *into* the core, i.e. we compute the flux + // *out* of the mantle, not into it. we fix this when we add the local + // contribution to the global flux + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + for (const unsigned int f : cell->face_indices()) + if (cell->at_boundary(f)) + if (cell->face(f)->boundary_id() == CMB_id) + { + fe_face_values.reinit (cell, f); + + in.reinit(fe_face_values, cell, this->introspection(), this->get_solution()); + + fe_face_values[this->introspection().extractors.temperature].get_function_gradients (this->get_solution(), + temperature_gradients); + + this->get_material_model().evaluate(in, out); + + + double local_normal_flux = 0; + double local_face_area = 0; + for (unsigned int q=0; qget_material_model().is_compressible()==false) + { + const double alpha = out.thermal_expansion_coefficients[q]; + const double cp = out.specific_heat[0]; + const double gravity = this->get_gravity_model().gravity_vector(in.position[q]).norm(); + if (cell->face(f)->boundary_id()==0) + adiabatic_flux = - alpha * gravity / cp; + else if (cell->face(f)->boundary_id()==1) + adiabatic_flux = alpha * gravity / cp; + } + + local_normal_flux += -thermal_conductivity * + (temperature_gradients[q] * fe_face_values.normal_vector(q) + + adiabatic_flux) * fe_face_values.JxW(q); + local_face_area += fe_face_values.JxW(q); + + } + local_CMB_flux += local_normal_flux; + local_CMB_area += local_face_area; + } + // now communicate to get the global values + double global_CMB_flux; + double global_CMB_area; + global_CMB_flux = Utilities::MPI::sum (local_CMB_flux, this->get_mpi_communicator()); + global_CMB_area = Utilities::MPI::sum (local_CMB_area, this->get_mpi_communicator()); + + // Using area averaged heat-flux density times core mantle boundary area to calculate total heat-flux on the 3d sphere. + // By doing this, using dynamic core evolution with geometry other than 3d spherical shell becomes possible. + double average_CMB_heatflux_density = global_CMB_flux / global_CMB_area; + core_data.Q = average_CMB_heatflux_density * 4. * M_PI * Rc * Rc; + } + + core_data.Q_OES = get_OES(this->get_time()); + + if ((core_data.Q + core_data.Q_OES) * core_data.dt!=0.) + { + double X1,R1=core_data.Ri,T1; + solve_time_step(X1,T1,R1); + if (core_data.dt!=0) + { + core_data.dR_dt=(R1-core_data.Ri)/core_data.dt; + core_data.dT_dt=(T1-core_data.Ti)/core_data.dt; + core_data.dX_dt=(X1-core_data.Xi)/core_data.dt; + } + else + { + core_data.dR_dt=0.; + core_data.dT_dt=0.; + core_data.dX_dt=0.; + } + core_data.Xi=X1; + core_data.Ri=R1; + core_data.Ti=T1; + } + + inner_temperature = core_data.Ti - dTa; + update_core_data(); + if ((core_data.Q + core_data.Q_OES + core_data.Qr) * core_data.dt!=0.) + { + std::stringstream output; + output<get_pcout() << output.str(); + } + } + + template + double + DynamicCore:: + get_Mass(double r) const + { + return 4.*M_PI*Rho_cen*(-pow(L,2)/2.*r*exp(-pow(r/L,2))+pow(L,3)/4.*sqrt(M_PI)*erf(r/L)); + } + + template + double + DynamicCore:: + fun_Sn(double B,double R,double n) const + { + double S=R/(2.*sqrt(M_PI)); + for (unsigned i=1; i<=n; ++i) + S+=B/sqrt(M_PI)*exp(-pow(i,2)/4.)/i*sinh(i*R/B); + return S; + } + + template + double + DynamicCore:: + get_Pressure(double r) const + { + return P_CMB-(4*M_PI*constants::big_g*pow(Rho_cen,2))/3 + *((3*pow(r,2)/10.-pow(L,2)/5)*exp(-pow(r/L,2)) + -(3*pow(Rc,2)/10-pow(L,2)/5)*exp(-pow(Rc/L,2))); + } + + template + double + DynamicCore:: + get_Rho(double r) const + { + return Rho_cen*exp(-pow(r/L,2)); + } + + template + double + DynamicCore:: + get_g(double r) const + { + return (4*M_PI/3)*constants::big_g*Rho_cen*r*(1-3*pow(r,2)/(5*pow(L,2))); + } + + template + double + DynamicCore:: + get_T(double Tc,double r) const + { + return Tc*exp((pow(Rc,2)-pow(r,2))/pow(D,2)); + } + + template + double + DynamicCore:: + get_gravity_potential(double r) const + { + return 2./3.*M_PI*constants::big_g*Rho_cen*(pow(r,2)*(1.-3.*pow(r,2) + /(10.*pow(L,2)))-pow(Rc,2)*(1.-3.*pow(Rc,2)/(10.*pow(L,2)))); + } + + template + void + DynamicCore:: + get_specific_heating(double Tc, double &Qs,double &Es) + { + double A=sqrt(1./(pow(L,-2)+pow(D,-2))); + double Is=4.*M_PI*get_T(Tc,0.)*Rho_cen*(-pow(A,2)*Rc/2.*exp(-pow(Rc/A,2))+pow(A,3)*sqrt(M_PI)/4.*erf(Rc/A)); + + Qs=-Cp/Tc*Is; + Es=Cp/Tc*(Mc-Is/Tc); + } + + template + void + DynamicCore:: + get_radio_heating(double Tc, double &Qr, double &Er) + { + double B,It; + if (D>L) + { + B=sqrt(1/(1/pow(L,2)-1/pow(D,2))); + It=4*M_PI*Rho_cen/get_T(Tc,0)*(-pow(B,2)*Rc/2*exp(-pow(Rc/B,2))+pow(B,3)/sqrt(M_PI)/4*erf(Rc/B)); + } + else + { + B=sqrt(1/(pow(D,-2)-pow(L,-2))); + It=4*M_PI*Rho_cen/get_T(Tc,0)*(pow(B,2)*Rc/2*exp(pow(Rc/B,2))-pow(B,2)*fun_Sn(B,Rc,100)/2); + } + Qr=Mc*core_data.H; + Er=(Mc/Tc-It)*core_data.H; + + } + + template + void + DynamicCore:: + get_heat_solution(double Tc, double r, double X,double &Eh) + { + double B,It; + if (D>L) + { + B=sqrt(1/(1/pow(L,2)-1/pow(D,2))); + It=4*M_PI*Rho_cen/get_T(Tc,0)*(-pow(B,2)*Rc/2*exp(-pow(Rc/B,2))+pow(B,3)/sqrt(M_PI)/4*erf(Rc/B)); + It-=4*M_PI*Rho_cen/get_T(Tc,0)*(-pow(B,2)*r/2*exp(-pow(r/B,2))+pow(B,3)/sqrt(M_PI)/4*erf(r/B)); + } + else + { + B=sqrt(1/(pow(D,-2)-pow(L,-2))); + It=4*M_PI*Rho_cen/get_T(Tc,0)*(pow(B,2)*Rc/2*exp(pow(Rc/B,2))-pow(B,2)*fun_Sn(B,Rc,100)/2); + It-=4*M_PI*Rho_cen/get_T(Tc,0)*(pow(B,2)*r/2*exp(pow(r/B,2))-pow(B,2)*fun_Sn(B,r,100)/2); + } + double Cc=4*M_PI*pow(r,2)*get_Rho(r)*X/(Mc-get_Mass(r)); + Eh=Rh*(It-(Mc-get_Mass(r))/get_T(Tc,r))*Cc; + } + + template + void + DynamicCore:: + get_gravity_heating(double Tc, double r,double X,double &Qg,double &Eg) + { + double Cc=4*M_PI*pow(r,2)*get_Rho(r)*X/(Mc-get_Mass(r)); + double C_2=3./16.*pow(L,2)-0.5*pow(Rc,2)*(1.-3./10.*pow(Rc/L,2)); + if (r==Rc) + Qg=0.; + else + Qg=(8./3.*pow(M_PI*Rho_cen,2)*constants::big_g*( + ((3./20.*pow(Rc,5)-pow(L,2)*pow(Rc,3)/8.-C_2*pow(L,2)*Rc)*exp(-pow(Rc/L,2)) + +C_2/2.*pow(L,3)*sqrt(M_PI)*erf(Rc/L)) + -((3./20.*pow(r,5)-pow(L,2)*pow(r,3)/8.-C_2*pow(L,2)*r)*exp(-pow(r/L,2)) + +C_2/2.*pow(L,3)*sqrt(M_PI)*erf(r/L))) + -(Mc-get_Mass(r))*get_gravity_potential(r))*Beta_c*Cc; + Eg=Qg/Tc; + + } + + template + void + DynamicCore:: + get_adiabatic_heating(double Tc, double &Ek, double &Qk) + { + Ek=16*M_PI*k_c*pow(Rc,5)/5/pow(D,4); + Qk=8*M_PI*pow(Rc,3)*k_c*Tc/pow(D,2); + } + template + void + DynamicCore:: + get_latent_heating(double Tc, double r, double &El, double &Ql) + { + Ql=4.*M_PI*pow(r,2)*Lh*get_Rho(r); + El=Ql*(get_T(Tc,r)-Tc)/(Tc*get_T(Tc,r)); + } + + template + double + DynamicCore:: + get_radioheating_rate() const + { + double time=this->get_time()+0.5*this->get_timestep(); + double Ht=0; + for (unsigned i=0; i + bool + DynamicCore:: + is_OES_used() const + { + if (data_OES.size()>0) + return true; + else + return false; + } + } + +} + + +// explicit instantiations +namespace aspect +{ + namespace BoundaryTemperature + { + ASPECT_REGISTER_BOUNDARY_TEMPERATURE_MODEL(DynamicCore, + "dynamic core", + "This is a boundary temperature model working only with spherical " + "shell geometry and core statistics postprocessor. The temperature " + "at the top is constant, and the core mantle boundary temperature " + "is dynamically evolving through time by calculating the heat flux " + "into the core and solving the core energy balance. The formulation " + "is mainly following \\cite{NPB+04}, and the plugin is used in " + "Zhang et al. [2016]. The energy of core cooling and freeing of the " + "inner core is included in the plugin. However, current plugin can not " + "deal with the energy balance if the core is in the `snowing core' regime " + "(i.e., the core solidifies from the top instead of bottom)." + ) + } +} diff --git a/source/boundary_temperature/function.cc.bak b/source/boundary_temperature/function.cc.bak new file mode 100644 index 00000000000..886715dcb0e --- /dev/null +++ b/source/boundary_temperature/function.cc.bak @@ -0,0 +1,186 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +namespace aspect +{ + namespace BoundaryTemperature + { + template + Function::Function () + : + boundary_temperature_function (1) + {} + + + + template + double + Function:: + boundary_temperature (const types::boundary_id /*boundary_indicator*/, + const Point &position) const + { + const Utilities::NaturalCoordinate point = + this->get_geometry_model().cartesian_to_other_coordinates(position, coordinate_system); + return boundary_temperature_function.value(Utilities::convert_array_to_point(point.get_coordinates())); + } + + + template + void + Function::update() + { + // we get time passed as seconds (always) but may want + // to reinterpret it in years + if (this->convert_output_to_years()) + boundary_temperature_function.set_time (this->get_time() / year_in_seconds); + else + boundary_temperature_function.set_time (this->get_time()); + } + + + + template + double + Function:: + minimal_temperature (const std::set &) const + { + return min_temperature; + } + + + + template + double + Function:: + maximal_temperature (const std::set &) const + { + return max_temperature; + } + + + template + void + Function::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Function"); + { + prm.declare_entry ("Coordinate system", "cartesian", + Patterns::Selection ("cartesian|spherical|depth"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `cartesian', `spherical', and `depth'. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle. `depth' " + "will create a function, in which only the first " + "parameter is non-zero, which is interpreted to " + "be the depth of the point."); + + Functions::ParsedFunction::declare_parameters (prm, 1); + + prm.declare_entry ("Minimal temperature", "273.", + Patterns::Double (), + "Minimal temperature. Units: \\si{\\kelvin}."); + prm.declare_entry ("Maximal temperature", "3773.", + Patterns::Double (), + "Maximal temperature. Units: \\si{\\kelvin}."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + Function::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Function"); + { + coordinate_system = Utilities::Coordinates::string_to_coordinate_system(prm.get("Coordinate system")); + + try + { + boundary_temperature_function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Boundary temperature model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + min_temperature = prm.get_double ("Minimal temperature"); + max_temperature = prm.get_double ("Maximal temperature"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryTemperature + { + ASPECT_REGISTER_BOUNDARY_TEMPERATURE_MODEL(Function, + "function", + "Implementation of a model in which the boundary " + "temperature is given in terms of an explicit formula " + "that is elaborated in the parameters in section " + "``Boundary temperature model|Function''. " + "\n\n" + "Since the symbol $t$ indicating time " + "may appear in the formulas for the prescribed " + "temperatures, it is interpreted as having units " + "seconds unless the global input parameter ``Use " + "years in output instead of seconds'' is set, in " + "which case we interpret the formula expressions " + "as having units year." + "\n\n" + "Because this class simply takes what the " + "function calculates, this class can not " + "know certain pieces of information such as the " + "minimal and maximal temperature on the boundary. " + "For operations that require this, for example in " + "post-processing, this boundary temperature model " + "must therefore be told what the minimal and " + "maximal values on the boundary are. This is done " + "using parameters set in section ``Boundary temperature model/Initial temperature''." + "\n\n" + "The format of these " + "functions follows the syntax understood by the " + "muparser library, see {ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") + } +} diff --git a/source/boundary_temperature/initial_temperature.cc.bak b/source/boundary_temperature/initial_temperature.cc.bak new file mode 100644 index 00000000000..87fb480f1ca --- /dev/null +++ b/source/boundary_temperature/initial_temperature.cc.bak @@ -0,0 +1,134 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + + +namespace aspect +{ + namespace BoundaryTemperature + { +// ------------------------------ InitialTemperature ------------------- + + template + void + InitialTemperature::initialize() + { + // Make sure we keep track of the initial temperature manager and + // that it continues to live beyond the time when the simulator + // class releases its pointer to it. + initial_temperature = this->get_initial_temperature_manager_pointer(); + } + + + + template + double + InitialTemperature:: + boundary_temperature (const types::boundary_id, + const Point &position) const + { + return initial_temperature->initial_temperature(position); + } + + + template + double + InitialTemperature:: + minimal_temperature (const std::set &) const + { + return min_temperature; + } + + + + template + double + InitialTemperature:: + maximal_temperature (const std::set &) const + { + return max_temperature; + } + + + + template + void + InitialTemperature::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Initial temperature"); + { + prm.declare_entry ("Minimal temperature", "0.", + Patterns::Double (), + "Minimal temperature. Units: \\si{\\kelvin}."); + prm.declare_entry ("Maximal temperature", "3773.", + Patterns::Double (), + "Maximal temperature. Units: \\si{\\kelvin}."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + InitialTemperature::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Initial temperature"); + { + min_temperature = prm.get_double ("Minimal temperature"); + max_temperature = prm.get_double ("Maximal temperature"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryTemperature + { + ASPECT_REGISTER_BOUNDARY_TEMPERATURE_MODEL(InitialTemperature, + "initial temperature", + "A model in which the temperature at the boundary " + "is chosen to be the same as given in the initial " + "conditions." + "\n\n" + "Because this class simply takes what the initial " + "temperature had described, this class can not " + "know certain pieces of information such as the " + "minimal and maximal temperature on the boundary. " + "For operations that require this, for example in " + "post-processing, this boundary temperature model " + "must therefore be told what the minimal and " + "maximal values on the boundary are. This is done " + "using parameters set in section ``Boundary temperature model/Initial temperature''.") + } +} diff --git a/source/boundary_temperature/interface.cc.bak b/source/boundary_temperature/interface.cc.bak new file mode 100644 index 00000000000..f42bf0826c3 --- /dev/null +++ b/source/boundary_temperature/interface.cc.bak @@ -0,0 +1,390 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace BoundaryTemperature + { + // ------------------------------ Manager ----------------------------- + // -------------------------------- Deal with registering boundary_temperature models and automating + // -------------------------------- their setup and selection at run time + + template + Manager::~Manager() + = default; + + + + template + void + Manager::update () + { + for (auto &p : this->plugin_objects) + p->update(); + } + + + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + template + void + Manager::register_boundary_temperature (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + template + void + Manager::parse_parameters (ParameterHandler &prm) + { + // find out which plugins are requested and the various other + // parameters we declare here + prm.enter_subsection ("Boundary temperature model"); + { + model_names + = Utilities::split_string_list(prm.get("List of model names")); + + AssertThrow(Utilities::has_unique_entries(model_names), + ExcMessage("The list of strings for the parameter " + "'Boundary temperature model/List of model names' contains entries more than once. " + "This is not allowed. Please check your parameter file.")); + + const std::string model_name = prm.get ("Model name"); + + AssertThrow (model_name == "unspecified" || model_names.size() == 0, + ExcMessage ("The parameter 'Model name' is only used for reasons" + "of backwards compatibility and can not be used together with " + "the new functionality 'List of model names'. Please add your " + "boundary temperature model to the list instead.")); + + if (!(model_name == "unspecified")) + model_names.push_back(model_name); + + // create operator list + std::vector model_operator_names = + Utilities::possibly_extend_from_1_to_N (Utilities::split_string_list(prm.get("List of model operators")), + model_names.size(), + "List of model operators"); + model_operators = Utilities::create_model_operator_list(model_operator_names); + + try + { + const std::vector x_fixed_temperature_boundary_indicators + = this->get_geometry_model().translate_symbolic_boundary_names_to_ids(Utilities::split_string_list + (prm.get ("Fixed temperature boundary indicators"))); + fixed_temperature_boundary_indicators + = std::set (x_fixed_temperature_boundary_indicators.begin(), + x_fixed_temperature_boundary_indicators.end()); + + // If no fixed temperature boundary indicators have been set, there should be no model_names chosen either. + // If that is indeed the case, clear the model_operators vector. Otherwise, raise an exception. + if (fixed_temperature_boundary_indicators.size() == 0) + { + AssertThrow(model_names.size() == 0, + ExcMessage ("You have indicated that you wish to apply a boundary temperature " + "model, but the parameter " + "is empty. Please use this parameter to specify the boundaries " + "on which the model(s) should be applied.")); + + model_operators.clear(); + } + } + catch (const std::string &error) + { + AssertThrow (false, ExcMessage ("While parsing the entry , there was an error. Specifically, " + "the conversion function complained as follows:\n\n" + + error)); + } + + allow_fixed_temperature_on_outflow_boundaries = prm.get_bool ("Allow fixed temperature on outflow boundaries"); + } + prm.leave_subsection (); + + // go through the list, create objects and let them parse + // their own parameters + for (auto &model_name : model_names) + { + // create boundary temperature objects + this->plugin_objects.push_back (std::unique_ptr> + (std::get(registered_plugins) + .create_plugin (model_name, + "Boundary temperature::Model names"))); + + if (SimulatorAccess *sim = dynamic_cast*>(this->plugin_objects.back().get())) + sim->initialize_simulator (this->get_simulator()); + + this->plugin_objects.back()->parse_parameters (prm); + this->plugin_objects.back()->initialize (); + } + } + + + + template + double + Manager::boundary_temperature (const types::boundary_id boundary_indicator, + const Point &position) const + { + double temperature = 0.0; + + auto p = this->plugin_objects.begin(); + for (unsigned int i=0; iplugin_objects.size(); ++p, ++i) + temperature = model_operators[i](temperature, + (*p)->boundary_temperature(boundary_indicator, + position)); + + return temperature; + } + + + + template + double + Manager::minimal_temperature (const std::set &fixed_boundary_ids) const + { + double temperature = std::numeric_limits::max(); + + for (const auto &p : this->plugin_objects) + temperature = std::min(temperature, + p->minimal_temperature(fixed_boundary_ids)); + + return temperature; + } + + + + template + double + Manager::maximal_temperature (const std::set &fixed_boundary_ids) const + { + double temperature = 0.0; + + for (const auto &p : this->plugin_objects) + temperature = std::max(temperature, + p->maximal_temperature(fixed_boundary_ids)); + + return temperature; + } + + + + template + const std::vector & + Manager::get_active_boundary_temperature_names () const + { + return model_names; + } + + + template + const std::list>> & + Manager::get_active_boundary_temperature_conditions () const + { + return this->plugin_objects; + } + + + + template + const std::set & + Manager::get_fixed_temperature_boundary_indicators() const + { + return fixed_temperature_boundary_indicators; + } + + + + template + bool + Manager::allows_fixed_temperature_on_outflow_boundaries() const + { + return allow_fixed_temperature_on_outflow_boundaries; + } + + + + template + void + Manager::declare_parameters (ParameterHandler &prm) + { + // declare the entry in the parameter file + prm.enter_subsection ("Boundary temperature model"); + { + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + + prm.declare_entry("List of model names", + "", + Patterns::MultipleSelection(pattern_of_names), + "A comma-separated list of boundary temperature models that " + "will be used to initialize the temperature. " + "These plugins are loaded in the order given, and modify the " + "existing temperature field via the operators listed " + "in 'List of model operators'.\n\n" + "The following boundary temperature models are available:\n\n" + + + std::get(registered_plugins).get_description_string()); + + prm.declare_entry("List of model operators", "add", + Patterns::MultipleSelection(Utilities::get_model_operator_options()), + "A comma-separated list of operators that " + "will be used to append the listed temperature models onto " + "the previous models. If only one operator is given, " + "the same operator is applied to all models."); + + prm.declare_entry ("Model name", "unspecified", + Patterns::Selection (pattern_of_names+"|unspecified"), + "Select one of the following models:\n\n" + + + std::get(registered_plugins).get_description_string() + + "\n\n" + + "\\textbf{Warning}: This parameter provides an old and " + "deprecated way of specifying " + "boundary temperature models and shouldn't be used. " + "Please use 'List of model names' instead."); + + prm.declare_entry ("Fixed temperature boundary indicators", "", + Patterns::List (Patterns::Anything()), + "A comma separated list of names denoting those boundaries " + "on which the temperature is fixed and described by the " + "boundary temperature object selected in the 'List of model names' " + "parameter. All boundary indicators used by the geometry " + "but not explicitly listed here will end up with no-flux " + "(insulating) boundary conditions, or, if they are listed in the " + "'Fixed heat flux boundary indicators', with Neumann boundary " + "conditions." + "\n\n" + "The names of the boundaries listed here can either be " + "numbers (in which case they correspond to the numerical " + "boundary indicators assigned by the geometry object), or they " + "can correspond to any of the symbolic names the geometry object " + "may have provided for each part of the boundary. You may want " + "to compare this with the documentation of the geometry model you " + "use in your model." + "\n\n" + "This parameter only describes which boundaries have a fixed " + "temperature, but not what temperature should hold on these " + "boundaries. The latter piece of information needs to be " + "implemented in a plugin in the BoundaryTemperature " + "group, unless an existing implementation in this group " + "already provides what you want."); + prm.declare_entry ("Allow fixed temperature on outflow boundaries", "true", + Patterns::Bool (), + "When the temperature is fixed on a given boundary as determined " + "by the list of 'Fixed temperature boundary indicators', there " + "might be parts of the boundary where material flows out and " + "one may want to prescribe the temperature only on the parts of " + "the boundary where there is inflow. This parameter determines " + "if temperatures are only prescribed at these inflow parts of the " + "boundary (if false) or everywhere on a given boundary, independent " + "of the flow direction (if true)." + "Note that in this context, `fixed' refers to the fact that these " + "are the boundary indicators where Dirichlet boundary conditions are " + "applied, and does not imply that the boundary temperature is " + "time-independent. " + "\n\n" + "Mathematically speaking, the temperature satisfies an " + "advection-diffusion equation. For this type of equation, one can " + "prescribe the temperature even on outflow boundaries as long as the " + "diffusion coefficient is nonzero. This would correspond to the " + "``true'' setting of this parameter, which is correspondingly the " + "default. In practice, however, this would only make physical sense " + "if the diffusion coefficient is actually quite large to prevent " + "the creation of a boundary layer. " + "In addition, if there is no diffusion, one can only impose " + "Dirichlet boundary conditions (i.e., prescribe a fixed temperature " + "value at the boundary) at those boundaries where material flows in. " + "This would correspond to the ``false'' setting of this parameter."); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + Manager::write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Boundary temperature interface", + out); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace BoundaryTemperature + { +#define INSTANTIATE(dim) \ + template class Interface; \ + template class Manager; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/boundary_temperature/spherical_constant.cc.bak b/source/boundary_temperature/spherical_constant.cc.bak new file mode 100644 index 00000000000..782788c322d --- /dev/null +++ b/source/boundary_temperature/spherical_constant.cc.bak @@ -0,0 +1,149 @@ +/* + Copyright (C) 2011 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include + + +namespace aspect +{ + namespace BoundaryTemperature + { + template + void + SphericalConstant:: + initialize () + { + // verify that the geometry is supported by this plugin + AssertThrow ( Plugins::plugin_type_matches>(this->get_geometry_model()) || + Plugins::plugin_type_matches>(this->get_geometry_model()) || + Plugins::plugin_type_matches>(this->get_geometry_model()) || + Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage ("This boundary model is only implemented if the geometry is " + "one of the spherical geometries.")); + + // no inner boundary in a full sphere + if (Plugins::plugin_type_matches>(this->get_geometry_model())) + inner_boundary_indicator = numbers::invalid_unsigned_int; + else + inner_boundary_indicator = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); + + outer_boundary_indicator = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + } + + + + template + double + SphericalConstant:: + boundary_temperature (const types::boundary_id boundary_indicator, + const Point &) const + { + if (boundary_indicator == outer_boundary_indicator) + return outer_temperature; + else if (boundary_indicator == inner_boundary_indicator) + return inner_temperature; + else + AssertThrow (false, + ExcMessage ("Unknown boundary indicator for geometry model. " + "The given boundary should be ``top'' or ``bottom''.")); + + return numbers::signaling_nan(); + } + + + + template + double + SphericalConstant:: + minimal_temperature (const std::set &) const + { + return std::min (inner_temperature, outer_temperature); + } + + + + template + double + SphericalConstant:: + maximal_temperature (const std::set &) const + { + return std::max (inner_temperature, outer_temperature); + } + + + + template + void + SphericalConstant::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Spherical constant"); + { + prm.declare_entry ("Outer temperature", "0.", + Patterns::Double (), + "Temperature at the outer boundary (lithosphere water/air). Units: \\si{\\kelvin}."); + prm.declare_entry ("Inner temperature", "6000.", + Patterns::Double (), + "Temperature at the inner boundary (core mantle boundary). Units: \\si{\\kelvin}."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + + template + void + SphericalConstant::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Spherical constant"); + { + inner_temperature = prm.get_double ("Inner temperature"); + outer_temperature = prm.get_double ("Outer temperature"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryTemperature + { + ASPECT_REGISTER_BOUNDARY_TEMPERATURE_MODEL(SphericalConstant, + "spherical constant", + "A model in which the temperature is chosen constant on " + "the inner and outer boundaries of a spherical shell, ellipsoidal " + "chunk or chunk. " + "Parameters are read from subsection 'Spherical constant'.") + } +} diff --git a/source/boundary_temperature/two_merged_boxes.cc.bak b/source/boundary_temperature/two_merged_boxes.cc.bak new file mode 100644 index 00000000000..8167dc0b253 --- /dev/null +++ b/source/boundary_temperature/two_merged_boxes.cc.bak @@ -0,0 +1,191 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace BoundaryTemperature + { + + template + double + TwoMergedBoxes:: + boundary_temperature (const types::boundary_id boundary_indicator, + const Point &) const + { + Assert (boundary_indicator<2*dim+2*(dim-1), ExcMessage ("Given boundary indicator needs to be less than 2*dimension+2*(dimension-1).")); + + return temperature_values[boundary_indicator]; + } + + + template + double + TwoMergedBoxes:: + minimal_temperature (const std::set &fixed_boundary_ids) const + { + if (fixed_boundary_ids.empty()) + return *std::min_element(temperature_values, temperature_values+2*dim+2*(dim-1)); + else + { + double min = maximal_temperature(fixed_boundary_ids); + for (const auto p : fixed_boundary_ids) + min = std::min(min,temperature_values[p]); + return min; + } + } + + + + template + double + TwoMergedBoxes:: + maximal_temperature (const std::set &fixed_boundary_ids) const + { + if (fixed_boundary_ids.empty()) + return *std::max_element(temperature_values, temperature_values+2*dim+2*(dim-1)); + else + { + double max = std::numeric_limits::lowest(); + for (const auto p : fixed_boundary_ids) + max = std::max(max,temperature_values[p]); + return max; + } + } + + template + void + TwoMergedBoxes::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Box with lithosphere boundary indicators"); + { + prm.declare_entry ("Left temperature", "1.", + Patterns::Double (), + "Temperature at the left boundary (at minimal $x$-value). Units: \\si{\\kelvin}."); + prm.declare_entry ("Right temperature", "0.", + Patterns::Double (), + "Temperature at the right boundary (at maximal $x$-value). Units: \\si{\\kelvin}."); + prm.declare_entry ("Bottom temperature", "0.", + Patterns::Double (), + "Temperature at the bottom boundary (at minimal $z$-value). Units: \\si{\\kelvin}."); + prm.declare_entry ("Top temperature", "0.", + Patterns::Double (), + "Temperature at the top boundary (at maximal $x$-value). Units: \\si{\\kelvin}."); + prm.declare_entry ("Left temperature lithosphere", "0.", + Patterns::Double (), + "Temperature at the additional left lithosphere boundary (specified by user in Geometry Model). Units: \\si{\\kelvin}."); + prm.declare_entry ("Right temperature lithosphere", "0.", + Patterns::Double (), + "Temperature at the additional right lithosphere boundary (specified by user in Geometry Model). Units: \\si{\\kelvin}."); + if (dim==3) + { + prm.declare_entry ("Front temperature", "0.", + Patterns::Double (), + "Temperature at the front boundary (at minimal $y$-value). Units: \\si{\\kelvin}."); + prm.declare_entry ("Back temperature", "0.", + Patterns::Double (), + "Temperature at the back boundary (at maximal $y$-value). Units: \\si{\\kelvin}."); + prm.declare_entry ("Front temperature lithosphere", "0.", + Patterns::Double (), + "Temperature at the additional front lithosphere boundary (at minimal $y$-value). Units: \\si{\\kelvin}."); + prm.declare_entry ("Back temperature lithosphere", "0.", + Patterns::Double (), + "Temperature at the additional back lithosphere boundary (at maximal $y$-value). Units: \\si{\\kelvin}."); + } + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + TwoMergedBoxes::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary temperature model"); + { + prm.enter_subsection("Box with lithosphere boundary indicators"); + { + // verify that the geometry is a box since only for this geometry + // do we know for sure what boundary indicators it uses and what they mean + AssertThrow (Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage ("This boundary model is only useful if the geometry is " + "a box with additional boundary indicators.")); + + switch (dim) + { + case 2: + temperature_values[0] = prm.get_double ("Left temperature"); + temperature_values[1] = prm.get_double ("Right temperature"); + temperature_values[2] = prm.get_double ("Bottom temperature"); + temperature_values[3] = prm.get_double ("Top temperature"); + temperature_values[4] = prm.get_double ("Left temperature lithosphere"); + temperature_values[5] = prm.get_double ("Right temperature lithosphere"); + break; + + case 3: + temperature_values[0] = prm.get_double ("Left temperature"); + temperature_values[1] = prm.get_double ("Right temperature"); + temperature_values[2] = prm.get_double ("Front temperature"); + temperature_values[3] = prm.get_double ("Back temperature"); + temperature_values[4] = prm.get_double ("Bottom temperature"); + temperature_values[5] = prm.get_double ("Top temperature"); + temperature_values[6] = prm.get_double ("Left temperature lithosphere"); + temperature_values[7] = prm.get_double ("Right temperature lithosphere"); + temperature_values[8] = prm.get_double ("Front temperature lithosphere"); + temperature_values[9] = prm.get_double ("Back temperature lithosphere"); + break; + + default: + Assert (false, ExcNotImplemented()); + } + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryTemperature + { + ASPECT_REGISTER_BOUNDARY_TEMPERATURE_MODEL(TwoMergedBoxes, + "box with lithosphere boundary indicators", + "A model in which the temperature is chosen constant on " + "all the sides of a box. Additional boundary indicators " + "are added to the lithospheric parts of the vertical boundaries. " + "This model is to be used with the 'Two Merged Boxes' Geometry Model.") + } +} diff --git a/source/boundary_traction/ascii_data.cc.bak b/source/boundary_traction/ascii_data.cc.bak new file mode 100644 index 00000000000..60c293d13f7 --- /dev/null +++ b/source/boundary_traction/ascii_data.cc.bak @@ -0,0 +1,140 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +namespace aspect +{ + namespace BoundaryTraction + { + template + AsciiData::AsciiData () + = default; + + + template + void + AsciiData::initialize () + { + for (const auto &bv : this->get_boundary_traction_manager().get_active_boundary_traction_conditions()) + { + for (const auto &plugin : bv.second) + if (plugin.get() == this) + boundary_ids.insert(bv.first); + } + AssertThrow(*(boundary_ids.begin()) != numbers::invalid_boundary_id, + ExcMessage("Did not find the boundary indicator for the traction ascii data plugin.")); + + Utilities::AsciiDataBoundary::initialize(boundary_ids, + 1); + } + + + template + Tensor<1,dim> + AsciiData:: + boundary_traction (const types::boundary_id boundary_indicator, + const Point &position, + const Tensor<1,dim> &normal_vector) const + { + const double pressure = Utilities::AsciiDataBoundary::get_data_component(boundary_indicator, + position, + 0); + return -pressure * normal_vector; + } + + + template + void + AsciiData::update() + { + Interface::update (); + Utilities::AsciiDataBoundary::update(); + } + + + template + void + AsciiData::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary traction model"); + { + Utilities::AsciiDataBoundary::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/boundary-traction/ascii-data/test/", + "box_2d_%s.%d.txt"); + } + prm.leave_subsection(); + } + + + template + void + AsciiData::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary traction model"); + { + Utilities::AsciiDataBoundary::parse_parameters(prm); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryTraction + { + ASPECT_REGISTER_BOUNDARY_TRACTION_MODEL(AsciiData, + "ascii data", + "Implementation of a model in which the boundary " + "traction is derived from files containing pressure data " + "in ascii format. The pressure given in the data file is " + "applied as traction normal to the surface of a given boundary, " + "pointing inwards. Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example `# POINTS: 3 3'. " + "The order of the data columns " + "has to be `x', `Pressure [Pa]' in a 2d model and " + " `x', `y', `Pressure [Pa]' in a 3d model, which means that " + "there has to be a single column " + "containing the pressure. " + "Note that the data in the input " + "files need to be sorted in a specific order: " + "the first coordinate needs to ascend first, " + "followed by the second in order to " + "assign the correct data to the prescribed coordinates. " + "If you use a spherical model, " + "then the data will still be handled as Cartesian, " + "however the assumed grid changes. `x' will be replaced by " + "the radial distance of the point to the bottom of the model, " + "`y' by the azimuth angle and `z' by the polar angle measured " + "positive from the north pole. The grid will be assumed to be " + "a latitude-longitude grid. Note that the order " + "of spherical coordinates is `r', `phi', `theta' " + "and not `r', `theta', `phi', since this allows " + "for dimension independent expressions.") + } +} diff --git a/source/boundary_traction/function.cc.bak b/source/boundary_traction/function.cc.bak new file mode 100644 index 00000000000..82c3ab75e77 --- /dev/null +++ b/source/boundary_traction/function.cc.bak @@ -0,0 +1,158 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +namespace aspect +{ + namespace BoundaryTraction + { + template + Function::Function () + : + boundary_traction_function (dim) + {} + + + + template + Tensor<1,dim> + Function:: + boundary_traction (const types::boundary_id, + const Point &position, + const Tensor<1,dim> &) const + { + Tensor<1,dim> traction; + Utilities::NaturalCoordinate point = + this->get_geometry_model().cartesian_to_other_coordinates(position, coordinate_system); + for (unsigned int d=0; d(point.get_coordinates()),d); + if (use_spherical_unit_vectors) + traction = Utilities::Coordinates::spherical_to_cartesian_vector(traction, position); + + return traction; + } + + + template + void + Function::update() + { + // we get time passed as seconds (always) but may want + // to reinterpret it in years + if (this->convert_output_to_years()) + boundary_traction_function.set_time (this->get_time() / year_in_seconds); + else + boundary_traction_function.set_time (this->get_time()); + } + + + template + void + Function::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary traction model"); + { + prm.enter_subsection("Function"); + { + prm.declare_entry ("Coordinate system", "cartesian", + Patterns::Selection ("cartesian|spherical|depth"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `cartesian', `spherical', and `depth'. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle. `depth' " + "will create a function, in which only the first " + "parameter is non-zero, which is interpreted to " + "be the depth of the point."); + prm.declare_entry ("Use spherical unit vectors", "false", + Patterns::Bool (), + "Specify traction as $r$, $\\phi$, and $\\theta$ components " + "instead of $x$, $y$, and $z$. Positive tractions point up, east, " + "and north (in 3d) or out and clockwise (in 2d). " + "This setting only makes sense for spherical geometries."); + + Functions::ParsedFunction::declare_parameters (prm, dim); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + Function::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary traction model"); + { + prm.enter_subsection("Function"); + { + coordinate_system = Utilities::Coordinates::string_to_coordinate_system(prm.get("Coordinate system")); + use_spherical_unit_vectors = prm.get_bool("Use spherical unit vectors"); + if (use_spherical_unit_vectors) + AssertThrow (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical, + ExcMessage ("Spherical unit vectors should not be used " + "when geometry model is not spherical.")); + } + try + { + boundary_traction_function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Boundary traction model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryTraction + { + ASPECT_REGISTER_BOUNDARY_TRACTION_MODEL(Function, + "function", + "Implementation of a model in which the boundary " + "traction is given in terms of an explicit formula " + "that is elaborated in the parameters in section " + "``Boundary traction model|Function''. " + "\n\n" + "The formula you describe in the mentioned " + "section is a semicolon separated list of traction components " + "for each of the $d$ components of the traction vector. " + "These $d$ formulas are interpreted as having units " + "Pa.") + } +} diff --git a/source/boundary_traction/initial_lithostatic_pressure.cc.bak b/source/boundary_traction/initial_lithostatic_pressure.cc.bak new file mode 100644 index 00000000000..985ca78071e --- /dev/null +++ b/source/boundary_traction/initial_lithostatic_pressure.cc.bak @@ -0,0 +1,442 @@ +/* + Copyright (C) 2016 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace BoundaryTraction + { + + template + void + InitialLithostaticPressure::initialize() + { + // Ensure the initial lithostatic pressure traction boundary conditions are used, + // and register for which boundary indicators these conditions are set. + std::set traction_bi; + for (const auto &p : this->get_boundary_traction_manager().get_active_boundary_traction_conditions()) + { + for (const auto &plugin : p.second) + if (plugin.get() == this) + traction_bi.insert(p.first); + } + AssertThrow(*(traction_bi.begin()) != numbers::invalid_boundary_id, + ExcMessage("Did not find any boundary indicators for the initial lithostatic pressure plugin.")); + + // Determine whether traction boundary conditions are only set on the bottom + // boundary and initial topography is applied. + bottom_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); + if (!Plugins::plugin_type_matches>(this->get_initial_topography_model()) && + traction_bi.size() == 1 && + *traction_bi.begin() == bottom_boundary_id) + prescribe_constant_pressure_at_bottom_boundary = true; + else + prescribe_constant_pressure_at_bottom_boundary = false; + + // The below is adapted from adiabatic_conditions/initial_profile.cc, + // but we use the initial temperature and composition and only calculate + // a pressure profile with depth. + + // The number of compositional fields + const unsigned int n_compositional_fields = this->n_compositional_fields(); + + // The pressure at the surface + pressure[0] = this->get_surface_pressure(); + + // For spherical(-like) domains, modify the representative point: + // go from degrees to radians... + std::array spherical_representative_point; + for (unsigned int d=0; dget_geometry_model().natural_coordinate_system() == Utilities::Coordinates::CoordinateSystem::cartesian) ? + (this->get_geometry_model().point_is_in_domain(representative_point)) : + (this->get_geometry_model().point_is_in_domain(Utilities::Coordinates::spherical_to_cartesian_coordinates(spherical_representative_point)))), + ExcMessage("The reference point does not lie with the domain.")); + + // Set the radius of the representative point to the surface radius for spherical domains + // or set the vertical coordinate to the surface value for box domains. + // Also get the depth extent without including initial topography, and the vertical coordinate + // of the bottom boundary (radius for spherical and z-coordinate for Cartesian domains). + double depth_extent = 0.; + if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + spherical_representative_point[0] = Plugins::get_plugin_as_type>(this->get_geometry_model()).outer_radius(); + // Spherical shell cannot include initial topography + depth_extent = Plugins::get_plugin_as_type>(this->get_geometry_model()).maximal_depth(); + } + else if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + // Does not include initial topography + spherical_representative_point[0] = Plugins::get_plugin_as_type>(this->get_geometry_model()).outer_radius(); + depth_extent = Plugins::get_plugin_as_type>(this->get_geometry_model()).maximal_depth(); + } + else if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + // Does not include initial topography + spherical_representative_point[0] = Plugins::get_plugin_as_type>(this->get_geometry_model()).outer_radius(); + depth_extent = Plugins::get_plugin_as_type>(this->get_geometry_model()).maximal_depth(); + } + else if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + const GeometryModel::EllipsoidalChunk &gm = Plugins::get_plugin_as_type> (this->get_geometry_model()); + // TODO + // If the eccentricity of the EllipsoidalChunk is non-zero, the radius can vary along a boundary, + // but the maximal depth is the same everywhere and we could calculate a representative pressure + // profile. However, it requires some extra logic with ellipsoidal + // coordinates, so for now we only allow eccentricity zero. + // Using the EllipsoidalChunk with eccentricity zero can still be useful, + // because the domain can be non-coordinate parallel. + AssertThrow(gm.get_eccentricity() == 0.0, ExcMessage("This initial lithospheric pressure plugin cannot be used with a non-zero eccentricity. ")); + + spherical_representative_point[0] = gm.get_semi_major_axis_a(); + // Does not include initial topography + depth_extent = gm.maximal_depth(); + } + else if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + AssertThrow(false, ExcMessage("Using the initial lithospheric pressure plugin does not make sense for a Sphere geometry.")); + spherical_representative_point[0] = Plugins::get_plugin_as_type>(this->get_geometry_model()).radius(); + // Cannot include initial topography. Radius and maximum depth are the same. + depth_extent = spherical_representative_point[0]; + } + else if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + representative_point[dim-1]= Plugins::get_plugin_as_type>(this->get_geometry_model()).get_extents()[dim-1]; + // Maximal_depth includes the maximum topography, while we need the topography at the + // representative point. Therefore, we only get the undeformed (uniform) depth. + depth_extent = representative_point[dim-1] - Plugins::get_plugin_as_type>(this->get_geometry_model()).get_origin()[dim-1]; + } + else if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + representative_point[dim-1]= Plugins::get_plugin_as_type>(this->get_geometry_model()).get_extents()[dim-1]; + // Maximal_depth includes the maximum topography, while we need the topography at the + // representative point. Therefore, we only get the undeformed (uniform) depth. + depth_extent = representative_point[dim-1] - Plugins::get_plugin_as_type>(this->get_geometry_model()).get_origin()[dim-1]; + } + else + AssertThrow(false, ExcNotImplemented()); + + // If present, retrieve initial topography at the reference point. + double topo = 0.; + if (!Plugins::plugin_type_matches>(this->get_initial_topography_model())) + { + // Get the surface x (,y) point + Point surface_point; + for (unsigned int d=0; dget_geometry_model().natural_coordinate_system() == Utilities::Coordinates::CoordinateSystem::cartesian) + surface_point[d] = representative_point[d]; + else + surface_point[d] = spherical_representative_point[d]; + + } + const InitialTopographyModel::Interface *topo_model = const_cast*>(&this->get_initial_topography_model()); + topo = topo_model->value(surface_point); + } + + // The spacing of the depth profile at the location of the representative point. + delta_z = (depth_extent + topo) / (n_points-1); + + // Set up the input for the density function of the material model. + typename MaterialModel::Interface::MaterialModelInputs in(1, n_compositional_fields); + typename MaterialModel::Interface::MaterialModelOutputs out(1, n_compositional_fields); + in.requested_properties = MaterialModel::MaterialProperties::density; + + // Where to calculate the density + // for Cartesian domains + if (Plugins::plugin_type_matches> (this->get_geometry_model()) || + Plugins::plugin_type_matches> (this->get_geometry_model())) + in.position[0] = representative_point; + // and for spherical domains + else + in.position[0] = Utilities::Coordinates::spherical_to_cartesian_coordinates(spherical_representative_point); + + // We need the initial temperature at this point + in.temperature[0] = this->get_initial_temperature_manager().initial_temperature(in.position[0]); + + // and the surface pressure. + in.pressure[0] = pressure[0]; + + // Then the compositions at this point. + for (unsigned int c=0; cget_initial_composition_manager().initial_composition(in.position[0], c); + + // Hopefully the material model won't needed in.strain_rate, we + // leave it as NaNs. + + // We set all entries of the velocity vector to zero since this is the lithostatic case. + in.velocity[0] = Tensor<1,dim> (); + + // Evaluate the material model to get the density. + this->get_material_model().evaluate(in, out); + const double density0 = out.densities[0]; + + // Get the magnitude of gravity. We assume + // that gravity always points along the depth direction. This + // may not strictly be true always but is likely a good enough + // approximation here. + const double gravity0 = this->get_gravity_model().gravity_vector(in.position[0]).norm(); + + // Now integrate pressure downward using trapezoidal integration + // p'(z) = rho(p,c,T) * |g| * delta_z + double sum = delta_z * 0.5 * density0 * gravity0; + + for (unsigned int i=1; i> (this->get_geometry_model()) || + Plugins::plugin_type_matches> (this->get_geometry_model())) + { + // decrease z coordinate with depth increment + representative_point[dim-1] -= delta_z; + in.position[0] = representative_point; + } + // and for spherical domains + else + { + // decrease radius with depth increment + spherical_representative_point[0] -= delta_z; + in.position[0] = Utilities::Coordinates::spherical_to_cartesian_coordinates(spherical_representative_point); + } + + // Retrieve the initial temperature at this point. + in.temperature[0] = this->get_initial_temperature_manager().initial_temperature(in.position[0]); + // and use the previous pressure + in.pressure[0] = pressure[i-1]; + + // Retrieve the compositions at this point. + for (unsigned int c=0; cget_initial_composition_manager().initial_composition(in.position[0], c); + + // We set all entries of the velocity vector to zero since this is the lithostatic case. + in.velocity[0] = Tensor<1,dim> (); + + // Evaluate the material model to get the density at the current point. + this->get_material_model().evaluate(in, out); + const double density = out.densities[0]; + + // Get the magnitude of gravity. + const double gravity = this->get_gravity_model().gravity_vector(in.position[0]).norm(); + + // Trapezoid integration + pressure[i] = sum + delta_z * 0.5 * density * gravity; + sum += delta_z * density * gravity; + } + + Assert (*std::min_element (pressure.begin(), pressure.end()) >= + -std::numeric_limits::epsilon() * pressure.size(), + ExcInternalError()); + + } + + template + Tensor<1,dim> + InitialLithostaticPressure:: + boundary_traction (const types::boundary_id boundary_indicator, + const Point &position, + const Tensor<1,dim> &normal_vector) const + { + // We want to set the normal component to the vertical boundary + // to the lithostatic pressure, the rest of the traction + // components are left set to zero. We get the lithostatic pressure + // from a linear interpolation of the calculated profile, + // unless boundary traction is only applied to the bottom boundary + // and initial topography is included. + // In that case we return the deepest pressure of the pressure + // profile directly. Otherwise, points on the bottom boundary + // with horizontal coordinates other than the reference point + // will not have a depth equal to the deepest depth of the profile. + Tensor<1, dim> traction; + if (prescribe_constant_pressure_at_bottom_boundary && boundary_indicator == bottom_boundary_id) + traction = -pressure.back() * normal_vector; + else + traction = -interpolate_pressure(position) * normal_vector; + + return traction; + } + + template + double + InitialLithostaticPressure:: + interpolate_pressure (const Point &p) const + { + // The depth at which we need the pressure. + const double z = this->get_geometry_model().depth(p); + + // Check that depth does not exceed the maximal depth. + if (z >= this->get_geometry_model().maximal_depth()) + { + Assert (z <= this->get_geometry_model().maximal_depth() + delta_z, + ExcInternalError()); + // Return deepest (last) pressure + return pressure.back(); + } + + const unsigned int i = static_cast(z/delta_z); + // If mesh deformation is allowed, the depth can become + // negative. However, the returned depth is capped at 0 + // by the geometry models and thus always positive. + Assert ((z/delta_z) >= 0, ExcInternalError()); + Assert (i+1 < pressure.size(), ExcInternalError()); + + // Now do the linear interpolation. + const double d=1.0+i-z/delta_z; + Assert ((d>=0) && (d<=1), ExcInternalError()); + + return d*pressure[i]+(1-d)*pressure[i+1]; + } + + + template + void + InitialLithostaticPressure::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary traction model"); + { + prm.enter_subsection("Initial lithostatic pressure"); + { + prm.declare_entry ("Representative point", "", + Patterns::List(Patterns::Double()), + "The point where the pressure profile will be calculated. " + "Cartesian coordinates $(x,y,z)$ when geometry is a box, otherwise enter radius, " + "longitude, and in 3d latitude. Note that the coordinate related to the depth " + "($y$ in 2d Cartesian, $z$ in 3d Cartesian and radius in spherical coordinates) is " + "not used. " + "Units: \\si{\\meter} or degrees."); + prm.declare_entry("Number of integration points", "1000", + Patterns::Integer(0), + "The number of integration points over which we integrate the lithostatic pressure " + "downwards."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + InitialLithostaticPressure::parse_parameters (ParameterHandler &prm) + { + unsigned int refinement; + prm.enter_subsection("Mesh refinement"); + { + refinement = prm.get_integer("Initial adaptive refinement") + prm.get_integer("Initial global refinement"); + } + prm.leave_subsection(); + + prm.enter_subsection("Boundary traction model"); + { + prm.enter_subsection("Initial lithostatic pressure"); + { + // The representative point where to calculate the depth profile. + const std::vector rep_point = + dealii::Utilities::string_to_double(dealii::Utilities::split_string_list(prm.get("Representative point"))); + AssertThrow(rep_point.size() == dim, ExcMessage("Representative point does not have the right dimensions.")); + for (unsigned int d = 0; d. +*/ + + +#include +#include +#include + +#include +#include + +#include + + +namespace aspect +{ + namespace BoundaryTraction + { + template + Manager::~Manager() + = default; + + + + template + void + Manager::update () + { + for (const auto &boundary : boundary_traction_objects) + for (const auto &p : boundary.second) + p->update(); + } + + + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + template + void + Manager::register_boundary_traction (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + template + Tensor<1,dim> + Manager::boundary_traction (const types::boundary_id boundary_indicator, + const Point &position, + const Tensor<1,dim> &normal_vector) const + { + typename std::map>>>::const_iterator boundary_plugins = + boundary_traction_objects.find(boundary_indicator); + + Assert(boundary_plugins != boundary_traction_objects.end(), + ExcMessage("The boundary traction manager class was asked for the " + "boundary traction at a boundary that contains no active " + "boundary traction plugin.")); + + Tensor<1,dim> traction = Tensor<1,dim>(); + + for (const auto &plugin : boundary_plugins->second) + traction += plugin->boundary_traction(boundary_indicator, + position,normal_vector); + + return traction; + } + + + + template + const std::map>> & + Manager::get_active_boundary_traction_names () const + { + return boundary_traction_indicators; + } + + + + template + const std::map>>> & + Manager::get_active_boundary_traction_conditions () const + { + return boundary_traction_objects; + } + + + + template + void + Manager::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Boundary traction model"); + { + prm.declare_entry ("Prescribed traction boundary indicators", "", + Patterns::Map (Patterns::Anything(), + Patterns::Selection(std::get(registered_plugins).get_pattern_of_names ())), + "A comma separated list denoting those boundaries " + "on which the traction is prescribed, i.e., where unknown " + "external forces act to prescribe a particular traction. This is " + "often used to prescribe a traction that equals that of " + "overlying plates." + "\n\n" + "The format of valid entries for this parameter is that of a map " + "given as ``key1 [selector]: value1, key2 [selector]: value2, key3: value3, ...'' where " + "each key must be a valid boundary indicator (which is either an " + "integer or the symbolic name the geometry model in use may have " + "provided for this part of the boundary) " + "and each value must be one of the currently implemented boundary " + "traction models. ``selector'' is an optional string given as a subset " + "of the letters `xyz' that allows you to apply the boundary conditions " + "only to the components listed. As an example, '1 y: function' applies " + "the type `function' to the y component on boundary 1. Without a selector " + "it will affect all components of the traction." + "\n\n" + "Note that traction should be given in N/m^2. " + + "The following boundary traction models are available:\n\n" + + + std::get(registered_plugins).get_description_string()); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + Manager::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Boundary traction model"); + { + // find out which plugins are requested and the various other + // parameters we declare here + const std::vector x_boundary_traction_indicators + = Utilities::split_string_list(prm.get("Prescribed traction boundary indicators")); + + for (const auto &p : x_boundary_traction_indicators) + { + // each entry has the format (white space is optional): + // [x][y][z] : + // + // first tease apart the two halves + const std::vector split_parts = Utilities::split_string_list (p, ':'); + AssertThrow (split_parts.size() == 2, + ExcMessage ("The format for prescribed traction boundary indicators " + "requires that each entry has the form `" + " [x][y][z] : ', but there does not " + "appear to be a colon in the entry <" + + p + + ">.")); + + // the easy part: get the value + const std::string &value = split_parts[1]; + + // now for the rest. since we don't know whether there is a + // component selector, start reading at the end and subtracting + // letters x, y and z + std::string key_and_comp = split_parts[0]; + std::string comp; + while ((key_and_comp.size()>0) && + ((key_and_comp[key_and_comp.size()-1] == 'x') + || + (key_and_comp[key_and_comp.size()-1] == 'y') + || + ((key_and_comp[key_and_comp.size()-1] == 'z') && (dim==3)))) + { + comp += key_and_comp[key_and_comp.size()-1]; + key_and_comp.erase (--key_and_comp.end()); + } + + // we've stopped reading component selectors now. there are three + // possibilities: + // - no characters are left. this means that key_and_comp only + // consisted of a single word that only consisted of 'x', 'y' + // and 'z's. then this would have been a mistake to classify + // as a component selector, and we better undo it + // - the last character of key_and_comp is not a whitespace. this + // means that the last word in key_and_comp ended in an 'x', 'y' + // or 'z', but this was not meant to be a component selector. + // in that case, put these characters back. + // - otherwise, we split successfully. eat spaces that may be at + // the end of key_and_comp to get key + if (key_and_comp.size() == 0) + key_and_comp.swap (comp); + else if (key_and_comp[key_and_comp.size()-1] != ' ') + { + key_and_comp += comp; + comp = ""; + } + else + { + while ((key_and_comp.size()>0) && (key_and_comp[key_and_comp.size()-1] == ' ')) + key_and_comp.erase (--key_and_comp.end()); + } + + // finally, try to translate the key into a boundary_id. then + // make sure we haven't seen it yet + types::boundary_id boundary_id; + try + { + boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id(key_and_comp); + } + catch (const std::string &error) + { + AssertThrow (false, ExcMessage ("While parsing the entry , there was an error. Specifically, " + "the conversion function complained as follows:\n\n" + + error)); + } + + if (boundary_traction_indicators.find(boundary_id) != boundary_traction_indicators.end()) + { + Assert(boundary_traction_indicators[boundary_id].first == comp, + ExcMessage("Different traction plugins for the same boundary have to have the same component selector. " + "This was not the case for boundary: " + key_and_comp + + ", for plugin: " + value + ", with component selector: " + comp)); + + // finally, put it into the list + boundary_traction_indicators[boundary_id].second.push_back(value); + } + else + { + boundary_traction_indicators[boundary_id] = std::make_pair(comp,std::vector(1,value)); + } + } + } + prm.leave_subsection(); + + // go through the list, create objects and let them parse + // their own parameters + for (const auto &boundary_id : boundary_traction_indicators) + { + for (const auto &name : boundary_id.second.second) + { + boundary_traction_objects[boundary_id.first].push_back( + std::unique_ptr> (std::get(registered_plugins) + .create_plugin (name, + "Boundary traction::Model names"))); + + if (SimulatorAccess *sim = dynamic_cast*>(boundary_traction_objects[boundary_id.first].back().get())) + sim->initialize_simulator (this->get_simulator()); + + boundary_traction_objects[boundary_id.first].back()->parse_parameters (prm); + boundary_traction_objects[boundary_id.first].back()->initialize (); + } + } + } + + + + template + void + Manager::write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Boundary traction interface", + out); + } + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace BoundaryTraction + { +#define INSTANTIATE(dim) \ + template class Interface; \ + template class Manager; \ + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/boundary_traction/zero_traction.cc.bak b/source/boundary_traction/zero_traction.cc.bak new file mode 100644 index 00000000000..3d4fb01e953 --- /dev/null +++ b/source/boundary_traction/zero_traction.cc.bak @@ -0,0 +1,62 @@ +/* + Copyright (C) 2011 - 2017 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + + +namespace aspect +{ + namespace BoundaryTraction + { + template + Tensor<1,dim> + ZeroTraction:: + boundary_traction (const types::boundary_id, + const Point &, + const Tensor<1,dim> &) const + { + // return a zero tensor regardless of position + return Tensor<1,dim>(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryTraction + { + ASPECT_REGISTER_BOUNDARY_TRACTION_MODEL(ZeroTraction, + "zero traction", + "Implementation of a model in which the boundary " + "traction is zero. This is commonly referred to as " + "an ``open boundary condition'', indicating that " + "the material experiences no forces in response to " + "what might exist on the other side of the boundary. " + "However, this is only true in the case where " + "hydrostatic pressure is not relevant. If hydrostatic " + "pressure is not negligible, for example at the sides " + "of a regional model, the material at the other side " + "of the boundary does exceed a force, namely the " + "force normal to the boundary induced by the " + "hydrostatic pressure.") + } +} diff --git a/source/boundary_velocity/ascii_data.cc.bak b/source/boundary_velocity/ascii_data.cc.bak new file mode 100644 index 00000000000..5e0843075e1 --- /dev/null +++ b/source/boundary_velocity/ascii_data.cc.bak @@ -0,0 +1,177 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include + +#include + + +namespace aspect +{ + namespace BoundaryVelocity + { + template + AsciiData::AsciiData () + = default; + + + template + void + AsciiData::initialize () + { + for (const auto &p : this->get_boundary_velocity_manager().get_active_boundary_velocity_conditions()) + { + for (const auto &plugin : p.second) + if (plugin.get() == this) + boundary_ids.insert(p.first); + } + AssertThrow(*(boundary_ids.begin()) != numbers::invalid_boundary_id, + ExcMessage("Did not find the boundary indicator for the prescribed data plugin.")); + + Utilities::AsciiDataBoundary::initialize(boundary_ids, + dim); + } + + + + template + void + AsciiData::update () + { + Interface::update (); + + Utilities::AsciiDataBoundary::update(); + } + + + template + Tensor<1,dim> + AsciiData:: + boundary_velocity (const types::boundary_id , + const Point &position) const + { + Tensor<1,dim> velocity; + for (unsigned int i = 0; i < dim; ++i) + velocity[i] = Utilities::AsciiDataBoundary::get_data_component(*(boundary_ids.begin()), + position, + i); + if (use_spherical_unit_vectors) + velocity = Utilities::Coordinates::spherical_to_cartesian_vector(velocity, position); + + return velocity; + } + + + template + void + AsciiData::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary velocity model"); + { + Utilities::AsciiDataBoundary::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/boundary-velocity/ascii-data/test/", + "box_2d_%s.%d.txt"); + prm.enter_subsection("Ascii data model"); + { + prm.declare_entry ("Use spherical unit vectors", "false", + Patterns::Bool (), + "Specify velocity as r, phi, and theta components " + "instead of x, y, and z. Positive velocities point up, east, " + "and north (in 3d) or out and clockwise (in 2d). " + "This setting only makes sense for spherical geometries." + ); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + AsciiData::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary velocity model"); + { + Utilities::AsciiDataBoundary::parse_parameters(prm); + + if (this->convert_output_to_years() == true) + { + this->scale_factor /= year_in_seconds; + } + prm.enter_subsection("Ascii data model"); + { + use_spherical_unit_vectors = prm.get_bool("Use spherical unit vectors"); + if (use_spherical_unit_vectors) + AssertThrow (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical, + ExcMessage ("Spherical unit vectors should not be used " + "when geometry model is not spherical.")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryVelocity + { + ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(AsciiData, + "ascii data", + "Implementation of a model in which the boundary " + "velocity is derived from files containing data " + "in ascii format. Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example `# POINTS: 3 3'. " + "The order of the data columns " + "has to be `x', `velocity${}_x$', `velocity${}_y$' in a 2d model " + "or `x', `y', `velocity${}_x$', `velocity${}_y$', " + "`velocity${}_z$' in a 3d model. " + "Note that the data in the input " + "files need to be sorted in a specific order: " + "the first coordinate needs to ascend first, " + "followed by the second in order to " + "assign the correct data to the prescribed coordinates." + "If you use a spherical model, " + "then the assumed grid changes. `x' will be replaced by " + "the radial distance of the point to the bottom of the model, " + "`y' by the azimuth angle and `z' by the polar angle measured " + "positive from the north pole. The grid will be assumed to be " + "a latitude-longitude grid. Note that the order " + "of spherical coordinates is `r', `phi', `theta' " + "and not `r', `theta', `phi', since this allows " + "for dimension independent expressions. " + "Velocities can be specified using cartesian " + "(by default) or spherical unit vectors. " + "No matter which geometry model is chosen, " + "the unit of the velocities is assumed to be " + "m/s or m/yr depending on the `Use years in output " + "instead of seconds' flag. If you provide velocities " + "in cm/yr, set the `Scale factor' option to 0.01.") + } +} diff --git a/source/boundary_velocity/function.cc.bak b/source/boundary_velocity/function.cc.bak new file mode 100644 index 00000000000..201d814e28c --- /dev/null +++ b/source/boundary_velocity/function.cc.bak @@ -0,0 +1,185 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + +namespace aspect +{ + namespace BoundaryVelocity + { + template + Function::Function () + : + boundary_velocity_function (dim) + {} + + + + template + Tensor<1,dim> + Function:: + boundary_velocity (const types::boundary_id , + const Point &position) const + { + Tensor<1,dim> velocity; + + const Utilities::NaturalCoordinate point = + this->get_geometry_model().cartesian_to_other_coordinates(position, coordinate_system); + + for (unsigned int d=0; d(point.get_coordinates()), d); + + if (use_spherical_unit_vectors) + velocity = Utilities::Coordinates::spherical_to_cartesian_vector(velocity, position); + + // ASPECT always wants things in MKS system. however, as described + // in the documentation of this class, we interpret the formulas + // given to this plugin as meters per year if the global flag + // for using years instead of seconds is given. so if someone + // write "5" in their parameter file and sets the flag, then this + // means "5 meters/year" and we need to convert it to the ASPECT + // time system by dividing by the number of seconds per year + // to get MKS units + if (this->convert_output_to_years()) + return velocity / year_in_seconds; + else + return velocity; + } + + + template + void + Function::update() + { + // we get time passed as seconds (always) but may want + // to reinterpret it in years + if (this->convert_output_to_years()) + boundary_velocity_function.set_time (this->get_time() / year_in_seconds); + else + boundary_velocity_function.set_time (this->get_time()); + } + + + template + void + Function::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary velocity model"); + { + prm.enter_subsection("Function"); + { + prm.declare_entry ("Coordinate system", "cartesian", + Patterns::Selection ("cartesian|spherical|depth"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `cartesian', `spherical', and `depth'. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle. `depth' " + "will create a function, in which only the first " + "parameter is non-zero, which is interpreted to " + "be the depth of the point."); + prm.declare_entry ("Use spherical unit vectors", "false", + Patterns::Bool (), + "Specify velocity as $r$, $\\phi$, and $\\theta$ components " + "instead of $x$, $y$, and $z$. Positive velocities point up, east, " + "and north (in 3d) or out and clockwise (in 2d). " + "This setting only makes sense for spherical geometries."); + + Functions::ParsedFunction::declare_parameters (prm, dim); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + Function::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary velocity model"); + { + prm.enter_subsection("Function"); + { + coordinate_system = Utilities::Coordinates::string_to_coordinate_system(prm.get("Coordinate system")); + use_spherical_unit_vectors = prm.get_bool("Use spherical unit vectors"); + if (use_spherical_unit_vectors) + AssertThrow (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical, + ExcMessage ("Spherical unit vectors should not be used " + "when geometry model is not spherical.")); + } + try + { + boundary_velocity_function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Boundary velocity model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryVelocity + { + ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(Function, + "function", + "Implementation of a model in which the boundary " + "velocity is given in terms of an explicit formula " + "that is elaborated in the parameters in section " + "``Boundary velocity model|Function''. The format of these " + "functions follows the syntax understood by the " + "muparser library, see " + "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`." + "\n\n" + "The formula you describe in the mentioned " + "section is a semicolon separated list of velocities " + "for each of the $d$ components of the velocity vector. " + "These $d$ formulas are interpreted as having units " + "m/s, unless the global input parameter ``Use " + "years in output instead of seconds'' is set, in " + "which case we interpret the formula expressions " + "as having units m/year." + "\n\n" + "Likewise, since the symbol $t$ indicating time " + "may appear in the formulas for the prescribed " + "velocities, it is interpreted as having units " + "seconds unless the global parameter above has " + "been set.") + } +} diff --git a/source/boundary_velocity/gplates.cc.bak b/source/boundary_velocity/gplates.cc.bak new file mode 100644 index 00000000000..a77b5d4f281 --- /dev/null +++ b/source/boundary_velocity/gplates.cc.bak @@ -0,0 +1,870 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace BoundaryVelocity + { + namespace internal + { + template + GPlatesLookup::GPlatesLookup(const Tensor<1,2> &surface_point_one, + const Tensor<1,2> &surface_point_two) + { + // get the Cartesian coordinates of the points the 2d model will lie in + // this computation is done also for 3d since it is not expensive and the + // template dim is currently not used here. Could be changed. + const Tensor<1,3> point_one = cartesian_surface_coordinates(convert_tensor<2,3>(surface_point_one)); + const Tensor<1,3> point_two = cartesian_surface_coordinates(convert_tensor<2,3>(surface_point_two)); + + rotation_matrix = Utilities::compute_rotation_matrix_for_slice(point_one, point_two); + } + + + + template + std::string + GPlatesLookup::screen_output(const Tensor<1,2> &surface_point_one, + const Tensor<1,2> &surface_point_two) const + { + const Tensor<1,3> point_one = cartesian_surface_coordinates(convert_tensor<2,3>(surface_point_one)); + const Tensor<1,3> point_two = cartesian_surface_coordinates(convert_tensor<2,3>(surface_point_two)); + + std::ostringstream output; + + output << std::setprecision (3) << std::setw(3) << std::fixed << std::endl + << " Setting up GPlates boundary velocity plugin." << std::endl + << std::endl; + if (dim == 2) + { + Tensor<1,3> rotation_axis; + const double rotation_angle = rotation_axis_from_matrix(rotation_axis,rotation_matrix); + + std::array angles = angles_from_matrix(rotation_matrix); + std::array back_angles = angles_from_matrix(transpose(rotation_matrix)); + + output << " Input point 1 spherical coordinates: " << surface_point_one << std::endl + << " Input point 1 normalized cartesian coordinates: " << point_one << std::endl + << " Input point 1 rotated model coordinates: " << transpose(rotation_matrix) * point_one << std::endl + << " Input point 2 spherical coordinates: " << surface_point_two << std::endl + << " Input point 2 normalized cartesian coordinates: " << point_two << std::endl + << " Input point 2 rotated model coordinates: " << transpose(rotation_matrix) * point_two << std::endl + << std::endl << std::setprecision(2) + << " Model will be rotated by " << -rotation_angle *constants::radians_to_degree + << " degrees around axis " << rotation_axis << std::endl + << " The ParaView rotation angles are: " << angles[0] << ' ' << angles [1] << ' ' << angles[2] << std::endl + << " The inverse ParaView rotation angles are: " << back_angles[0] << ' ' << back_angles [1] << ' ' << back_angles[2] + + << std::endl; + } + + return output.str(); + } + + + + template + void + GPlatesLookup::load_file(const std::string &filename, + const MPI_Comm comm) + { + // Read data from disk and distribute among processes + std::istringstream filecontent( + Utilities::read_and_distribute_file_content(filename, comm)); + + boost::property_tree::ptree pt; + + // populate tree structure pt + read_xml(filecontent, pt); + + const unsigned int n_points = pt.get_child("gpml:FeatureCollection.gml:featureMember.gpml:VelocityField.gml:domainSet.gml:MultiPoint").size(); + + // These formulas look magic, but they are the proper solution to the equation: + // n_points = n_theta * n_phi with n_phi = 2 * (n_theta - 1) + // From the XML information we only know n_points, but need n_theta + // and n_phi to properly size the arrays and get the grip point positions + const double dn_theta = 0.5 + std::sqrt(0.25 + n_points/2); + const unsigned int n_theta = static_cast (dn_theta); + const unsigned int n_phi = static_cast (2 * (dn_theta - 1)); + + AssertThrow(dn_theta - n_theta <= 1e-5, + ExcMessage("The velocity file has a grid structure that is not readable. Please refer to the manual for a proper grid structure.")); + + delta_theta = numbers::PI / (n_theta-1); + delta_phi = 2*numbers::PI / n_phi; + + /** + * Two tables (one for the theta and one for the phi component) + * which contain the velocities at every point. + * velocity_values[0] is the table for the theta component, whereas + * velocity_values[1] is the table for the phi component. + */ + Table<2,double> velocity_values[2] = {Table<2,double>(n_theta,n_phi+1), Table<2,double>(n_theta,n_phi+1)}; + + std::string velos = pt.get("gpml:FeatureCollection.gml:featureMember.gpml:VelocityField.gml:rangeSet.gml:DataBlock.gml:tupleList"); + std::stringstream in(velos, std::ios::in); + AssertThrow (in, + ExcMessage (std::string("Could not find velocities. Is file native gpml format for velocities?"))); + + // The lat-lon mesh has changed its starting longitude in gplates1.4 + // correct for this while reading in the velocity data + unsigned int longitude_correction = 0; + if (gplates_1_4_or_higher(pt)) + longitude_correction = n_phi/2; + + unsigned int i = 0; + char sep; + Tensor<1,2> spherical_velocities; + + while (in >> spherical_velocities[0] >> sep >> spherical_velocities[1]) + { + const double cmyr_si = 0.01/year_in_seconds; + + const unsigned int idx_theta = i / n_phi; + const unsigned int idx_phi = (i + longitude_correction) % n_phi; + + velocity_values[0][idx_theta][idx_phi]= spherical_velocities[0] * cmyr_si; + velocity_values[1][idx_theta][idx_phi]= spherical_velocities[1] * cmyr_si; + + ++i; + } + + // Pad the longitude data with values for phi == 2*pi (== 0), + // this simplifies interpolation later. + for (unsigned int i=0; i table_intervals; + table_intervals[0] = n_theta - 1; + table_intervals[1] = n_phi; + + // Min and Max coordinates in data file + std::array,2> grid_extent; + + // min and max extent of the grid in the direction of theta and phi (whole spheres in GPlates) + // polar angle theta: from 0° to 180°(PI) + grid_extent[0].first = 0; + grid_extent[0].second = numbers::PI; + // azimuthal angle phi: from 0° to 360°(2*PI) + grid_extent[1].first = 0; + grid_extent[1].second = 2 * numbers::PI; + + for (unsigned int i = 0; i < 2; ++i) + { + velocities[i] + = std::make_unique> (grid_extent, + table_intervals, + velocity_values[i]); + } + + AssertThrow(i == n_points, + ExcMessage (std::string("Number of read in points does not match number of points in file. File corrupted?"))); + } + + + + template + Tensor<1,dim> + GPlatesLookup::surface_velocity(const Point &position) const + { + const Point<3> internal_position ((dim == 2) + ? + rotation_matrix * convert_tensor(position) + : + convert_tensor(position)); + + // transform internal_position in spherical coordinates + std::array spherical_point = + Utilities::Coordinates::cartesian_to_spherical_coordinates(internal_position); + + Tensor<1,dim> output_boundary_velocity; + // Handle all points that are not close to the poles + if ((spherical_point[2] >= delta_theta) && (spherical_point[2] <= numbers::PI - delta_theta)) + { + output_boundary_velocity = cartesian_velocity_at_surface_point(spherical_point); + } + + // The longitude of data points at the poles is set to zero (according to the internal + // GPlates routine). Because we interpolate velocities before converting them to the + // cartesian coordinate system, we need to evaluate them twice: First at the poles, + // and then at the latitude of the first data point that is not at the poles. + // Afterwards we average the two velocities to the real position. + else if (spherical_point[2] < delta_theta) + { + const double theta = spherical_point[2]; + spherical_point[2] = delta_theta; + const Tensor<1,dim> first_velocity = cartesian_velocity_at_surface_point(spherical_point); + + spherical_point[1] = 0.0; + spherical_point[2] = 0.0; + const Tensor<1,dim> polar_velocity = cartesian_velocity_at_surface_point(spherical_point); + + output_boundary_velocity = (theta / delta_theta) * first_velocity + + (1.0 - theta / delta_theta) * polar_velocity; + } + else if (spherical_point[2] > numbers::PI - delta_theta) + { + const double theta = spherical_point[2]; + spherical_point[2] = numbers::PI - delta_theta; + const Tensor<1,dim> first_velocity = cartesian_velocity_at_surface_point(spherical_point); + + spherical_point[1] = 0.0; + spherical_point[2] = numbers::PI; + const Tensor<1,dim> polar_velocity = cartesian_velocity_at_surface_point(spherical_point); + + output_boundary_velocity = ((numbers::PI - theta) / delta_theta) * first_velocity + + (1.0 - (numbers::PI - theta) / delta_theta) * polar_velocity; + } + else + Assert(false,ExcInternalError()); + + return output_boundary_velocity; + } + + + + template + Tensor<1,dim> + GPlatesLookup::cartesian_velocity_at_surface_point(const std::array &spherical_point) const + { + // Re-sort the components of the spherical position from [r,phi,theta] to [theta, phi] + const Point<2> lookup_coordinates(spherical_point[2],spherical_point[1]); + + // Main work, interpolate velocity at this point + Tensor<1,2> interpolated_velocity; + + for (unsigned int i = 0; i < 2; ++i) + interpolated_velocity[i] = velocities[i]->value(lookup_coordinates); + + // Transform interpolated_velocity in cartesian coordinates + const Tensor<1,3> interpolated_velocity_in_cart = sphere_to_cart_velocity(interpolated_velocity,spherical_point); + + // Convert_tensor conveniently also handles the projection to the 2d plane by + // omitting the z-component of velocity (since the 2d model lies in the x-y plane). + const Tensor<1,dim> output_boundary_velocity = (dim == 2) + ? + convert_tensor<3,dim>(transpose(rotation_matrix) * interpolated_velocity_in_cart) + : + convert_tensor<3,dim>(interpolated_velocity_in_cart); + + return output_boundary_velocity; + } + + + + template + Tensor<1,3> + GPlatesLookup::cartesian_surface_coordinates(const Tensor<1,3> &sposition) const + { + Tensor<1,3> ccoord; + + ccoord[0] = std::sin(sposition[0]) * std::cos(sposition[1]); // X + ccoord[1] = std::sin(sposition[0]) * std::sin(sposition[1]); // Y + ccoord[2] = std::cos(sposition[0]); // Z + return ccoord; + } + + + + template + Tensor<1,3> + GPlatesLookup::sphere_to_cart_velocity(const Tensor<1,2> &s_velocities, const std::array &s_position) const + { + Tensor<1,3> velocity; + + velocity[0] = std::cos(s_position[2]) * std::cos(s_position[1]) * s_velocities[0] + - 1.0 * std::sin(s_position[1]) * s_velocities[1]; + velocity[1] = std::cos(s_position[2]) * std::sin(s_position[1]) * s_velocities[0] + + std::cos(s_position[1]) * s_velocities[1]; + velocity[2] = -1.0 * std::sin(s_position[2]) * s_velocities[0]; + + return velocity; + } + + + + template + double + GPlatesLookup::rotation_axis_from_matrix (Tensor<1,3> &rotation_axis, + const Tensor<2,3> &rotation_matrix) const + { + double rotation_angle = std::acos(0.5 * (rotation_matrix[0][0] + rotation_matrix[1][1] + rotation_matrix[2][2] - 1)); + + if (rotation_angle > std::numeric_limits::min()) + { + rotation_axis[0] = (rotation_matrix[2][1] - rotation_matrix[1][2]) / (2*std::sin(rotation_angle)); + rotation_axis[1] = (rotation_matrix[0][2] - rotation_matrix[2][0]) / (2*std::sin(rotation_angle)); + rotation_axis[2] = (rotation_matrix[1][0] - rotation_matrix[0][1]) / (2*std::sin(rotation_angle)); + } + else + { + rotation_axis[0] = 0.0; + rotation_axis[1] = 0.0; + rotation_axis[2] = 1.0; + } + + return rotation_angle; + } + + + + template + std::array + GPlatesLookup::angles_from_matrix(const Tensor<2,3> &rotation_matrix) const + { + std::array orientation; + + /* + * The following code is part of the VTK project and copied here for + * compatibility to the paraview rotation formalism. It is protected by + * the following license: + * + * + * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted under certain conditions. See + * http://www.kitware.com/Copyright.htm for details. + + * This software is distributed WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the above copyright notice for more information. + * + * + * The original code in the VTK-6.0.0 source folder is found in: + * /Common/Transforms/vtkTransform.cxx in the function GetOrientation() + * + */ + + // first rotate about y axis + const double x2 = rotation_matrix[2][0]; + const double y2 = rotation_matrix[2][1]; + const double z2 = rotation_matrix[2][2]; + + const double x3 = rotation_matrix[1][0]; + const double y3 = rotation_matrix[1][1]; + const double z3 = rotation_matrix[1][2]; + + double d1 = sqrt(x2*x2 + z2*z2); + + double cosTheta, sinTheta; + if (d1 < std::numeric_limits::min()) + { + cosTheta = 1.0; + sinTheta = 0.0; + } + else + { + cosTheta = z2/d1; + sinTheta = x2/d1; + } + + double theta = atan2(sinTheta, cosTheta); + orientation[1] = - theta * constants::radians_to_degree; + + // now rotate about x axis + double d = sqrt(x2*x2 + y2*y2 + z2*z2); + + double sinPhi, cosPhi; + if (d < std::numeric_limits::min()) + { + sinPhi = 0.0; + cosPhi = 1.0; + } + else if (d1 < std::numeric_limits::min()) + { + sinPhi = y2/d; + cosPhi = z2/d; + } + else + { + sinPhi = y2/d; + cosPhi = (x2*x2 + z2*z2)/(d1*d); + } + + double phi = atan2(sinPhi, cosPhi); + orientation[0] = phi * constants::radians_to_degree; + + // finally, rotate about z + double x3p = x3*cosTheta - z3*sinTheta; + double y3p = - sinPhi*sinTheta*x3 + cosPhi*y3 - sinPhi*cosTheta*z3; + double d2 = sqrt(x3p*x3p + y3p*y3p); + + double cosAlpha, sinAlpha; + if (d2 < std::numeric_limits::min()) + { + cosAlpha = 1.0; + sinAlpha = 0.0; + } + else + { + cosAlpha = y3p/d2; + sinAlpha = x3p/d2; + } + + double alpha = atan2(sinAlpha, cosAlpha); + orientation[2] = alpha * constants::radians_to_degree; + return orientation; + } + + + + template + template + Tensor<1,out> + GPlatesLookup::convert_tensor (const Tensor<1,in> &old_tensor) const + { + Tensor<1,out> new_tensor; + for (unsigned int i = 0; i < out; ++i) + if (i < in) new_tensor[i] = old_tensor[i]; + else new_tensor[i] = 0.0; + + return new_tensor; + } + + + + template + bool + GPlatesLookup::gplates_1_4_or_higher(const boost::property_tree::ptree &pt) const + { + const std::string gpml_version = pt.get("gpml:FeatureCollection..gpml:version"); + const std::vector string_versions = dealii::Utilities::split_string_list(gpml_version,'.'); + const std::vector int_versions = dealii::Utilities::string_to_int(string_versions); + + const int gplates_1_3_version[3] = {1,6,322}; + + for (unsigned int i = 0; i < int_versions.size(); ++i) + { + if (int_versions[i] > gplates_1_3_version[i]) + return true; + if (int_versions[i] < gplates_1_3_version[i]) + return false; + } + + return false; + } + } + + + + template + GPlates::GPlates () + : + current_file_number(0), + first_data_file_model_time(0.0), + first_data_file_number(0), + decreasing_file_order(false), + data_file_time_step(0.0), + time_weight(0.0), + time_dependent(true), + point1("0.0,0.0"), + point2("0.0,0.0"), + lithosphere_thickness(0.0), + lookup(), + old_lookup() + {} + + + + template + void + GPlates::initialize () + { + char sep; + + std::stringstream streampoint(point1); + streampoint >> pointone[0] >> sep >> pointone[1]; + + std::stringstream streampoint2(point2); + streampoint2 >> pointtwo[0] >> sep >> pointtwo[1]; + + if (dim == 2) + Assert (pointone != pointtwo, + ExcMessage ("To define a plane for the 2d model the two assigned points " + "may not be equal.")); + + AssertThrow (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical, + ExcMessage ("This gplates plugin can only be used when the " + "preferred coordinate system of the geometry model is spherical " + "(e.g. spherical shell, chunk, sphere).")); + + lookup = std::make_unique>(pointone, pointtwo); + old_lookup = std::make_unique>(pointone, pointtwo); + + // display the GPlates module information at model start. + this->get_pcout() << lookup->screen_output(pointone, pointtwo); + + // Set the first file number and load the first files + current_file_number = first_data_file_number; + + const int next_file_number = + (decreasing_file_order) + ? + (current_file_number - 1) + : + (current_file_number + 1); + + this->get_pcout() << std::endl << " Loading GPlates data boundary file " + << create_filename (current_file_number) << '.' << std::endl << std::endl; + + const std::string filename (create_filename (current_file_number)); + if (Utilities::fexists(filename, this->get_mpi_communicator())) + lookup->load_file(filename,this->get_mpi_communicator()); + else + AssertThrow(false, + ExcMessage (std::string("GPlates data file <") + + + filename + + + "> not found!")); + + // If the boundary condition is constant, switch off time_dependence + // immediately. If not, also load the second file for interpolation. + // This catches the case that many files are present, but the + // parameter file requests a single file. + if (create_filename (current_file_number) == create_filename (current_file_number+1)) + { + end_time_dependence (); + } + else + { + const std::string filename (create_filename (next_file_number)); + this->get_pcout() << std::endl << " Loading GPlates data boundary file " + << filename << '.' << std::endl << std::endl; + if (Utilities::fexists(filename, this->get_mpi_communicator())) + { + lookup.swap(old_lookup); + lookup->load_file(filename,this->get_mpi_communicator()); + } + else + end_time_dependence (); + } + } + + + + template + std::string + GPlates::create_filename (const int timestep) const + { + std::string templ = data_directory+velocity_file_name; + const int size = templ.length(); + std::vector buffer(size+10); + snprintf (buffer.data(), size + 10, templ.c_str(), timestep); + std::string str_filename (buffer.data()); + return str_filename; + } + + + + template + void + GPlates::update () + { + const double time_since_start = this->get_time() - first_data_file_model_time; + + if (time_dependent && (time_since_start >= 0.0)) + { + const int time_steps_since_start = static_cast (time_since_start / data_file_time_step); + + // whether we need to update our data files. This looks so complicated + // because we need to catch increasing and decreasing file orders and all + // possible first_data_file_model_times and first_data_file_numbers. + const bool need_update = time_steps_since_start + > std::abs(current_file_number - first_data_file_number); + + if (need_update) + { + // The last file, which was tried to be loaded was + // number current_file_number +/- 1, because current_file_number + // is the file older than the current model time + const int old_file_number = + (decreasing_file_order) + ? + (current_file_number - 1) + : + (current_file_number + 1); + + // Calculate new file_number + current_file_number = + (decreasing_file_order) + ? + (first_data_file_number - time_steps_since_start) + : + (first_data_file_number + time_steps_since_start); + + const bool load_both_files = std::abs(current_file_number - old_file_number) >= 1; + + update_data(load_both_files); + } + + time_weight = (time_since_start / data_file_time_step) + - std::abs(current_file_number - first_data_file_number); + + Assert ((0 <= time_weight) && (time_weight <= 1), + ExcMessage ( + "Error in set_current_time. Time_weight has to be in [0,1]")); + } + } + + + + template + void + GPlates::update_data (const bool load_both_files) + { + // If the time step was large enough to move forward more + // then one data file we need to load both current files + // to stay accurate in interpolation + if (load_both_files) + { + const std::string filename (create_filename (current_file_number)); + this->get_pcout() << std::endl << " Loading GPlates data boundary file " + << filename << '.' << std::endl << std::endl; + if (Utilities::fexists(filename, this->get_mpi_communicator())) + { + lookup.swap(old_lookup); + lookup->load_file(filename,this->get_mpi_communicator()); + } + + // If loading current_time_step failed, end time dependent part with old_file_number. + else + end_time_dependence (); + } + + // Now load the next data file. This part is the main purpose of this function. + const int next_file_number = + (decreasing_file_order) ? + current_file_number - 1 + : + current_file_number + 1; + + const std::string filename (create_filename (next_file_number)); + this->get_pcout() << std::endl << " Loading GPlates data boundary file " + << filename << '.' << std::endl << std::endl; + if (Utilities::fexists(filename, this->get_mpi_communicator())) + { + lookup.swap(old_lookup); + lookup->load_file(filename,this->get_mpi_communicator()); + } + + // If next file does not exist, end time dependent part with current_time_step. + else + end_time_dependence (); + } + + + + template + void + GPlates::end_time_dependence () + { + // no longer consider the problem time dependent from here on out + // this cancels all attempts to read files at the next time steps + time_dependent = false; + // Give warning if first processor + this->get_pcout() << std::endl + << " Loading new gplates velocity file did not succeed." << std::endl + << " Assuming constant boundary conditions for rest of model run." + << std::endl << std::endl; + } + + + + template + Tensor<1,dim> + GPlates:: + boundary_velocity (const types::boundary_id /*boundary_indicator*/, + const Point &position) const + { + // We compare the depth of the current point to the lithosphere thickness. + // The depth is calculated using squares, sums, square-roots and differences + // of large numbers, and we possibly end up with a very small number close to + // the surface, thus rounding errors can get quite large. We therefore + // compare the depth to lithosphere_thickness plus a magic number, which we + // choose as 1e-7 times the maximal model depth, because we safely assume no + // model will have more than 1e7 quadrature points in depth direction. + // Without the magic number it may unintentionally happen that the GPlates + // velocities are not prescribed at every point on the surface. + const double magic_number = 1e-7 * this->get_geometry_model().maximal_depth(); + + if ((this->get_time() - first_data_file_model_time >= 0.0) && (this->get_geometry_model().depth(position) <= lithosphere_thickness + magic_number)) + { + const Tensor<1,dim> data = velocity_scaling_factor * lookup->surface_velocity(position); + + if (!time_dependent) + return data; + + const Tensor<1,dim> old_data = velocity_scaling_factor * old_lookup->surface_velocity(position); + + return time_weight * data + (1 - time_weight) * old_data; + } + else + return Tensor<1,dim>(); + } + + + + template + void + GPlates::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Boundary velocity model"); + { + prm.enter_subsection ("GPlates model"); + { + prm.declare_entry ("Data directory", + "$ASPECT_SOURCE_DIR/data/boundary-velocity/gplates/", + Patterns::DirectoryName (), + "The name of a directory that contains the model data. This path " + "may either be absolute (if starting with a '/') or relative to " + "the current directory. The path may also include the special " + "text '$ASPECT_SOURCE_DIR' which will be interpreted as the path " + "in which the ASPECT source files were located when ASPECT was " + "compiled. This interpretation allows, for example, to reference " + "files located in the `data/' subdirectory of ASPECT. "); + prm.declare_entry ("Velocity file name", "phi.%d", + Patterns::Anything (), + "The file name of the material data. Provide file in format: " + "(Velocity file name).\\%d.gpml where \\%d is any sprintf integer " + "qualifier, specifying the format of the current file number."); + prm.declare_entry ("First data file model time", "0.", + Patterns::Double (0.), + "Time from which on the velocity file with number 'First velocity " + "file number' is used as boundary condition. Previous to this " + "time, a no-slip boundary condition is assumed. Depending on the setting " + "of the global 'Use years in output instead of seconds' flag " + "in the input file, this number is either interpreted as seconds or as years."); + prm.declare_entry ("First data file number", "0", + Patterns::Integer (), + "Number of the first velocity file to be loaded when the model time " + "is larger than 'First velocity file model time'."); + prm.declare_entry ("Decreasing file order", "false", + Patterns::Bool (), + "In some cases the boundary files are not numbered in increasing " + "but in decreasing order (e.g. 'Ma BP'). If this flag is set to " + "'True' the plugin will first load the file with the number " + "'First velocity file number' and decrease the file number during " + "the model run."); + prm.declare_entry ("Data file time step", "1e6", + Patterns::Double (0.), + "Time step between following velocity files. " + "Depending on the setting of the global 'Use years in output instead of seconds' flag " + "in the input file, this number is either interpreted as seconds or as years. " + "The default is one million, i.e., either one million seconds or one million years."); + prm.declare_entry ("Scale factor", "1.", + Patterns::Double (), + "Scalar factor, which is applied to the boundary velocity. " + "You might want to use this to scale the velocities to a " + "reference model (e.g. with free-slip boundary) or another " + "plate reconstruction."); + prm.declare_entry ("Point one", "1.570796,0.0", + Patterns::Anything (), + "Point that determines the plane in which a 2d model lies in. Has to be in the format `a,b' where a and b are theta (polar angle) and " + "phi in radians. This value is not utilized in 3d geometries, and can therefore be set to the default or any user-defined quantity."); + prm.declare_entry ("Point two", "1.570796,1.570796", + Patterns::Anything (), + "Point that determines the plane in which a 2d model lies in. Has to be in the format `a,b' where a and b are theta (polar angle) and " + "phi in radians. This value is not utilized in 3d geometries, and can therefore be set to the default or any user-defined quantity."); + prm.declare_entry ("Lithosphere thickness", "100000.", + Patterns::Double (0.), + "Determines the depth of the lithosphere, so that the GPlates velocities can be applied at the sides of the model " + "as well as at the surface."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + GPlates::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Boundary velocity model"); + { + prm.enter_subsection("GPlates model"); + { + data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get ("Data directory")); + + velocity_file_name = prm.get ("Velocity file name"); + data_file_time_step = prm.get_double ("Data file time step"); + first_data_file_model_time = prm.get_double ("First data file model time"); + first_data_file_number = prm.get_integer("First data file number"); + decreasing_file_order = prm.get_bool ("Decreasing file order"); + velocity_scaling_factor = prm.get_double ("Scale factor"); + point1 = prm.get ("Point one"); + point2 = prm.get ("Point two"); + lithosphere_thickness = prm.get_double ("Lithosphere thickness"); + + if (this->convert_output_to_years()) + { + data_file_time_step *= year_in_seconds; + first_data_file_model_time *= year_in_seconds; + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryVelocity + { + namespace internal + { +#define INSTANTIATE(dim) \ + template class GPlatesLookup; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + + ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(GPlates, + "gplates", + "Implementation of a model in which the boundary " + "velocity is derived from files that are generated " + "by the GPlates program.") + } +} diff --git a/source/boundary_velocity/interface.cc.bak b/source/boundary_velocity/interface.cc.bak new file mode 100644 index 00000000000..1c63df61c8f --- /dev/null +++ b/source/boundary_velocity/interface.cc.bak @@ -0,0 +1,414 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + +#include + + +namespace aspect +{ + namespace BoundaryVelocity + { + // ------------------------------ Manager ----------------------------- + // -------------------------------- Deal with registering boundary_velocity models and automating + // -------------------------------- their setup and selection at run time + + template + Manager::~Manager() + = default; + + + + template + void + Manager::update () + { + for (const auto &boundary : boundary_velocity_objects) + for (const auto &p : boundary.second) + p->update(); + } + + + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + template + void + Manager::register_boundary_velocity (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + + template + Tensor<1,dim> + Manager::boundary_velocity (const types::boundary_id boundary_indicator, + const Point &position) const + { + typename std::map>>>::const_iterator boundary_plugins = + boundary_velocity_objects.find(boundary_indicator); + + Assert(boundary_plugins != boundary_velocity_objects.end(), + ExcMessage("The boundary velocity manager class was asked for the " + "boundary velocity at a boundary that contains no active " + "boundary velocity plugin.")); + + Tensor<1,dim> velocity = Tensor<1,dim>(); + + for (const auto &plugin : boundary_plugins->second) + velocity += plugin->boundary_velocity(boundary_indicator, + position); + + return velocity; + } + + + + template + const std::map>> & + Manager::get_active_boundary_velocity_names () const + { + return boundary_velocity_indicators; + } + + + + template + const std::map>>> & + Manager::get_active_boundary_velocity_conditions () const + { + return boundary_velocity_objects; + } + + + + template + const std::set & + Manager::get_zero_boundary_velocity_indicators () const + { + return zero_velocity_boundary_indicators; + } + + + + template + const std::set & + Manager::get_tangential_boundary_velocity_indicators () const + { + return tangential_velocity_boundary_indicators; + } + + + + template + void + Manager::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Boundary velocity model"); + { + prm.declare_entry ("Prescribed velocity boundary indicators", "", + Patterns::Map (Patterns::Anything(), + Patterns::Selection(std::get(registered_plugins).get_pattern_of_names ())), + "A comma separated list denoting those boundaries " + "on which the velocity is prescribed, i.e., where unknown " + "external forces act to prescribe a particular velocity. This is " + "often used to prescribe a velocity that equals that of " + "overlying plates." + "\n\n" + "The format of valid entries for this parameter is that of a map " + "given as ``key1 [selector]: value1, key2 [selector]: value2, key3: value3, ...'' where " + "each key must be a valid boundary indicator (which is either an " + "integer or the symbolic name the geometry model in use may have " + "provided for this part of the boundary) " + "and each value must be one of the currently implemented boundary " + "velocity models. ``selector'' is an optional string given as a subset " + "of the letters `xyz' that allows you to apply the boundary conditions " + "only to the components listed. As an example, '1 y: function' applies " + "the type `function' to the y component on boundary 1. Without a selector " + "it will affect all components of the velocity." + "\n\n" + "Note that the no-slip boundary condition is " + "a special case of the current one where the prescribed velocity " + "happens to be zero. It can thus be implemented by indicating that " + "a particular boundary is part of the ones selected " + "using the current parameter and using ``zero velocity'' as " + "the boundary values. Alternatively, you can simply list the " + "part of the boundary on which the velocity is to be zero with " + "the parameter ``Zero velocity boundary indicator'' in the " + "current parameter section." + "\n\n" + "Note that when ``Use years in output instead of seconds'' is set " + "to true, velocity should be given in m/yr. " + "The following boundary velocity models are available:\n\n" + + + std::get(registered_plugins).get_description_string()); + prm.declare_entry ("Zero velocity boundary indicators", "", + Patterns::List (Patterns::Anything()), + "A comma separated list of names denoting those boundaries " + "on which the velocity is zero." + "\n\n" + "The names of the boundaries listed here can either by " + "numbers (in which case they correspond to the numerical " + "boundary indicators assigned by the geometry object), or they " + "can correspond to any of the symbolic names the geometry object " + "may have provided for each part of the boundary. You may want " + "to compare this with the documentation of the geometry model you " + "use in your model."); + prm.declare_entry ("Tangential velocity boundary indicators", "", + Patterns::List (Patterns::Anything()), + "A comma separated list of names denoting those boundaries " + "on which the velocity is tangential and unrestrained, i.e., free-slip where " + "no external forces act to prescribe a particular tangential " + "velocity (although there is a force that requires the flow to " + "be tangential)." + "\n\n" + "The names of the boundaries listed here can either by " + "numbers (in which case they correspond to the numerical " + "boundary indicators assigned by the geometry object), or they " + "can correspond to any of the symbolic names the geometry object " + "may have provided for each part of the boundary. You may want " + "to compare this with the documentation of the geometry model you " + "use in your model."); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + Manager::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Boundary velocity model"); + { + try + { + const std::vector x_zero_velocity_boundary_indicators + = this->get_geometry_model().translate_symbolic_boundary_names_to_ids(Utilities::split_string_list + (prm.get ("Zero velocity boundary indicators"))); + zero_velocity_boundary_indicators + = std::set (x_zero_velocity_boundary_indicators.begin(), + x_zero_velocity_boundary_indicators.end()); + } + catch (const std::string &error) + { + AssertThrow (false, ExcMessage ("While parsing the entry , there was an error. Specifically, " + "the conversion function complained as follows:\n\n" + + error)); + } + + try + { + const std::vector x_tangential_velocity_boundary_indicators + = this->get_geometry_model().translate_symbolic_boundary_names_to_ids(Utilities::split_string_list + (prm.get ("Tangential velocity boundary indicators"))); + tangential_velocity_boundary_indicators + = std::set (x_tangential_velocity_boundary_indicators.begin(), + x_tangential_velocity_boundary_indicators.end()); + } + catch (const std::string &error) + { + AssertThrow (false, ExcMessage ("While parsing the entry , there was an error. Specifically, " + "the conversion function complained as follows:\n\n" + + error)); + } + + // find out which plugins are requested and the various other + // parameters we declare here + const std::vector x_boundary_velocity_indicators + = Utilities::split_string_list(prm.get("Prescribed velocity boundary indicators")); + + for (const auto &p : x_boundary_velocity_indicators) + { + // each entry has the format (white space is optional): + // [x][y][z] : + // + // first tease apart the two halves + const std::vector split_parts = Utilities::split_string_list (p, ':'); + AssertThrow (split_parts.size() == 2, + ExcMessage ("The format for prescribed velocity boundary indicators " + "requires that each entry has the form `" + " [x][y][z] : ', but there does not " + "appear to be a colon in the entry <" + + p + + ">.")); + + // the easy part: get the value + const std::string &value = split_parts[1]; + + // now for the rest. since we don't know whether there is a + // component selector, start reading at the end and subtracting + // letters x, y and z + std::string key_and_comp = split_parts[0]; + std::string comp; + while ((key_and_comp.size()>0) && + ((key_and_comp[key_and_comp.size()-1] == 'x') + || + (key_and_comp[key_and_comp.size()-1] == 'y') + || + ((key_and_comp[key_and_comp.size()-1] == 'z') && (dim==3)))) + { + comp += key_and_comp[key_and_comp.size()-1]; + key_and_comp.erase (--key_and_comp.end()); + } + + // we've stopped reading component selectors now. there are three + // possibilities: + // - no characters are left. this means that key_and_comp only + // consisted of a single word that only consisted of 'x', 'y' + // and 'z's. then this would have been a mistake to classify + // as a component selector, and we better undo it + // - the last character of key_and_comp is not a whitespace. this + // means that the last word in key_and_comp ended in an 'x', 'y' + // or 'z', but this was not meant to be a component selector. + // in that case, put these characters back. + // - otherwise, we split successfully. eat spaces that may be at + // the end of key_and_comp to get key + if (key_and_comp.size() == 0) + key_and_comp.swap (comp); + else if (key_and_comp[key_and_comp.size()-1] != ' ') + { + key_and_comp += comp; + comp = ""; + } + else + { + while ((key_and_comp.size()>0) && (key_and_comp[key_and_comp.size()-1] == ' ')) + key_and_comp.erase (--key_and_comp.end()); + } + + // finally, try to translate the key into a boundary_id. then + // make sure we haven't seen it yet + types::boundary_id boundary_id; + try + { + boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id(key_and_comp); + } + catch (const std::string &error) + { + AssertThrow (false, ExcMessage ("While parsing the entry , there was an error. Specifically, " + "the conversion function complained as follows:\n\n" + + error)); + } + + if (boundary_velocity_indicators.find(boundary_id) != boundary_velocity_indicators.end()) + { + Assert(boundary_velocity_indicators[boundary_id].first == comp, + ExcMessage("Different velocity plugins for the same boundary have to have the same component selector. " + "This was not the case for boundary: " + key_and_comp + + ", for plugin: " + value + ", with component selector: " + comp)); + + // finally, put it into the list + boundary_velocity_indicators[boundary_id].second.push_back(value); + } + else + { + boundary_velocity_indicators[boundary_id] = std::make_pair(comp,std::vector(1,value)); + } + } + } + prm.leave_subsection(); + + // go through the list, create objects and let them parse + // their own parameters + for (const auto &boundary_id : boundary_velocity_indicators) + { + for (const auto &name : boundary_id.second.second) + { + boundary_velocity_objects[boundary_id.first].push_back( + std::unique_ptr> (std::get(registered_plugins) + .create_plugin (name, + "Boundary velocity::Model names"))); + + if (SimulatorAccess *sim = dynamic_cast*>(boundary_velocity_objects[boundary_id.first].back().get())) + sim->initialize_simulator (this->get_simulator()); + + boundary_velocity_objects[boundary_id.first].back()->parse_parameters (prm); + boundary_velocity_objects[boundary_id.first].back()->initialize (); + } + } + } + + + + template + void + Manager::write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Boundary velocity interface", + out); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace BoundaryVelocity + { +#define INSTANTIATE(dim) \ + template class Interface; \ + template class Manager; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/boundary_velocity/zero_velocity.cc.bak b/source/boundary_velocity/zero_velocity.cc.bak new file mode 100644 index 00000000000..23b58e8e952 --- /dev/null +++ b/source/boundary_velocity/zero_velocity.cc.bak @@ -0,0 +1,54 @@ +/* + Copyright (C) 2011 - 2017 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + + +namespace aspect +{ + namespace BoundaryVelocity + { + template + Tensor<1,dim> + ZeroVelocity:: + boundary_velocity (const types::boundary_id , + const Point &) const + { + // return a zero tensor regardless of position + return Tensor<1,dim>(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace BoundaryVelocity + { + ASPECT_REGISTER_BOUNDARY_VELOCITY_MODEL(ZeroVelocity, + "zero velocity", + "Implementation of a model in which the boundary " + "velocity is zero. This is commonly referred to as " + "a ``stick boundary condition'', indicating that " + "the material ``sticks'' to the material on the " + "other side of the boundary.") + } +} diff --git a/source/citation_info.cc.bak b/source/citation_info.cc.bak new file mode 100644 index 00000000000..f047bab8f9a --- /dev/null +++ b/source/citation_info.cc.bak @@ -0,0 +1,55 @@ +/* + Copyright (C) 2017 - 2018 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + +#include +#include + +#include +#include + +namespace CitationInfo +{ + std::set citation_ids; + + const std::string get_url_part () + { + // version: + std::string url = "citing.html?ver="; + url += ASPECT_PACKAGE_VERSION; + + // all ids: + for (const auto &id : citation_ids) + url += "&" + id + "=1"; + + // sha1: + url += "&sha="; + url += ASPECT_GIT_SHORTREV; + + // src: + url += "&src=code"; + + return url; + } + + void add (const std::string &id) + { + citation_ids.insert(id); + } +} diff --git a/source/compat.cc.bak b/source/compat.cc.bak new file mode 100644 index 00000000000..bb71563d160 --- /dev/null +++ b/source/compat.cc.bak @@ -0,0 +1,800 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +// deal.II versions up to 9.5 had a poorly designed interface of the +// SphericalManifold class that made it impossible for us to use. +// This file thus contains a copy of it. +#if !DEAL_II_VERSION_GTE(9,6,0) + +namespace aspect +{ + namespace + { + template + bool + spherical_face_is_horizontal( + const typename Triangulation::face_iterator &face, + const Point &manifold_center) + { + // We test whether a face is horizontal by checking that the vertices + // all have roughly the same distance from the center: If the + // maximum deviation for the distances from the vertices to the + // center is less than 1.e-5 of the distance between vertices (as + // measured by the minimum distance from any of the other vertices + // to the first vertex), then we call this a horizontal face. + constexpr unsigned int n_vertices = + GeometryInfo::vertices_per_face; + std::array sqr_distances_to_center; + std::array sqr_distances_to_first_vertex; + sqr_distances_to_center[0] = + (face->vertex(0) - manifold_center).norm_square(); + for (unsigned int i = 1; i < n_vertices; ++i) + { + sqr_distances_to_center[i] = + (face->vertex(i) - manifold_center).norm_square(); + sqr_distances_to_first_vertex[i - 1] = + (face->vertex(i) - face->vertex(0)).norm_square(); + } + const auto minmax_sqr_distance = + std::minmax_element(sqr_distances_to_center.begin(), + sqr_distances_to_center.end()); + const auto min_sqr_distance_to_first_vertex = + std::min_element(sqr_distances_to_first_vertex.begin(), + sqr_distances_to_first_vertex.end()); + + return (*minmax_sqr_distance.second - *minmax_sqr_distance.first < + 1.e-10 * *min_sqr_distance_to_first_vertex); + } + } // namespace + + + // ============================================================ + // SphericalManifold + // ============================================================ + + template + SphericalManifold::SphericalManifold( + const Point center) + : center(center) + , polar_manifold(center) + {} + + + + template + std::unique_ptr> + SphericalManifold::clone() const + { + return std::make_unique>(*this); + } + + + + template + Point + SphericalManifold::get_intermediate_point( + const Point &p1, + const Point &p2, + const double w) const + { + const double tol = 1e-10; + + if ((p1 - p2).norm_square() < tol * tol || std::abs(w) < tol) + return p1; + else if (std::abs(w - 1.0) < tol) + return p2; + + // If the points are one dimensional then there is no need for anything but + // a linear combination. + if (spacedim == 1) + return Point(w * p2 + (1 - w) * p1); + + const Tensor<1, spacedim> v1 = p1 - center; + const Tensor<1, spacedim> v2 = p2 - center; + const double r1 = v1.norm(); + const double r2 = v2.norm(); + + Assert(r1 > tol && r2 > tol, + ExcMessage("p1 and p2 cannot coincide with the center.")); + + const Tensor<1, spacedim> e1 = v1 / r1; + const Tensor<1, spacedim> e2 = v2 / r2; + + // Find the cosine of the angle gamma described by v1 and v2. + const double cosgamma = e1 * e2; + + // Points are collinear with the center (allow for 8*eps as a tolerance) + if (cosgamma < -1 + 8. * std::numeric_limits::epsilon()) + return center; + + // Points are along a line, in which case e1 and e2 are essentially the same. + if (cosgamma > 1 - 8. * std::numeric_limits::epsilon()) + return Point(center + w * v2 + (1 - w) * v1); + + // Find the angle sigma that corresponds to arclength equal to w. acos + // should never be undefined because we have ruled out the two special cases + // above. + const double sigma = w * std::acos(cosgamma); + + // Normal to v1 in the plane described by v1,v2,and the origin. + // Since p1 and p2 do not coincide n is not zero and well defined. + Tensor<1, spacedim> n = v2 - (v2 * e1) * e1; + const double n_norm = n.norm(); + Assert(n_norm > 0, + ExcInternalError("n should be different from the null vector. " + "Probably, this means v1==v2 or v2==0.")); + + n /= n_norm; + + // Find the point Q along O,v1 such that + // P1,V,P2 has measure sigma. + const Tensor<1, spacedim> P = std::cos(sigma) * e1 + std::sin(sigma) * n; + + // Project this point on the manifold. + return Point(center + (w * r2 + (1.0 - w) * r1) * P); + } + + + + template + Tensor<1, spacedim> + SphericalManifold::get_tangent_vector( + const Point &p1, + const Point &p2) const + { + const double tol = 1e-10; + (void)tol; + + Assert(p1 != p2, ExcMessage("p1 and p2 should not concide.")); + + const Tensor<1, spacedim> v1 = p1 - center; + const Tensor<1, spacedim> v2 = p2 - center; + const double r1 = v1.norm(); + const double r2 = v2.norm(); + + Assert(r1 > tol, ExcMessage("p1 cannot coincide with the center.")); + + Assert(r2 > tol, ExcMessage("p2 cannot coincide with the center.")); + + const Tensor<1, spacedim> e1 = v1 / r1; + const Tensor<1, spacedim> e2 = v2 / r2; + + // Find the cosine of the angle gamma described by v1 and v2. + const double cosgamma = e1 * e2; + + Assert(cosgamma > -1 + 8. * std::numeric_limits::epsilon(), + ExcMessage("p1 and p2 cannot lie on the same diameter and be opposite " + "respect to the center.")); + + if (cosgamma > 1 - 8. * std::numeric_limits::epsilon()) + return v2 - v1; + + // Normal to v1 in the plane described by v1,v2,and the origin. + // Since p1 and p2 do not coincide n is not zero and well defined. + Tensor<1, spacedim> n = v2 - (v2 * e1) * e1; + const double n_norm = n.norm(); + Assert(n_norm > 0, + ExcInternalError("n should be different from the null vector. " + "Probably, this means v1==v2 or v2==0.")); + + n /= n_norm; + + // this is the derivative of the geodesic in get_intermediate_point + // derived with respect to w and inserting w=0. + const double gamma = std::acos(cosgamma); + return (r2 - r1) * e1 + r1 * gamma * n; + } + + + + template + Tensor<1, spacedim> + SphericalManifold::normal_vector( + const typename Triangulation::face_iterator &face, + const Point &p) const + { + // Let us first test whether we are on a "horizontal" face + // (tangential to the sphere). In this case, the normal vector is + // easy to compute since it is proportional to the vector from the + // center to the point 'p'. + if (spherical_face_is_horizontal(face, center)) + { + // So, if this is a "horizontal" face, then just compute the normal + // vector as the one from the center to the point 'p', adequately + // scaled. + const Tensor<1, spacedim> unnormalized_spherical_normal = p - center; + const Tensor<1, spacedim> normalized_spherical_normal = + unnormalized_spherical_normal / unnormalized_spherical_normal.norm(); + return normalized_spherical_normal; + } + else + // If it is not a horizontal face, just use the machinery of the + // base class. + return Manifold::normal_vector(face, p); + + return Tensor<1, spacedim>(); + } + + + + template <> + void + SphericalManifold<1, 1>::get_normals_at_vertices( + const Triangulation<1>::face_iterator &, + Manifold<1, 1>::FaceVertexNormals &) const + { + Assert(false, ExcImpossibleInDim(1)); + } + + + + template <> + void + SphericalManifold<1, 2>::get_normals_at_vertices( + const Triangulation<1, 2>::face_iterator &, + Manifold<1, 2>::FaceVertexNormals &) const + { + Assert(false, ExcImpossibleInDim(1)); + } + + + + template + void + SphericalManifold::get_normals_at_vertices( + const typename Triangulation::face_iterator &face, + typename Manifold::FaceVertexNormals &face_vertex_normals) + const + { + // Let us first test whether we are on a "horizontal" face + // (tangential to the sphere). In this case, the normal vector is + // easy to compute since it is proportional to the vector from the + // center to the point 'p'. + if (spherical_face_is_horizontal(face, center)) + { + // So, if this is a "horizontal" face, then just compute the normal + // vector as the one from the center to the point 'p', adequately + // scaled. + for (unsigned int vertex = 0; + vertex < GeometryInfo::vertices_per_face; + ++vertex) + face_vertex_normals[vertex] = face->vertex(vertex) - center; + } + else + Manifold::get_normals_at_vertices(face, face_vertex_normals); + } + + + + template + void + SphericalManifold::get_new_points( + const ArrayView> &surrounding_points, + const Table<2, double> &weights, + ArrayView> new_points) const + { + AssertDimension(new_points.size(), weights.size(0)); + AssertDimension(surrounding_points.size(), weights.size(1)); + + do_get_new_points(surrounding_points, make_array_view(weights), new_points); + + return; + } + + + + template + Point + SphericalManifold::get_new_point( + const ArrayView> &vertices, + const ArrayView &weights) const + { + // To avoid duplicating all of the logic in get_new_points, simply call it + // for one position. + Point new_point; + do_get_new_points(vertices, + weights, + make_array_view(&new_point, &new_point + 1)); + + return new_point; + } + + + + namespace internal + { + // Rotate a given unit vector u around the axis dir + // where the angle is given by the length of dir. + // This is the exponential map for a sphere. + Tensor<1, 3> + apply_exponential_map(const Tensor<1, 3> &u, const Tensor<1, 3> &dir) + { + const double theta = dir.norm(); + if (theta < 1.e-10) + { + return u; + } + else + { + const Tensor<1, 3> dirUnit = dir / theta; + const Tensor<1, 3> tmp = + std::cos(theta) * u + std::sin(theta) * dirUnit; + return tmp / tmp.norm(); + } + } + + + // Returns the direction to go from v to u + // projected to the plane perpendicular to the unit vector v. + // This one is more stable when u and v are nearly equal. + Tensor<1, 3> + projected_direction(const Tensor<1, 3> &u, const Tensor<1, 3> &v) + { + Tensor<1, 3> ans = u - v; + ans -= (ans * v) * v; + return ans; // ans = (u-v) - ((u-v)*v)*v + } + + + // helper function to compute a vector orthogonal to a given one. + // does nothing unless spacedim == 3. + template + Point + compute_normal(const Tensor<1, spacedim> & /*vector*/, + bool /*normalize*/ = false) + { + return {}; + } + + Point<3> + compute_normal(const Tensor<1, 3> &vector, bool normalize = false) + { + Assert(vector.norm_square() != 0., + ExcMessage("The direction parameter must not be zero!")); + Point<3> normal; + if (std::abs(vector[0]) >= std::abs(vector[1]) && + std::abs(vector[0]) >= std::abs(vector[2])) + { + normal[1] = -1.; + normal[2] = -1.; + normal[0] = (vector[1] + vector[2]) / vector[0]; + } + else if (std::abs(vector[1]) >= std::abs(vector[0]) && + std::abs(vector[1]) >= std::abs(vector[2])) + { + normal[0] = -1.; + normal[2] = -1.; + normal[1] = (vector[0] + vector[2]) / vector[1]; + } + else + { + normal[0] = -1.; + normal[1] = -1.; + normal[2] = (vector[0] + vector[1]) / vector[2]; + } + if (normalize) + normal /= normal.norm(); + return normal; + } + + + namespace SphericalManifold + { + namespace + { + template + Point + do_get_new_point( + const ArrayView> & /*directions*/, + const ArrayView & /*distances*/, + const ArrayView & /*weights*/, + const Point & /*candidate_point*/) + { + Assert(false, ExcNotImplemented()); + return {}; + } + + template <> + Point<3> + do_get_new_point(const ArrayView> &directions, + const ArrayView &distances, + const ArrayView &weights, + const Point<3> &candidate_point) + { + (void)distances; + + AssertDimension(directions.size(), distances.size()); + AssertDimension(directions.size(), weights.size()); + + Point<3> candidate = candidate_point; + const unsigned int n_merged_points = directions.size(); + const double tolerance = 1e-10; + const int max_iterations = 10; + + { + // If the candidate happens to coincide with a normalized + // direction, we return it. Otherwise, the Hessian would be singular. + for (unsigned int i = 0; i < n_merged_points; ++i) + { + const double squared_distance = + (candidate - directions[i]).norm_square(); + if (squared_distance < tolerance * tolerance) + return candidate; + } + + // check if we only have two points now, in which case we can use the + // get_intermediate_point function + if (n_merged_points == 2) + { + static const dealii::SphericalManifold<3, 3> unit_manifold; + Assert(std::abs(weights[0] + weights[1] - 1.0) < 1e-13, + ExcMessage("Weights do not sum up to 1")); + const Point<3> intermediate = + unit_manifold.get_intermediate_point(Point<3>(directions[0]), + Point<3>(directions[1]), + weights[1]); + return intermediate; + } + + Tensor<1, 3> vPerp; + Tensor<2, 2> Hessian; + Tensor<1, 2> gradient; + Tensor<1, 2> gradlocal; + + // On success we exit the loop early. + // Otherwise, we just take the result after max_iterations steps. + for (unsigned int i = 0; i < max_iterations; ++i) + { + // Step 2a: Find new descent direction + + // Get local basis for the estimate candidate + const Tensor<1, 3> Clocalx = internal::compute_normal(candidate); + const Tensor<1, 3> Clocaly = cross_product_3d(candidate, Clocalx); + + // For each vertices vector, compute the tangent vector from + // candidate towards the vertices vector -- its length is the + // spherical length from candidate to the vertices vector. Then + // compute its contribution to the Hessian. + gradient = 0.; + Hessian = 0.; + for (unsigned int i = 0; i < n_merged_points; ++i) + if (std::abs(weights[i]) > 1.e-15) + { + vPerp = + internal::projected_direction(directions[i], candidate); + const double sinthetaSq = vPerp.norm_square(); + const double sintheta = std::sqrt(sinthetaSq); + if (sintheta < tolerance) + { + Hessian[0][0] += weights[i]; + Hessian[1][1] += weights[i]; + } + else + { + const double costheta = (directions[i]) * candidate; + const double theta = std::atan2(sintheta, costheta); + const double sincthetaInv = theta / sintheta; + + const double cosphi = vPerp * Clocalx; + const double sinphi = vPerp * Clocaly; + + gradlocal[0] = cosphi; + gradlocal[1] = sinphi; + gradient += (weights[i] * sincthetaInv) * gradlocal; + + const double wt = weights[i] / sinthetaSq; + const double sinphiSq = sinphi * sinphi; + const double cosphiSq = cosphi * cosphi; + const double tt = sincthetaInv * costheta; + const double offdiag = + cosphi * sinphi * wt * (1.0 - tt); + Hessian[0][0] += wt * (cosphiSq + tt * sinphiSq); + Hessian[0][1] += offdiag; + Hessian[1][0] += offdiag; + Hessian[1][1] += wt * (sinphiSq + tt * cosphiSq); + } + } + + Assert(determinant(Hessian) > tolerance, ExcInternalError()); + + const Tensor<2, 2> inverse_Hessian = invert(Hessian); + + const Tensor<1, 2> xDisplocal = inverse_Hessian * gradient; + const Tensor<1, 3> xDisp = + xDisplocal[0] * Clocalx + xDisplocal[1] * Clocaly; + + // Step 2b: rotate candidate in direction xDisp for a new + // candidate. + const Point<3> candidateOld = candidate; + candidate = + Point<3>(internal::apply_exponential_map(candidate, xDisp)); + + // Step 2c: return the new candidate if we didn't move + if ((candidate - candidateOld).norm_square() < + tolerance * tolerance) + break; + } + } + return candidate; + } + } // namespace + } // namespace SphericalManifold + } // namespace internal + + + + template + void + SphericalManifold::do_get_new_points( + const ArrayView> &surrounding_points, + const ArrayView &weights, + ArrayView> new_points) const + { + AssertDimension(weights.size(), + new_points.size() * surrounding_points.size()); + const unsigned int weight_rows = new_points.size(); + const unsigned int weight_columns = surrounding_points.size(); + + if (surrounding_points.size() == 2) + { + for (unsigned int row = 0; row < weight_rows; ++row) + new_points[row] = + SphericalManifold::get_intermediate_point(surrounding_points[0], + surrounding_points[1], + weights[row * weight_columns + 1]); + return; + } + + boost::container::small_vector>, 100> + new_candidates(new_points.size()); + boost::container::small_vector, 100> directions( + surrounding_points.size(), Point()); + boost::container::small_vector distances( + surrounding_points.size(), 0.0); + double max_distance = 0.; + for (unsigned int i = 0; i < surrounding_points.size(); ++i) + { + directions[i] = surrounding_points[i] - center; + distances[i] = directions[i].norm(); + + if (distances[i] != 0.) + directions[i] /= distances[i]; + else + Assert(false, + ExcMessage("One of the vertices coincides with the center. " + "This is not allowed!")); + + // Check if an estimate is good enough, + // this is often the case for sufficiently refined meshes. + for (unsigned int k = 0; k < i; ++k) + { + const double squared_distance = + (directions[i] - directions[k]).norm_square(); + max_distance = std::max(max_distance, squared_distance); + } + } + + // Step 1: Check for some special cases, create simple linear guesses + // otherwise. + const double tolerance = 1e-10; + boost::container::small_vector accurate_point_was_found( + new_points.size(), false); + const ArrayView> array_directions = + make_array_view(directions.begin(), directions.end()); + const ArrayView array_distances = + make_array_view(distances.begin(), distances.end()); + for (unsigned int row = 0; row < weight_rows; ++row) + { + new_candidates[row] = + guess_new_point(array_directions, + array_distances, + ArrayView(&weights[row * weight_columns], + weight_columns)); + + // If the candidate is the center, mark it as found to avoid entering + // the Newton iteration in step 2, which would crash. + if (new_candidates[row].first == 0.0) + { + new_points[row] = center; + accurate_point_was_found[row] = true; + continue; + } + + // If not in 3d, just use the implementation from PolarManifold + // after we verified that the candidate is not the center. + if (spacedim < 3) + new_points[row] = polar_manifold.get_new_point( + surrounding_points, + ArrayView(&weights[row * weight_columns], + weight_columns)); + } + + // In this case, we treated the case that the candidate is the center and + // obtained the new locations from the PolarManifold object otherwise. + if (spacedim < 3) + return; + else + { + // If all the points are close to each other, we expect the estimate to + // be good enough. This tolerance was chosen such that the first iteration + // for a at least three time refined HyperShell mesh with radii .5 and 1. + // doesn't already succeed. + if (max_distance < 2e-2) + { + for (unsigned int row = 0; row < weight_rows; ++row) + new_points[row] = + center + new_candidates[row].first * new_candidates[row].second; + + return; + } + + // Step 2: + // Do more expensive Newton-style iterations to improve the estimate. + + // Search for duplicate directions and merge them to minimize the cost of + // the get_new_point function call below. + boost::container::small_vector merged_weights( + weights.size()); + boost::container::small_vector, 100> + merged_directions(surrounding_points.size(), Point()); + boost::container::small_vector merged_distances( + surrounding_points.size(), 0.0); + + unsigned int n_unique_directions = 0; + for (unsigned int i = 0; i < surrounding_points.size(); ++i) + { + bool found_duplicate = false; + + // This inner loop is of $O(N^2)$ complexity, but + // surrounding_points.size() is usually at most 8 points large. + for (unsigned int j = 0; j < n_unique_directions; ++j) + { + const double squared_distance = + (directions[i] - directions[j]).norm_square(); + if (!found_duplicate && squared_distance < 1e-28) + { + found_duplicate = true; + for (unsigned int row = 0; row < weight_rows; ++row) + merged_weights[row * weight_columns + j] += + weights[row * weight_columns + i]; + } + } + + if (found_duplicate == false) + { + merged_directions[n_unique_directions] = directions[i]; + merged_distances[n_unique_directions] = distances[i]; + for (unsigned int row = 0; row < weight_rows; ++row) + merged_weights[row * weight_columns + n_unique_directions] = + weights[row * weight_columns + i]; + + ++n_unique_directions; + } + } + + // Search for duplicate weight rows and merge them to minimize the cost of + // the get_new_point function call below. + boost::container::small_vector merged_weights_index( + new_points.size(), numbers::invalid_unsigned_int); + for (unsigned int row = 0; row < weight_rows; ++row) + { + for (unsigned int existing_row = 0; existing_row < row; + ++existing_row) + { + bool identical_weights = true; + + for (unsigned int weight_index = 0; + weight_index < n_unique_directions; + ++weight_index) + if (std::abs( + merged_weights[row * weight_columns + weight_index] - + merged_weights[existing_row * weight_columns + + weight_index]) > tolerance) + { + identical_weights = false; + break; + } + + if (identical_weights) + { + merged_weights_index[row] = existing_row; + break; + } + } + } + + // Note that we only use the n_unique_directions first entries in the + // ArrayView + const ArrayView> array_merged_directions = + make_array_view(merged_directions.begin(), + merged_directions.begin() + n_unique_directions); + const ArrayView array_merged_distances = + make_array_view(merged_distances.begin(), + merged_distances.begin() + n_unique_directions); + + for (unsigned int row = 0; row < weight_rows; ++row) + if (!accurate_point_was_found[row]) + { + if (merged_weights_index[row] == numbers::invalid_unsigned_int) + { + const ArrayView array_merged_weights( + &merged_weights[row * weight_columns], n_unique_directions); + new_candidates[row].second = + internal::SphericalManifold::do_get_new_point( + array_merged_directions, + array_merged_distances, + array_merged_weights, + Point(new_candidates[row].second)); + } + else + new_candidates[row].second = + new_candidates[merged_weights_index[row]].second; + + new_points[row] = + center + new_candidates[row].first * new_candidates[row].second; + } + } + } + + + + template + std::pair> + SphericalManifold::guess_new_point( + const ArrayView> &directions, + const ArrayView &distances, + const ArrayView &weights) const + { + const double tolerance = 1e-10; + double rho = 0.; + Tensor<1, spacedim> candidate; + + // Perform a simple average ... + double total_weights = 0.; + for (unsigned int i = 0; i < directions.size(); ++i) + { + // if one weight is one, return its direction + if (std::abs(1 - weights[i]) < tolerance) + return std::make_pair(distances[i], directions[i]); + + rho += distances[i] * weights[i]; + candidate += directions[i] * weights[i]; + total_weights += weights[i]; + } + + // ... and normalize if the candidate is different from the origin. + const double norm = candidate.norm(); + if (norm == 0.) + return std::make_pair(0.0, Point()); + candidate /= norm; + rho /= total_weights; + + return std::make_pair(rho, candidate); + } + + + template class SphericalManifold<2>; + template class SphericalManifold<3>; +} + +#endif diff --git a/source/fe_variable_collection.cc.bak b/source/fe_variable_collection.cc.bak new file mode 100644 index 00000000000..ef8b9030d77 --- /dev/null +++ b/source/fe_variable_collection.cc.bak @@ -0,0 +1,268 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#include +#include + +namespace aspect +{ + + + + template + VariableDeclaration::VariableDeclaration(const std::string &name, + const std::shared_ptr> &fe, + const unsigned int multiplicity, + const unsigned int n_blocks) + : name(name), + fe(fe), + multiplicity(multiplicity), + n_blocks(n_blocks) + { + // TODO: non-scalar FEs are not tested and can not be split into >1 block in general + Assert(fe->n_components() == 1, ExcNotImplemented()); + + Assert(n_blocks == 0 + || n_blocks == 1 + || n_blocks == n_components(), + ExcMessage("A Variable can only have 0, 1, or n_components() number of blocks.")); + } + + template + VariableDeclaration::VariableDeclaration() + = default; + + template + unsigned int + VariableDeclaration::n_components() const + { + return fe->n_components() * multiplicity; + } + + + template + FEVariable::FEVariable(const VariableDeclaration &fe_variable, + const unsigned int component_index, + const unsigned int block_index, + const unsigned int base_index) + : VariableDeclaration (fe_variable), + first_component_index (component_index), + block_index (block_index), + base_index (base_index), + scalar_extractor ( (this->n_components()==1) ? component_index : -1), + vector_extractor ( (this->n_components()==dim) ? component_index : -1) + {} + + + + template + const FEValuesExtractors::Scalar & + FEVariable::extractor_scalar() const + { + Assert(this->n_components()==1, + ExcMessage("You cannot ask for the scalar extractor of a non-scalar variable.")); + return scalar_extractor; + } + + + + template + const FEValuesExtractors::Vector & + FEVariable::extractor_vector() const + { + Assert(this->n_components()==dim, + ExcMessage("You cannot ask for the vector extractor of a variable that is not a vector.")); + return vector_extractor; + } + + + + template + FEVariableCollection::FEVariableCollection() + = default; + + + + template + FEVariableCollection::FEVariableCollection(const std::vector> &variable_definitions) + { + initialize(variable_definitions); + } + + + + template + void + FEVariableCollection::initialize(const std::vector> &variable_definitions) + { + variables.clear(); + variables.reserve(variable_definitions.size()); + + unsigned int component_index = 0; + unsigned int block_index = 0; + + for (unsigned int i=0; i(variable_definitions[i], + component_index, block_index, i)); + component_index+= variables[i].n_components(); + block_index += variables[i].n_blocks; + } + + Assert(variables.back().n_blocks != 0 + || variables.back().n_components() == 0, + ExcMessage("The last variable needs to have >0 blocks.")); + + n_components_ = component_index; + n_blocks_ = block_index; + + fes.resize(variables.size()); + multiplicities.resize(variables.size()); + for (unsigned int i=0; i1)?c:0)); + } + Assert(components_to_blocks.size() == n_components(), ExcInternalError()); + + Assert(fes.size() == variables.size(), ExcInternalError()); + Assert(multiplicities.size() == variables.size(), ExcInternalError()); + } + + + + template + const FEVariable & + FEVariableCollection::variable(const std::string &name) const + { + for (unsigned int i=0; i + std::vector*> + FEVariableCollection::variables_with_name(const std::string &name) const + { + std::vector*> result; + for (unsigned int i=0; i + bool + FEVariableCollection::variable_exists(const std::string &name) const + { + for (unsigned int i=0; i + const std::vector> & + FEVariableCollection::get_variables() const + { + return variables; + } + + + + template + unsigned int + FEVariableCollection::n_components() const + { + return n_components_; + } + + + + template + unsigned int + FEVariableCollection::n_blocks() const + { + return n_blocks_; + } + + + + template + const std::vector *> & + FEVariableCollection::get_fes() const + { + return fes; + } + + + template + const std::vector & + FEVariableCollection::get_multiplicities() const + { + return multiplicities; + } + + + template + const std::vector & + FEVariableCollection::get_components_to_blocks() const + { + return components_to_blocks; + } +} + + +// explicit instantiations +namespace aspect +{ +#define INSTANTIATE(dim) \ + template struct VariableDeclaration; \ + template struct FEVariable; \ + template class FEVariableCollection; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE +} diff --git a/source/geometry_model/box.cc.bak b/source/geometry_model/box.cc.bak new file mode 100644 index 00000000000..882efeb7e68 --- /dev/null +++ b/source/geometry_model/box.cc.bak @@ -0,0 +1,524 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace aspect +{ + namespace GeometryModel + { + template + void + Box::initialize () + { + // Get pointer to initial topography model + topo_model = const_cast*>(&this->get_initial_topography_model()); + + // Check that initial topography is required. + // If so, connect the initial topography function + // to the right signals: It should be applied after + // the final initial adaptive refinement and after a restart. + if (Plugins::plugin_type_matches>(*topo_model) == false) + { + this->get_signals().pre_set_initial_state.connect( + [&](typename parallel::distributed::Triangulation &tria) + { + this->topography(tria); + } + ); + this->get_signals().post_resume_load_user_data.connect( + [&](typename parallel::distributed::Triangulation &tria) + { + this->topography(tria); + } + ); + } + } + + + template + void + Box:: + create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const + { + const std::vector rep_vec(repetitions.begin(), repetitions.end()); + GridGenerator::subdivided_hyper_rectangle (coarse_grid, + rep_vec, + box_origin, + box_origin+extents, + true); + + // Tell p4est about the periodicity of the mesh. + std::vector::cell_iterator>> + periodicity_vector; + for (int i=0; i 0) + coarse_grid.add_periodicity (periodicity_vector); + } + + template + void + Box:: + topography (typename parallel::distributed::Triangulation &grid) const + { + // Here we provide GridTools with the function to displace vertices + // in the vertical direction by an amount specified by the initial topography model + GridTools::transform( + [&](const Point &p) -> Point + { + return this->add_topography(p); + }, + grid); + + this->get_pcout() << " Added initial topography to grid" << std::endl << std::endl; + } + + + template + Point + Box:: + add_topography (const Point &x_y_z) const + { + // Get the surface x (,y) point + Point surface_point; + for (unsigned int d=0; dvalue(surface_point); + + // Compute the displacement of the z coordinate + const double ztopo = (x_y_z[dim-1] - box_origin[dim-1]) / extents[dim-1] * topo; + + // Compute the new point + Point x_y_ztopo = x_y_z; + x_y_ztopo[dim-1] += ztopo; + + return x_y_ztopo; + } + + + template + std::set + Box:: + get_used_boundary_indicators () const + { + // boundary indicators are zero through 2*dim-1 + std::set s; + for (unsigned int i=0; i<2*dim; ++i) + s.insert (i); + return s; + } + + + template + std::map + Box:: + get_symbolic_boundary_names_map () const + { + switch (dim) + { + case 2: + { + return + { + {"left", 0}, + {"right", 1}, + {"bottom", 2}, + {"top", 3} + }; + } + + case 3: + { + return + { + {"left", 0}, + {"right", 1}, + {"front", 2}, + {"back", 3}, + {"bottom", 4}, + {"top", 5} + + }; + } + } + + Assert (false, ExcNotImplemented()); + return {}; + } + + + template + std::set, unsigned int>> + Box:: + get_periodic_boundary_pairs () const + { + std::set, unsigned int>> periodic_boundaries; + for ( unsigned int i=0; i(2*i, 2*i+1), i) ); + return periodic_boundaries; + } + + + + template + void + Box::adjust_positions_for_periodicity (Point &position, + const ArrayView> &connected_positions, + const ArrayView> &/*connected_velocities*/) const + { + for (unsigned int i = 0; i < dim; ++i) + if (periodic[i]) + { + if (position[i] < box_origin[i]) + { + position[i] += extents[i]; + for (auto &connected_position: connected_positions) + connected_position[i] += extents[i]; + } + else if (position[i] > box_origin[i] + extents[i]) + { + position[i] -= extents[i]; + for (auto &connected_position: connected_positions) + connected_position[i] -= extents[i]; + } + } + } + + + + template + Point + Box::get_extents () const + { + return extents; + } + + template + const std::array & + Box::get_repetitions () const + { + return repetitions; + } + + template + Point + Box::get_origin () const + { + return box_origin; + } + + template + double + Box:: + length_scale () const + { + return 0.01*extents[0]; + } + + + template + double + Box::depth(const Point &position) const + { + // Get the surface x (,y) point + Point surface_point; + for (unsigned int d=0; dvalue(surface_point); + + const double d = extents[dim-1] + topo - (position(dim-1)-box_origin[dim-1]); + return std::min (std::max (d, 0.), maximal_depth()); + } + + + template + double + Box::height_above_reference_surface(const Point &position) const + { + return (position(dim-1)-box_origin[dim-1]) - extents[dim-1]; + } + + + template + Point + Box::representative_point(const double depth) const + { + Assert (depth >= 0, + ExcMessage ("Given depth must be positive or zero.")); + Assert (depth <= maximal_depth(), + ExcMessage ("Given depth must be less than or equal to the maximal depth of this geometry.")); + + // choose a point on the center axis of the domain (without topography) + Point p = extents/2+box_origin; + + // We need a dim-1 point to get the topo value. + Point surface_point; + for (unsigned int d=0; dvalue(surface_point); + p[dim-1] = extents[dim-1]+box_origin[dim-1]-depth+topo; + + return p; + } + + + template + double + Box::maximal_depth() const + { + return extents[dim-1] + topo_model->max_topography(); + } + + template + bool + Box::has_curved_elements() const + { + return false; + } + + template + bool + Box::point_is_in_domain(const Point &point) const + { + // If mesh deformation is enabled, we have to loop over all the current + // grid cells to see if the given point lies in the domain. + // If mesh deformation is not enabled, or has not happened yet, + // we can use the global extents of the model domain with or without + // initial topography instead. + // This function only checks if the given point lies in the domain + // in its current shape at the current time. It can be called before + // mesh deformation is applied in the first timestep (e.g., by the boundary + // traction plugins), and therefore there is no guarantee + // that the point will still lie in the domain after initial mesh deformation. + if (this->get_parameters().mesh_deformation_enabled && + this->simulator_is_past_initialization()) + { + return Utilities::point_is_in_triangulation(this->get_mapping(), + this->get_triangulation(), + point, + this->get_mpi_communicator()); + } + // Without mesh deformation enabled, it is much cheaper to check whether the point lies in the domain. + else + { + // The maximal extents of the unperturbed box domain. + Point max_point = extents+box_origin; + + // If mesh deformation is not enabled, but initial topography + // was/will be applied to the mesh, include this topography in the + // extent of the domain. + if (!Plugins::plugin_type_matches>(this->get_initial_topography_model())) + { + // Get the surface x (,y) point + Point surface_point; + for (unsigned int d=0; dvalue(surface_point); + max_point[dim-1] += topo; + } + + // Check whether point lies within the min/max coordinates of the domain including initial topography. + for (unsigned int d = 0; d < dim; ++d) + if (point[d] > max_point[d]+std::numeric_limits::epsilon()*extents[d] || + point[d] < box_origin[d]-std::numeric_limits::epsilon()*extents[d]) + return false; + + return true; + } + } + + template + std::array + Box::cartesian_to_natural_coordinates(const Point &position_point) const + { + std::array position_array; + for (unsigned int i = 0; i < dim; ++i) + position_array[i] = position_point(i); + + return position_array; + } + + + template + aspect::Utilities::Coordinates::CoordinateSystem + Box::natural_coordinate_system() const + { + return aspect::Utilities::Coordinates::CoordinateSystem::cartesian; + } + + + template + Point + Box::natural_to_cartesian_coordinates(const std::array &position_tensor) const + { + Point position_point; + for (unsigned int i = 0; i < dim; ++i) + position_point[i] = position_tensor[i]; + + return position_point; + } + + + template + void + Box:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Box"); + { + prm.declare_entry ("X extent", "1.", + Patterns::Double (0.), + "Extent of the box in x-direction. Units: \\si{\\meter}."); + prm.declare_entry ("Y extent", "1.", + Patterns::Double (0.), + "Extent of the box in y-direction. Units: \\si{\\meter}."); + prm.declare_entry ("Z extent", "1.", + Patterns::Double (0.), + "Extent of the box in z-direction. This value is ignored " + "if the simulation is in 2d. Units: \\si{\\meter}."); + + prm.declare_entry ("Box origin X coordinate", "0.", + Patterns::Double (), + "X coordinate of box origin. Units: \\si{\\meter}."); + prm.declare_entry ("Box origin Y coordinate", "0.", + Patterns::Double (), + "Y coordinate of box origin. Units: \\si{\\meter}."); + prm.declare_entry ("Box origin Z coordinate", "0.", + Patterns::Double (), + "Z coordinate of box origin. This value is ignored " + "if the simulation is in 2d. Units: \\si{\\meter}."); + + prm.declare_entry ("X repetitions", "1", + Patterns::Integer (1), + "Number of cells in X direction."); + prm.declare_entry ("Y repetitions", "1", + Patterns::Integer (1), + "Number of cells in Y direction."); + prm.declare_entry ("Z repetitions", "1", + Patterns::Integer (1), + "Number of cells in Z direction."); + + prm.declare_entry ("X periodic", "false", + Patterns::Bool (), + "Whether the box should be periodic in X direction"); + prm.declare_entry ("Y periodic", "false", + Patterns::Bool (), + "Whether the box should be periodic in Y direction"); + prm.declare_entry ("Z periodic", "false", + Patterns::Bool (), + "Whether the box should be periodic in Z direction"); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + Box::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Box"); + { + box_origin[0] = prm.get_double ("Box origin X coordinate"); + extents[0] = prm.get_double ("X extent"); + periodic[0] = prm.get_bool ("X periodic"); + repetitions[0] = prm.get_integer ("X repetitions"); + + if (dim >= 2) + { + box_origin[1] = prm.get_double ("Box origin Y coordinate"); + extents[1] = prm.get_double ("Y extent"); + periodic[1] = prm.get_bool ("Y periodic"); + repetitions[1] = prm.get_integer ("Y repetitions"); + } + + if (dim >= 3) + { + // Use dim-1 instead of 2 to avoid compiler warning in 2d: + box_origin[dim-1] = prm.get_double ("Box origin Z coordinate"); + extents[dim-1] = prm.get_double ("Z extent"); + periodic[dim-1] = prm.get_bool ("Z periodic"); + repetitions[dim-1] = prm.get_integer ("Z repetitions"); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + + +// explicit instantiations +namespace aspect +{ + namespace GeometryModel + { + ASPECT_REGISTER_GEOMETRY_MODEL(Box, + "box", + "A box geometry parallel to the coordinate directions. " + "The extent of the box in each coordinate direction " + "is set in the parameter file. The box geometry labels its " + "2*dim sides as follows: in 2d, boundary indicators 0 through 3 " + "denote the left, right, bottom and top boundaries; in 3d, boundary " + "indicators 0 through 5 indicate left, right, front, back, bottom " + "and top boundaries (see also the documentation of the deal.II class " + "``ReferenceCell''). You can also use symbolic names ``left'', ``right'', " + "etc., to refer to these boundaries in input files. " + "It is also possible to add initial topography to the box model. Note however that " + "this is done after the last initial adaptive refinement cycle. " + "Also, initial topography is supposed to be small, as it is not taken into account " + "when depth or a representative point is computed. ") + + + } +} diff --git a/source/geometry_model/chunk.cc.bak b/source/geometry_model/chunk.cc.bak new file mode 100644 index 00000000000..b81fbeb7ad3 --- /dev/null +++ b/source/geometry_model/chunk.cc.bak @@ -0,0 +1,949 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +namespace aspect +{ + namespace GeometryModel + { + namespace internal + { + template + ChunkGeometry::ChunkGeometry(const InitialTopographyModel::Interface &topo, + const double min_longitude, + const double min_radius, + const double max_depth) + : + topo (&topo), + point1_lon(min_longitude), + inner_radius(min_radius), + max_depth(max_depth) + {} + + + + template + DerivativeForm<1,dim,dim> + ChunkGeometry:: + push_forward_gradient(const Point &chart_point) const + { + const double R = chart_point[0]; // Radius + + Assert (R > 0.0, ExcMessage("Negative radius for given point.")); + + Tensor<2,dim> DX; + + // We only have access to the topography gradients + // (dtopo/dphi and dtopo/dtheta) for the AsciiData + // initial topography model. We assume 0.0 otherwise; + // while this is valid for the ZeroTopography model, + // this will result in incorrect gradients for + // other initial topography models. Hence only AsciiData + // and ZeroTopography are allowed for now in Chunk::initialize(). + Tensor<1,dim-1> topo_derivatives; + if (const InitialTopographyModel::AsciiData *itm = dynamic_cast *> (topo)) + topo_derivatives = itm->vector_gradient(push_forward_sphere(chart_point)); + else if (dynamic_cast *> (topo)) + { + // Gradient is zero (which it is already initialized to from before) + } + else + Assert (false, ExcNotImplemented()); + + // Construct surface point in lon(,lat) coordinates + Point surface_point; + for (unsigned int d=0; dvalue(surface_point); + + // get the spherical point including topography + const Point topo_point = push_forward_topo(chart_point); + const double R_topo = topo_point[0]; + const double phi_topo = topo_point[1]; + + // The derivatives of topo_point to chart_point + Tensor<2, dim> Dtopo; + // The derivatives of the cartesian point to chart_point + DerivativeForm<1, dim, dim> Dtotal; + + + switch (dim) + { + case 2: + { + // R_topo = R + topo(phi) * ((R-R_0)/(R_1-R_0)) = R + topo(phi) * ((R-R_0)/max_depth) + // phi_topo = phi + //dR_topo/dR + Dtopo[0][0] = (d_topo / max_depth) + 1.; + //dR_topo/dphi = dR_topo/dtopo * dtopo/dphi + Dtopo[0][1] = (R-inner_radius)/max_depth * topo_derivatives[0]; + //dphi_topo/dR + Dtopo[1][0] = 0.; + //dphi_topo/dphi + Dtopo[1][1] = 1.; + + //dx/dR_topo + DX[0][0] = std::cos(phi_topo); + //dx/dphi_topo + DX[0][1] = -R_topo * std::sin(phi_topo); + //dy/dR_topo + DX[1][0] = std::sin(phi_topo); + //dy/dphi_topo + DX[1][1] = R_topo * std::cos(phi_topo); + + break; + } + case 3: + { + // R_topo = R + topo(phi,theta) * ((R-R_0)/(R_1-R_0)) + // phi_topo = phi + // theta_topo = theta + //dR_topo/dR + Dtopo[0][0] = (d_topo / max_depth) + 1.; + //dR_topo/dphi + Dtopo[0][1] = (R - inner_radius) / max_depth * topo_derivatives[0]; + //dR_topo/dtheta + Dtopo[0][2] = (R - inner_radius) / max_depth * topo_derivatives[1]; + //dphi_topo/dR + Dtopo[1][0] = 0.; + //dphi_topo/dphi + Dtopo[1][1] = 1.; + //dphi_topo/dtheta + Dtopo[1][2] = 0.; + //dtheta_topo/dR + Dtopo[2][0] = 0.; + //dtheta_topo/dphi + Dtopo[2][1] = 0.; + //dtheta_topo/dtheta + Dtopo[2][2] = 1.; + + const double theta_topo = topo_point[2]; + + // The derivatives of the cartesian points to topo_point + DX[0][0] = std::cos(theta_topo) * std::cos(phi_topo); + DX[0][1] = -R_topo * std::cos(theta_topo) * std::sin(phi_topo); + DX[0][2] = -R_topo * std::sin(theta_topo) * std::cos(phi_topo); //reorder + DX[1][0] = std::cos(theta_topo) * std::sin(phi_topo); + DX[1][1] = R_topo * std::cos(theta_topo) * std::cos(phi_topo); + DX[1][2] = -R_topo * std::sin(theta_topo) * std::sin(phi_topo); + DX[2][0] = std::sin(theta_topo); + DX[2][1] = 0; + DX[2][2] = R_topo * std::cos(theta_topo); + + break; + } + default: + Assert (false, ExcNotImplemented ()); + } + + Dtotal = DerivativeForm<1,dim,dim>(DX * Dtopo); + + return Dtotal; + } + + + + template + Point + ChunkGeometry:: + push_forward(const Point &r_phi_theta) const + { + // Only take into account topography when we're not using the ZeroTopography plugin + if (dynamic_cast*>(topo) != nullptr) + return push_forward_sphere(r_phi_theta); + else + return push_forward_sphere(push_forward_topo(r_phi_theta)); + + } + + + + template + Point + ChunkGeometry:: + pull_back(const Point &x_y_z) const + { + // Only take into account topography when we're not using the ZeroTopography plugin + if (dynamic_cast*>(topo) != nullptr) + return pull_back_sphere(x_y_z); + else + return pull_back_topo(pull_back_sphere(x_y_z)); + } + + + + template + Point + ChunkGeometry:: + push_forward_sphere(const Point &input_vertex) const + { + Point output_vertex; + switch (dim) + { + case 2: + { + output_vertex[0] = input_vertex[0]*std::cos(input_vertex[1]); // x=rcosphi + output_vertex[1] = input_vertex[0]*std::sin(input_vertex[1]); // z=rsinphi + break; + } + case 3: + { + output_vertex[0] = input_vertex[0]*std::cos(input_vertex[2])*std::cos(input_vertex[1]); // x=rsinthetacosphi + output_vertex[1] = input_vertex[0]*std::cos(input_vertex[2])*std::sin(input_vertex[1]); // y=rsinthetasinphi + output_vertex[2] = input_vertex[0]*std::sin(input_vertex[2]); // z=rcostheta + break; + } + default: + Assert (false, ExcNotImplemented ()); + } + return output_vertex; + } + + + + template + Tensor<1, dim> + ChunkGeometry:: + normal_vector(const typename Triangulation::face_iterator &face, + const Point &p) const + { + // Let us first test whether we are on a "horizontal" face + // (tangential to the sphere). In this case, the normal vector is + // easy to compute since it is proportional to the vector from the + // center to the point 'p'. + // + // We test whether a face is horizontal by checking that the vertices + // all have roughly the same distance from the center: If the + // maximum deviation for the distances from the vertices to the + // center is less than 1.e-5 of the distance between vertices (as + // measured by the minimum distance from any of the other vertices + // to the first vertex), then we call this a horizontal face. + constexpr unsigned int max_n_vertices_per_face = (dim==2 ? 2 : 4); + std::array distances_to_center {}; + std::array distances_to_first_vertex {}; + distances_to_center[0] = face->vertex(0).norm_square(); + for (unsigned int i = 1; i < face->n_vertices(); ++i) + { + AssertIndexRange (i, distances_to_center.size()); + AssertIndexRange (i-1, distances_to_first_vertex.size()); + + distances_to_center[i] = face->vertex(i).norm_square(); + distances_to_first_vertex[i - 1] = + (face->vertex(i) - face->vertex(0)).norm_square(); + } + const auto minmax_distance = + std::minmax_element(distances_to_center.begin(), + distances_to_center.begin()+face->n_vertices()); + const auto min_distance_to_first_vertex = + std::min_element(distances_to_first_vertex.begin(), + distances_to_first_vertex.begin()+face->n_vertices()-1); + + // So, if this is a "horizontal" face, then just compute the normal + // vector as the one from the center to the point 'p', adequately + // scaled. + if (*minmax_distance.second - *minmax_distance.first < + 1.e-10 * *min_distance_to_first_vertex) + { + const Tensor<1, dim> unnormalized_spherical_normal = p; + const Tensor<1, dim> normalized_spherical_normal = + unnormalized_spherical_normal / unnormalized_spherical_normal.norm(); + return normalized_spherical_normal; + } + + // If it is not a horizontal face, just use the machinery of the + // base class. + return Manifold::normal_vector(face, p); + } + + + + template + Point + ChunkGeometry:: + pull_back_sphere(const Point &v) const + { + Point output_vertex; + switch (dim) + { + case 2: + { + output_vertex[1] = std::atan2(v[1], v[0]); + output_vertex[0] = v.norm(); + + // We must guarantee that all returned points have a longitude coordinate + // value that is larger than (or equal to) the longitude of point1. + // For example: + // If the domain runs from longitude -10 to 200 degrees, + // atan2 will also return a negative value (-180 to -160) for the points + // with longitude 180 to 200. These values must be corrected + // so that they are larger than the minimum longitude value of -10, + // by adding 360 degrees. + // A 100*epsilon ensures we catch all cases. + if (output_vertex[1] < 0.0) + if (output_vertex[1] < point1_lon - 100 * std::abs(point1_lon)*std::numeric_limits::epsilon()) + output_vertex[1] += 2.0 * numbers::PI; + break; + } + case 3: + { + const double radius=v.norm(); + output_vertex[0] = radius; + output_vertex[1] = std::atan2(v[1], v[0]); + // See 2d case + if (output_vertex[1] < 0.0) + if (output_vertex[1] < point1_lon - 100 * std::abs(point1_lon)*std::numeric_limits::epsilon()) + output_vertex[1] += 2.0 * numbers::PI; + output_vertex[2] = std::asin(v[2]/radius); + break; + } + default: + Assert (false, ExcNotImplemented ()); + } + return output_vertex; + } + + + + template + std::unique_ptr> + ChunkGeometry:: + clone() const + { + return std::make_unique(*this); + } + + + + template + Point + ChunkGeometry:: + push_forward_topo(const Point &r_phi_theta) const + { + // the radius of the current point without topography + const double radius = r_phi_theta[0]; + + // Grab lon,lat coordinates + Point surface_point; + for (unsigned int d=0; dvalue(surface_point); + + // adjust the radius based on the radius of the point + // through a linear interpolation between 0 at max depth and + // "topography" at the surface + const double topo_radius = std::max(inner_radius,radius + (radius-inner_radius)/max_depth*topography); + + // return the point with adjusted radius + Point topo_r_phi_theta = r_phi_theta; + topo_r_phi_theta[0] = topo_radius; + + return topo_r_phi_theta; + } + + + + template + Point + ChunkGeometry:: + pull_back_topo(const Point &topo_r_phi_theta) const + { + // the radius of the point with topography + const double topo_radius = topo_r_phi_theta[0]; + + // Grab lon,lat coordinates + Point surface_point; + for (unsigned int d=0; dvalue(surface_point); + + // remove the topography (which scales with radius) + const double radius = std::max(inner_radius, + (topo_radius*max_depth+inner_radius*topography)/(max_depth+topography)); + + // return the point without topography + Point r_phi_theta = topo_r_phi_theta; + r_phi_theta[0] = radius; + + return r_phi_theta; + } + + + + template + double + ChunkGeometry:: + get_radius(const Point &x_y_z) const + { + const Point r_phi_theta = pull_back(x_y_z); + Point surface_point; + for (unsigned int d=0; dvalue(surface_point); + + // return the outer radius at this phi, theta point including topography + return topography + inner_radius + max_depth; + } + } + + + + template + void + Chunk::initialize () + { + AssertThrow(Plugins::plugin_type_matches>(this->get_initial_topography_model()) || + Plugins::plugin_type_matches>(this->get_initial_topography_model()), + ExcMessage("At the moment, only the Zero or AsciiData initial topography model can be used with the Chunk geometry model.")); + + manifold = std::make_unique>(this->get_initial_topography_model(), + point1[1], + point1[0], + point2[0]-point1[0]); + } + + + template + void + Chunk:: + create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const + { + // First create a box in Cartesian coordinates: + const std::vector rep_vec(repetitions.begin(), repetitions.end()); + GridGenerator::subdivided_hyper_rectangle (coarse_grid, + rep_vec, + point1, + point2, + true); + + // Then transform this box into a spherical chunk (possibly with + // topography -- the 'manifold' has that built in): + GridTools::transform ( + [&](const Point &p) -> Point + { + return manifold->push_forward(p); + }, + coarse_grid); + + // Deal with a curved mesh by assigning a manifold. We arbitrarily + // choose manifold_id 15 for this. + coarse_grid.set_manifold (my_manifold_id, *manifold); + for (const auto &cell : coarse_grid.active_cell_iterators()) + cell->set_all_manifold_ids (my_manifold_id); + } + + + + template + std::set + Chunk:: + get_used_boundary_indicators () const + { + // boundary indicators are zero through 2*dim-1 + std::set s; + for (unsigned int i=0; i<2*dim; ++i) + s.insert (i); + return s; + } + + + + template + std::map + Chunk:: + get_symbolic_boundary_names_map () const + { + switch (dim) + { + case 2: + { + return + { + {"bottom", 0}, + {"top", 1}, + {"west", 2}, + {"east", 3} + }; + } + + case 3: + { + return + { + {"bottom", 0}, + {"top", 1}, + {"west", 2}, + {"east", 3}, + {"south", 4}, + {"north", 5} + }; + } + } + + Assert (false, ExcNotImplemented()); + return {}; + } + + + + template + double + Chunk:: + length_scale () const + { + // As described in the first ASPECT paper, a length scale of + // 10km = 1e4m works well for the pressure scaling for earth + // sized spherical shells. use a length scale that + // yields this value for the R0,R1 corresponding to earth + // but otherwise scales like (R1-R0) + return 1e4 * maximal_depth() / (6336000.-3481000.); + } + + + + template + double + Chunk::depth(const Point &position) const + { + // depth is defined wrt the reference surface point2[0] + // negative depth is not allowed + return std::max (0., std::min (point2[0]-position.norm(), maximal_depth())); + } + + + + template + double + Chunk::height_above_reference_surface(const Point &position) const + { + return position.norm()-point2[0]; + } + + + + template + Point + Chunk::representative_point(const double depth) const + { + Assert (depth >= 0, + ExcMessage ("Given depth must be positive or zero.")); + Assert (depth <= maximal_depth(), + ExcMessage ("Given depth must be less than or equal to the maximal depth of this geometry.")); + + // Choose a point at the mean longitude (and latitude) + Point p = 0.5*(point2+point1); + // at a depth beneath the top surface + p[0] = point2[0]-depth; + + // Now convert to Cartesian coordinates. This ignores the surface topography, + // but that is as documented. + return manifold->push_forward_sphere(p); + } + + + + template + double + Chunk::west_longitude () const + { + return point1[1]; + } + + + + template + double + Chunk::east_longitude () const + { + return point2[1]; + } + + + + template + double + Chunk::longitude_range () const + { + return point2[1] - point1[1]; + } + + + + template + double + Chunk::south_latitude () const + { + if (dim == 3) + return point1[2]; + else + return 0; + } + + + + template + double + Chunk::north_latitude () const + { + if (dim==3) + return point2[2]; + else + return 0; + } + + + + template + double + Chunk::latitude_range () const + { + if (dim==3) + return point2[2] - point1[2]; + else + return 0; + } + + + + template + double + Chunk::maximal_depth() const + { + // The depth is defined as relative to a reference surface (without + // topography) and since we don't apply topography on the CMB, + // the maximal depth really is the formula below, unless one applies a + // topography that is always strictly below zero (i.e., where the + // actual surface lies strictly below the reference surface). + return point2[0]-point1[0]; + } + + + + template + double + Chunk::inner_radius () const + { + return point1[0]; + } + + + + template + double + Chunk::outer_radius () const + { + return point2[0]; + } + + + + template + bool + Chunk::has_curved_elements() const + { + return true; + } + + + + template + bool + Chunk::point_is_in_domain(const Point &point) const + { + // If mesh deformation is enabled, we have to loop over all the current + // grid cells to see if the given point lies in the domain. + // If mesh deformation is not enabled, or has not happened yet, + // we can use the global extents of the model domain with or without + // initial topography instead. + // This function only checks if the given point lies in the domain + // in its current shape at the current time. It can be called before + // mesh deformation is applied in the first timestep (e.g., by the boundary + // traction plugins), and therefore there is no guarantee + // that the point will still lie in the domain after initial mesh deformation. + if (this->get_parameters().mesh_deformation_enabled && + this->simulator_is_past_initialization()) + { + return Utilities::point_is_in_triangulation(this->get_mapping(), this->get_triangulation(), point, this->get_mpi_communicator()); + } + // Without mesh deformation enabled, it is much cheaper to check whether the point lies in the domain. + else + { + const Point spherical_point = manifold->pull_back(point); + + for (unsigned int d = 0; d < dim; ++d) + if (spherical_point[d] > point2[d]+std::numeric_limits::epsilon()*std::abs(point2[d]) || + spherical_point[d] < point1[d]-std::numeric_limits::epsilon()*std::abs(point2[d])) + return false; + + return true; + } + } + + + + template + std::array + Chunk::cartesian_to_natural_coordinates(const Point &position_point) const + { + // The chunk manifold uses (radius, longitude, latitude). + // This is exactly what we need. + + // Ignore the topography to avoid a loop when calling the + // AsciiDataBoundary for topography which uses this function.... + const Point transformed_point = manifold->pull_back_sphere(position_point); + std::array position_array; + for (unsigned int i = 0; i < dim; ++i) + position_array[i] = transformed_point(i); + + // Internally, the Chunk geometry uses longitudes in the range -pi...pi, + // and that is what pull_back_sphere() produces. But externally, we need + // to use 0...2*pi to match what Utilities::Coordinates::cartesian_to_spherical_coordinates() + // returns, for example, and what we document the AsciiBoundaryData class + // wants to see from input files. + if (position_array[1] < 0) + position_array[1] += 2*numbers::PI; + + return position_array; + } + + + + template + aspect::Utilities::Coordinates::CoordinateSystem + Chunk::natural_coordinate_system() const + { + // TODO This will give problems somewhere down the line + // if geometry models are asked for their coordinate system, + // chunk returns spherical and then Utilitiess::Coordinates::cartesian_to_spherical + // is used + return aspect::Utilities::Coordinates::CoordinateSystem::spherical; + } + + + + template + Point + Chunk::natural_to_cartesian_coordinates(const std::array &position_tensor) const + { + // Ignore the topography to avoid a loop when calling the + // AsciiDataBoundary for topography which uses this function.... + Point position_point; + for (unsigned int i = 0; i < dim; ++i) + position_point[i] = position_tensor[i]; + const Point transformed_point = manifold->push_forward_sphere(position_point); + + return transformed_point; + } + + + + template + void + Chunk:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Chunk"); + { + prm.declare_entry ("Chunk inner radius", "0.", + Patterns::Double (0.), + "Radius at the bottom surface of the chunk. Units: \\si{\\meter}."); + prm.declare_entry ("Chunk outer radius", "1.", + Patterns::Double (0.), + "Radius at the top surface of the chunk. Units: \\si{\\meter}."); + + prm.declare_entry ("Chunk minimum longitude", "0.", + Patterns::Double (-180., 360.), // enables crossing of either hemisphere + "Minimum longitude of the chunk. Units: degrees."); + prm.declare_entry ("Chunk maximum longitude", "1.", + Patterns::Double (-180., 360.), // enables crossing of either hemisphere + "Maximum longitude of the chunk. Units: degrees."); + + prm.declare_entry ("Chunk minimum latitude", "0.", + Patterns::Double (-90., 90.), + "Minimum latitude of the chunk. This value is ignored " + "if the simulation is in 2d. Units: degrees."); + prm.declare_entry ("Chunk maximum latitude", "1.", + Patterns::Double (-90., 90.), + "Maximum latitude of the chunk. This value is ignored " + "if the simulation is in 2d. Units: degrees."); + + prm.declare_entry ("Radius repetitions", "1", + Patterns::Integer (1), + "Number of cells in radius."); + prm.declare_entry ("Longitude repetitions", "1", + Patterns::Integer (1), + "Number of cells in longitude."); + prm.declare_entry ("Latitude repetitions", "1", + Patterns::Integer (1), + "Number of cells in latitude. This value is ignored " + "if the simulation is in 2d"); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + Chunk::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Chunk"); + { + point1[0] = prm.get_double ("Chunk inner radius"); + point2[0] = prm.get_double ("Chunk outer radius"); + repetitions[0] = prm.get_integer ("Radius repetitions"); + point1[1] = prm.get_double ("Chunk minimum longitude") * constants::degree_to_radians; + point2[1] = prm.get_double ("Chunk maximum longitude") * constants::degree_to_radians; + repetitions[1] = prm.get_integer ("Longitude repetitions"); + + AssertThrow (point1[0] < point2[0], + ExcMessage ("Inner radius must be less than outer radius.")); + AssertThrow (point1[1] < point2[1], + ExcMessage ("Minimum longitude must be less than maximum longitude.")); + AssertThrow (point2[1] - point1[1] < 2.*numbers::PI, + ExcMessage ("Maximum - minimum longitude should be less than 360 degrees.")); + + if (dim == 3) + { + point1[2] = prm.get_double ("Chunk minimum latitude") * constants::degree_to_radians; + point2[2] = prm.get_double ("Chunk maximum latitude") * constants::degree_to_radians; + repetitions[2] = prm.get_integer ("Latitude repetitions"); + + AssertThrow (point1[2] < point2[2], + ExcMessage ("Minimum latitude must be less than maximum latitude.")); + AssertThrow (point1[2] > -0.5*numbers::PI, + ExcMessage ("Minimum latitude needs to be larger than -90 degrees.")); + AssertThrow (point2[2] < 0.5*numbers::PI, + ExcMessage ("Maximum latitude needs to be less than 90 degrees.")); + } + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace GeometryModel + { + namespace internal + { +#define INSTANTIATE(dim) \ + template class ChunkGeometry; + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + + ASPECT_REGISTER_GEOMETRY_MODEL(Chunk, + "chunk", + "A geometry which can be described as a chunk of a spherical shell, " + "bounded by lines of longitude, latitude and radius. " + "The minimum and maximum longitude, latitude (if in 3d) and depth of the chunk " + "is set in the parameter file. The chunk geometry labels its " + "2*dim sides as follows: ``west'' and ``east'': minimum and maximum " + "longitude, ``south'' and ``north'': minimum and maximum latitude, " + "``inner'' and ``outer'': minimum and maximum radii. " + "\n\n" + "The dimensions of the model are specified by parameters " + "of the following form: " + "Chunk (minimum || maximum) (longitude || latitude): " + "edges of geographical quadrangle (in degrees)" + "Chunk (inner || outer) radius: Radii at bottom and top of chunk" + "(Longitude || Latitude || Radius) repetitions: " + "number of cells in each coordinate direction." + "\n\n" + "When used in 2d, this geometry does not imply the use of " + "a spherical coordinate system. Indeed, " + "in 2d the geometry is simply a sector of an annulus in a Cartesian " + "coordinate system and consequently would correspond to " + "a sector of a cross section of the fluid filled space between two " + "infinite cylinders where one has made the assumption that " + "the velocity in direction of the cylinder axes is zero. " + "This is consistent with the definition of what we consider " + "the two-dimension case given in " + "Section~\\ref{sec:methods:2d-models}. " + "It is also possible to add initial topography to the chunk geometry, " + "based on an ascii data file. ") + } +} diff --git a/source/geometry_model/ellipsoidal_chunk.cc.bak b/source/geometry_model/ellipsoidal_chunk.cc.bak new file mode 100644 index 00000000000..94200b97708 --- /dev/null +++ b/source/geometry_model/ellipsoidal_chunk.cc.bak @@ -0,0 +1,833 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include + + +/** + * This geometry model implements an (3d) ellipsoidal_chunk geometry which can be non-coordinate parallel. + * @author This plugin is a joint effort of Menno Fraters, D Sarah Stamps and Wolfgang Bangerth + */ + +namespace aspect +{ + namespace GeometryModel + { + namespace + { + template + void + set_manifold_ids(Triangulation &triangulation) + { + for (const auto &cell : triangulation.active_cell_iterators()) + cell->set_all_manifold_ids (15); + } + + template + void + clear_manifold_ids(Triangulation &triangulation) + { + for (const auto &cell : triangulation.active_cell_iterators()) + cell->set_all_manifold_ids (numbers::flat_manifold_id); + } + } + + + namespace internal + { + /* + * the EllipsoidalChunkGeometry class + */ + + // Constructor + template + EllipsoidalChunkGeometry::EllipsoidalChunkGeometry(const InitialTopographyModel::Interface &topo, + const double para_semi_major_axis_a, + const double para_eccentricity, + const double para_semi_minor_axis_b, + const double para_bottom_depth, + const std::vector> ¶_corners) + : + topography (&topo), + semi_major_axis_a (para_semi_major_axis_a), + eccentricity (para_eccentricity), + semi_minor_axis_b (para_semi_minor_axis_b), + bottom_depth (para_bottom_depth), + corners (para_corners) + { + AssertThrow (dim == 3, ExcMessage("This manifold can currently only be used in 3d.")); + } + + + + template + Point<3> + EllipsoidalChunkGeometry::push_forward_ellipsoid(const Point<3> &phi_theta_d, const double semi_major_axis_a, const double eccentricity) const + { + // The following converts phi, theta and negative depth to x, y, z + // Depth is measured perpendicular to the ellipsoid surface + // (i.e. along a vector which does not generally pass through the origin) + // Expressions can be found in Ellipsoidal and Cartesian Coordinates Conversion + // Subirana, Zornoza and Hernandez-Pajares, 2011: + // https://gssc.esa.int/navipedia/index.php/Ellipsoidal_and_Cartesian_Coordinates_Conversion + + const double phi = phi_theta_d[0]; // Longitude in radians + const double theta = phi_theta_d[1]; // Latitude in radians + const double d = phi_theta_d[2]; // The negative depth (a depth of 10 meters is -10) + + const double R_bar = semi_major_axis_a / std::sqrt(1 - (eccentricity * eccentricity * + std::sin(theta) * std::sin(theta))); // radius of curvature of the prime vertical + + return Point<3> ((R_bar + d) * std::cos(phi) * std::cos(theta), + (R_bar + d) * std::sin(phi) * std::cos(theta), + ((1 - eccentricity * eccentricity) * R_bar + d) * std::sin(theta)); + } + + template + Point<3> + EllipsoidalChunkGeometry::pull_back_ellipsoid(const Point<3> &x, const double semi_major_axis_a, const double eccentricity) const + { + // The following converts x, y, z to phi, theta and negative depth + // Depth is measured perpendicular to the ellipsoid surface + // (i.e. along a vector which does not generally pass through the origin) + // Expressions can be found in Ellipsoidal and Cartesian Coordinates Conversion + // Subirana, Zornoza and Hernandez-Pajares, 2011: + // https://gssc.esa.int/navipedia/index.php/Ellipsoidal_and_Cartesian_Coordinates_Conversion + + const double R = semi_major_axis_a; // semi-major axis + const double b = R * std::sqrt(1 - eccentricity * eccentricity); // semi-minor axis + const double p = std::sqrt(x(0) * x(0) + x(1) * x(1)); // distance from origin projected onto x-y plane + const double th = std::atan2(R * x(2), b * p); // starting guess for theta + const double phi = std::atan2(x(1), x(0)); // azimuth (geodetic longitude) + const double theta = std::atan2(x(2) + (R * R - b * b) / b * std::pow(std::sin(th),3), + (p - (eccentricity * eccentricity * R * std::pow(std::cos(th),3)))); // first iterate for theta + const double R_bar = R / (std::sqrt(1 - eccentricity * eccentricity * std::sin(theta) * std::sin(theta))); // first iterate for R_bar + + Point<3> phi_theta_d; + phi_theta_d[0] = phi; + + phi_theta_d[1] = theta; + phi_theta_d[2] = p / std::cos(theta) - R_bar; // first iterate for d + return phi_theta_d; + } + + template + Point<3> + EllipsoidalChunkGeometry::push_forward_topography(const Point<3> &phi_theta_d_hat) const + { + const double d_hat = phi_theta_d_hat[2]; // long, lat, depth + Point phi_theta; + if (dim == 3) + phi_theta = Point(phi_theta_d_hat[0] * constants::radians_to_degree,phi_theta_d_hat[1] * constants::radians_to_degree); + const double h = topography != nullptr ? topography->value(phi_theta) : 0; + const double d = d_hat + (d_hat + bottom_depth)/bottom_depth*h; + const Point<3> phi_theta_d (phi_theta_d_hat[0], + phi_theta_d_hat[1], + d); + return phi_theta_d; + } + + template + Point<3> + EllipsoidalChunkGeometry::pull_back_topography(const Point<3> &phi_theta_d) const + { + const double d = phi_theta_d[2]; + Point phi_theta; + if (dim == 3) + phi_theta = Point(phi_theta_d[0] * constants::radians_to_degree, + phi_theta_d[1] * constants::radians_to_degree); + const double h = topography != nullptr ? topography->value(phi_theta) : 0; + const double d_hat = bottom_depth * (d-h)/(bottom_depth+h); + const Point<3> phi_theta_d_hat (phi_theta_d[0], + phi_theta_d[1], + d_hat); + return phi_theta_d_hat; + } + + /** + * TODO: These functions (pull back and push forward) should be changed that they always + * take and return 3d points, because 2d points make no sense for an ellipsoid, even with + * a 2d triangulation. To do this correctly we need to add the spacedim to the triangulation + * in ASPECT. What is now presented is just a temporary fix to get access to the pull back + * function from outside. The push forward function can't be fixed in this way, because + * it is used by a bind statement. + */ + template + Point<3> + EllipsoidalChunkGeometry::pull_back(const Point<3> &space_point) const + { + return pull_back_topography(pull_back_ellipsoid (space_point, semi_major_axis_a, eccentricity)); + + } + + template + Point<2> + EllipsoidalChunkGeometry::pull_back(const Point<2> &space_point) const + { + return space_point; + + } + + template + Point<3> + EllipsoidalChunkGeometry::push_forward(const Point<3> &chart_point) const + { + return push_forward_ellipsoid (push_forward_topography(chart_point), semi_major_axis_a, eccentricity); + } + + template + std::unique_ptr> + EllipsoidalChunkGeometry::clone() const + { + return std::make_unique(*this); + } + } + + template + void + EllipsoidalChunk::initialize() + { + manifold = std::make_unique>(this->get_initial_topography_model(), + semi_major_axis_a, + eccentricity, + semi_minor_axis_b, + bottom_depth, + corners); + } + + + + template <> + void + EllipsoidalChunk<3>::create_coarse_mesh(parallel::distributed::Triangulation<3> &coarse_grid) const + { + const int dim = 3; + + // Generate parallelepiped grid with one point (point 0) at (0,0,0) and the + // other corners (respectively corner 1,2 and 4) placed relative to that point. + const Point<3> corner_points[dim] = {Point((corners[1][0]-corners[0][0])*constants::degree_to_radians, + (corners[1][1]-corners[0][1])*constants::degree_to_radians, + 0), + Point((corners[3][0]-corners[0][0])*constants::degree_to_radians, + (corners[3][1]-corners[0][1])*constants::degree_to_radians, + 0), + Point(0, + 0, + bottom_depth) + }; + const unsigned int subdivisions[dim] = {EW_subdiv, NS_subdiv, depth_subdiv}; + + GridGenerator::subdivided_parallelepiped (coarse_grid, subdivisions, corner_points, true); + + // Shift the grid point at (0,0,0) (and the rest of the + // points with it) to the correct location at corner[0] at a + // negative depth. + const Point<3> base_point(corners[0][0] * constants::degree_to_radians, + corners[0][1] * constants::degree_to_radians, + -bottom_depth); + GridTools::shift(base_point,coarse_grid); + + // Transform to the ellipsoid surface + GridTools::transform ( + [&](const Point &x) -> Point + { + return manifold->push_forward(x); + }, + coarse_grid); + + // Also attach the real manifold to slot 15 (arbitrarily chosen). + // We won't use it during regular operation, but we set manifold_ids for + // all cells, faces and edges immediately before refinement and + // clear it again afterwards + coarse_grid.set_manifold (15, *manifold); + + coarse_grid.signals.pre_refinement.connect ( + [&] {set_manifold_ids(coarse_grid);}); + coarse_grid.signals.post_refinement.connect ( + [&] {clear_manifold_ids(coarse_grid);}); + coarse_grid.signals.post_refinement.connect ( + [&] {this->set_boundary_ids(coarse_grid);}); + } + + template + void + EllipsoidalChunk::create_coarse_mesh(parallel::distributed::Triangulation &/*coarse_grid*/) const + { + Assert(false, ExcNotImplemented()); + } + + template + void + EllipsoidalChunk::set_boundary_ids(parallel::distributed::Triangulation &coarse_grid) const + { + // set all boundary indicators. we want the edges to be curved + // as well. for this, it matters in which order we call + // set_all_boundary_indicators() -- we have to do it last for + // the inner and outer boundary, which conveniently is what + // happens in the following loop + for (const auto &cell : coarse_grid.active_cell_iterators()) + for (const unsigned int f : cell->face_indices()) + if (cell->face(f)->at_boundary()) + cell->face(f)->set_boundary_id(f); + } + + template + std::set + EllipsoidalChunk::get_used_boundary_indicators() const + { + // boundary indicators are zero through 2*dim-1 + std::set s; + for (unsigned int i = 0; i < 2 * dim; ++i) + s.insert(i); + return s; + } + + template + std::map + EllipsoidalChunk:: + get_symbolic_boundary_names_map () const + { + switch (dim) + { + case 2: + { + return + { + {"east", 0}, + {"west", 1}, + {"bottom", 2}, + {"top", 3} + }; + } + + case 3: + { + return + { + {"east", 0}, + {"west", 1}, + {"north", 2}, + {"south", 3}, + {"bottom", 4}, + {"top", 5} + }; + } + } + + Assert (false, ExcNotImplemented()); + return {}; + } + + template + void + EllipsoidalChunk::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Ellipsoidal chunk"); + { + prm.declare_entry("NE corner", + "", + Patterns::Anything(), + "Longitude:latitude in degrees of the North-East corner point of model region." + "The North-East direction is positive. If one of the three corners is not provided " + "the missing corner value will be calculated so all faces are parallel."); + prm.declare_entry("NW corner", + "", + Patterns::Anything(), + "Longitude:latitude in degrees of the North-West corner point of model region. " + "The North-East direction is positive. If one of the three corners is not provided " + "the missing corner value will be calculated so all faces are parallel."); + prm.declare_entry("SW corner", + "", + Patterns::Anything(), + "Longitude:latitude in degrees of the South-West corner point of model region. " + "The North-East direction is positive. If one of the three corners is not provided " + "the missing corner value will be calculated so all faces are parallel."); + prm.declare_entry("SE corner", + "", + Patterns::Anything(), + "Longitude:latitude in degrees of the South-East corner point of model region. " + "The North-East direction is positive. If one of the three corners is not provided " + "the missing corner value will be calculated so all faces are parallel."); + prm.declare_entry("Depth", + "500000.0", + Patterns::Double(0.), + "Bottom depth of model region."); + prm.declare_entry("Semi-major axis", + "6378137.0", + Patterns::Double(0.), + "The semi-major axis (a) of an ellipsoid. This is the radius for a sphere (eccentricity=0). Default WGS84 semi-major axis."); + prm.declare_entry("Eccentricity", + "8.1819190842622e-2", + Patterns::Double(0.), + "Eccentricity of the ellipsoid. Zero is a perfect sphere, default (8.1819190842622e-2) is WGS84."); + prm.declare_entry("East-West subdivisions", + "1", + Patterns::Integer(0), + "The number of subdivisions of the coarse (initial) mesh in the East-West direction."); + prm.declare_entry("North-South subdivisions", + "1", + Patterns::Integer(0), + "The number of subdivisions of the coarse (initial) mesh in the North-South direction."); + prm.declare_entry("Depth subdivisions", + "1", + Patterns::Integer(0), + "The number of subdivisions of the coarse (initial) mesh in depth."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + EllipsoidalChunk::parse_parameters(ParameterHandler &prm) + { + AssertThrow (dim == 3, ExcMessage("This geometry can currently only be used in 3d.")); + + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Ellipsoidal chunk"); + { + // Get latitude and longitudes defining region of interest from + // the parameter file. + corners.resize(4); + std::string NEcorner = prm.get("NE corner"); + std::string NWcorner = prm.get("NW corner"); + std::string SWcorner = prm.get("SW corner"); + std::string SEcorner = prm.get("SE corner"); + + // make a list of what corners are present and check that there should be one or two corner missing, + // otherwise throw an exception + std::vector present(4,true); + unsigned int missing = 0; + if (NEcorner == "") + { + ++missing; + present[0] = false; + } + if (NWcorner == "") + { + ++missing; + present[1] = false; + } + if (SWcorner == "") + { + ++missing; + present[2] = false; + } + if (SEcorner == "") + { + ++missing; + present[3] = false; + } + + AssertThrow (missing != 0, + ExcMessage ("Only two or three of the four corner points should be provided.")); + AssertThrow (missing == 1 || missing == 2, + ExcMessage ("Please provide two or three corner points.")); + + std::vector temp; + + if (present[0]) + { + temp = Utilities::string_to_double(Utilities::split_string_list(NEcorner,':')); + AssertThrow (temp.size() == 2, ExcMessage ("Two coordinates should be given for the NE-corner (longitude:latitude).")); + corners[0] = Point<2>(temp[0],temp[1]); + } + else + corners[0]= Point<2>(); + + if (present[1]) + { + temp = Utilities::string_to_double(Utilities::split_string_list(NWcorner,':')); + AssertThrow (temp.size() == 2, ExcMessage ("Two coordinates should be given for the NW-corner (longitude:latitude).")); + corners[1] = Point<2>(temp[0],temp[1]); + } + else + corners[1]= Point<2>(); + + if (present[2]) + { + temp = Utilities::string_to_double(Utilities::split_string_list(SWcorner,':')); + AssertThrow (temp.size() == 2, ExcMessage ("Two coordinates should be given for the SW-corner (longitude:latitude).")); + corners[2] = Point<2>(temp[0],temp[1]); + } + else + corners[2]= Point<2>(); + + if (present[3]) + { + temp = Utilities::string_to_double(Utilities::split_string_list(SEcorner,':')); + AssertThrow (temp.size() == 2, ExcMessage ("Two coordinates should be given for the SE-corner (longitude:latitude).")); + corners[3] = Point<2>(temp[0],temp[1]); + } + else + corners[3]= Point<2>(); + + + bottom_depth = prm.get_double("Depth"); + semi_major_axis_a = prm.get_double("Semi-major axis"); + eccentricity = prm.get_double("Eccentricity"); + semi_minor_axis_b = std::sqrt((1 - pow(eccentricity,2.)) * pow(semi_major_axis_a,2.)); + EW_subdiv = prm.get_integer("East-West subdivisions"); + NS_subdiv = prm.get_integer("North-South subdivisions"); + depth_subdiv = prm.get_integer("Depth subdivisions"); + + // Check whether the corners of the rectangle are really placed correctly + if (present[0] == true && present[1] == true) + { + AssertThrow (corners[0][0] >= corners[1][0], + ExcMessage ("The longitude of the NE corner (" + boost::lexical_cast(corners[0][0]) + ") cannot be smaller than the longitude of the NW corner (" + boost::lexical_cast(corners[1][0]) + ").")); + } + if (present[0] == true && present[3] == true) + { + AssertThrow (corners[0][1] >= corners[3][1], + ExcMessage ("The latitude of the NE (" + boost::lexical_cast(corners[0][1]) + ") corner cannot be smaller than the latitude of the SE corner (" + boost::lexical_cast(corners[3][1]) + ").")); + } + if (present[2] == true && present[3] == true) + { + AssertThrow (corners[2][0] <= corners[3][0], + ExcMessage ("The longitude of the SW (" + boost::lexical_cast(corners[2][0]) + ") corner cannot be larger than the longitude of the SE corner (" + boost::lexical_cast(corners[3][0]) + ").")); + } + if (present[2] == true && present[1] == true) + { + AssertThrow (corners[2][1] <= corners[1][1], + ExcMessage ("The latitude of the SW corner (" + boost::lexical_cast(corners[2][1]) + ") cannot be larger than the latitude of the NW corner (" + boost::lexical_cast(corners[1][1]) + ").")); + } + if (missing == 2) + { + AssertThrow ((present[0] == true && present[2] == true) || (present[1] == true && present[3] == true), + ExcMessage ("Please provide two opposing corners.")); + + if (present[0] == true && present[2] == true) + AssertThrow (corners[0][0] > corners[2][0] && corners[0][1] > corners[2][1], + ExcMessage ("The Northeast corner (" + boost::lexical_cast(corners[0][0]) + ":" + boost::lexical_cast(corners[0][1]) + ") must be strictly north and east of the Southwest corner (" + boost::lexical_cast(corners[2][0]) + ":" + boost::lexical_cast(corners[2][1]) + ") when only two points are given.")); + + if (present[1] == true && present[3] == true) + AssertThrow (corners[1][0] < corners[3][0] && corners[1][1] > corners[3][1], + ExcMessage ("The Northwest corner (" + boost::lexical_cast(corners[1][0]) + ":" + boost::lexical_cast(corners[1][1]) + ") must be strictly north and west of the Southeast corner (" + boost::lexical_cast(corners[3][0]) + ":" + boost::lexical_cast(corners[3][1]) + ") when only two points are given.")); + } + + + // If one or two of the corners is not provided, calculate it. + if (missing == 1) + { + for (unsigned int i = 0; i <= 3; ++i) + { + // find the corner which is missing, if there is one + if (present[i] == false) + { + // find the location of this corner + // the values for the values is: + // [i] = [i+1] + ([i+3] - [i+2]) + unsigned int ip = i + 1; + unsigned int ipp = i + 2; + unsigned int ippp = i + 3; + + if (ip > 3) + ip -= 4; + if (ipp > 3) + ipp -= 4; + if (ippp > 3) + ippp -=4; + + corners[i] = corners[ip]; + corners[i][0] = corners[ip][0] + (corners[ippp][0] - corners[ipp][0]); + corners[i][1] = corners[ip][1] + (corners[ippp][1] - corners[ipp][1]); + } + } + } + else if (missing == 2) + { + // find the location of this corner + if (present[0] == false) + { + corners[0] = corners[1]; + corners[2] = corners[3]; + corners[0][0] = corners[3][0]; + corners[2][0] = corners[1][0]; + } + else + { + corners[1] = corners[0]; + corners[3] = corners[2]; + corners[1][0] = corners[2][0]; + corners[3][0] = corners[0][0]; + } + } + // Check that the calculated corners also obey the rules for the location of the corners. + Assert (corners[0][0] >= corners[1][0], + ExcMessage ("The longitude of the NE corner (" + boost::lexical_cast(corners[0][0]) + ") cannot be smaller than the longitude of the NW corner (" + boost::lexical_cast(corners[1][0]) + "). This is an internal check, if you see this please contact the developer.")); + + Assert (corners[0][1] >= corners[3][1], + ExcMessage ("The latitude of the NE (" + boost::lexical_cast(corners[0][1]) + ") corner cannot be smaller than the latitude of the SE corner (" + boost::lexical_cast(corners[3][1]) + "). This is an internal check, if you see this please contact the developer.")); + + Assert (corners[2][0] <= corners[3][0], + ExcMessage ("The longitude of the SW (" + boost::lexical_cast(corners[2][0]) + ") corner cannot be larger than the longitude of the SE corner (" + boost::lexical_cast(corners[3][0]) + "). This is an internal check, if you see this please contact the developer.")); + + Assert (corners[2][1] <= corners[1][1], + ExcMessage ("The latitude of the SW corner (" + boost::lexical_cast(corners[2][1]) + ") cannot be larger than the latitude of the NW corner (" + boost::lexical_cast(corners[1][1]) + "). This is an internal check, if you see this please contact the developer.")); + + westLongitude = corners[2][0]; + eastLongitude = corners[0][0]; + northLatitude = corners[0][1]; + southLatitude = corners[2][1]; + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + double + EllipsoidalChunk::depth(const Point &position) const + { + return std::max(std::min(-manifold->pull_back(position)[dim-1], maximal_depth()), 0.0); + } + + template + double + EllipsoidalChunk::height_above_reference_surface(const Point &/*position*/) const + { + AssertThrow(false, ExcMessage("Function height_above_reference_surface is not yet implemented " + "for the ellipsoidal chunk geometry model. " + "Consider using a box, spherical shell, or chunk.") ); + return numbers::signaling_nan(); + } + + + template + double + EllipsoidalChunk::maximal_depth() const + { + return bottom_depth; + } + + template + double + EllipsoidalChunk::get_radius(const Point &position) const + { + const Point long_lat_depth = manifold->pull_back(position); + return semi_major_axis_a / (std::sqrt(1 - eccentricity * eccentricity * std::sin(long_lat_depth[1]) * std::sin(long_lat_depth[1]))); + } + + template + double + EllipsoidalChunk::get_eccentricity() const + { + return eccentricity; + } + + template + const std::vector> & + EllipsoidalChunk::get_corners() const + { + return corners; + } + + template + double + EllipsoidalChunk::get_semi_minor_axis_b() const + { + return semi_minor_axis_b; + } + + template + double + EllipsoidalChunk::get_semi_major_axis_a() const + { + return semi_major_axis_a; + } + + + template + double + EllipsoidalChunk::length_scale() const + { + // As described in the first ASPECT paper, a length scale of + // 10km = 1e4m works well for the pressure scaling for earth + // sized spherical shells. use a length scale that + // yields this value for the R0,R1 corresponding to earth + // but otherwise scales like (R1-R0) + return 1e4 * maximal_depth() / (6336000.-3481000.); + } + + template + Point + EllipsoidalChunk::representative_point(const double /*depth*/) const + { + return Point(); + } + + template <> + Point<3> + EllipsoidalChunk<3>::representative_point(const double depth) const + { + const int dim = 3; + Assert(depth >= 0, ExcMessage("Given depth must be positive or zero.")); + Assert(depth <= maximal_depth(), + ExcMessage("Given depth must be less than or equal to the maximal depth of this geometry.")); + + // Choose a point on the center axis of the domain + Point p = Point<3>((eastLongitude + westLongitude) * 0.5 * constants::degree_to_radians, + (southLatitude + northLatitude) * 0.5 * constants::degree_to_radians, + -depth); + + return manifold->push_forward(p); + } + + + template + bool + EllipsoidalChunk::point_is_in_domain(const Point &point) const + { + AssertThrow(!this->get_parameters().mesh_deformation_enabled || + this->get_timestep_number() == 0, + ExcMessage("After displacement of the mesh, this function can no longer be used to determine whether a point lies in the domain or not.")); + + // dim = 3 + const Point ellipsoidal_point = manifold->pull_back(point); + + // compare deflection from the ellipsoid surface + if (ellipsoidal_point[dim-1] > 0.0+std::numeric_limits::epsilon()*bottom_depth || + -ellipsoidal_point[dim-1] > bottom_depth+std::numeric_limits::epsilon()*bottom_depth) + return false; + + // compare lon/lat + if (!Utilities::polygon_contains_point(corners, Point<2>(ellipsoidal_point[0]*constants::radians_to_degree,ellipsoidal_point[1]*constants::radians_to_degree))) + return false; + + return true; + } + + template + std::array + EllipsoidalChunk::cartesian_to_natural_coordinates(const Point &position_point) const + { + // the chunk manifold works internally with a vector with longitude, latitude, depth. + // We need to output radius, longitude, latitude to be consistent. + // Ignore the topography by calling pull_back_ellipsoid to avoid a loop when calling the + // AsciiDataBoundary for topography which uses this function.... + Point<3> cartesian_point; + for (unsigned int d=0; d transformed_point = manifold->pull_back_ellipsoid(cartesian_point, semi_major_axis_a, eccentricity); + + const double radius = semi_major_axis_a / + (std::sqrt(1 - eccentricity * eccentricity * std::sin(transformed_point[1]) * std::sin(transformed_point[1]))); + std::array position_array; + position_array[0] = radius + transformed_point(2); + position_array[1] = transformed_point(0); + position_array[2] = transformed_point(1); + + return position_array; + } + + + template + aspect::Utilities::Coordinates::CoordinateSystem + EllipsoidalChunk::natural_coordinate_system() const + { + return aspect::Utilities::Coordinates::CoordinateSystem::ellipsoidal; + } + + + template <> + Point<3> + EllipsoidalChunk<3>::natural_to_cartesian_coordinates(const std::array &position_tensor) const + { + // We receive radius, longitude, latitude and we need to turn it first back into + // longitude, latitude, depth for internal use, and push_forward to cartesian coordinates. + // Ignore the topography by calling push_forward_ellipsoid to avoid a loop when calling the + // AsciiDataBoundary for topography which uses this function.... + Point<3> position_point; + position_point(0) = position_tensor[1]; + position_point(1) = position_tensor[2]; + + const double radius = semi_major_axis_a / (std::sqrt(1 - eccentricity * eccentricity * std::sin(position_point(1)) * std::sin(position_point(1)))); + position_point(2) = position_tensor[0] - radius; + + Point<3> transformed_point = manifold->push_forward_ellipsoid(position_point, semi_major_axis_a, eccentricity); + return transformed_point; + } + + + template <> + Point<2> + EllipsoidalChunk<2>::natural_to_cartesian_coordinates(const std::array &/*position_tensor*/) const + { + Assert(false, ExcMessage("This geometry model doesn't support 2d.")); + return {}; + } + + } +} + +template +typename aspect::GeometryModel::internal::EllipsoidalChunkGeometry +aspect::GeometryModel::EllipsoidalChunk::get_manifold() const +{ + return *manifold; +} + +// explicit instantiations +namespace aspect +{ + namespace GeometryModel + { + namespace internal + { +#define INSTANTIATE(dim) \ + template class EllipsoidalChunkGeometry; + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + + ASPECT_REGISTER_GEOMETRY_MODEL(EllipsoidalChunk, + "ellipsoidal chunk", + "A 3d chunk geometry that accounts for Earth's ellipticity (default assuming the " + "WGS84 ellipsoid definition) which can be defined in non-coordinate directions. " + "In the description of the ellipsoidal chunk, two of the ellipsoidal axes have the " + "same length so that there is only a semi-major axis and a semi-minor axis. " + "The user has two options for creating an ellipsoidal chunk geometry: 1) by defining " + "two opposing points (SW and NE or NW and SE) a coordinate parallel ellipsoidal " + "chunk geometry will be created. 2) by defining three points a non-coordinate " + "parallel ellipsoidal chunk will be created. The points are defined in the input " + "file by longitude:latitude. It is also possible to define additional subdivisions " + "of the mesh in each direction. The boundary of the domain is formed by linear " + "interpolation in longitude-latitude space between adjacent points " + "(i.e. $[lon, lat](f) = [lon1 \\cdot f + lon2 \\cdot(1-f), lat1 \\cdot f + lat2 \\cdot (1-f)]$, " + "where f is a value between 0 and 1). Faces of the model are defined as " + "0, west; 1,east; 2, south; 3, north; 4, inner; 5, outer.\n\n" + "This geometry model supports initial topography for deforming the initial mesh.") + } +} diff --git a/source/geometry_model/initial_topography_model/ascii_data.cc.bak b/source/geometry_model/initial_topography_model/ascii_data.cc.bak new file mode 100644 index 00000000000..121128a23ba --- /dev/null +++ b/source/geometry_model/initial_topography_model/ascii_data.cc.bak @@ -0,0 +1,204 @@ +/* + Copyright (C) 2016 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +namespace aspect +{ + namespace InitialTopographyModel + { + template + AsciiData::AsciiData () + : + surface_boundary_id(1) + {} + + + template + void + AsciiData::initialize () + { + surface_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + + Utilities::AsciiDataBoundary::initialize({surface_boundary_id}, + 1); + } + + + template + double + AsciiData::value (const Point &surface_point) const + { + // In a first step, create a global 'dim'-dimensional point that we can pass to the + // function expression as input -- because the function is a dim-dimensional + // function. + // + // Different geometry models pass the surface point in in different ways. + // In the following, we will first normalize the input to a dim-dimensional + // point with a dummy vertical/radial coordinate that, one would hope, + // the AsciiDataBoundary class will then simply ignore. + Point global_point; + if (Plugins::plugin_type_matches> (this->get_geometry_model()) || + Plugins::plugin_type_matches> (this->get_geometry_model())) + { + for (unsigned int d=0; d> (this->get_geometry_model()) || + Plugins::plugin_type_matches> (this->get_geometry_model()) || + Plugins::plugin_type_matches> (this->get_geometry_model())) + { + // AsciiDataBoundary always expects to get the input + // parameters for its functions in Cartesian + // coordinates. The get_data_component function then changes + // the coordinate system, or more precisely it asks the + // geometry model to convert the point into its natural + // coordinate system, before doing the table lookup. + // + // This is of course all not very efficient (TODO: Think + // about a better scheme), but the first step then needs to + // be to convert what we have into Cartesian coordinates... + std::array point; + point[0] = 6371000.0; + for (unsigned int d=0; d(point); + } + else + AssertThrow(false, ExcNotImplemented()); + + const double topo = this->Utilities::AsciiDataBoundary::get_data_component(surface_boundary_id, + global_point, + 0); + + return topo; + } + + + + template + Tensor<1,dim-1> + AsciiData::vector_gradient(const Point &point) const + { + return Utilities::AsciiDataBoundary::vector_gradient(surface_boundary_id, point,0); + } + + + + template + double + AsciiData::max_topography () const + { + return Utilities::AsciiDataBoundary::get_maximum_component_value(surface_boundary_id,0); + } + + + + template + void + AsciiData::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Initial topography model"); + { + Utilities::AsciiDataBase::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/geometry-model/initial-topography-model/ascii-data/test/", + "box_2d_%s.0.txt"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + AsciiData::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Initial topography model"); + { + Utilities::AsciiDataBase::parse_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTopographyModel + { + ASPECT_REGISTER_INITIAL_TOPOGRAPHY_MODEL(AsciiData, + "ascii data", + "Implementation of a model in which the surface " + "topography is derived from a file containing data " + "in ascii format. The following geometry models " + "are currently supported: box, chunk. " + "Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example `# POINTS: 3 3'. " + "The order of the data columns " + "has to be `x', `Topography [m]' in a 2d model and " + " `x', `y', `Topography [m]' in a 3d model, which means that " + "there has to be a single column " + "containing the topography. " + "Note that the data in the input " + "file needs to be sorted in a specific order: " + "the first coordinate needs to ascend first, " + "followed by the second in order to " + "assign the correct data to the prescribed coordinates. " + "If you use a spherical model, " + "then the assumed grid changes. " + "`x' will be replaced by the azimuth angle (longitude) " + "in radians (between zero and $2\\pi$, not between $-\\pi$ " + "corresponding to 180 degrees west, and $+\\pi$ corresponding " + "to 180 degrees east), " + "and `y' by the polar angle in radians (between $0$ and $\\pi$) measured " + "positive from the north pole. The grid will be assumed to be " + "a longitude-colatitude grid. Note that the order " + "of spherical coordinates is `phi', `theta' " + "and not `theta', `phi', since this allows " + "for dimension independent expressions.") + } +} diff --git a/source/geometry_model/initial_topography_model/function.cc.bak b/source/geometry_model/initial_topography_model/function.cc.bak new file mode 100644 index 00000000000..39b15e95768 --- /dev/null +++ b/source/geometry_model/initial_topography_model/function.cc.bak @@ -0,0 +1,190 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace aspect +{ + namespace InitialTopographyModel + { + template + Function::Function () + : + max_topo(0), + initial_topography_function (1), + coordinate_system(Utilities::Coordinates::CoordinateSystem::cartesian) + {} + + + + template + double + Function:: + value (const Point &surface_point) const + { + // In a first step, create a global 'dim'-dimensional point that we can pass to the + // function expression as input -- because the function is a dim-dimensional + // function. + // + // Different geometry models pass the surface point in in different ways. + // In the following, we will first normalize the input to a dim-dimensional + // point with a dummy vertical/radial coordinate that, one would hope, + // the function expression will then simply ignore. + Point global_point; + + if (Plugins::plugin_type_matches>(this->get_geometry_model()) || + Plugins::plugin_type_matches> (this->get_geometry_model())) + { + for (unsigned int d=0; d>(this->get_geometry_model()) || + Plugins::plugin_type_matches>(this->get_geometry_model()) || + Plugins::plugin_type_matches>(this->get_geometry_model()) ) + { + std::array point; + point[0] = 6371000.0; + for (unsigned int d=0; d(point); + + // The point as it is would have to be translated into a different + // coordinate system (or, perhaps, better just left in the spherical + // coordinates we received) if that was requested in the input file. + // This is not currently implemented. + Assert (coordinate_system == Utilities::Coordinates::CoordinateSystem::cartesian, + ExcNotImplemented()); + } + else + AssertThrow(false, ExcNotImplemented()); + + const double topo = initial_topography_function.value(global_point); + + return topo; + } + + + template + double + Function:: + max_topography () const + { + return max_topo; + } + + + template + void + Function::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Initial topography model"); + { + prm.enter_subsection("Function"); + { + prm.declare_entry ("Maximum topography value", "2000.", + Patterns::Double (0.), + "The maximum value the topography given by " + "the function can take. "); + prm.declare_entry ("Coordinate system", "cartesian", + Patterns::Selection ("cartesian|spherical"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `cartesian' and `spherical'. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle. "); + + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + Function::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Initial topography model"); + { + prm.enter_subsection("Function"); + { + coordinate_system = Utilities::Coordinates::string_to_coordinate_system(prm.get("Coordinate system")); + } + max_topo = prm.get_double("Maximum topography value"); + try + { + initial_topography_function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Boundary traction model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTopographyModel + { + ASPECT_REGISTER_INITIAL_TOPOGRAPHY_MODEL(Function, + "function", + "Implementation of a model in which the initial topography " + "is described by a function in Cartesian or spherical coordinates. ") + } +} diff --git a/source/geometry_model/initial_topography_model/interface.cc.bak b/source/geometry_model/initial_topography_model/interface.cc.bak new file mode 100644 index 00000000000..f056b45c7f0 --- /dev/null +++ b/source/geometry_model/initial_topography_model/interface.cc.bak @@ -0,0 +1,176 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include +#include + +namespace aspect +{ + namespace InitialTopographyModel + { +// -------------------------------- Deal with registering initial topography models and automating +// -------------------------------- their setup and selection at run time + + namespace + { + std::tuple + >, + internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + register_initial_topography_model (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + template + std::unique_ptr> + create_initial_topography_model (ParameterHandler &prm) + { + std::string model_name; + prm.enter_subsection ("Geometry model"); + { + prm.enter_subsection ("Initial topography model"); + { + model_name = prm.get ("Model name"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + // If one sets the model name to an empty string in the input file, + // ParameterHandler produces an error while reading the file. However, + // if one omits specifying any model name at all (not even setting it to + // the empty string) then the value we get here is the empty string. If + // we don't catch this case here, we end up with awkward downstream + // errors because the value obviously does not conform to the Pattern. + AssertThrow(model_name != "unspecified", + ExcMessage("You need to select a Initial topography model " + "(`set Model name' in `subsection Initial topography model').")); + + return std::get(registered_plugins).create_plugin (model_name, + "Initial topography model::model name", + prm); + } + + + + template + void + declare_parameters (ParameterHandler &prm) + { + // declare the entry in the parameter file + prm.enter_subsection ("Geometry model"); + { + prm.enter_subsection ("Initial topography model"); + { + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + prm.declare_entry ("Model name", "zero topography", + Patterns::Selection (pattern_of_names), + "Select one of the following models:\n\n" + + + std::get(registered_plugins).get_description_string()); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Initial topography interface", + out); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace InitialTopographyModel + { +#define INSTANTIATE(dim) \ + template class Interface; \ + \ + template \ + void \ + register_initial_topography_model (const std::string &, \ + const std::string &, \ + void ( *) (ParameterHandler &), \ + std::unique_ptr>( *) ()); \ + \ + template \ + void \ + declare_parameters (ParameterHandler &); \ + \ + template \ + void \ + write_plugin_graph (std::ostream &); \ + \ + template \ + std::unique_ptr> \ + create_initial_topography_model (ParameterHandler &prm); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/geometry_model/initial_topography_model/prm_polygon.cc.bak b/source/geometry_model/initial_topography_model/prm_polygon.cc.bak new file mode 100644 index 00000000000..6de5df06e5c --- /dev/null +++ b/source/geometry_model/initial_topography_model/prm_polygon.cc.bak @@ -0,0 +1,172 @@ +/* + Copyright (C) 2016 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include + +namespace aspect +{ + namespace InitialTopographyModel + { + template + double + PrmPolygon:: + value (const Point &p) const + { + const Point<2> p1 = (dim == 2 ? Point<2>(p[0],0) : Point<2>(p[0],p[1])); + + /** + * We go through the loop in the reverse order, because we + * want the last entry in the list to prescribe the value. + */ + for (unsigned int i = point_lists.size(); i > 0; i--) + { + if (aspect::Utilities::polygon_contains_point(point_lists[i-1],p1)) + { + return topography_values[i-1]; + } + } + + // Point is not in any of the polygons. Return zero. + return 0; + } + + + + template + double + PrmPolygon:: + max_topography () const + { + return maximum_topography; + } + + + + template + void + PrmPolygon:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Initial topography model"); + { + prm.enter_subsection("Prm polygon"); + { + prm.declare_entry("Topography parameters", + "", + Patterns::Anything(), + "Set the topography height and the polygon which should be set to that height. " + "The format is : \"The topography height \textgreater The point list describing " + "a polygon \\& The next topography height \textgreater the next point list " + "describing a polygon.\" The format for the point list describing the polygon is " + "\"x1,y1;x2,y2\". For example for two triangular areas of 100 and -100 meters high " + "set: '100 \textgreater 0,0;5,5;0,10 \\& -100 \textgreater 10,10;10,15;20,15'. " + "Units of the height are always in meters. The units of the coordinates are " + "dependent on the geometry model. In the box model they are in meters, in the " + "chunks they are in degrees, etc. Please refer to the manual of the individual " + "geometry model to so see how the topography is implemented."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + PrmPolygon::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Initial topography model"); + { + prm.enter_subsection("Prm polygon"); + { + /** + * we need to fill the point lists and topography values. They + * are stored in the Topography subsection in the Topography parameter. + */ + maximum_topography = std::numeric_limits::lowest(); + const std::string temptopo = prm.get("Topography parameters"); + const std::vector temp_topographies = Utilities::split_string_list(temptopo,'&'); + const unsigned int temp_topographies_size = temp_topographies.size(); + + topography_values.resize(temp_topographies_size,0); + point_lists.resize(temp_topographies_size); + for (unsigned int i_topo = 0; i_topo < temp_topographies_size; ++i_topo) + { + const std::vector temp_topography = Utilities::split_string_list(temp_topographies[i_topo],'>'); + Assert(temp_topography.size() == 2,ExcMessage ("The given line '" + temp_topographies[i_topo] + + "' is not correct. It consists of " + + boost::lexical_cast(temp_topography.size()) + + " parts separated by >, but it should only contain " + "two parts: the height and the list of point coordinates," + " separated by a >.'")); + + topography_values[i_topo] = Utilities::string_to_double(temp_topography[0]); + maximum_topography = std::max(topography_values[i_topo],maximum_topography); + + const std::vector temp_coordinates = Utilities::split_string_list(temp_topography[1],';'); + const unsigned int temp_coordinate_size = temp_coordinates.size(); + point_lists[i_topo].resize(temp_coordinate_size); + for (unsigned int i_coord = 0; i_coord < temp_coordinate_size; ++i_coord) + { + const std::vector temp_point = Utilities::string_to_double(Utilities::split_string_list(temp_coordinates[i_coord],',')); + Assert(temp_point.size() == 2,ExcMessage ("The given coordinate '" + temp_coordinates[i_coord] + "' is not correct. " + "It consists of " + boost::lexical_cast(temp_topography.size()) + + " parts separated by :, but it should only contain 2 parts: " + "the two coordinates of the polygon points, separated by a ','.")); + + + point_lists[i_topo][i_coord] = Point<2>(temp_point[0], temp_point[1]); + } + + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTopographyModel + { + ASPECT_REGISTER_INITIAL_TOPOGRAPHY_MODEL(PrmPolygon, + "prm polygon", + "An initial topography model that defines the initial topography " + "as constant inside each of a set of polygonal parts of the " + "surface. The polygons, and their associated surface elevation, " + "are defined in the `Geometry model/Initial topography/Prm polygon' " + "section.") + } +} diff --git a/source/geometry_model/initial_topography_model/zero_topography.cc.bak b/source/geometry_model/initial_topography_model/zero_topography.cc.bak new file mode 100644 index 00000000000..3ed908aad28 --- /dev/null +++ b/source/geometry_model/initial_topography_model/zero_topography.cc.bak @@ -0,0 +1,58 @@ +/* + Copyright (C) 2011 - 2017 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + + +namespace aspect +{ + namespace InitialTopographyModel + { + template + double + ZeroTopography:: + value (const Point &/*p*/) const + { + // return a zero value regardless of position + return 0.0; + } + + template + double + ZeroTopography:: + max_topography () const + { + return 0; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTopographyModel + { + ASPECT_REGISTER_INITIAL_TOPOGRAPHY_MODEL(ZeroTopography, + "zero topography", + "Implementation of a model in which the initial topography " + "is zero. ") + } +} diff --git a/source/geometry_model/interface.cc.bak b/source/geometry_model/interface.cc.bak new file mode 100644 index 00000000000..0f977683d3b --- /dev/null +++ b/source/geometry_model/interface.cc.bak @@ -0,0 +1,368 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace GeometryModel + { + template + std::map + Interface::get_symbolic_boundary_names_map() const + { + // return an empty map in the base class + return {}; + } + + + + template + std::set, unsigned int>> + Interface::get_periodic_boundary_pairs() const + { + // return an empty set in the base class + return {}; + } + + + + template + void + Interface::adjust_positions_for_periodicity (Point &/*position*/, + const ArrayView> &/*connected_positions*/, + const ArrayView> &/*connected_velocities*/) const + { + AssertThrow(false, + ExcMessage("Positions cannot be adjusted for periodicity in the chosen geometry model.")); + return; + } + + + + template + bool + Interface::has_curved_elements() const + { + return true; + } + + + + template + std::array + Interface::cartesian_to_natural_coordinates(const Point &) const + { + Assert (false, + ExcMessage ("The cartesian_to_natural_coordinates function has " + "not been implemented in this geometry model.")); + return {}; + } + + + template + Utilities::NaturalCoordinate + Interface::cartesian_to_other_coordinates(const Point &position, + const Utilities::Coordinates::CoordinateSystem &coordinate_system) const + { + std::array other_coord; + switch (coordinate_system) + { + case Utilities::Coordinates::cartesian: + other_coord = Utilities::convert_point_to_array(position); + break; + + case Utilities::Coordinates::spherical: + other_coord = Utilities::Coordinates::cartesian_to_spherical_coordinates(position); + break; + + case Utilities::Coordinates::depth: + other_coord[0] = depth(position); + break; + + case Utilities::Coordinates::ellipsoidal: + default: + AssertThrow(false, ExcNotImplemented()); + } + + return Utilities::NaturalCoordinate(other_coord, coordinate_system); + } + + template + Point + Interface::natural_to_cartesian_coordinates(const std::array &) const + { + Assert (false, + ExcMessage ("The natural_to_cartesian_coordinates function has " + "not been implemented in this geometry model.")); + return Point(); + } + + + /* --------- functions to translate between symbolic and numeric boundary indicators ------ */ + + namespace + { + types::boundary_id + translate_boundary_indicator (const std::string &name_, + const std::map &boundary_names_mapping) + { + // trim whitespace on either side of the name if necessary + std::string name = name_; + while ((name.size() > 0) && (name[0] == ' ')) + name.erase (name.begin()); + while ((name.size() > 0) && (name[name.size()-1] == ' ')) + name.erase (name.end()-1); + + // backwards compatibility (rename boundaries to all use "top" and "bottom" + if (name == "surface" || name == "outer") + name = "top"; + else if (name == "inner") + name = "bottom"; + + // see if the given name is a symbolic one + if (boundary_names_mapping.find (name) != boundary_names_mapping.end()) + return boundary_names_mapping.find(name)->second; + else + return dealii::Utilities::string_to_int(name); + } + + + std::vector + translate_boundary_indicators (const std::vector &names, + const std::map &boundary_names_mapping) + { + std::vector results; + results.reserve(names.size()); + for (const auto &name : names) + results.push_back (translate_boundary_indicator(name, boundary_names_mapping)); + + return results; + } + } + + + template + types::boundary_id + Interface:: + translate_symbolic_boundary_name_to_id (const std::string &name) const + { + return translate_boundary_indicator(name, get_symbolic_boundary_names_map()); + } + + + + template + std::vector + Interface:: + translate_symbolic_boundary_names_to_ids (const std::vector &names) const + { + return translate_boundary_indicators(names, get_symbolic_boundary_names_map()); + } + + + template + std::string + Interface:: + translate_id_to_symbol_name(const types::boundary_id boundary_id) const + { + const std::map mapping = get_symbolic_boundary_names_map(); + + // loop over all entries in the map, and set 'name' to the key if the + // value matches the given 'boundary_id'. if 'name' has already been + // set, then this means that we had previously already found it -- i.e., + // that it is in the map at least twice. produce an error in that case. + std::string name; + for (const auto &p : mapping) + if (p.second == boundary_id) + { + Assert (name == "", + ExcMessage ("This geometry model appears to provide multiple " + "names for the boundary with indicator <" + + Utilities::int_to_string (boundary_id) + ">.")); + name = p.first; + } + + return name; + } + + +// -------------------------------- Deal with registering geometry models and automating +// -------------------------------- their setup and selection at run time + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + register_geometry_model (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + template + std::unique_ptr> + create_geometry_model (ParameterHandler &prm) + { + std::string model_name; + prm.enter_subsection ("Geometry model"); + { + model_name = prm.get ("Model name"); + } + prm.leave_subsection (); + + // If one sets the model name to an empty string in the input file, + // ParameterHandler produces an error while reading the file. However, + // if one omits specifying any model name at all (not even setting it to + // the empty string) then the value we get here is the empty string. If + // we don't catch this case here, we end up with awkward downstream + // errors because the value obviously does not conform to the Pattern. + AssertThrow(model_name != "unspecified", + ExcMessage("You need to select a Geometry model " + "(`set Model name' in `subsection Geometry model').")); + + return std::get(registered_plugins).create_plugin (model_name, + "Geometry model::model name", + prm); + } + + + + template + void + declare_parameters (ParameterHandler &prm) + { + // declare the entry in the parameter file + prm.enter_subsection ("Geometry model"); + { + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + prm.declare_entry ("Model name", "unspecified", + Patterns::Selection (pattern_of_names+"|unspecified"), + "Select one of the following models:\n\n" + + + std::get(registered_plugins).get_description_string()); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Geometry model interface", + out); + } + + + + template + void + Interface::make_periodicity_constraints(const DoFHandler &dof_handler, + AffineConstraints &constraints) const + { + using periodic_boundary_set + = std::set, unsigned int>>; + periodic_boundary_set pbs = get_periodic_boundary_pairs(); + + for (const auto &pb : pbs) + { + DoFTools::make_periodicity_constraints(dof_handler, + pb.first.first, // first boundary id + pb.first.second, // second boundary id + pb.second, // cartesian direction for translational symmetry + constraints); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace GeometryModel + { +#define INSTANTIATE(dim) \ + template class Interface; \ + \ + template \ + void \ + register_geometry_model (const std::string &, \ + const std::string &, \ + void ( *) (ParameterHandler &), \ + std::unique_ptr>( *) ()); \ + \ + template \ + void \ + declare_parameters (ParameterHandler &); \ + \ + template \ + void \ + write_plugin_graph (std::ostream &); \ + \ + template \ + std::unique_ptr> \ + create_geometry_model (ParameterHandler &prm); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/geometry_model/sphere.cc.bak b/source/geometry_model/sphere.cc.bak new file mode 100644 index 00000000000..08420710357 --- /dev/null +++ b/source/geometry_model/sphere.cc.bak @@ -0,0 +1,238 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include +#include + +namespace aspect +{ + namespace GeometryModel + { + template + void + Sphere:: + create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const + { + GridGenerator::hyper_ball (coarse_grid, + Point(), + R); + + coarse_grid.set_manifold(0, SphericalManifold()); + coarse_grid.set_all_manifold_ids_on_boundary(0); + } + + + template + std::set + Sphere:: + get_used_boundary_indicators () const + { + const types::boundary_id s[] = { 0 }; + return std::set(std::begin(s), std::end(s)); + } + + + template + std::map + Sphere:: + get_symbolic_boundary_names_map () const + { + return {{"top", 0}}; + } + + + template + double + Sphere:: + length_scale () const + { + // as described in the first ASPECT paper, a length scale of + // 10km = 1e4m works well for the pressure scaling for earth + // sized spherical shells. use a length scale that + // yields this value for the R0,R1 corresponding to earth + // but otherwise scales like (R1-R0) + return 1e4 * maximal_depth() / (6336000.-3481000.); + } + + + + template + double + Sphere::depth(const Point &position) const + { + return std::min (std::max (R-position.norm(), 0.), maximal_depth()); + } + + template + double + Sphere::height_above_reference_surface(const Point &position) const + { + return position.norm()-radius(); + } + + + template + Point + Sphere::representative_point(const double depth) const + { + Point p; + p(dim-1) = std::min (std::max(R - depth, 0.), maximal_depth()); + return p; + } + + + + template + double + Sphere::maximal_depth() const + { + return R; + } + + template + double Sphere::radius () const + { + return R; + } + + template + bool + Sphere::has_curved_elements () const + { + return true; + } + + + + template + bool + Sphere::point_is_in_domain(const Point &point) const + { + AssertThrow(!this->get_parameters().mesh_deformation_enabled || + this->get_timestep_number() == 0, + ExcMessage("After displacement of the mesh, this function can no longer be used to determine whether a point lies in the domain or not.")); + + AssertThrow(Plugins::plugin_type_matches>(this->get_initial_topography_model()), + ExcMessage("After adding topography, this function can no longer be used to determine whether a point lies in the domain or not.")); + + const double radius = point.norm(); + + if (radius > R+std::numeric_limits::epsilon()*R) + return false; + + return true; + } + + + + template + std::array + Sphere::cartesian_to_natural_coordinates(const Point &position) const + { + return Utilities::Coordinates::cartesian_to_spherical_coordinates(position); + } + + + + template + aspect::Utilities::Coordinates::CoordinateSystem + Sphere::natural_coordinate_system() const + { + return aspect::Utilities::Coordinates::CoordinateSystem::spherical; + } + + + + template + Point + Sphere::natural_to_cartesian_coordinates(const std::array &position) const + { + return Utilities::Coordinates::spherical_to_cartesian_coordinates(position); + } + + + + template + void + Sphere::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Sphere"); + { + prm.declare_entry ("Radius", "6371000.", + Patterns::Double (0.), + "Radius of the sphere. Units: \\si{\\meter}."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + Sphere::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Sphere"); + { + R = prm.get_double ("Radius"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace GeometryModel + { + ASPECT_REGISTER_GEOMETRY_MODEL(Sphere, + "sphere", + "A geometry model for a sphere with a user specified " + "radius. This geometry has only a single boundary, so " + "the only valid boundary indicator to " + "specify in input files is ``0''. It can also be " + "referenced by the symbolic name ``surface'' in " + "input files." + "\n\n" + "Despite the name, this geometry does not imply the use of " + "a spherical coordinate system when used in 2d. Indeed, " + "in 2d the geometry is simply a circle in a Cartesian " + "coordinate system and consequently would correspond to " + "a cross section of the fluid filled interior of an " + "infinite cylinder where one has made the assumption that " + "the velocity in direction of the cylinder axes is zero. " + "This is consistent with the definition of what we consider " + "the two-dimension case given in " + "Section~\\ref{sec:methods:2d-models}.") + } +} diff --git a/source/geometry_model/spherical_shell.cc.bak b/source/geometry_model/spherical_shell.cc.bak new file mode 100644 index 00000000000..0f06e10d786 --- /dev/null +++ b/source/geometry_model/spherical_shell.cc.bak @@ -0,0 +1,1074 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace GeometryModel + { + namespace + { + void append_face_to_subcell_data(SubCellData &subcell_data, const CellData<1> &face) + { + subcell_data.boundary_lines.push_back(face); + } + + + + void append_face_to_subcell_data(SubCellData &subcell_data, const CellData<2> &face) + { + subcell_data.boundary_quads.push_back(face); + } + } + + + namespace internal + { + template + SphericalManifoldWithTopography:: + SphericalManifoldWithTopography(const InitialTopographyModel::Interface &topography, + const double inner_radius, + const double outer_radius) + : + SphericalManifold(Point()), + topo (&topography), + R0 (inner_radius), + R1 (outer_radius) + {} + + + template + std::unique_ptr> + SphericalManifoldWithTopography::clone() const + { + return std::make_unique>(*this); + } + + + + template + double + SphericalManifoldWithTopography:: + topography_for_point(const Point &x_y_z) const + { + if (dynamic_cast*>(topo) != nullptr) + return 0; + else + { + Assert (dim==3, ExcNotImplemented()); + + // The natural coordinate system of the sphere geometry is r/phi/theta. + // This is what we need to query the topography with. So start by + // converting into this coordinate system + const std::array r_phi_theta = Utilities::Coordinates::cartesian_to_spherical_coordinates(x_y_z); + + // Grab lon,lat coordinates + Point surface_point; + for (unsigned int d=0; dvalue(surface_point); + } + } + + + + template + Point + SphericalManifoldWithTopography:: + push_forward_from_sphere(const Point &p) const + { + const double topography = topography_for_point(p); + + // We can short-circuit the computations here if the topography + // is zero. + if (topography == 0) + return p; + else + { + // For the case with (non-zero) topography, we have to project + // the point out/inward. + + // We start from the undeformed sphere. So the current radius must be + // between R0 and R1. Check this, with a slight tolerance to account + // for the fact that our mesh is not *completely* spherical. + const double r = p.norm(); + Assert (r>=R0*0.99, ExcInternalError()); + Assert (r<=R1*1.01, ExcInternalError()); + + // Then we need to stretch the point p outward by a factor that is + // zero at the core-mantle boundary and results in the right topography + // at the top. + // + // The stretching factor is relative to the distance from the core + // mantle boundary. + const double cmb_stretching_factor = (R1+topography-R0)/(R1-R0); + + // From this we can compute what the desired radius is going to be, and + // scale the given point accordingly: + const double new_radius = (r-R0)*cmb_stretching_factor + R0; + return p * (new_radius/r); + } + } + + + + template + Point + SphericalManifoldWithTopography:: + pull_back_to_sphere(const Point &p) const + { + const double topography = topography_for_point(p); + + // We can short-circuit the computations here if the topography + // is zero. + if (topography == 0) + return p; + else + { + // For the case with (non-zero) topography, we have to project + // the point in/outward. + + // We start from the deformed sphere. So the current radius must be + // between R0 and R1+topography. Check this, with a slight tolerance + // to account for the fact that our mesh is not *completely* spherical. + const double r = p.norm(); + Assert (r>=R0*0.99, ExcInternalError()); + Assert (r<=(R1+topography)*1.01, ExcInternalError()); + + // Then we need to stretch(=shrink) the point p outward by a factor that is + // zero at the core-mantle boundary and results in the right topography + // at the top. + const double cmb_stretching_factor = (R1-R0)/(R1+topography-R0); + + // From this we can compute what the desired radius is going to be, and + // scale the given point accordingly: + const double new_radius = (r-R0)*cmb_stretching_factor + R0; + return p * (new_radius/r); + } + } + + + + template + Point + SphericalManifoldWithTopography:: + get_intermediate_point(const Point &p1, + const Point &p2, + const double w) const + { + return + push_forward_from_sphere + (SphericalManifold::get_intermediate_point (pull_back_to_sphere(p1), + pull_back_to_sphere(p2), w)); + } + + + + template + Tensor<1, dim> + SphericalManifoldWithTopography:: + get_tangent_vector(const Point &x1, + const Point &x2) const + { + // TODO: Deal with pull back and push forward + return SphericalManifold::get_tangent_vector (x1, x2); + } + + + + template + Tensor<1, dim> + SphericalManifoldWithTopography:: + normal_vector(const typename Triangulation::face_iterator &face, + const Point &p) const + { + // We calculate radial, rather than *normal*, vectors here if a face is + // at the boundary. This is as described in the documentation of this + // function. + + // TODO: Add an input parameter that determines whether we use this + // or the "geometrically correct" behavior. + return SphericalManifold::normal_vector (face, p); + } + + + + template + void + SphericalManifoldWithTopography:: + get_normals_at_vertices( + const typename Triangulation::face_iterator &face, + typename Manifold::FaceVertexNormals &face_vertex_normals) const + { + // TODO: Deal with pull back and push forward + SphericalManifold::get_normals_at_vertices(face, face_vertex_normals); + } + + + + template + void + SphericalManifoldWithTopography:: + get_new_points(const ArrayView> &surrounding_points, + const Table<2, double> &weights, + ArrayView> new_points) const + { + // First compute the points in the untransformed coordinate system + // without surface topography: + std::vector> untransformed_points; + untransformed_points.reserve(surrounding_points.size()); + for (const Point &p : surrounding_points) + untransformed_points.emplace_back (pull_back_to_sphere(p)); + + // Call the function in the base class: + SphericalManifold::get_new_points(untransformed_points, weights, new_points); + + // Since the function in the base class returned its information + // in a writable array, we can in-place push forward to the deformed + // sphere with topography: + for (Point &p : new_points) + p = push_forward_from_sphere(p); + } + + + + template + Point + SphericalManifoldWithTopography:: + get_new_point(const ArrayView> &surrounding_points, + const ArrayView &weights) const + { + // First compute the points in the untransformed coordinate system + // without surface topography: + std::vector> untransformed_points; + untransformed_points.reserve(surrounding_points.size()); + for (const Point &p : surrounding_points) + untransformed_points.emplace_back (pull_back_to_sphere(p)); + + // Call the function in the base class, and transform the + // returned value: + return push_forward_from_sphere(SphericalManifold::get_new_point(untransformed_points, + weights)); + } + } + + + + template + void + SphericalShell::initialize () + { + manifold = std::make_unique>(this->get_initial_topography_model(), + R0, R1); + } + + + + template + void + SphericalShell:: + create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const + { + AssertThrow (phi == 360 || phi == 90 || ((phi == 180) && (dim == 2)), + ExcMessage ("The only opening angles that are allowed for " + "this geometry are 90, 180, and 360 in 2d; " + "and 90 and 360 in 3d.")); + + // Custom mesh extrusion is only implemented for full spherical shells + // for now, so check that custom mesh schemes are only being used when + // the opening angle is 360 degrees. + AssertThrow (phi == 360 || (custom_mesh == none), + ExcMessage ("The only opening angle that is allowed for " + "this geometry with a custom mesh is 360.")); + + if (phi == 360) + { + if (custom_mesh == none) + { + // If we are not using a custom mesh scheme, the mesh is generated + // as per the original code. + GridGenerator::hyper_shell (coarse_grid, + Point(), + R0, + R1, + (n_cells_along_circumference == 0 + ? + // automatic choice that leads to reasonable + // meshes with the typical aspect ratio of + // the Earth + (dim==3 ? 96 : 12) + : + // user choice + n_cells_along_circumference), + true); + } + else + { + Assert(custom_mesh == slices || custom_mesh == list, ExcNotImplemented()); + // If we are using a custom mesh scheme, we need to create + // a new triangulation to extrude (this will be a 1D line in + // 2d space, or a 2d surface in 3d space). + Triangulation sphere_mesh; + GridGenerator::hyper_sphere (sphere_mesh); + sphere_mesh.refine_global (initial_lateral_refinement); + + // Calculate the number of R_values wrt custom mesh scheme + unsigned int n_R_values; + if (custom_mesh == slices) + n_R_values = n_slices+1; + else + n_R_values = R_values_list.size()+2; + + // Allocate R_values wrt the number of slices + std::vector R_values (n_R_values); + if (custom_mesh == slices) + { + for (unsigned int s=0; s> points(R_values.size() * sphere_mesh.n_vertices()); + + + // Copy the array of points as many times as there will be slices, + // one slice at a time. The z-axis value are defined in slices_coordinates + for (unsigned int point_layer = 0; point_layer < R_values.size(); ++point_layer) + { + for (unsigned int vertex_n = 0; vertex_n < sphere_mesh.n_vertices(); + ++vertex_n) + { + const Point vertex = sphere_mesh.get_vertices()[vertex_n]; + points[point_layer * sphere_mesh.n_vertices() + vertex_n] = + vertex * R_values[point_layer]; + } + } + + // Then create the cells of each of the slices, one stack at a + // time + std::vector> cells; + cells.reserve((R_values.size() - 1) * sphere_mesh.n_active_cells()); + + SubCellData subcell_data; + + for (const auto &cell : sphere_mesh.active_cell_iterators()) + { + for (unsigned int cell_layer = 0; cell_layer < R_values.size() - 1; ++cell_layer) + { + CellData this_cell; + for (const unsigned int vertex_n : cell->vertex_indices()) + { + this_cell.vertices[vertex_n] = + cell->vertex_index(vertex_n) + cell_layer * sphere_mesh.n_vertices(); + this_cell.vertices[vertex_n + cell->n_vertices()] = + cell->vertex_index(vertex_n) + + (cell_layer + 1) * sphere_mesh.n_vertices(); + } + + this_cell.material_id = cell->material_id(); + + + Assert(GridTools::cell_measure (points, this_cell.vertices) > 0, ExcInternalError()); + + cells.push_back(this_cell); + + // Mark the bottom face of the cell as boundary 0 if we are in + // the bottom layer of cells + if (cell_layer == 0) + { + CellData face; + for (const unsigned int vertex_n : cell->vertex_indices()) + face.vertices[vertex_n] = + cell->vertex_index(vertex_n) + cell_layer * sphere_mesh.n_vertices(); + face.boundary_id = 0; + + append_face_to_subcell_data(subcell_data, face); + } + + // Mark the top face of the cell as boundary 1 if we are in + // the top layer of cells + if (cell_layer == R_values.size()-2) + { + CellData face; + for (const unsigned int vertex_n : cell->vertex_indices()) + face.vertices[vertex_n] = + cell->vertex_index(vertex_n) + + (cell_layer + 1) * sphere_mesh.n_vertices(); + face.boundary_id = 1; + + append_face_to_subcell_data(subcell_data, face); + } + + } + } + + // Then create the actual mesh: + GridTools::consistently_order_cells (cells); + coarse_grid.create_triangulation(points, cells, subcell_data); + } + } + else if (phi == 90) + { + GridGenerator::quarter_hyper_shell (coarse_grid, + Point(), + R0, + R1, + 0, + true); + + if (periodic) + { + // Tell p4est about the periodicity of the mesh. + std::vector::cell_iterator>> + matched_pairs; + FullMatrix rotation_matrix(dim); + rotation_matrix[0][1] = 1.; + rotation_matrix[1][0] = -1.; + + GridTools::collect_periodic_faces(coarse_grid, /*b_id1*/ 2, /*b_id2*/ 3, + /*direction*/ 1, matched_pairs, + Tensor<1, dim>(), rotation_matrix); + + if (matched_pairs.size() > 0) + coarse_grid.add_periodicity (matched_pairs); + } + } + else if (phi == 180) + { + GridGenerator::half_hyper_shell (coarse_grid, + Point(), + R0, + R1, + 0, + true); + } + else + { + Assert (false, ExcInternalError()); + } + + // Then add the topography to the mesh by moving all vertices from the + // undeformed sphere to the sphere with topography: + GridTools::transform ( + [&](const Point &p) -> Point + { + return manifold->push_forward_from_sphere(p); + }, + coarse_grid); + + // Use a manifold description for all cells. Use manifold_id 99 in order + // not to step on the boundary indicators used below. + coarse_grid.set_manifold (my_manifold_id, *manifold); + set_manifold_ids(coarse_grid); + } + + + + template + void + SphericalShell::set_manifold_ids (parallel::distributed::Triangulation &triangulation) const + { + for (const auto &cell : triangulation.active_cell_iterators()) + cell->set_all_manifold_ids (my_manifold_id); + } + + + + template + std::set + SphericalShell:: + get_used_boundary_indicators () const + { + // Follow what is described in the documentation of this class. + // see the documentation of the various GridGenerator::*hyper_shell + // functions for a description of which boundary indicators are + // set and how they correlate to what's used below + if (phi == 360) + { + const types::boundary_id s[] = { 0, 1 }; + return std::set(std::begin(s), std::end(s)); + } + else if (phi == 90 && dim == 3) + { + const types::boundary_id s[] = { 0, 1, 2, 3, 4}; + return std::set(std::begin(s), std::end(s)); + } + else + { + const types::boundary_id s[] = { 0, 1, 2, 3 }; + return std::set(std::begin(s), std::end(s)); + } + } + + + + template + std::map + SphericalShell:: + get_symbolic_boundary_names_map () const + { + switch (dim) + { + case 2: + { + static const std::pair mapping[] + = { {"bottom", 0}, + {"top", 1}, + {"left", 2}, + {"right", 3} + }; + + if (phi == 360) + return std::map (std::begin(mapping), + std::begin(mapping)+2); + else + return std::map (std::begin(mapping), + std::begin(mapping)+4); + } + + case 3: + { + if (phi == 360) + { + return + { + {"bottom", 0}, + {"top", 1} + }; + } + else if (phi == 90) + { + return + { + {"bottom", 0}, + {"top", 1}, + {"east", 2}, + {"west", 3}, + {"south", 4} + }; + } + else + Assert (false, ExcNotImplemented()); + } + } + + Assert (false, ExcNotImplemented()); + return {}; + } + + + + template + std::set, unsigned int>> + SphericalShell:: + get_periodic_boundary_pairs () const + { + std::set, unsigned int>> periodic_boundaries; + if (periodic) + { + periodic_boundaries.insert( std::make_pair( std::pair(2, 3), 1) ); + } + return periodic_boundaries; + } + + + + template + void + SphericalShell::adjust_positions_for_periodicity (Point &position, + const ArrayView> &connected_positions, + const ArrayView> &connected_velocities) const + { + AssertThrow(dim == 2, + ExcMessage("Periodic boundaries currently " + "only work with 2d spherical shell.")); + AssertThrow(phi == 90, + ExcMessage("Periodic boundaries currently " + "only work with 90 degree opening angle in spherical shell.")); + + if (periodic) + { + // define a rotation matrix for the new position depending on the boundary + Tensor<2,dim> rotation_matrix; + + if (position[0] < 0.) + { + rotation_matrix[0][1] = 1.; + rotation_matrix[1][0] = -1.; + } + else if (position[1] < 0.) + { + rotation_matrix[0][1] = -1.; + rotation_matrix[1][0] = 1.; + } + else + return; + + position = rotation_matrix * position; + + for (auto &connected_position: connected_positions) + connected_position = rotation_matrix * connected_position; + + for (auto &connected_velocity: connected_velocities) + connected_velocity = rotation_matrix * connected_velocity; + } + + return; + } + + + + template + double + SphericalShell:: + length_scale () const + { + // As described in the first ASPECT paper, a length scale of + // 10km = 1e4m works well for the pressure scaling for earth + // sized spherical shells. So use a formulation that yields this + // value for the R0,R1 corresponding to earth, and that more + // generally scales with (R1-R0), which we can get by calling + // maximal_depth(). In essence, the factor in front of the call + // to maximal_depth() is just a magic number that has turned out + // to work well. + return (1e4 / (6336000.-3481000.)) * maximal_depth(); + } + + + + template + double + SphericalShell::depth(const Point &position) const + { + return std::min (std::max (R1-position.norm(), 0.), maximal_depth()); + } + + + + template + double + SphericalShell::height_above_reference_surface(const Point &position) const + { + return position.norm()-R1; + } + + + + template + Point + SphericalShell::representative_point(const double depth) const + { + Assert (depth >= 0, + ExcMessage ("Given depth must be positive or zero.")); + Assert (depth <= maximal_depth(), + ExcMessage ("Given depth must be less than or equal to the maximal depth of this geometry.")); + + // Choose a point along the axes toward the north pole, at the + // requested depth. + Point p; + p[dim-1] = std::min (std::max(R1 - depth, R0), R1); + + // Return this point. This ignores the surface topography, + // but that is as documented. + return p; + } + + + + template + double + SphericalShell::maximal_depth() const + { + // The depth is defined as relative to a reference surface (without + // topography) and since we don't apply topography on the CMB, + // the maximal depth really is R1-R0 unless one applies a + // topography that is always strictly below zero (i.e., where the + // actual surface lies strictly below the reference surface). + return R1-R0; + } + + + + template + double SphericalShell::inner_radius () const + { + return R0; + } + + + + template + double SphericalShell::outer_radius () const + { + return R1; + } + + + + template + double SphericalShell::opening_angle () const + { + return phi; + } + + + + template + bool + SphericalShell::has_curved_elements () const + { + return true; + } + + + + template + bool + SphericalShell::point_is_in_domain(const Point &point) const + { + AssertThrow(!this->get_parameters().mesh_deformation_enabled || + this->simulator_is_past_initialization() == false, + ExcMessage("After displacement of the free surface, this function can no longer be used to determine whether a point lies in the domain or not.")); + + AssertThrow(Plugins::plugin_type_matches>(this->get_initial_topography_model()), + ExcMessage("After adding topography, this function can no longer be used to determine whether a point lies in the domain or not.")); + + const std::array spherical_point = Utilities::Coordinates::cartesian_to_spherical_coordinates(point); + + std::array point1, point2; + point1[0] = R0; + point2[0] = R1; + point1[1] = 0.0; + point2[1] = phi * constants::degree_to_radians; + if (dim == 3) + { + point1[2] = 0.0; + + if (phi == 90.0) + // Octant + point2[2] = 0.5 * numbers::PI; + else + // Full shell + point2[2] = numbers::PI; + } + + for (unsigned int d = 0; d < dim; ++d) + if (spherical_point[d] > point2[d]+std::numeric_limits::epsilon()*std::abs(point2[d]) || + spherical_point[d] < point1[d]-std::numeric_limits::epsilon()*std::abs(point2[d])) + return false; + + // TODO: Take into account topography + + return true; + } + + + + template + std::array + SphericalShell::cartesian_to_natural_coordinates(const Point &position) const + { + // TODO: Take into account topography + return Utilities::Coordinates::cartesian_to_spherical_coordinates(position); + } + + + + template + aspect::Utilities::Coordinates::CoordinateSystem + SphericalShell::natural_coordinate_system() const + { + return aspect::Utilities::Coordinates::CoordinateSystem::spherical; + } + + + + template + Point + SphericalShell::natural_to_cartesian_coordinates(const std::array &position) const + { + // TODO: Take into account topography + return Utilities::Coordinates::spherical_to_cartesian_coordinates(position); + } + + + + template + void + SphericalShell::make_periodicity_constraints(const DoFHandler &dof_handler, + AffineConstraints &constraints) const + { + if (periodic) + { + std::vector::cell_iterator>> + matched_pairs; + FullMatrix rotation_matrix(dim); + rotation_matrix[0][1] = 1.; + rotation_matrix[1][0] = -1.; + + GridTools::collect_periodic_faces(dof_handler, /*b_id1*/ 2, /*b_id2*/ 3, + /*direction*/ 1, matched_pairs, + Tensor<1, dim>(), rotation_matrix); + + DoFTools::make_periodicity_constraints(matched_pairs, + constraints, + ComponentMask(), + {0}, + 1.); + } + } + + + + template + void + SphericalShell::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Spherical shell"); + { + prm.declare_entry ("Custom mesh subdivision", "none", + Patterns::Selection ("none|list of radial values|number of slices"), + "Choose how the spherical shell mesh is generated. " + "By default, a coarse mesh is generated with respect to the " + "inner and outer radius, and an initial number of cells along " + "circumference. " + "In the other cases, a surface mesh is first generated and " + "refined as desired, before it is extruded radially following " + "the specified subdivision scheme."); + prm.declare_entry ("List of radial values", "", + Patterns::List(Patterns::Double ()), + "List of radial values for the custom mesh scheme. Units: " + "$\\si{m}$. " + "A list of radial values subdivides the spherical shell at " + "specified radii. The list must be strictly ascending, and " + "the first value must be greater than the inner radius " + "while the last must be less than the outer radius."); + prm.declare_entry ("Number of slices", "1", + Patterns::Integer (1), + "Number of slices for the custom mesh subdivision scheme. " + "The number of slices subdivides the spherical shell into N " + "slices of equal thickness. Must be greater than 0."); + prm.declare_entry ("Initial lateral refinement", "0", + Patterns::Integer (0), + "Initial lateral refinement for the custom mesh subdivision " + "schemes." + "The number of refinement steps performed on the initial " + "coarse surface mesh, before the surface is extruded " + "radially. This parameter allows the user more control " + "over the ratio between radial and lateral refinement of " + "the mesh."); + prm.declare_entry ("Inner radius", "3481000.", // 6371-2890 in km + Patterns::Double (0.), + "Inner radius of the spherical shell. Units: \\si{\\meter}." + "\n\n" + ":::{note}\n" + "The default value of 3,481,000 m equals the " + "radius of a sphere with equal volume as Earth (i.e., " + "6371 km) minus the average depth of the core-mantle " + "boundary (i.e., 2890 km).\n" + ":::"); + prm.declare_entry ("Outer radius", "6336000.", // 6371-35 in km + Patterns::Double (0.), + "Outer radius of the spherical shell. Units: \\si{\\meter}." + "\n\n" + ":::{note}\n" + "The default value of 6,336,000 m equals the " + "radius of a sphere with equal volume as Earth (i.e., " + "6371 km) minus the average depth of the mantle-crust " + "interface (i.e., 35 km).\n" + ":::"); + prm.declare_entry ("Opening angle", "360.", + Patterns::Double (0., 360.), + "Opening angle in degrees of the section of the shell " + "that we want to build. " + "The only opening angles that are allowed for " + "this geometry are 90, 180, and 360 in 2d; " + "and 90 and 360 in 3d. " + "Units: degrees."); + prm.declare_entry ("Cells along circumference", "0", + Patterns::Integer (0), + "The number of cells in circumferential direction that are " + "created in the coarse mesh in 2d. If zero, this number " + "is chosen automatically in a way that produces meshes " + "in which cells have a reasonable aspect ratio for models " + "in which the depth of the mantle is roughly that of the " + "Earth. For planets with much shallower mantles and larger " + "cores, you may want to chose a larger number to avoid " + "cells that are elongated in tangential and compressed in " + "radial direction." + "\n\n" + "In 3d, the number of cells is computed differently and does " + "not have an easy interpretation. Valid values for this parameter " + "in 3d are 0 (let this class choose), 6, 12 and 96. " + "Other possible values may be discussed in the documentation " + "of the deal.II function GridGenerator::hyper_shell. " + "The parameter is best left at its default in 3d." + "\n\n" + "In either case, this parameter is ignored unless the opening " + "angle of the domain is 360 degrees. This parameter is also " + "ignored when using a custom mesh subdivision scheme."); + prm.declare_entry ("Phi periodic", "false", + Patterns::Bool (), + "Whether the shell should be periodic in the phi direction."); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + SphericalShell::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Spherical shell"); + { + R0 = prm.get_double ("Inner radius"); + R1 = prm.get_double ("Outer radius"); + phi = prm.get_double ("Opening angle"); + n_cells_along_circumference = prm.get_integer ("Cells along circumference"); + initial_lateral_refinement = prm.get_integer ("Initial lateral refinement"); + R_values_list = Utilities::string_to_double(Utilities::split_string_list(prm.get("List of radial values"))); + n_slices = prm.get_integer ("Number of slices"); + + if (prm.get ("Custom mesh subdivision") == "none") + custom_mesh = none; + else if (prm.get ("Custom mesh subdivision") == "list of radial values") + custom_mesh = list; + else if (prm.get ("Custom mesh subdivision") == "number of slices") + custom_mesh = slices; + else + AssertThrow (false, ExcMessage ("Not a valid custom mesh subdivision scheme.")); + + // Check that inner radius is less than outer radius + AssertThrow (R0 < R1, + ExcMessage ("Inner radius must be less than outer radius.")); + + // If we are using list of radial values for a custom mesh + if (custom_mesh == list) + { + // Check that list is in ascending order + for (unsigned int i = 1; i < R_values_list.size(); ++i) + AssertThrow(R_values_list[i] > R_values_list[i-1], + ExcMessage("Radial values must be strictly ascending")); + // Check that first value is not smaller than the inner radius + AssertThrow(R_values_list[1] > R0, + ExcMessage("First value in List of radial values must be greater than inner radius")); + // Check that last layer is not larger than the outer radius + AssertThrow( *(R_values_list.end()-1) < R1, + ExcMessage("Last value in List of radial values must be less than outer radius")); + } + + + // If we are extruding the mesh according to a number of slices + if (custom_mesh == slices) + { + AssertThrow (n_slices > 0, ExcMessage("You must set a positive number of slices for extrusion")); + } + + periodic = prm.get_bool ("Phi periodic"); + if (periodic) + { + AssertThrow (dim == 2, ExcMessage("Periodic boundaries in the spherical shell are only supported for 2d models.")); + AssertThrow (phi == 90, ExcMessage("Periodic boundaries in the spherical shell are only supported for an opening angle of 90 degrees.")); + } + + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace GeometryModel + { + ASPECT_REGISTER_GEOMETRY_MODEL(SphericalShell, + "spherical shell", + "A geometry representing a spherical shell or a piece of it. " + "Inner and outer radii are read from the parameter file " + "in subsection 'Spherical shell'." + "\n\n" + "The spherical shell may be generated as per the original " + "code (with respect to the inner and outer radius, and an " + "initial number of cells along circumference) or following " + "a custom mesh scheme: list of radial values or number of " + "slices. A surface mesh is first generated and refined as " + "desired, before it is extruded radially. A list of radial " + "values subdivides the spherical shell at specified radii. " + "The number of slices subdivides the spherical shell into N " + "slices of equal thickness. The custom spherical shell only " + "works with an opening angle of 360 degrees." + "\n\n" + "Despite the name, this geometry does not imply the use of " + "a spherical coordinate system when used in 2d. Indeed, " + "in 2d the geometry is simply an annulus in a Cartesian " + "coordinate system and consequently would correspond to " + "a cross section of the fluid filled space between two " + "infinite cylinders where one has made the assumption that " + "the velocity in direction of the cylinder axes is zero. " + "This is consistent with the definition of what we consider " + "the two-dimension case given in " + "Section~\\ref{sec:methods:2d-models}." + "\n\n" + "The model assigns boundary indicators as follows: In 2d, " + "inner and outer boundaries get boundary indicators zero " + "and one, and if the opening angle set in the input file " + "is less than 360, then left and right boundaries are " + "assigned indicators two and three. These boundaries can " + "also be referenced using the symbolic names `inner', `outer' " + "and (if applicable) `left', `right'." + "\n\n" + "In 3d, inner and " + "outer indicators are treated as in 2d. If the opening " + "angle is chosen as 90 degrees, i.e., the domain is the " + "intersection of a spherical shell and the first octant, " + "then indicator 2 is at the face $x=0$, 3 at $y=0$, " + "and 4 at $z=0$. These last three boundaries can then also " + "be referred to as `east', `west' and `south' symbolically " + "in input files.") + } +} diff --git a/source/geometry_model/two_merged_boxes.cc.bak b/source/geometry_model/two_merged_boxes.cc.bak new file mode 100644 index 00000000000..fad3973b171 --- /dev/null +++ b/source/geometry_model/two_merged_boxes.cc.bak @@ -0,0 +1,570 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace GeometryModel + { + template + void + TwoMergedBoxes:: + set_boundary_indicators (parallel::distributed::Triangulation &triangulation) const + { + // iterate over all active cells and (re)set the boundary indicators + for (const auto &cell : triangulation.active_cell_iterators()) + { + // first set the default boundary indicators + for (const unsigned int f : cell->face_indices()) + if (cell->face(f)->at_boundary()) + cell->face(f)->set_boundary_id (f); + + // Then for individual faces set the boundary indicators in specific ways: + if (cell->face(0)->at_boundary()) + // set the lithospheric part of the left boundary to indicator 2*dim + if (cell->face(0)->vertex(cell->face(0)->n_vertices()-1)[dim-1] > height_lith) + cell->face(0)->set_boundary_id (2*dim); + + if (cell->face(1)->at_boundary()) + // set the lithospheric part of the right boundary to indicator 2*dim+1 + if (cell->face(1)->vertex(cell->face(1)->n_vertices()-1)[dim-1] > height_lith) + cell->face(1)->set_boundary_id (2*dim+1); + + if (dim==3) + { + // set the lithospheric part of the front boundary to indicator 2*dim+2 + if (cell->face(2)->at_boundary()) + if (cell->face(2)->vertex(cell->face(2)->n_vertices()-1)[dim-1] > height_lith) + cell->face(2)->set_boundary_id (2*dim+2); + + // set the lithospheric part of the back boundary to indicator 2*dim+3 + if (cell->face(3)->at_boundary()) + if (cell->face(3)->vertex(cell->face(3)->n_vertices()-1)[dim-1] > height_lith) + cell->face(3)->set_boundary_id (2*dim+3); + } + } + } + + template + void + TwoMergedBoxes:: + create_coarse_mesh (parallel::distributed::Triangulation &total_coarse_grid) const + { + std::vector lower_rep_vec(lower_repetitions.begin(), lower_repetitions.end()); + if (use_merged_grids) + { + std::vector upper_rep_vec(upper_repetitions.begin(), upper_repetitions.end()); + + // the two triangulations that will be merged + Triangulation lower_coarse_grid; + Triangulation upper_coarse_grid; + + // create lower_coarse_grid mesh + GridGenerator::subdivided_hyper_rectangle (lower_coarse_grid, + lower_rep_vec, + lower_box_origin, + lower_box_origin+lower_extents, + false); + + // create upper_coarse_grid mesh + GridGenerator::subdivided_hyper_rectangle (upper_coarse_grid, + upper_rep_vec, + upper_box_origin, + upper_box_origin+upper_extents, + false); + + // merge the lower and upper mesh into one total_coarse_grid. + // now we have at least two cells + GridGenerator::merge_triangulations(lower_coarse_grid, + upper_coarse_grid, + total_coarse_grid); + } + else + { + GridGenerator::subdivided_hyper_rectangle (total_coarse_grid, + lower_rep_vec, + lower_box_origin, + upper_box_origin+upper_extents, + false); + } + + // set the boundary indicators + set_boundary_indicators(total_coarse_grid); + + // tell p4est about the periodicity of the mesh. + std::vector::cell_iterator>> + periodicity_vector; + for (int i=0; i 0) + total_coarse_grid.add_periodicity (periodicity_vector); + + // make sure the right boundary indicators are set after refinement + // through the function set_boundary_indicators above + total_coarse_grid.signals.post_refinement.connect ( + [&]() + { + this->set_boundary_indicators(total_coarse_grid); + }); + } + + + template + std::set + TwoMergedBoxes:: + get_used_boundary_indicators () const + { + // boundary indicators are zero through 2*dim+2*(dim-1)-1 + std::set s; + for (unsigned int i=0; i<2*dim+2*(dim-1); ++i) + s.insert (i); + return s; + } + + + + template + std::map + TwoMergedBoxes:: + get_symbolic_boundary_names_map () const + { + switch (dim) + { + case 2: + { + return + { + {"left", 0}, + {"right", 1}, + {"bottom", 2}, + {"top", 3}, + {"left lithosphere", 4}, + {"right lithosphere",5} + }; + } + + case 3: + { + return + { + {"left", 0}, + {"right", 1}, + {"front", 2}, + {"back", 3}, + {"bottom", 4}, + {"top", 5}, + {"left lithosphere", 6}, + {"right lithosphere", 7}, + {"front lithosphere", 8}, + {"back lithosphere", 9} + }; + } + } + + Assert (false, ExcNotImplemented()); + return {}; + } + + + + template + std::set, unsigned int>> + TwoMergedBoxes:: + get_periodic_boundary_pairs () const + { + std::set, unsigned int>> periodic_boundaries; + for ( unsigned int i=0; i=dim ? i-dim : i; + periodic_boundaries.insert( std::make_pair( std::pair(2*i, 2*i+1), direction) ); + } + return periodic_boundaries; + } + + + + template + void + TwoMergedBoxes::adjust_positions_for_periodicity (Point &position, + const ArrayView> &connected_positions, + const ArrayView> &/*connected_velocities*/) const + { + for (unsigned int i = 0; i < dim; ++i) + if (periodic[i]) + { + if (position[i] < lower_box_origin[i]) + { + position[i] += extents[i]; + for (auto &connected_position: connected_positions) + connected_position[i] += extents[i]; + } + else if (position[i] > lower_box_origin[i] + extents[i]) + { + position[i] -= extents[i]; + for (auto &connected_position: connected_positions) + connected_position[i] -= extents[i]; + } + } + } + + + + template + Point + TwoMergedBoxes::get_extents () const + { + return extents; + } + + template + Point + TwoMergedBoxes::get_origin () const + { + return lower_box_origin; + } + + template + double + TwoMergedBoxes:: + length_scale () const + { + return 0.01*extents[0]; + } + + + template + double + TwoMergedBoxes::depth(const Point &position) const + { + const double d = maximal_depth()-(position(dim-1)-lower_box_origin[dim-1]); + return std::min (std::max (d, 0.), maximal_depth()); + } + + + template + double + TwoMergedBoxes::height_above_reference_surface(const Point &position) const + { + return (position(dim-1)-lower_box_origin[dim-1]) - extents[dim-1]; + } + + + + template + Point + TwoMergedBoxes::representative_point(const double depth) const + { + Assert (depth >= 0, + ExcMessage ("Given depth must be positive or zero.")); + Assert (depth <= maximal_depth(), + ExcMessage ("Given depth must be less than or equal to the maximal depth of this geometry.")); + + // choose a point on the center axis of the domain + Point p = extents/2+lower_box_origin; + p[dim-1] = extents[dim-1]+lower_box_origin[dim-1]-depth; + + return p; + } + + + template + double + TwoMergedBoxes::maximal_depth() const + { + return extents[dim-1]; + } + + template + bool + TwoMergedBoxes::has_curved_elements() const + { + return false; + } + + + + template + bool + TwoMergedBoxes::point_is_in_domain(const Point &point) const + { + AssertThrow(!this->get_parameters().mesh_deformation_enabled == 0 || + this->simulator_is_past_initialization() == false, + ExcMessage("After displacement of the mesh, this function can no longer be used to determine whether a point lies in the domain or not.")); + + AssertThrow(Plugins::plugin_type_matches>(this->get_initial_topography_model()), + ExcMessage("After adding topography, this function can no longer be used to determine whether a point lies in the domain or not.")); + + for (unsigned int d = 0; d < dim; ++d) + if (point[d] > extents[d]+lower_box_origin[d]+std::numeric_limits::epsilon()*extents[d] || + point[d] < lower_box_origin[d]-std::numeric_limits::epsilon()*extents[d]) + return false; + + return true; + } + + + template + aspect::Utilities::Coordinates::CoordinateSystem + TwoMergedBoxes::natural_coordinate_system() const + { + return aspect::Utilities::Coordinates::CoordinateSystem::cartesian; + } + + + template + std::array + TwoMergedBoxes::cartesian_to_natural_coordinates(const Point &position_point) const + { + std::array position_array; + for (unsigned int i = 0; i < dim; ++i) + position_array[i] = position_point(i); + + return position_array; + } + + + + template + Point + TwoMergedBoxes::natural_to_cartesian_coordinates(const std::array &position_tensor) const + { + Point position_point; + for (unsigned int i = 0; i < dim; ++i) + position_point[i] = position_tensor[i]; + + return position_point; + } + + + + template + void + TwoMergedBoxes:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Box with lithosphere boundary indicators"); + { + prm.declare_entry ("Lithospheric thickness", "0.2", + Patterns::Double (0.), + "The thickness of the lithosphere used to create " + "additional boundary indicators to set specific " + "boundary conditions for the lithosphere. "); + + // Total box extents + prm.declare_entry ("X extent", "1.", + Patterns::Double (0.), + "Extent of the box in x-direction. Units: \\si{\\meter}."); + prm.declare_entry ("Y extent", "1.", + Patterns::Double (0.), + "Extent of the box in y-direction. Units: \\si{\\meter}."); + prm.declare_entry ("Z extent", "1.", + Patterns::Double (0.), + "Extent of the box in z-direction. This value is ignored " + "if the simulation is in 2d. Units: \\si{\\meter}."); + + // Total box origin + prm.declare_entry ("Box origin X coordinate", "0.", + Patterns::Double (), + "X coordinate of box origin. Units: \\si{\\meter}."); + prm.declare_entry ("Box origin Y coordinate", "0.", + Patterns::Double (), + "Y coordinate of box origin. Units: \\si{\\meter}."); + prm.declare_entry ("Box origin Z coordinate", "0.", + Patterns::Double (), + "Z coordinate of box origin. This value is ignored " + "if the simulation is in 2d. Units: \\si{\\meter}."); + + // Lower box repetitions + prm.declare_entry ("X repetitions", "1", + Patterns::Integer (1), + "Number of cells in X direction of the lower box. " + "The same number of repetitions will be used in the upper box."); + prm.declare_entry ("Y repetitions", "1", + Patterns::Integer (1), + "Number of cells in Y direction of the lower box. If the simulation " + "is in 3d, the same number of repetitions will be used in the upper box."); + prm.declare_entry ("Z repetitions", "1", + Patterns::Integer (1), + "Number of cells in Z direction of the lower box. " + "This value is ignored if the simulation is in 2d."); + + // Upper box repetitions + prm.declare_entry ("Y repetitions lithosphere", "1", + Patterns::Integer (1), + "Number of cells in Y direction in the lithosphere. " + "This value is ignored if the simulation is in 3d."); + prm.declare_entry ("Z repetitions lithosphere", "1", + Patterns::Integer (1), + "Number of cells in Z direction in the lithosphere. " + "This value is ignored if the simulation is in 2d."); + + // Whole box periodicity + prm.declare_entry ("X periodic", "false", + Patterns::Bool (), + "Whether the box should be periodic in X direction."); + prm.declare_entry ("Y periodic", "false", + Patterns::Bool (), + "Whether the box should be periodic in Y direction."); + prm.declare_entry ("Z periodic", "false", + Patterns::Bool (), + "Whether the box should be periodic in Z direction. " + "This value is ignored if the simulation is in 2d."); + prm.declare_entry ("X periodic lithosphere", "false", + Patterns::Bool (), + "Whether the box should be periodic in X direction in the lithosphere."); + prm.declare_entry ("Y periodic lithosphere", "false", + Patterns::Bool (), + "Whether the box should be periodic in Y direction in the lithosphere. " + "This value is ignored if the simulation is in 2d. "); + + // grid creation parameters + prm.declare_entry ("Use merged grids", "true", + Patterns::Bool (), + "Whether to make the grid by gluing together two boxes, or just " + "use one chunk to make the grid. Using two grids glued together " + "is a safer option, since it forces the boundary conditions " + "to be always applied to the same depth, but using one grid allows " + "for a more flexible usage of the adaptive refinement. Note that if " + "there is no cell boundary exactly on the boundary between the lithosphere " + "and the mantle, the velocity boundary will not be exactly at that depth. " + "Therefore, using a merged grid is generally recommended over using one grid." + "When using one grid, the parameter for lower repetitions is used and the upper " + "repetitions are ignored."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + TwoMergedBoxes::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Box with lithosphere boundary indicators"); + { + const double thickness_lith = prm.get_double("Lithospheric thickness"); + + extents[0] = prm.get_double ("X extent"); + lower_extents[0] = extents[0]; + upper_extents[0] = extents[0]; + lower_box_origin[0] = prm.get_double ("Box origin X coordinate"); + upper_box_origin[0] = lower_box_origin[0]; + periodic[0] = prm.get_bool ("X periodic"); + periodic[dim] = prm.get_bool ("X periodic lithosphere"); + // to match the two triangulations, it is required that the + // number of horizontal repetitions are the same + lower_repetitions[0] = prm.get_integer ("X repetitions"); + upper_repetitions[0] = lower_repetitions[0]; + + extents[1] = prm.get_double ("Y extent"); + lower_box_origin[1] = prm.get_double ("Box origin Y coordinate"); + periodic[1] = prm.get_bool ("Y periodic"); + lower_repetitions[1] = prm.get_integer ("Y repetitions"); + + if (dim == 2) + { + lower_extents[1] = extents[1] - thickness_lith; + upper_extents[1] = thickness_lith; + upper_box_origin[1] = lower_box_origin[1] + lower_extents[1]; + upper_repetitions[1] = prm.get_integer ("Y repetitions lithosphere"); + } + + if (dim == 3) + { + lower_extents[1] = extents[1]; + upper_extents[1] = extents[1]; + upper_box_origin[1] = lower_box_origin[1]; + periodic[dim+1] = prm.get_bool ("Y periodic lithosphere"); + // to match the two triangulations, it is required that the + // number of horizontal repetitions are the same + upper_repetitions[1] = lower_repetitions[1]; + extents[2] = prm.get_double ("Z extent"); + lower_extents[2] = extents[2] - thickness_lith; + upper_extents[2] = thickness_lith; + lower_box_origin[2] = prm.get_double ("Box origin Z coordinate"); + upper_box_origin[2] = lower_box_origin[2] + lower_extents[2]; + periodic[2] = prm.get_bool ("Z periodic"); + lower_repetitions[2] = prm.get_integer ("Z repetitions"); + upper_repetitions[2] = prm.get_integer ("Z repetitions lithosphere"); + } + + height_lith = upper_box_origin[dim-1]; + use_merged_grids = prm.get_bool ("Use merged grids"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace GeometryModel + { + ASPECT_REGISTER_GEOMETRY_MODEL(TwoMergedBoxes, + "box with lithosphere boundary indicators", + "A box geometry parallel to the coordinate directions. " + "The extent of the box in each coordinate direction " + "is set in the parameter file. This geometry model labels its " + "sides with 2*dim+2*(dim-1) boundary indicators: in 2d, boundary indicators 0 through 3 " + "denote the left, right, bottom and top boundaries, while indicators" + "4 and 5 denote the upper part of the left and right vertical boundary, " + "respectively. In 3d, boundary " + "indicators 0 through 5 indicate left, right, front, back, bottom " + "and top boundaries (see also the documentation of the deal.II class " + "``ReferenceCell''), while indicators 6, 7, 8 and 9 denote the left, " + "right, front and back upper parts of the vertical boundaries, respectively. " + "You can also use symbolic names ``left'', ``right'', " + "``left lithosphere'', etc., to refer to these boundaries in input files." + "\n\n" + "Note that for a given ``Global refinement level'' and no user-specified " + "``Repetitions'', the lithosphere part of the mesh will be more refined. " + "\n\n" + "The additional boundary indicators for the lithosphere allow for " + "selecting boundary conditions for the " + "lithosphere different from those for the underlying mantle. " + "An example application of this geometry is to prescribe a velocity on " + "the lithospheric plates, but use open boundary conditions underneath. ") + } +} diff --git a/source/geometry_model/two_merged_chunks.cc.bak b/source/geometry_model/two_merged_chunks.cc.bak new file mode 100644 index 00000000000..1c120768195 --- /dev/null +++ b/source/geometry_model/two_merged_chunks.cc.bak @@ -0,0 +1,635 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +namespace aspect +{ + namespace GeometryModel + { + template + void + TwoMergedChunks::initialize () + { + AssertThrow(Plugins::plugin_type_matches>(this->get_initial_topography_model()) || + Plugins::plugin_type_matches>(this->get_initial_topography_model()), + ExcMessage("At the moment, only the Zero or AsciiData initial topography model can be used with the TwoMergedChunks geometry model.")); + + manifold = std::make_unique>(this->get_initial_topography_model(), + point1[1], + point1[0], + point2[0]-point1[0]); + } + + + + template + void + TwoMergedChunks:: + create_coarse_mesh (parallel::distributed::Triangulation &coarse_grid) const + { + if (use_merged_grids) + { + // The two triangulations that will be merged into coarse_grid. + Triangulation lower_coarse_grid; + Triangulation upper_coarse_grid; + + const std::vector lower_rep_vec(lower_repetitions.begin(), lower_repetitions.end()); + const std::vector upper_rep_vec(upper_repetitions.begin(), upper_repetitions.end()); + + // Create the lower box. + GridGenerator::subdivided_hyper_rectangle (lower_coarse_grid, + lower_rep_vec, + point1, + point4, + false); + + // Create the upper box. + GridGenerator::subdivided_hyper_rectangle (upper_coarse_grid, + upper_rep_vec, + point3, + point2, + false); + + // Merge the lower and upper mesh into one coarse_grid. + // Now we have at least two cells. + GridGenerator::merge_triangulations(lower_coarse_grid, + upper_coarse_grid, + coarse_grid); + } + else + { + const std::vector lower_rep_vec(lower_repetitions.begin(), lower_repetitions.end()); + GridGenerator::subdivided_hyper_rectangle (coarse_grid, + lower_rep_vec, + point1, + point2, + false); + + } + + // Transform box into spherical chunk + GridTools::transform ( + [&](const Point &p) -> Point + { + return manifold->push_forward(p); + }, + coarse_grid); + + // Deal with a curved mesh by assigning a manifold. We arbitrarily + // choose manifold_id 15 for this. + coarse_grid.set_manifold (my_manifold_id, *manifold); + for (const auto &cell : coarse_grid.active_cell_iterators()) + cell->set_all_manifold_ids (my_manifold_id); + + // Set the boundary indicators. + set_boundary_indicators(coarse_grid); + // Make sure the right boundary indicators are set after refinement + // through the function set_boundary_indicators above. + coarse_grid.signals.post_refinement.connect ( + [&]() + { + this->set_boundary_indicators(coarse_grid); + }); + } + + + + template + void + TwoMergedChunks:: + set_boundary_indicators (parallel::distributed::Triangulation &triangulation) const + { + // Iterate over all active cells and (re)set the boundary indicators. + for (typename Triangulation::active_cell_iterator + cell = triangulation.begin_active(); + cell != triangulation.end(); + ++cell) + { + // First set the default boundary indicators. + for (const unsigned int f : cell->face_indices()) + if (cell->face(f)->at_boundary()) + cell->face(f)->set_boundary_id (f); + + if (cell->face(3)->at_boundary()) + // Set the upper part of the eastern boundary to indicator 2*dim+1 + // by comparing the radius of the face's center point with the + // minimum radius of the upper radius. + if (cell->face(3)->center(true).norm() > point3[0]) + cell->face(3)->set_boundary_id(2 * dim + 1); + + if (cell->face(2)->at_boundary()) + // Set the upper part of the western boundary to indicator 2*dim + // by comparing the radius of the face's center point with the + // minimum radius of the upper radius. + if (cell->face(2)->center(true).norm() > point3[0]) + cell->face(2)->set_boundary_id (2*dim); + + if (dim==3) + { + // Set the upper part of the southern boundary to indicator 2*dim+2. + if (cell->face(4)->at_boundary()) + if ((cell->vertex(cell->face(4)->n_vertices()-1).norm() + cell->vertex(0).norm()) / 2.0 > point3[0]) + cell->face(4)->set_boundary_id (2*dim+2); + + // Set the upper part of the northern boundary to indicator 2*dim+3. + if (cell->face(5)->at_boundary()) + if ((cell->vertex((cell->face(5)->n_vertices()-1)/2).norm() + cell->vertex(0).norm()) / 2.0 > point3[0]) + cell->face(5)->set_boundary_id (2*dim+3); + } + + } + } + + + + template + std::set + TwoMergedChunks:: + get_used_boundary_indicators () const + { + // boundary indicators are zero through 2*dim+2*(dim-1)-1 + std::set s; + for (unsigned int i=0; i<2*dim+2*(dim-1); ++i) + s.insert (i); + return s; + } + + + + template + std::map + TwoMergedChunks:: + get_symbolic_boundary_names_map () const + { + switch (dim) + { + case 2: + { + return + { + {"bottom", 0}, + {"top", 1}, + {"lowerwest", 2}, + {"lowereast", 3}, + {"uppereast", 4}, + {"upperwest", 5} + }; + } + + case 3: + { + return + { + {"bottom", 0}, + {"top", 1}, + {"lowerwest", 2}, + {"lowereast", 3}, + {"lowersouth", 4}, + {"lowernorth", 5}, + {"upperwest", 6}, + {"uppereast", 7}, + {"uppersouth", 8}, + {"uppernorth", 9} + }; + } + } + + Assert (false, ExcNotImplemented()); + return {}; + } + + + + template + double + TwoMergedChunks:: + length_scale () const + { + // As described in the first ASPECT paper, a length scale of + // 10km = 1e4m works well for the pressure scaling for earth + // sized spherical shells. use a length scale that + // yields this value for the R0,R1 corresponding to earth + // but otherwise scales like (R1-R0) + return 1e4 * maximal_depth() / (6336000.-3481000.); + } + + + + template + double + TwoMergedChunks::depth(const Point &position) const + { + // depth is defined wrt the reference surface point2[0] + // negative depth is not allowed + return std::max (0., std::min (point2[0]-position.norm(), maximal_depth())); + } + + + + template + double + TwoMergedChunks::height_above_reference_surface(const Point &position) const + { + return position.norm()-point2[0]; + } + + + + template + Point + TwoMergedChunks::representative_point(const double depth) const + { + Assert (depth >= 0, + ExcMessage ("Given depth must be positive or zero.")); + Assert (depth <= maximal_depth(), + ExcMessage ("Given depth must be less than or equal to the maximal depth of this geometry.")); + + // Choose a point at the mean longitude (and latitude) + Point p = 0.5*(point2+point1); + // at a depth beneath the top surface + p[0] = point2[0]-depth; + + // Now convert to Cartesian coordinates + return manifold->push_forward_sphere(p); + } + + + + template + double + TwoMergedChunks::west_longitude () const + { + return point1[1]; + } + + + + template + double + TwoMergedChunks::east_longitude () const + { + return point2[1]; + } + + + + template + double + TwoMergedChunks::longitude_range () const + { + return point2[1] - point1[1]; + } + + + + template + double + TwoMergedChunks::south_latitude () const + { + if (dim == 3) + return point1[2]; + else + return 0; + } + + + + template + double + TwoMergedChunks::north_latitude () const + { + if (dim==3) + return point2[2]; + else + return 0; + } + + + + template + double + TwoMergedChunks::latitude_range () const + { + if (dim==3) + return point2[2] - point1[2]; + else + return 0; + } + + + + template + double + TwoMergedChunks::maximal_depth() const + { + return point2[0]-point1[0]; + } + + + + template + double + TwoMergedChunks::inner_radius () const + { + return point1[0]; + } + + + + template + double + TwoMergedChunks::outer_radius () const + { + return point2[0]; + } + + + + template + bool + TwoMergedChunks::has_curved_elements() const + { + return true; + } + + + + template + bool + TwoMergedChunks::point_is_in_domain(const Point &point) const + { + AssertThrow(!this->get_parameters().mesh_deformation_enabled || + // we are still before the first time step has started + this->get_timestep_number() == 0 || + this->get_timestep_number() == numbers::invalid_unsigned_int, + ExcMessage("After displacement of the mesh, this function can no longer be used to determine whether a point lies in the domain or not.")); + + AssertThrow(Plugins::plugin_type_matches>(this->get_initial_topography_model()), + ExcMessage("After adding topography, this function can no longer be used to determine whether a point lies in the domain or not.")); + + const Point spherical_point = manifold->pull_back(point); + + for (unsigned int d = 0; d < dim; ++d) + if (spherical_point[d] > point2[d]+std::numeric_limits::epsilon()*std::abs(point2[d]) || + spherical_point[d] < point1[d]-std::numeric_limits::epsilon()*std::abs(point2[d])) + return false; + + return true; + } + + + + template + std::array + TwoMergedChunks::cartesian_to_natural_coordinates(const Point &position_point) const + { + // the chunk manifold has a order of radius, longitude, latitude. + // This is exactly what we need. + // Ignore the topography to avoid a loop when calling the + // AsciiDataBoundary for topography which uses this function.... + const Point transformed_point = manifold->pull_back_sphere(position_point); + std::array position_array; + for (unsigned int i = 0; i < dim; ++i) + position_array[i] = transformed_point(i); + + return position_array; + } + + + + template + aspect::Utilities::Coordinates::CoordinateSystem + TwoMergedChunks::natural_coordinate_system() const + { + // TODO This will give problems somewhere down the line + // if geometry models are asked for their coordinate system, + // chunk returns spherical and then Utilities::Coordinates::cartesian_to_spherical + // is used + return aspect::Utilities::Coordinates::CoordinateSystem::spherical; + } + + + + template + Point + TwoMergedChunks::natural_to_cartesian_coordinates(const std::array &position_tensor) const + { + // Ignore the topography to avoid a loop when calling the + // AsciiDataBoundary for topography which uses this function.... + Point position_point; + for (unsigned int i = 0; i < dim; ++i) + position_point[i] = position_tensor[i]; + const Point transformed_point = manifold->push_forward_sphere(position_point); + + return transformed_point; + } + + + + template + void + TwoMergedChunks:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Chunk with lithosphere boundary indicators"); + { + prm.declare_entry ("Chunk inner radius", "0.", + Patterns::Double (0.), + "Radius at the bottom surface of the chunk. Units: \\si{\\meter}."); + prm.declare_entry ("Chunk outer radius", "1.", + Patterns::Double (0.), + "Radius at the top surface of the chunk. Units: \\si{\\meter}."); + prm.declare_entry ("Chunk middle boundary radius", "1", + Patterns::Double (0), + "Radius at the top surface of the lower chunk, " + "where it merges with the upper chunk. Units: \\si{\\meter}."); + + prm.declare_entry ("Chunk minimum longitude", "0.", + Patterns::Double (-180., 360.), // enables crossing of either hemisphere + "Minimum longitude of the chunk. Units: degrees."); + prm.declare_entry ("Chunk maximum longitude", "1.", + Patterns::Double (-180., 360.), // enables crossing of either hemisphere + "Maximum longitude of the chunk. Units: degrees."); + + prm.declare_entry ("Chunk minimum latitude", "0.", + Patterns::Double (-90., 90.), + "Minimum latitude of the chunk. This value is ignored " + "if the simulation is in 2d. Units: degrees."); + prm.declare_entry ("Chunk maximum latitude", "1.", + Patterns::Double (-90., 90.), + "Maximum latitude of the chunk. This value is ignored " + "if the simulation is in 2d. Units: degrees."); + + prm.declare_entry ("Outer chunk radius repetitions", "1", + Patterns::Integer (1), + "Number of cells in radial direction for the upper chunk."); + prm.declare_entry ("Inner chunk radius repetitions", "1", + Patterns::Integer (1), + "Number of cells in radial direction for the lower chunk."); + prm.declare_entry ("Longitude repetitions", "1", + Patterns::Integer (1), + "Number of cells in longitude."); + prm.declare_entry ("Latitude repetitions", "1", + Patterns::Integer (1), + "Number of cells in latitude. This value is ignored " + "if the simulation is in 2d"); + + prm.declare_entry ("Use merged grids", "true", + Patterns::Bool (), + "Whether to make the grid by gluing together two boxes, or just " + "use one chunk to make the grid. Using two grids glued together " + "is a safer option, since it forces the boundary conditions " + "to be always applied to the same depth, but using one grid allows " + "for a more flexible usage of the adaptive refinement. Note that if " + "there is no cell boundary exactly on the boundary between the lithosphere " + "and the mantle, the velocity boundary will not be exactly at that depth. " + "Therefore, using a merged " + "grid is generally recommended over using one grid. " + "When using one grid, the parameter for lower repetitions is used and the upper " + "repetitions are ignored."); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + TwoMergedChunks::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Geometry model"); + { + prm.enter_subsection("Chunk with lithosphere boundary indicators"); + { + point1[0] = prm.get_double("Chunk inner radius"); + point2[0] = prm.get_double("Chunk outer radius"); + point3[0] = prm.get_double("Chunk middle boundary radius"); + point4[0] = point3[0]; + lower_repetitions[0] = prm.get_integer("Inner chunk radius repetitions"); + upper_repetitions[0] = prm.get_integer("Outer chunk radius repetitions"); + point1[1] = prm.get_double("Chunk minimum longitude") * constants::degree_to_radians; + point2[1] = prm.get_double("Chunk maximum longitude") * constants::degree_to_radians; + point3[1] = point1[1]; + point4[1] = point2[1]; + lower_repetitions[1] = prm.get_integer("Longitude repetitions"); + upper_repetitions[1] = lower_repetitions[1]; + + AssertThrow(point1[0] < point2[0], + ExcMessage("Inner radius must be less than outer radius.")); + AssertThrow(point1[1] < point2[1], + ExcMessage("Minimum longitude must be less than maximum longitude.")); + AssertThrow(point2[1] - point1[1] < 2. * numbers::PI, + ExcMessage("Maximum - minimum longitude should be less than 360 degrees.")); + AssertThrow(point3[0] < point2[0], + ExcMessage("Middle boundary radius must be less than outer radius.")); + + if (dim == 3) + { + point1[2] = prm.get_double ("Chunk minimum latitude") * constants::degree_to_radians; + point2[2] = prm.get_double ("Chunk maximum latitude") * constants::degree_to_radians; + point3[2] = point1[2]; + point4[2] = point2[2]; + lower_repetitions[2] = prm.get_integer ("Latitude repetitions"); + upper_repetitions[2] = lower_repetitions[2]; + + AssertThrow (point1[2] < point2[2], + ExcMessage ("Minimum latitude must be less than maximum latitude.")); + AssertThrow (point1[2] > -0.5*numbers::PI, + ExcMessage ("Minimum latitude needs to be larger than -90 degrees.")); + AssertThrow (point2[2] < 0.5*numbers::PI, + ExcMessage ("Maximum latitude needs to be less than 90 degrees.")); + } + use_merged_grids = prm.get_bool ("Use merged grids"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace GeometryModel + { + ASPECT_REGISTER_GEOMETRY_MODEL(TwoMergedChunks, + "chunk with lithosphere boundary indicators", + "A geometry which can be described as a chunk of a spherical shell, " + "bounded by lines of longitude, latitude and radius. " + "The side boundaries have two boundary indicators, so the user " + "can prescribe different boundary conditions on these boundaries. " + "The minimum and maximum longitude, (latitude) and depth of the chunk " + "are set in the parameter file. The chunk geometry labels its " + "2*dim+2*(dim-1) sides as follows: ``lowerwest'' and ``lowereast'': " + "minimum and maximum longitude of the lower part of the east and west " + "side boundaries, ``upperwest'' and ``uppereast'': " + "minimum and maximum longitude of the upper part of the east and west " + "side boundaries, ``lowersouth'' and ``lowernorth'': " + "minimum and maximum latitude of the lower part of the south and north " + "side boundaries, ``uppersouth'' and ``uppernorth'': " + "minimum and maximum latitude of the upper part of the south and north " + "side boundaries, " + "\n\n" + "The dimensions of the model are specified by parameters " + "of the following form: " + "Chunk (minimum | maximum) (longitude | latitude): " + "edges of geographical quadrangle (in degrees). " + "Chunk (inner | outer | middle boundary) radius: Radii at bottom and top of chunk " + "and the radius at which the lower boundary indicator along a side " + "boundary transitions into the upper boundary indicator. " + "(Longitude | Latitude) repetitions: " + "number of cells in each coordinate direction." + "(Inner | Outer) chunk radius repetitions: " + "number of cells in the radial coordinate direction for the lower part " + "of the domain (up to the Middle boundary radius) and for the upper part " + "of the domain. " + "\n\n" + "When used in 2d, this geometry does not imply the use of " + "a spherical coordinate system. Indeed, " + "in 2d the geometry is simply a sector of an annulus in a Cartesian " + "coordinate system and consequently would correspond to " + "a sector of a cross section of the fluid filled space between two " + "infinite cylinders where one has made the assumption that " + "the velocity in direction of the cylinder axes is zero. " + "This is consistent with the definition of what we consider " + "the two-dimension case given in " + "Section~\\ref{sec:methods:2d-models}. " + "It is also possible to add initial topography to the chunk geometry, " + "based on an ascii data file. ") + } +} diff --git a/source/global.cc.bak b/source/global.cc.bak new file mode 100644 index 00000000000..e3d9292375a --- /dev/null +++ b/source/global.cc.bak @@ -0,0 +1,112 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include +#include + +#ifdef ASPECT_WITH_WORLD_BUILDER +#include +#endif + +#include + + + +template +void print_aspect_header(Stream &stream) +{ + const int n_tasks = dealii::Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD); + + stream << "-----------------------------------------------------------------------------\n" + << "-- This is ASPECT --\n" + << "-- The Advanced Solver for Planetary Evolution, Convection, and Tectonics. --\n" + << "-----------------------------------------------------------------------------\n" + << "-- . version " << ASPECT_PACKAGE_VERSION; + if (strcmp(ASPECT_GIT_BRANCH,"") != 0) + stream << " (" << ASPECT_GIT_BRANCH << ", " << ASPECT_GIT_SHORTREV << ")\n"; + else + stream << "\n"; + + stream << "-- . using deal.II " << DEAL_II_PACKAGE_VERSION; + if (strcmp(DEAL_II_GIT_BRANCH,"") != 0) + stream << " (" << DEAL_II_GIT_BRANCH << ", " << DEAL_II_GIT_SHORTREV << ')'; + stream << "\n"; + stream << "-- . with " +#ifdef DEAL_II_WITH_64BIT_INDICES + << "64" +#else + << "32" +#endif + << " bit indices\n"; + + const unsigned int n_vectorization_doubles = dealii::VectorizedArray::size(); + const unsigned int n_vectorization_bits = 8 * sizeof(double) * n_vectorization_doubles; + const std::string vectorization_level = dealii::Utilities::System::get_current_vectorization_level(); + + stream << "-- . with vectorization level "; + stream << DEAL_II_COMPILER_VECTORIZATION_LEVEL + << " (" << vectorization_level << ", " + << n_vectorization_doubles << " doubles, " + << n_vectorization_bits << " bits)\n"; + + stream << "-- . using Trilinos " + << DEAL_II_TRILINOS_VERSION_MAJOR << '.' + << DEAL_II_TRILINOS_VERSION_MINOR << '.' + << DEAL_II_TRILINOS_VERSION_SUBMINOR << '\n'; + stream << "-- . using p4est " + << DEAL_II_P4EST_VERSION_MAJOR << '.' + << DEAL_II_P4EST_VERSION_MINOR << '.' + << DEAL_II_P4EST_VERSION_SUBMINOR << '\n'; + +#ifdef ASPECT_WITH_WORLD_BUILDER + stream << "-- . using Geodynamic World Builder " + << WORLD_BUILDER_VERSION_MAJOR << '.' + << WORLD_BUILDER_VERSION_MINOR << '.' + << WORLD_BUILDER_VERSION_PATCH; + + if (WorldBuilder::Version::GIT_SHA1 != "") + stream << " (" << WorldBuilder::Version::GIT_BRANCH << ", " << WorldBuilder::Version::GIT_SHA1.substr(0,9) << ')'; + + stream << '\n'; +#endif + +#ifdef DEBUG + stream << "-- . running in DEBUG mode\n" +#else + stream << "-- . running in OPTIMIZED mode\n" +#endif + << "-- . running with " << n_tasks << " MPI process" << (n_tasks == 1 ? "\n" : "es\n"); + + const int n_threads = + dealii::MultithreadInfo::n_threads(); + if (n_threads>1) + stream << "-- . using " << n_threads << " threads " << (n_tasks == 1 ? "\n" : "each\n"); + + stream << "-----------------------------------------------------------------------------\n" + << std::endl; +} + +template void print_aspect_header (std::ostream &stream); +template void print_aspect_header (std::ofstream &stream); diff --git a/source/gravity_model/ascii_data.cc.bak b/source/gravity_model/ascii_data.cc.bak new file mode 100644 index 00000000000..0bea4da69a3 --- /dev/null +++ b/source/gravity_model/ascii_data.cc.bak @@ -0,0 +1,126 @@ +/* + Copyright (C) 2016 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include + +namespace aspect +{ + namespace GravityModel + { + template + AsciiData::AsciiData () + : + gravity_index(numbers::invalid_unsigned_int) + {} + + + template + void + AsciiData::initialize () + { + this->initialize(this->get_mpi_communicator()); + gravity_index = this->get_column_index_from_name("gravity"); + } + + + template + Tensor<1,dim> + AsciiData:: + gravity_vector (const Point &position) const + { + const double depth = this->get_geometry_model().depth(position); + const double magnitude = this->get_data_component(Point<1>(depth),gravity_index); + + // in dependence of what the geometry model is, gravity points in a different direction + if (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical || + this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::ellipsoidal) + return - magnitude * position/position.norm(); + else if (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::cartesian) + { + Tensor<1,dim> g; + g[dim-1] = -magnitude; + return g; + } + else + AssertThrow (false, + ExcMessage ("Not a valid geometry model for the gravity model" + "ascii data.")); + return Tensor<1,dim>(); + } + + template + void + AsciiData::declare_parameters (ParameterHandler &prm) + { + // we use the same file that is used for the adiabatic conditions model, + // as it also contains gravity + prm.enter_subsection("Gravity model"); + { + Utilities::AsciiDataBase::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/gravity-model/", + "prem.txt"); + } + prm.leave_subsection(); + } + + + template + void + AsciiData::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Gravity model"); + { + Utilities::AsciiDataBase::parse_parameters(prm); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace GravityModel + { + ASPECT_REGISTER_GRAVITY_MODEL(AsciiData, + "ascii data", + "Gravity is read from a file that describes the reference " + "state. The default profile follows the preliminary " + "reference Earth model (PREM, Dziewonski and Anderson, 1981). " + "Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of points in the reference state as " + "for example `# POINTS: 3'. " + "Following the comment lines there has to be a single line " + "containing the names of all data columns, separated by arbitrarily " + "many spaces. Column names are not allowed to contain spaces. " + "The file can contain unnecessary columns, but for this plugin it " + "needs to at least provide a column named `gravity'. " + "Note that the data lines in the file need to be sorted in order " + "of increasing depth from 0 to the maximal depth in the model " + "domain. Points in the model that are outside of the provided " + "depth range will be assigned the maximum or minimum depth values, " + "respectively. Points do not need to be equidistant, " + "but the computation of properties is optimized in speed " + "if they are.") + } +} diff --git a/source/gravity_model/function.cc.bak b/source/gravity_model/function.cc.bak new file mode 100644 index 00000000000..a3c31bef2bd --- /dev/null +++ b/source/gravity_model/function.cc.bak @@ -0,0 +1,138 @@ +/* + Copyright (C) 2011 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include + +namespace aspect +{ + namespace GravityModel + { + template + Function::Function () + : + function (dim) + {} + + template + Tensor<1,dim> + Function:: + gravity_vector (const Point &position) const + { + Tensor<1,dim> gravity; + const Utilities::NaturalCoordinate point = + this->get_geometry_model().cartesian_to_other_coordinates(position, coordinate_system); + const Point point_in_coordinate_system = Utilities::convert_array_to_point(point.get_coordinates()); + for (unsigned int d=0; d + void + Function::update() + { + // we get time passed as seconds (always) but may want + // to reinterpret it in years + if (this->convert_output_to_years()) + function.set_time (this->get_time() / year_in_seconds); + else + function.set_time (this->get_time()); + } + + + template + void + Function::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Gravity model"); + { + prm.enter_subsection("Function"); + { + prm.declare_entry ("Coordinate system", "cartesian", + Patterns::Selection ("cartesian|spherical|depth"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `cartesian', `spherical', and `depth'. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle. `depth' " + "will create a function, in which only the first " + "parameter is non-zero, which is interpreted to " + "be the depth of the point."); + + Functions::ParsedFunction::declare_parameters (prm, dim); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + Function::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Gravity model"); + { + prm.enter_subsection("Function"); + { + coordinate_system = Utilities::Coordinates::string_to_coordinate_system(prm.get("Coordinate system")); + } + try + { + function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Gravity Model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace GravityModel + { + ASPECT_REGISTER_GRAVITY_MODEL(Function, + "function", + "Gravity is given in terms of an explicit formula " + "that is elaborated in the parameters in section " + "``Gravity model|Function''. The format of these " + "functions follows the syntax understood by the " + "muparser library, see " + "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") + } +} diff --git a/source/gravity_model/interface.cc.bak b/source/gravity_model/interface.cc.bak new file mode 100644 index 00000000000..c657036a514 --- /dev/null +++ b/source/gravity_model/interface.cc.bak @@ -0,0 +1,167 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + +#include + + +namespace aspect +{ + namespace GravityModel + { +// -------------------------------- Deal with registering gravity models and automating +// -------------------------------- their setup and selection at run time + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + register_gravity_model (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + template + std::unique_ptr> + create_gravity_model (ParameterHandler &prm) + { + std::string model_name; + prm.enter_subsection ("Gravity model"); + { + model_name = prm.get ("Model name"); + } + prm.leave_subsection (); + + // If one sets the model name to an empty string in the input file, + // ParameterHandler produces an error while reading the file. However, + // if one omits specifying any model name at all (not even setting it to + // the empty string) then the value we get here is the empty string. If + // we don't catch this case here, we end up with awkward downstream + // errors because the value obviously does not conform to the Pattern. + AssertThrow(model_name != "unspecified", + ExcMessage("You need to select a Gravity model " + "(`set Model name' in `subsection Gravity model').")); + + return std::get(registered_plugins).create_plugin (model_name, + "Gravity model::Model name"); + } + + + + template + void + declare_parameters (ParameterHandler &prm) + { + // declare the entry in the parameter file + prm.enter_subsection ("Gravity model"); + { + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + prm.declare_entry ("Model name", "unspecified", + Patterns::Selection (pattern_of_names+"|unspecified"), + "Select one of the following models:\n\n" + + + std::get(registered_plugins).get_description_string()); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Gravity model interface", + out); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace GravityModel + { +#define INSTANTIATE(dim) \ + template class Interface; \ + \ + template \ + void \ + register_gravity_model (const std::string &, \ + const std::string &, \ + void ( *) (ParameterHandler &), \ + std::unique_ptr>( *) ()); \ + \ + template \ + void \ + declare_parameters (ParameterHandler &); \ + \ + template \ + void \ + write_plugin_graph (std::ostream &); \ + \ + template \ + std::unique_ptr> \ + create_gravity_model (ParameterHandler &prm); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/gravity_model/radial.cc.bak b/source/gravity_model/radial.cc.bak new file mode 100644 index 00000000000..86b59a38141 --- /dev/null +++ b/source/gravity_model/radial.cc.bak @@ -0,0 +1,211 @@ +/* + Copyright (C) 2011 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include + +namespace aspect +{ + namespace GravityModel + { +// ------------------------------ RadialConstant ------------------- + template + Tensor<1,dim> + RadialConstant::gravity_vector (const Point &p) const + { + if (p.norm() == 0.0) + return Tensor<1,dim>(); + + const double r = p.norm(); + return -magnitude * p/r; + } + + + + template + void + RadialConstant::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Gravity model"); + { + prm.enter_subsection("Radial constant"); + { + prm.declare_entry ("Magnitude", "9.81", + Patterns::Double (), + "Magnitude of the gravity vector in $m/s^2$. For positive values " + "the direction is radially inward towards the center of the earth."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + RadialConstant::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Gravity model"); + { + prm.enter_subsection("Radial constant"); + { + magnitude = prm.get_double ("Magnitude"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + AssertThrow (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical || + this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::ellipsoidal, + ExcMessage ("Gravity model 'radial constant' should not be used with geometry models that " + "do not have either a spherical or ellipsoidal natural coordinate system.")); + } + +// ------------------------------ RadialEarthLike ------------------- + + template + void + RadialEarthLike::initialize () + { + AssertThrow(false, + ExcMessage("The 'radial earth-like' gravity model has been removed " + "due to its misleading name. The available AsciiData gravity " + "model (using default parameters) is much more earth-like, since " + "it uses the gravity profile used in the construction of the " + "Preliminary Reference Earth Model (PREM, Dziewonski and Anderson, " + "1981). Use the 'ascii data' model instead of 'radial earth-like'.")); + } + + + + template + Tensor<1,dim> + RadialEarthLike::gravity_vector (const Point &/*p*/) const + { + // We should never get here, because of the assertion in initialize(). + AssertThrow(false,ExcInternalError()); + return Tensor<1,dim>(); + } + + +// ----------------------------- RadialLinear ---------------------- + + + template + Tensor<1,dim> + RadialLinear::gravity_vector (const Point &p) const + { + if (p.norm() == 0.0) + return Tensor<1,dim>(); + + const double depth = this->get_geometry_model().depth(p); + const double maximal_depth = this->get_geometry_model().maximal_depth(); + + return (-magnitude_at_surface * (1.0 - depth/maximal_depth) + -magnitude_at_bottom * (depth/maximal_depth)) + * p/p.norm(); + } + + + template + void + RadialLinear::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Gravity model"); + { + prm.enter_subsection("Radial linear"); + { + prm.declare_entry ("Magnitude at surface", "9.8", + Patterns::Double (), + "Magnitude of the radial gravity vector " + "at the surface of the domain. " + "Units: \\si{\\meter\\per\\second\\squared}."); + prm.declare_entry ("Magnitude at bottom", "10.7", + Patterns::Double (), + "Magnitude of the radial gravity vector " + "at the bottom of the domain. `Bottom' means the" + "maximum depth in the chosen geometry, and for " + "example represents the core-mantle boundary in " + "the case of the `spherical shell' geometry model, " + "and the center in the case of the `sphere' " + "geometry model. Units: \\si{\\meter\\per\\second\\squared}."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + RadialLinear::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Gravity model"); + { + prm.enter_subsection("Radial linear"); + { + magnitude_at_surface = prm.get_double ("Magnitude at surface"); + magnitude_at_bottom = prm.get_double ("Magnitude at bottom"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + AssertThrow (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical || + this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::ellipsoidal, + ExcMessage ("Gravity model 'radial linear' should not be used with geometry models that " + "do not have either a spherical or ellipsoidal natural coordinate system.")); + + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace GravityModel + { + ASPECT_REGISTER_GRAVITY_MODEL(RadialConstant, + "radial constant", + "A gravity model in which the gravity has a constant magnitude " + "and the direction is radial (pointing inward if the value " + "is positive). The magnitude is read from the parameter " + "file in subsection 'Radial constant'.") + + ASPECT_REGISTER_GRAVITY_MODEL(RadialEarthLike, + "radial earth-like", + "This plugin has been removed due to its misleading name. " + "The included profile was hard-coded and was less earth-like " + "than the `ascii data' plugin, which uses the profile " + "of the Preliminary Reference Earth Model (PREM). Use `ascii data' " + "instead of `radial earth-like'.") + + ASPECT_REGISTER_GRAVITY_MODEL(RadialLinear, + "radial linear", + "A gravity model which is radial (pointing inward if the gravity " + "is positive) and the magnitude changes linearly with depth. The " + "magnitude of gravity at the surface and bottom is read from the " + "input file in a section ``Gravity model/Radial linear''.") + } +} diff --git a/source/gravity_model/vertical.cc.bak b/source/gravity_model/vertical.cc.bak new file mode 100644 index 00000000000..df7c1898222 --- /dev/null +++ b/source/gravity_model/vertical.cc.bak @@ -0,0 +1,98 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include + +#include + +namespace aspect +{ + namespace GravityModel + { + template + Tensor<1,dim> + Vertical::gravity_vector (const Point &) const + { + Tensor<1,dim> g; + g[dim-1] = -gravity_magnitude; + return g; + } + + + + template + void + Vertical::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Gravity model"); + { + prm.enter_subsection("Vertical"); + { + prm.declare_entry ("Magnitude", "1.", + Patterns::Double (), + "Value of the gravity vector in $m/s^2$ directed " + "along negative y (2d) or z (3d) axis (if the magnitude " + "is positive."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + + template + void + Vertical::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Gravity model"); + { + prm.enter_subsection("Vertical"); + { + gravity_magnitude = prm.get_double ("Magnitude"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + AssertThrow (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::cartesian, + ExcMessage ("Gravity model 'vertical' should not be used with geometry models that " + "do not have a Cartesian natural coordinate system.")); + } + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace GravityModel + { + ASPECT_REGISTER_GRAVITY_MODEL(Vertical, + "vertical", + "A gravity model in which the gravity direction is vertical (pointing " + "downward for positive values) and at a constant magnitude by default " + "equal to one.") + } +} diff --git a/source/heating_model/adiabatic_heating.cc.bak b/source/heating_model/adiabatic_heating.cc.bak new file mode 100644 index 00000000000..6b4f3936e34 --- /dev/null +++ b/source/heating_model/adiabatic_heating.cc.bak @@ -0,0 +1,112 @@ +/* + Copyright (C) 2011 - 2017 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + + +namespace aspect +{ + namespace HeatingModel + { + template + bool + AdiabaticHeating::use_simplified_adiabatic_heating() const + { + return simplified_adiabatic_heating; + } + + template + void + AdiabaticHeating:: + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + Assert(heating_model_outputs.heating_source_terms.size() == material_model_inputs.n_evaluation_points(), + ExcMessage ("Heating outputs need to have the same number of entries as the material model inputs.")); + + for (unsigned int q=0; qget_gravity_model().gravity_vector(material_model_inputs.position[q])) + * material_model_outputs.thermal_expansion_coefficients[q] + * material_model_inputs.temperature[q] + * material_model_outputs.densities[q]; + + heating_model_outputs.lhs_latent_heat_terms[q] = 0.0; + } + } + + template + void + AdiabaticHeating::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Adiabatic heating"); + { + prm.declare_entry ("Use simplified adiabatic heating", "false", + Patterns::Bool (), + "A flag indicating whether the adiabatic heating should be simplified " + "from $\\alpha T (\\mathbf u \\cdot \\nabla p)$ to " + "$ \\alpha \\rho T (\\mathbf u \\cdot \\mathbf g) $."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + AdiabaticHeating::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Adiabatic heating"); + { + simplified_adiabatic_heating = prm.get_bool ("Use simplified adiabatic heating"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(AdiabaticHeating, + "adiabatic heating", + "Implementation of a standard and a simplified model of " + "adiabatic heating.") + } +} diff --git a/source/heating_model/adiabatic_heating_of_melt.cc.bak b/source/heating_model/adiabatic_heating_of_melt.cc.bak new file mode 100644 index 00000000000..7b5c333206f --- /dev/null +++ b/source/heating_model/adiabatic_heating_of_melt.cc.bak @@ -0,0 +1,160 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + +namespace aspect +{ + namespace HeatingModel + { + template + void + AdiabaticHeatingMelt:: + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + Assert(heating_model_outputs.heating_source_terms.size() == material_model_inputs.n_evaluation_points(), + ExcMessage ("Heating outputs need to have the same number of entries as the material model inputs.")); + + AssertThrow(this->include_melt_transport(), + ExcMessage ("Heating model Adiabatic heating with melt only works if melt transport is enabled.")); + + // get the melt velocity + const MaterialModel::MeltInputs *melt_in = material_model_inputs.template get_additional_input>(); + AssertThrow(melt_in != nullptr, + ExcMessage ("Need MeltInputs from the material model for adiabatic heating with melt!")); + + for (unsigned int q=0; qintrospection().compositional_index_for_name("porosity")]; + + if (!simplified_adiabatic_heating) + heating_model_outputs.heating_source_terms[q] = ((-porosity * material_model_inputs.velocity[q] + porosity * melt_in->fluid_velocities[q]) + * material_model_inputs.pressure_gradient[q]) + * material_model_outputs.thermal_expansion_coefficients[q] + * material_model_inputs.temperature[q]; + else + { + const MaterialModel::MeltOutputs *melt_outputs = material_model_outputs.template get_additional_output>(); + Assert(melt_outputs != nullptr, ExcMessage("Need MeltOutputs from the material model for adiabatic heating with melt.")); + + heating_model_outputs.heating_source_terms[q] = (-porosity * material_model_inputs.velocity[q] + * this->get_gravity_model().gravity_vector(material_model_inputs.position[q])) + * material_model_outputs.thermal_expansion_coefficients[q] + * material_model_inputs.temperature[q] + * material_model_outputs.densities[q] + + + ((porosity * melt_in->fluid_velocities[q]) + * this->get_gravity_model().gravity_vector(material_model_inputs.position[q])) + * material_model_outputs.thermal_expansion_coefficients[q] + * material_model_inputs.temperature[q] + * melt_outputs->fluid_densities[q]; + } + + heating_model_outputs.lhs_latent_heat_terms[q] = 0.0; + } + } + + template + void + AdiabaticHeatingMelt::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Adiabatic heating of melt"); + { + prm.declare_entry ("Use simplified adiabatic heating", "false", + Patterns::Bool (), + "A flag indicating whether the adiabatic heating should be simplified " + "from $\\alpha T (\\mathbf u \\cdot \\nabla p)$ to " + "$ \\alpha \\rho T (\\mathbf u \\cdot \\mathbf g) $."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + AdiabaticHeatingMelt::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Adiabatic heating of melt"); + { + simplified_adiabatic_heating = prm.get_bool ("Use simplified adiabatic heating"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + AdiabaticHeatingMelt:: + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &output) const + { + MeltHandler::create_material_model_outputs(output); + } + + + + template + void + AdiabaticHeatingMelt:: + create_additional_material_model_inputs(MaterialModel::MaterialModelInputs &inputs) const + { + // we need the melt inputs for this adiabatic heating of melt + if (inputs.template get_additional_input>() == nullptr) + inputs.additional_inputs.emplace_back( + std::make_unique> (inputs.n_evaluation_points())); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(AdiabaticHeatingMelt, + "adiabatic heating of melt", + "Implementation of a standard and a simplified model of " + "adiabatic heating of melt. The full model implements the " + "heating term \n" + "$\\alpha T (-\\phi \\mathbf u_s \\cdot \\nabla p) " + "+ \\alpha T (\\phi \\mathbf u_f \\cdot \\nabla p)$.\n" + "For full adiabatic heating, " + "this has to be used in combination with the heating model " + "`adiabatic heating' to also include adiabatic heating for " + "the solid part, and the full heating term is then " + "$\\alpha T ((1-\\phi) \\mathbf u_s \\cdot \\nabla p) " + "+ \\alpha T (\\phi \\mathbf u_f \\cdot \\nabla p)$.") + } +} diff --git a/source/heating_model/compositional_heating.cc.bak b/source/heating_model/compositional_heating.cc.bak new file mode 100644 index 00000000000..85bc7700c26 --- /dev/null +++ b/source/heating_model/compositional_heating.cc.bak @@ -0,0 +1,141 @@ +/* + Copyright (C) 2017 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#include +#include +#include + +namespace aspect +{ + namespace HeatingModel + { + template + void + CompositionalHeating:: + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &/*material_model_outputs*/, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + for (unsigned int q = 0; q < heating_model_outputs.heating_source_terms.size(); ++q) + { + // Compute compositional volume fractions + const std::vector volume_fractions = MaterialModel::MaterialUtilities::compute_composition_fractions(material_model_inputs.composition[q], + ComponentMask(fields_used_in_heat_production_averaging)); + + // Calculate average compositional heat production + double compositional_heat_production = 0.; + for (unsigned int c=0; c < volume_fractions.size(); ++c) + if (c>0 || use_background_field_for_heat_production_averaging) + compositional_heat_production += volume_fractions[c] * heating_values[c]; + + heating_model_outputs.heating_source_terms[q] = compositional_heat_production; + heating_model_outputs.lhs_latent_heat_terms[q] = 0.0; + } + } + + + template + void + CompositionalHeating::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Compositional heating"); + { + prm.declare_entry("Compositional heating values","0.", + Patterns::List (Patterns::Double(0.)), + "List of heat production per unit volume values for " + "background and compositional fields, for a total of " + "N+1 values, where the first value corresponds to the " + "background material, and N is the number of compositional fields. " + "Units: \\si{\\watt\\per\\meter\\cubed}."); + prm.declare_entry ("Use compositional field for heat production averaging", "1", + Patterns::List(Patterns::Integer(0,1)), + "A list of integers with as many entries as compositional fields plus one. " + "The first entry corresponds to the background material, each following " + "entry corresponds to a particular compositional field. If the entry for " + "a field is '1' this field is considered during the computation of volume " + "fractions, if it is '0' the field is ignored. This is useful " + "if some compositional fields are used to track properties like " + "finite strain that should not contribute to heat production. The first " + "entry determines whether the background field contributes to heat production " + "or not (essentially similar to setting its 'Compositional heating values' to " + "zero, but included for consistency in the length of the input lists)."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + CompositionalHeating::parse_parameters (ParameterHandler &prm) + { + // increment by one for background: + const unsigned int n_fields = this->n_compositional_fields() + 1; + + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Compositional heating"); + { + const std::vector used_fields = Utilities::possibly_extend_from_1_to_N ( + Utilities::string_to_int( + Utilities::split_string_list( + prm.get("Use compositional field for heat production averaging"))), + n_fields, + "Use compositional field for heat production averaging"); + + use_background_field_for_heat_production_averaging = static_cast(used_fields[0]); + + fields_used_in_heat_production_averaging.resize(this->n_compositional_fields()); + for (unsigned int i=0; i(used_fields[i+1]); + + heating_values = Utilities::possibly_extend_from_1_to_N ( + Utilities::string_to_double( + Utilities::split_string_list( + prm.get("Compositional heating values"))), + n_fields, + "Compositional heating values"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(CompositionalHeating, + "compositional heating", + "Implementation of a model in which magnitude of internal heat production " + "is determined from fixed values assigned to each compositional " + "field. These values are interpreted as having units " + "\\si{\\watt\\per\\meter\\cubed}.") + } +} diff --git a/source/heating_model/constant_heating.cc.bak b/source/heating_model/constant_heating.cc.bak new file mode 100644 index 00000000000..f6b87d3d9cb --- /dev/null +++ b/source/heating_model/constant_heating.cc.bak @@ -0,0 +1,96 @@ +/* + Copyright (C) 2011 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + + +namespace aspect +{ + namespace HeatingModel + { + template + void + ConstantHeating:: + evaluate (const MaterialModel::MaterialModelInputs &/*material_model_inputs*/, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + for (unsigned int q=0; q + void + ConstantHeating::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Constant heating"); + { + prm.declare_entry ("Radiogenic heating rate", "0.", + Patterns::Double (0.), + "The specific rate of heating due to radioactive decay (or other bulk sources " + "you may want to describe). This parameter corresponds to the variable " + "$H$ in the temperature equation stated in the manual, and the heating " + "term is $\\rho H$. Units: W/kg."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + ConstantHeating::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Constant heating"); + { + radiogenic_heating_rate = prm.get_double ("Radiogenic heating rate"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(ConstantHeating, + "constant heating", + "Implementation of a model in which the heating " + "rate is constant.") + } +} diff --git a/source/heating_model/function.cc.bak b/source/heating_model/function.cc.bak new file mode 100644 index 00000000000..dd7f833e2e0 --- /dev/null +++ b/source/heating_model/function.cc.bak @@ -0,0 +1,157 @@ +/* + Copyright (C) 2011 - 2017 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include + +namespace aspect +{ + namespace HeatingModel + { + template + Function::Function () + : + heating_model_function (1) + {} + + + template + void + Function:: + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + for (unsigned int q=0; q position = material_model_inputs.position[q]; + const Utilities::NaturalCoordinate point = + this->get_geometry_model().cartesian_to_other_coordinates(position, coordinate_system); + + // then compute the heating function value at this position + heating_model_outputs.heating_source_terms[q] = heating_model_function.value(Utilities::convert_array_to_point(point.get_coordinates())) + * material_model_outputs.densities[q]; + heating_model_outputs.lhs_latent_heat_terms[q] = 0.0; + } + } + + + template + void + Function::update () + { + const double time = this->get_time(); + // we get time passed as seconds (always) but may want + // to reinterpret it in years + if (this->convert_output_to_years()) + heating_model_function.set_time (time / year_in_seconds); + else + heating_model_function.set_time (time); + } + + + template + void + Function::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Function"); + { + prm.declare_entry ("Coordinate system", "cartesian", + Patterns::Selection ("cartesian|spherical|depth"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `cartesian', `spherical', and `depth'. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle. `depth' " + "will create a function, in which only the first " + "parameter is non-zero, which is interpreted to " + "be the depth of the point."); + + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + Function::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Function"); + { + try + { + heating_model_function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Heating model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + + coordinate_system = Utilities::Coordinates::string_to_coordinate_system(prm.get("Coordinate system")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(Function, + "function", + "Implementation of a model in which the heating " + "rate is given in terms of an explicit formula " + "that is elaborated in the parameters in section " + "``Heating model|Function''. The format of these " + "functions follows the syntax understood by the " + "muparser library, see " + "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`." + "\n\n" + "The formula is interpreted as having units " + "W/kg." + "\n\n" + "Since the symbol $t$ indicating time " + "may appear in the formulas for the heating rate" + ", it is interpreted as having units " + "seconds unless the global parameter ``Use " + "years in output instead of seconds'' is set.") + } +} diff --git a/source/heating_model/interface.cc.bak b/source/heating_model/interface.cc.bak new file mode 100644 index 00000000000..ac0fff5b29e --- /dev/null +++ b/source/heating_model/interface.cc.bak @@ -0,0 +1,324 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + + +namespace aspect +{ + namespace HeatingModel + { + template + void + Interface:: + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs & /*outputs*/) const + {} + + + + template + void + Interface:: + create_additional_material_model_inputs(MaterialModel::MaterialModelInputs & /*inputs*/) const + {} + + + // ------------------------------ Manager ----------------------------- + + + + template + bool + Manager::adiabatic_heating_enabled() const + { + return has_matching_heating_model>() ; + } + + + + template + bool + Manager::shear_heating_enabled() const + { + return has_matching_heating_model>() ; + } + + + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + template + void + Manager::register_heating_model (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + template + void + Manager::parse_parameters (ParameterHandler &prm) + { + // find out which plugins are requested and the various other + // parameters we declare here + prm.enter_subsection ("Heating model"); + { + model_names + = Utilities::split_string_list(prm.get("List of model names")); + + AssertThrow(Utilities::has_unique_entries(model_names), + ExcMessage("The list of strings for the parameter " + "'Heating model/List of model names' contains entries more than once. " + "This is not allowed. Please check your parameter file.")); + } + prm.leave_subsection (); + + // go through the list, create objects and let them parse + // their own parameters + for (auto &model_name : model_names) + { + this->plugin_objects.push_back (std::unique_ptr> + (std::get(registered_plugins) + .create_plugin (model_name, + "Heating model::Model names"))); + + if (SimulatorAccess *sim = dynamic_cast*>(&*this->plugin_objects.back())) + sim->initialize_simulator (this->get_simulator()); + + this->plugin_objects.back()->parse_parameters (prm); + this->plugin_objects.back()->initialize (); + } + } + + + template + void + Manager::evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + // Initialize all outputs to zero, because heating_model_outputs is + // often reused in loops over all cells + for (unsigned int q=0; qn_compositional_fields()); + + const MaterialModel::ReactionRateOutputs *reaction_rate_outputs + = material_model_outputs.template get_additional_output>(); + + for (const auto &heating_model : this->plugin_objects) + { + heating_model->evaluate(material_model_inputs, material_model_outputs, individual_heating_outputs); + for (unsigned int q=0; qget_parameters().use_operator_splitting) + Assert(individual_heating_outputs.rates_of_temperature_change[q] == 0.0, + ExcMessage("Rates of temperature change heating model outputs have to be zero " + "if the model does not use operator splitting.")); + heating_model_outputs.rates_of_temperature_change[q] += individual_heating_outputs.rates_of_temperature_change[q]; + } + individual_heating_outputs.reset(); + } + + // If the heating model does not get the reaction rate outputs, it can not correctly compute + // the rates of temperature change. To make sure these (incorrect) values are never used anywhere, + // overwrite them with signaling_NaNs. + if (reaction_rate_outputs == nullptr) + for (double &q : heating_model_outputs.rates_of_temperature_change) + q = numbers::signaling_nan(); + } + + + + template + void + Manager:: + create_additional_material_model_inputs_and_outputs(MaterialModel::MaterialModelInputs &material_model_inputs, + MaterialModel::MaterialModelOutputs &material_model_outputs) const + { + for (const auto &heating_model : this->plugin_objects) + { + heating_model->create_additional_material_model_inputs(material_model_inputs); + } + + for (const auto &heating_model : this->plugin_objects) + { + heating_model->create_additional_material_model_outputs(material_model_outputs); + } + } + + + + template + const std::vector & + Manager::get_active_heating_model_names () const + { + return model_names; + } + + + template + const std::list>> & + Manager::get_active_heating_models () const + { + return this->plugin_objects; + } + + + template + void + Manager::declare_parameters (ParameterHandler &prm) + { + // declare the actual entry in the parameter file + prm.enter_subsection ("Heating model"); + { + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + + prm.declare_entry("List of model names", + "", + Patterns::MultipleSelection(pattern_of_names), + "A comma separated list of heating models that " + "will be used to calculate the heating terms in the energy " + "equation. The results of each of these criteria, i.e., " + "the heating source terms and the latent heat terms for the " + "left hand side will be added.\n\n" + "The following heating models are available:\n\n" + + + std::get(registered_plugins).get_description_string()); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + Manager::write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Heating model interface", + out); + } + + + + HeatingModelOutputs::HeatingModelOutputs(const unsigned int n_points, + const unsigned int) + : + heating_source_terms(n_points,numbers::signaling_nan()), + // initialize the reaction terms with zeroes because they are not filled + // in all heating models + rates_of_temperature_change(n_points,0.0), + lhs_latent_heat_terms(n_points,numbers::signaling_nan()) + { + } + + + + void + HeatingModelOutputs::reset() + { + for (unsigned int q=0; q(); + lhs_latent_heat_terms[q] = numbers::signaling_nan(); + rates_of_temperature_change[q] = 0.0; + } + } + + + + template + std::string + get_valid_model_names_pattern () + { + return std::get(registered_plugins).get_pattern_of_names (); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace HeatingModel + { +#define INSTANTIATE(dim) \ + template class Interface; \ + template class Manager; \ + \ + template \ + std::string \ + get_valid_model_names_pattern (); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/heating_model/latent_heat.cc.bak b/source/heating_model/latent_heat.cc.bak new file mode 100644 index 00000000000..40e56610f0c --- /dev/null +++ b/source/heating_model/latent_heat.cc.bak @@ -0,0 +1,63 @@ +/* + Copyright (C) 2011 - 2017 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + + +namespace aspect +{ + namespace HeatingModel + { + template + void + LatentHeat:: + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + Assert(heating_model_outputs.heating_source_terms.size() == material_model_inputs.n_evaluation_points(), + ExcMessage ("Heating outputs need to have the same number of entries as the material model inputs.")); + + for (unsigned int q=0; q. +*/ + + +#include +#include + + +namespace aspect +{ + namespace HeatingModel + { + template + void + LatentHeatMelt:: + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + Assert(heating_model_outputs.heating_source_terms.size() == material_model_inputs.n_evaluation_points(), + ExcMessage ("Heating outputs need to have the same number of entries as the material model inputs.")); + + const bool use_operator_split = (this->get_parameters().use_operator_splitting); + + const MaterialModel::ReactionRateOutputs *reaction_rate_out + = material_model_outputs.template get_additional_output>(); + + const MaterialModel::EnthalpyOutputs *enthalpy_out + = material_model_outputs.template get_additional_output>(); + + double enthalpy_change; + + for (unsigned int q=0; qenthalpies_of_fusion[q]; + else + enthalpy_change = melting_entropy_change * material_model_inputs.temperature[q]; + + if (this->introspection().compositional_name_exists("porosity") && this->get_timestep_number() > 0) + { + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + double melting_rate = 0.0; + + if (!use_operator_split) + { + // with melt migration the reaction term is a mass reaction rate, + // without melt migration, the reaction term is a constant value in terms of volume, + // and we have to scale it to the correct units + if (this->include_melt_transport()) + melting_rate = material_model_outputs.reaction_terms[q][porosity_idx]; + else + melting_rate = material_model_outputs.reaction_terms[q][porosity_idx] + * material_model_outputs.densities[q] / this->get_timestep(); + + heating_model_outputs.heating_source_terms[q] = enthalpy_change * melting_rate; + } + else if (use_operator_split && reaction_rate_out != nullptr) + { + // if operator splitting is used in the model, we have to use the reaction rates from the + // material model outputs instead of the reaction terms + AssertThrow (std::isfinite(reaction_rate_out->reaction_rates[q][porosity_idx]), + ExcMessage ("You are trying to use reaction rate outputs from the material " + "model to compute the latent heat of melt in an operator splitting solver scheme, " + "but the material model you use does not actually fill these reaction rate outputs.")); + + // with melt migration the reaction term is a mass reaction rate, + // without melt migration, the reaction term is a rate of change of the compositional field, + // and we have to scale it to the same units to compute the rate of temperature change + melting_rate = reaction_rate_out->reaction_rates[q][porosity_idx]; + + // if operator splitting is used in the model, we want the heating rates due to latent heat of melt + // to be part of the reactions (not the advection) in the operator split, and they are changes + // in temperature rather than changes in energy + heating_model_outputs.rates_of_temperature_change[q] = enthalpy_change + * melting_rate + / material_model_outputs.specific_heat[q]; + } + else if (use_operator_split && reaction_rate_out == nullptr) + { + // if operator plit is used, but the reaction rate outputs are not there, + // fill the rates of temperature change with NaNs, so that an error is thrown + // if they are used anywhere + heating_model_outputs.rates_of_temperature_change[q] = std::numeric_limits::quiet_NaN(); + } + } + } + } + + template + void + LatentHeatMelt::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Latent heat melt"); + { + prm.declare_entry ("Melting entropy change", "-300.", + Patterns::Double (), + "The entropy change for the phase transition " + "from solid to melt. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Retrieve entropy change from material model", "false", + Patterns::Bool (), + "Instead of using the entropy change given in the " + "'Melting entropy change' query the EnthalpyAdditionalOutputs " + "in the material model to compute the entropy change for the " + "phase transition from solid to melt." + "Units: $J/(kg K)$."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + LatentHeatMelt::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Latent heat melt"); + { + melting_entropy_change = prm.get_double ("Melting entropy change"); + retrieve_entropy_change_from_material_model = prm.get_bool ("Retrieve entropy change from material model"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + LatentHeatMelt::create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &outputs) const + { + if (this->include_melt_transport() && retrieve_entropy_change_from_material_model + && outputs.template get_additional_output>() == nullptr) + { + outputs.additional_outputs.push_back( + std::make_unique> (outputs.n_evaluation_points())); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(LatentHeatMelt, + "latent heat melt", + "Implementation of a standard model for latent heat " + "of melting. This assumes that there is a compositional field " + "called porosity, and it uses the reaction term of this field " + "(the fraction of material that melted in the current time step) " + "multiplied by a constant entropy change for melting all " + "of the material as source term of the heating model.\n" + "If there is no field called porosity, the heating terms are 0.") + } +} diff --git a/source/heating_model/radioactive_decay.cc.bak b/source/heating_model/radioactive_decay.cc.bak new file mode 100644 index 00000000000..4fc3403c495 --- /dev/null +++ b/source/heating_model/radioactive_decay.cc.bak @@ -0,0 +1,206 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#include +#include +#include + +namespace aspect +{ + namespace HeatingModel + { + template + RadioactiveDecay::RadioactiveDecay () + = default; + + + template + void + RadioactiveDecay:: + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + if (is_crust_defined_by_composition) + { + AssertThrow(crust_composition_num < material_model_inputs.composition[0].size(), + ExcMessage("The composition number of crust is larger than number of composition fields.")); + } + + for (unsigned int q = 0; q < heating_model_outputs.heating_source_terms.size(); ++q) + { + double timedependent_radioactive_heating_rates = 0; + + if (n_radio_heating_elements != 0) + { + double crust_fraction = 0; + + if (is_crust_defined_by_composition) + { + crust_fraction = material_model_inputs.composition[q][crust_composition_num]; + + if (crust_fraction < 0.0) + crust_fraction = 0; + if (crust_fraction > 1.0) + crust_fraction = 1; + } + else if ((this->get_geometry_model()).depth(material_model_inputs.position[q]) < crust_depth) + crust_fraction = 1; + + for (unsigned element = 0; element < n_radio_heating_elements; ++element) + { + timedependent_radioactive_heating_rates += radioactive_heating_rates[element] + * (radioactive_initial_concentrations_mantle[element] * (1-crust_fraction) + + radioactive_initial_concentrations_crust[element] * crust_fraction) + * std::pow(0.5,this->get_time()/half_decay_times[element]); + } + } + + heating_model_outputs.heating_source_terms[q] = timedependent_radioactive_heating_rates + * material_model_outputs.densities[q]; + + heating_model_outputs.lhs_latent_heat_terms[q] = 0.0; + } + } + + + template + void + RadioactiveDecay::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Radioactive decay"); + { + prm.declare_entry("Number of elements","0", + Patterns::Integer(0), + "Number of radioactive elements"); + prm.declare_entry("Heating rates","", + Patterns::List (Patterns::Double ()), + "Heating rates of different elements (W/kg)"); + prm.declare_entry("Half decay times","", + Patterns::List (Patterns::Double (0.)), + "Half decay times. Units: (Seconds), or " + "(Years) if set `use years instead of seconds'."); + prm.declare_entry("Initial concentrations crust","", + Patterns::List (Patterns::Double (0.)), + "Initial concentrations of different elements (ppm)"); + prm.declare_entry("Initial concentrations mantle","", + Patterns::List (Patterns::Double (0.)), + "Initial concentrations of different elements (ppm)"); + prm.declare_entry("Crust defined by composition","false", + Patterns::Bool(), + "Whether crust defined by composition or depth"); + prm.declare_entry("Crust depth","0.", + Patterns::Double(), + "Depth of the crust when crust if defined by depth. " + "Units: \\si{\\meter}."); + prm.declare_entry("Crust composition number","0", + Patterns::Integer(0), + "Which composition field should be treated as crust"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + RadioactiveDecay::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Radioactive decay"); + { + + n_radio_heating_elements = prm.get_integer ("Number of elements"); + + radioactive_heating_rates = Utilities::string_to_double + (Utilities::split_string_list + (prm.get("Heating rates"))); + + half_decay_times = Utilities::string_to_double + (Utilities::split_string_list + (prm.get("Half decay times"))); + + radioactive_initial_concentrations_crust = Utilities::string_to_double + (Utilities::split_string_list + (prm.get("Initial concentrations crust"))); + + radioactive_initial_concentrations_mantle = Utilities::string_to_double + (Utilities::split_string_list + (prm.get("Initial concentrations mantle"))); + + is_crust_defined_by_composition = prm.get_bool ("Crust defined by composition"); + crust_depth = prm.get_double ("Crust depth"); + crust_composition_num = prm.get_integer ("Crust composition number"); + + + AssertThrow(radioactive_heating_rates.size() == n_radio_heating_elements, + ExcMessage("Number of heating rate entities does not match " + "the number of radioactive elements.")); + AssertThrow(half_decay_times.size() == n_radio_heating_elements, + ExcMessage("Number of half decay time entities does not match " + "the number of radioactive elements.")); + AssertThrow(radioactive_initial_concentrations_crust.size() == n_radio_heating_elements, + ExcMessage("Number of initial concentration entities in crust " + "does not match the number of radioactive elements.")); + AssertThrow(radioactive_initial_concentrations_mantle.size() == n_radio_heating_elements, + ExcMessage("Number of initial concentration entities in mantle " + "does not match the number of radioactive elements.")); + + // if we get half_decay_times passed as years convert it to seconds + if (this->convert_output_to_years()) + for (unsigned int i = 0; i < n_radio_heating_elements; ++i) + half_decay_times[i] *= year_in_seconds; + + // Convert ppm to SI concentrations + for (unsigned int i = 0; i < n_radio_heating_elements; ++i) + { + radioactive_initial_concentrations_crust[i] *= 1e-6; + radioactive_initial_concentrations_mantle[i] *= 1e-6; + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(RadioactiveDecay, + "radioactive decay", + "Implementation of a model in which the internal " + "heating rate is radioactive decaying in the following rule:\n" + "\\[(\\text{initial concentration})\\cdot 0.5^{\\text{time}/(\\text{half life})}\\]\n" + "The crust and mantle can have different concentrations, and the crust can be " + "defined either by depth or by a certain compositional field.\n" + "The formula is interpreted as having units W/kg.") + } +} diff --git a/source/heating_model/shear_heating.cc.bak b/source/heating_model/shear_heating.cc.bak new file mode 100644 index 00000000000..153ffbfe601 --- /dev/null +++ b/source/heating_model/shear_heating.cc.bak @@ -0,0 +1,203 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + + +namespace aspect +{ + namespace HeatingModel + { + template + void + ShearHeating:: + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + Assert(heating_model_outputs.heating_source_terms.size() == material_model_inputs.n_evaluation_points(), + ExcMessage ("Heating outputs need to have the same number of entries as the material model inputs.")); + + // Check if the material model has additional outputs relevant for the shear heating. + const ShearHeatingOutputs *shear_heating_out = + material_model_outputs.template get_additional_output>(); + + for (unsigned int q=0; q deviatoric_strain_rate = + (this->get_material_model().is_compressible() + ? + material_model_inputs.strain_rate[q] + - 1./3. * trace(material_model_inputs.strain_rate[q]) * unit_symmetric_tensor() + : + material_model_inputs.strain_rate[q]); + + SymmetricTensor<2,dim> stress = 2 * material_model_outputs.viscosities[q] * deviatoric_strain_rate; + + if (limit_stress) + { + // Compute yield stress. + const double pressure = std::max(material_model_inputs.pressure[q], 0.0); + const double yield_stress = drucker_prager_plasticity.compute_yield_stress(cohesion, + friction_angle, + pressure, + std::numeric_limits::max()); + + // Scale the stress accordingly. + const double deviatoric_stress = 2 * material_model_outputs.viscosities[q] * std::sqrt(std::fabs(second_invariant(deviatoric_strain_rate))); + double scaling_factor = 1.0; + if (deviatoric_stress > 0.0) + scaling_factor = std::min(yield_stress / deviatoric_stress, 1.0); + + stress *= scaling_factor; + } + + heating_model_outputs.heating_source_terms[q] = stress * deviatoric_strain_rate; + + // If shear heating work fractions are provided, reduce the + // overall heating by this amount (which is assumed to be converted into other forms of energy) + if (shear_heating_out != nullptr) + { + heating_model_outputs.heating_source_terms[q] *= shear_heating_out->shear_heating_work_fractions[q]; + } + + heating_model_outputs.lhs_latent_heat_terms[q] = 0.0; + } + } + + + template + void + ShearHeating::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Shear heating"); + { + prm.declare_entry ("Limit stress contribution to shear heating", "false", + Patterns::Bool (), + "In models with prescribed boundary velocities, stresses can become " + "unrealistically large. Using these large stresses when calculating " + "the amount of shear heating would then lead to an unreasonable " + "increase in temperature. This parameter indicates if the stress being " + "used to compute the amount of shear heating should be limited based on " + "a Drucker-Prager yield criterion with the cohesion given by the " + "'Cohesion for maximum shear stress' parameter and the friction angle " + "given by the 'Friction angle for maximum shear stress' parameter."); + prm.declare_entry ("Cohesion for maximum shear stress", "2e7", + Patterns::Double (0), + "Cohesion for maximum shear stress that should be used for the computation " + "of shear heating. It can be useful to limit the shear stress " + "in models where velocities are prescribed, and actual stresses " + "in the Earth would be lower than the stresses introduced by the " + "boundary conditions. Only used if 'Limit stress contribution to shear heating' " + "is true. " + "Units: Pa."); + prm.declare_entry ("Friction angle for maximum shear stress", "0", + Patterns::Double (0), + "Friction angle for maximum shear stress that should be used for the computation " + "of shear heating. It can be useful to limit the shear stress " + "in models where velocities are prescribed, and actual stresses " + "in the Earth would be lower than the stresses introduced by the " + "boundary conditions. Only used if 'Limit stress contribution to shear heating' " + "is true. " + "Units: none."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + ShearHeating::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Shear heating"); + { + limit_stress = prm.get_bool ("Limit stress contribution to shear heating"); + cohesion = prm.get_double ("Cohesion for maximum shear stress"); + friction_angle = prm.get_double ("Friction angle for maximum shear stress"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + + template + void + ShearHeating:: + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &material_model_outputs) const + { + this->get_material_model().create_additional_named_outputs(material_model_outputs); + } + + + + template + ShearHeatingOutputs::ShearHeatingOutputs (const unsigned int n_points) + : + MaterialModel::NamedAdditionalMaterialOutputs({"shear_heating_work_fraction"}), + shear_heating_work_fractions(n_points, numbers::signaling_nan()) + {} + + + + template + std::vector + ShearHeatingOutputs::get_nth_output(const unsigned int idx) const + { + (void) idx; + AssertIndexRange (idx, 1); + + return shear_heating_work_fractions; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(ShearHeating, + "shear heating", + "Implementation of a standard model for shear heating. " + "Adds the term: " + "$ 2 \\eta \\left( \\varepsilon - \\frac{1}{3} \\text{tr} " + "\\varepsilon \\mathbf 1 \\right) : \\left( \\varepsilon - \\frac{1}{3} " + "\\text{tr} \\varepsilon \\mathbf 1 \\right)$ to the " + "right-hand side of the temperature equation.") + +#define INSTANTIATE(dim) \ + template class ShearHeatingOutputs; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/heating_model/shear_heating_with_melt.cc.bak b/source/heating_model/shear_heating_with_melt.cc.bak new file mode 100644 index 00000000000..9f0dd11a508 --- /dev/null +++ b/source/heating_model/shear_heating_with_melt.cc.bak @@ -0,0 +1,122 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + + +namespace aspect +{ + namespace HeatingModel + { + template + void + ShearHeatingMelt:: + evaluate (const MaterialModel::MaterialModelInputs &material_model_inputs, + const MaterialModel::MaterialModelOutputs &material_model_outputs, + HeatingModel::HeatingModelOutputs &heating_model_outputs) const + { + Assert(heating_model_outputs.heating_source_terms.size() == material_model_inputs.n_evaluation_points(), + ExcMessage ("Heating outputs need to have the same number of entries as the material model inputs.")); + + Assert(this->introspection().compositional_name_exists("porosity"), + ExcMessage("Heating model shear heating with melt only works if there " + "is a compositional field called porosity.")); + + // get the melt velocity + const MaterialModel::MeltInputs *melt_in = material_model_inputs.template get_additional_input>(); + AssertThrow(melt_in != nullptr, + ExcMessage ("Need MeltInputs from the material model for shear heating with melt!")); + + bool is_melt_cell = false; + if (material_model_inputs.current_cell.state() == IteratorState::valid) + is_melt_cell = this->get_melt_handler().is_melt_cell(material_model_inputs.current_cell); + + const MaterialModel::MeltOutputs *melt_outputs = material_model_outputs.template get_additional_output>(); + Assert(melt_outputs != nullptr, ExcMessage("Need MeltOutputs from the material model for shear heating with melt.")); + + for (unsigned int q=0; qintrospection().compositional_index_for_name("porosity")]; + + if (is_melt_cell) + heating_model_outputs.heating_source_terms[q] = melt_outputs->compaction_viscosities[q] + * pow(trace(material_model_inputs.strain_rate[q]),2) + + + (melt_outputs->permeabilities[q] > 0 + ? + melt_outputs->fluid_viscosities[q] * porosity * porosity + / melt_outputs->permeabilities[q] + * (melt_in->fluid_velocities[q] - material_model_inputs.velocity[q]) + * (melt_in->fluid_velocities[q] - material_model_inputs.velocity[q]) + : + 0.0); + else + heating_model_outputs.heating_source_terms[q] = 0.0; + + heating_model_outputs.lhs_latent_heat_terms[q] = 0.0; + } + } + + + template + void + ShearHeatingMelt:: + create_additional_material_model_outputs(MaterialModel::MaterialModelOutputs &output) const + { + MeltHandler::create_material_model_outputs(output); + } + + + + template + void + ShearHeatingMelt:: + create_additional_material_model_inputs(MaterialModel::MaterialModelInputs &inputs) const + { + // we need the melt inputs for this shear heating of melt + if (inputs.template get_additional_input>() == nullptr) + inputs.additional_inputs.emplace_back( + std::make_unique> (inputs.n_evaluation_points())); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace HeatingModel + { + ASPECT_REGISTER_HEATING_MODEL(ShearHeatingMelt, + "shear heating with melt", + "Implementation of a standard model for shear heating " + "of migrating melt, including bulk (compression) heating " + "$\\xi \\left( \\nabla \\cdot \\mathbf u_s \\right)^2 $ " + "and heating due to melt segregation " + "$\\frac{\\eta_f \\phi^2}{k} \\left( \\mathbf u_f - \\mathbf u_s \\right)^2 $. " + "For full shear heating, " + "this has to be used in combination with the heating model " + "shear heating to also include shear heating for " + "the solid part.") + } +} diff --git a/source/initial_composition/adiabatic_density.cc.bak b/source/initial_composition/adiabatic_density.cc.bak new file mode 100644 index 00000000000..64c3af31dc5 --- /dev/null +++ b/source/initial_composition/adiabatic_density.cc.bak @@ -0,0 +1,54 @@ +/* + Copyright (C) 2017 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include + +namespace aspect +{ + namespace InitialComposition + { + template + double + AdiabaticDensity:: + initial_composition (const Point &position, const unsigned int n_comp) const + { + if (n_comp == this->introspection().find_composition_type(CompositionalFieldDescription::density)) + return this->get_adiabatic_conditions().density(position); + + return 0.0; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialComposition + { + ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(AdiabaticDensity, + "adiabatic density", + "Specify the initial composition as the adiabatic reference density at " + "each position. Note that only the field of the type 'density' " + "will be filled. For all other fields this plugin returns 0.0.") + } +} diff --git a/source/initial_composition/ascii_data.cc.bak b/source/initial_composition/ascii_data.cc.bak new file mode 100644 index 00000000000..49448b30dfd --- /dev/null +++ b/source/initial_composition/ascii_data.cc.bak @@ -0,0 +1,118 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include + + +namespace aspect +{ + namespace InitialComposition + { + template + AsciiData::AsciiData () + = default; + + + template + void + AsciiData::initialize () + { + ascii_data_initial->initialize(this->n_compositional_fields()); + } + + + template + double + AsciiData:: + initial_composition (const Point &position, + const unsigned int n_comp) const + { + return ascii_data_initial->get_data_component(position,n_comp); + } + + + template + void + AsciiData::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + Utilities::AsciiDataInitial::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/initial-composition/ascii-data/test/", + "box_2d.txt"); + } + prm.leave_subsection(); + } + + + template + void + AsciiData::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + ascii_data_initial = std::make_unique>(); + ascii_data_initial->initialize_simulator(this->get_simulator()); + ascii_data_initial->parse_parameters(prm); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialComposition + { + ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(AsciiData, + "ascii data", + "Implementation of a model in which the initial " + "composition is derived from files containing data " + "in ascii format. Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example `# POINTS: 3 3'. " + "The order of the data columns " + "has to be `x', `y', `composition1', `composition2', " + "etc. in a 2d model and `x', `y', `z', `composition1', " + "`composition2', etc. in a 3d model, according " + "to the number of compositional fields, which means that " + "there has to be a single column " + "for every composition in the model." + "Note that the data in the input " + "files need to be sorted in a specific order: " + "the first coordinate needs to ascend first, " + "followed by the second and the third at last in order to " + "assign the correct data to the prescribed coordinates. " + "If you use a spherical model, " + "then the assumed grid changes. `x' will be replaced by " + "the radial distance of the point to the bottom of the model, " + "`y' by the azimuth angle and `z' by the polar angle measured " + "positive from the north pole. The grid will be assumed to be " + "a latitude-longitude grid. Note that the order " + "of spherical coordinates is `r', `phi', `theta' " + "and not `r', `theta', `phi', since this allows " + "for dimension independent expressions.") + } +} diff --git a/source/initial_composition/ascii_data_layered.cc.bak b/source/initial_composition/ascii_data_layered.cc.bak new file mode 100644 index 00000000000..6834f403f1a --- /dev/null +++ b/source/initial_composition/ascii_data_layered.cc.bak @@ -0,0 +1,123 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include + + +namespace aspect +{ + namespace InitialComposition + { + template + AsciiDataLayered::AsciiDataLayered () + = default; + + + template + void + AsciiDataLayered::initialize () + { + // First additional field is the layer depth, so we need one additional non-compositional field + Utilities::AsciiDataLayered::initialize(this->n_compositional_fields() + 1); + } + + + template + double + AsciiDataLayered:: + initial_composition (const Point &position, + const unsigned int n_comp) const + { + + // First additional field is the layer depth, so we need the data component from the n_comp+1th column + return Utilities::AsciiDataLayered::get_data_component(position,n_comp + 1); + } + + + template + void + AsciiDataLayered::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + Utilities::AsciiDataLayered::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/initial-composition/ascii-data/test/", + "initial_composition_top_mantle_box_3d.txt"); + } + prm.leave_subsection(); + } + + + template + void + AsciiDataLayered::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + Utilities::AsciiDataLayered::parse_parameters(prm); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialComposition + { + ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(AsciiDataLayered, + "ascii data layered", + "Implementation of a model in which the initial " + "composition is derived from files containing data " + "in ascii format. Each file defines a surface on which " + "compositional fields are defined. " + "Between the surfaces, the fields can be chosen to be " + "constant (with a value defined by the nearest shallower " + "surface), or linearly interpolated between surfaces. " + "Note the required format of the input ascii data file: " + "The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example `# POINTS: 3 3'. " + "The order of the data columns " + "has to be `x', `y', `composition1', `composition2' etc. " + "in a 2d model and `x', `y', `z', `composition1', " + "`composition2' etc. in a 3d model; i.e. " + "the columns before the compositional field always contains " + "the position of the surface along the vertical direction. " + "The first column needs to ascend first, " + "followed by the second in order to assign the correct data " + "to the prescribed coordinates. If you use a spherical model, " + "then the assumed grid changes. `x' will be replaced by the " + "azimuth angle and `y' (if 3d) by the polar angle measured " + "positive from the north pole. The last column will be the " + "distance of the point from the origin " + "(i.e. radial position). The grid in this case will be " + "a latitude-longitude grid. Note that the order " + "of spherical coordinates in 3d is `phi', `theta', `r', `T'" + "and not `theta', `phi', `r', `T' as this is " + "more consistent with other ASPECT plugins. Outside of the " + "region defined by the grid, the plugin will use the value " + "at the edge of the region.") + } +} diff --git a/source/initial_composition/entropy_table_lookup.cc.bak b/source/initial_composition/entropy_table_lookup.cc.bak new file mode 100644 index 00000000000..b388942cf44 --- /dev/null +++ b/source/initial_composition/entropy_table_lookup.cc.bak @@ -0,0 +1,138 @@ +/* + Copyright (C) 2017 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + + +namespace aspect +{ + namespace InitialComposition + { + template + void + EntropyTableLookUp::initialize() + { + AssertThrow (this->introspection().compositional_name_exists("entropy"), + ExcMessage("The 'entropy table lookup' initial composition requires the existence of a compositional field " + "named 'entropy'. This field does not exist.")); + + // Make sure we keep track of the initial temperature manager and + // that it continues to live beyond the time when the simulator + // class releases its pointer to it. + initial_temperature_manager = this->get_initial_temperature_manager_pointer(); + + // Make sure we keep track of the initial composition manager and + // that it continues to live beyond the time when the simulator + // class releases its pointer to it. + initial_composition_manager = this->get_initial_composition_manager_pointer(); + + entropy_index = this->introspection().compositional_index_for_name("entropy"); + + material_lookup = std::make_unique>(7,1.0); + material_lookup->load_file(data_directory+material_file_name, + this->get_mpi_communicator()); + } + + + template + double + EntropyTableLookUp:: + initial_composition (const Point &position, + const unsigned int compositional_index) const + { + if (compositional_index == entropy_index) + { + const double temperature = initial_temperature_manager->initial_temperature(position); + const double pressure = this->get_adiabatic_conditions().pressure(position); + + // Convert pressure from Pa to bar, bar is used in the table. + Point<2> temperature_pressure(temperature, pressure / 1.e5); + + const double entropy = material_lookup->get_data(temperature_pressure, 0); + + return entropy; + } + return 0.0; + } + + template + void + EntropyTableLookUp::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + prm.enter_subsection("Entropy table lookup"); + { + prm.declare_entry ("Data directory", "$ASPECT_SOURCE_DIR/data/material-model/entropy-table/pyrtable/", + Patterns::DirectoryName (), + "The path to the model data. The path may also include the special " + "text '$ASPECT_SOURCE_DIR' which will be interpreted as the path " + "in which the ASPECT source files were located when ASPECT was " + "compiled. This interpretation allows, for example, to reference " + "files located in the `data/' subdirectory of ASPECT."); + prm.declare_entry ("Material file name", "material_table_temperature_pressure.txt", + Patterns::List (Patterns::Anything()), + "The file name of the material data."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + EntropyTableLookUp::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + prm.enter_subsection("Entropy table lookup"); + { + data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get("Data directory")); + material_file_name = prm.get("Material file name"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialComposition + { + ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(EntropyTableLookUp, + "entropy table lookup", + "A class that implements initial conditions for the entropy field " + "by converting the initial temperature field through a look up table. " + "Note that this plugin only works if there is a compositional field " + "called `entropy', and an additional look up table that can convert " + "pressure and temperature to entropy. " + "For all compositional fields except entropy this plugin returns 0.0, " + "and they are therefore not changed as long as the default `add' " + "operator is selected for this plugin.") + } +} diff --git a/source/initial_composition/function.cc.bak b/source/initial_composition/function.cc.bak new file mode 100644 index 00000000000..731a0ecd80c --- /dev/null +++ b/source/initial_composition/function.cc.bak @@ -0,0 +1,125 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + +namespace aspect +{ + namespace InitialComposition + { + + template + double + Function:: + initial_composition (const Point &position, const unsigned int n_comp) const + { + const Utilities::NaturalCoordinate point = + this->get_geometry_model().cartesian_to_other_coordinates(position, coordinate_system); + + return function->value(Utilities::convert_array_to_point(point.get_coordinates()),n_comp); + } + + + template + void + Function::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + prm.enter_subsection("Function"); + { + /** + * Choose the coordinates to evaluate the maximum refinement level + * function. The function can be declared in dependence of depth, + * cartesian coordinates or spherical coordinates. Note that the order + * of spherical coordinates is r,phi,theta and not r,theta,phi, since + * this allows for dimension independent expressions. + */ + prm.declare_entry ("Coordinate system", "cartesian", + Patterns::Selection ("cartesian|spherical|depth"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `cartesian', `spherical', and `depth'. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle. `depth' " + "will create a function, in which only the first " + "parameter is non-zero, which is interpreted to " + "be the depth of the point."); + + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + Function::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + prm.enter_subsection("Function"); + { + coordinate_system = Utilities::Coordinates::string_to_coordinate_system(prm.get("Coordinate system")); + } + + try + { + function + = std::make_unique>(this->n_compositional_fields()); + function->parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Initial composition model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'\n" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialComposition + { + ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(Function, + "function", + "Specify the composition in terms of an explicit formula. The format of these " + "functions follows the syntax understood by the " + "muparser library, see {ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") + } +} diff --git a/source/initial_composition/interface.cc.bak b/source/initial_composition/interface.cc.bak new file mode 100644 index 00000000000..cf2a64b8e42 --- /dev/null +++ b/source/initial_composition/interface.cc.bak @@ -0,0 +1,275 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + +#include + + +namespace aspect +{ + namespace InitialComposition + { + // ------------------------------ Manager ----------------------------- + // ------------------------------ Deal with registering initial composition models and automating + // ------------------------------ their setup and selection at run time + + template + Manager::~Manager() + = default; + + + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + Manager::register_initial_composition (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + + template + void + Manager::parse_parameters (ParameterHandler &prm) + { + // find out which plugins are requested and the various other + // parameters we declare here + prm.enter_subsection ("Initial composition model"); + { + model_names + = Utilities::split_string_list(prm.get("List of model names")); + + AssertThrow(Utilities::has_unique_entries(model_names), + ExcMessage("The list of strings for the parameter " + "'Initial composition model/List of model names' contains entries more than once. " + "This is not allowed. Please check your parameter file.")); + + const std::string model_name = prm.get ("Model name"); + + AssertThrow (model_name == "unspecified" || model_names.size() == 0, + ExcMessage ("The parameter 'Model name' is only used for reasons" + "of backwards compatibility and can not be used together with " + "the new functionality 'List of model names'. Please add your " + "initial composition model to the list instead.")); + + if (!(model_name == "unspecified")) + model_names.push_back(model_name); + + // create operator list + const std::vector model_operator_names = + Utilities::possibly_extend_from_1_to_N (Utilities::split_string_list(prm.get("List of model operators")), + model_names.size(), + "List of model operators"); + model_operators = Utilities::create_model_operator_list(model_operator_names); + + } + prm.leave_subsection (); + + if (model_names.size() > 0) + AssertThrow(this->n_compositional_fields() > 0, + ExcMessage("A plugin for the initial composition condition was specified, but there " + "is no compositional field. This can lead to errors within the initialization of " + "the initial composition plugin and is therefore not supported. Please remove " + "the initial composition plugin or add a compositional field.")); + + // go through the list, create objects and let them parse + // their own parameters + for (const auto &model_name : model_names) + { + this->plugin_objects.push_back (std::unique_ptr> + (std::get(registered_plugins) + .create_plugin (model_name, + "Initial composition model::Model names"))); + + if (SimulatorAccess *sim = dynamic_cast*>(&*this->plugin_objects.back())) + sim->initialize_simulator (this->get_simulator()); + + this->plugin_objects.back()->parse_parameters (prm); + this->plugin_objects.back()->initialize (); + } + } + + + + template + void + Manager::update() + { + for (auto &initial_composition_object : this->plugin_objects) + initial_composition_object->update(); + } + + + + template + double + Manager::initial_composition (const Point &position, + const unsigned int n_comp) const + { + double composition = 0.0; + int i = 0; + + for (const auto &initial_composition_object : this->plugin_objects) + { + composition = model_operators[i](composition, + initial_composition_object->initial_composition(position,n_comp)); + ++i; + } + + return composition; + } + + + template + const std::vector & + Manager::get_active_initial_composition_names () const + { + return model_names; + } + + + template + const std::list>> & + Manager::get_active_initial_composition_conditions () const + { + return this->plugin_objects; + } + + + template + void + Manager::declare_parameters (ParameterHandler &prm) + { + // declare the entry in the parameter file + prm.enter_subsection ("Initial composition model"); + { + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + + prm.declare_entry("List of model names", + "", + Patterns::MultipleSelection(pattern_of_names), + "A comma-separated list of initial composition models that " + "together describe the initial composition field. " + "These plugins are loaded in the order given, and modify the " + "existing composition field via the operators listed " + "in 'List of model operators'.\n\n" + "The following composition models are available:\n\n" + + + std::get(registered_plugins).get_description_string()); + + prm.declare_entry("List of model operators", "add", + Patterns::MultipleSelection(Utilities::get_model_operator_options()), + "A comma-separated list of operators that " + "will be used to append the listed composition models onto " + "the previous models. If only one operator is given, " + "the same operator is applied to all models."); + + prm.declare_entry ("Model name", "unspecified", + Patterns::Selection (pattern_of_names+"|unspecified"), + "Select one of the following models:\n\n" + + + std::get(registered_plugins).get_description_string() + + "\n\n" + + "\\textbf{Warning}: This parameter provides an old and " + "deprecated way of specifying " + "initial composition models and shouldn't be used. " + "Please use 'List of model names' instead."); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + template + std::string + get_valid_model_names_pattern () + { + return std::get(registered_plugins).get_pattern_of_names (); + } + + + + template + void + Manager::write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Initial composition interface", + out); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace InitialComposition + { +#define INSTANTIATE(dim) \ + template class Interface; \ + template class Manager; \ + \ + template \ + std::string \ + get_valid_model_names_pattern (); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/initial_composition/porosity.cc.bak b/source/initial_composition/porosity.cc.bak new file mode 100644 index 00000000000..566e1d497e1 --- /dev/null +++ b/source/initial_composition/porosity.cc.bak @@ -0,0 +1,116 @@ +/* + Copyright (C) 2017 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include + + +namespace aspect +{ + namespace InitialComposition + { + template + void + Porosity::initialize() + { + // Make sure we keep track of the initial temperature manager and + // that it continues to live beyond the time when the simulator + // class releases its pointer to it. + initial_temperature_manager = this->get_initial_temperature_manager_pointer(); + + // Make sure we keep track of the initial composition manager and + // that it continues to live beyond the time when the simulator + // class releases its pointer to it. + initial_composition_manager = this->get_initial_composition_manager_pointer(); + } + + + + template + double + Porosity:: + initial_composition (const Point &position, + const unsigned int compositional_index) const + { + AssertThrow(this->introspection().compositional_name_exists("porosity"), + ExcMessage("The initial composition plugin `porosity' did not find a " + "compositional field called `porosity' to initialize. Please add a " + "compositional field with this name.")); + + AssertThrow(MaterialModel::MeltFractionModel::is_melt_fraction_model(this->get_material_model()), + ExcMessage("The used material model is not derived from the 'MeltFractionModel' class, " + "and therefore does not support computing equilibrium melt fractions. " + "This is incompatible with the `porosity' " + "initial composition plugin, which needs to compute these melt fractions.")); + + const unsigned int porosity_index = this->introspection().compositional_index_for_name("porosity"); + if (compositional_index == porosity_index) + { + MaterialModel::MaterialModelInputs in(1, this->n_compositional_fields()); + + in.position[0] = position; + in.temperature[0] = initial_temperature_manager->initial_temperature(position); + in.pressure[0] = this->get_adiabatic_conditions().pressure(position); + in.pressure_gradient[0] = 0.0; + in.velocity[0] = 0.0; + + // Use the initial composition, except for the porosity, to prevent + // infinite recursion + for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) + if (i != porosity_index) + in.composition[0][i] = initial_composition_manager->initial_composition(position,i); + else + in.composition[0][i] = 0.0; + + in.strain_rate[0] = SymmetricTensor<2,dim>(); + + std::vector melt_fraction(1); + + MaterialModel::MeltFractionModel::as_melt_fraction_model(this->get_material_model()) + .melt_fractions(in, melt_fraction); + + return melt_fraction[0]; + } + return 0.0; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialComposition + { + ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(Porosity, + "porosity", + "A class that implements initial conditions for the porosity field " + "by computing the equilibrium melt fraction for the given initial " + "condition and reference pressure profile. Note that this plugin only " + "works if there is a compositional field called `porosity', and the " + "used material model implements the 'MeltFractionModel' interface. " + "For all compositional fields except porosity this plugin returns 0.0, " + "and they are therefore not changed as long as the default `add' " + "operator is selected for this plugin.") + } +} diff --git a/source/initial_composition/slab_model.cc.bak b/source/initial_composition/slab_model.cc.bak new file mode 100644 index 00000000000..e3a6e8cf0dd --- /dev/null +++ b/source/initial_composition/slab_model.cc.bak @@ -0,0 +1,147 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include +#include + + +namespace aspect +{ + namespace InitialComposition + { + template + void + SlabModel::initialize () + { + AssertThrow(this->introspection().compositional_name_exists("slabs"), + ExcMessage("The initial composition plugin `slab model' did not find a " + "compositional field called `slabs' to initialize. Please add a " + "compositional field with this name.")); + + slab_index = this->introspection().compositional_index_for_name("slabs"); + + // The input slabs are defined from the surface of the model + surface_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + + // The two columns correspond to slabs depth and thickness + slab_boundary.initialize({surface_boundary_id}, 2); + } + + + template + double + SlabModel:: + initial_composition (const Point &position, + const unsigned int compositional_index) const + { + if (compositional_index != slab_index) + return 0.0; + + // The first data column corresponds to the slab depth and the second column to the slab thickness. + // 'Slab depth' stands for the depth of the upper surface of the slab, 'Slab thickness' + // for the vertical distance between upper and lower surface. + const double slab_depth = slab_boundary.get_data_component(surface_boundary_id, position, 0); + const double slab_thickness = slab_boundary.get_data_component(surface_boundary_id, position, 1); + + // Return 0.0 if there is no slab in this location in the data. No slab is encoded in + // the data file as a slab thickness of 0.0 and/or a depth larger than the depth of + // the domain. + if (slab_thickness == 0.0 || + slab_depth > this->get_geometry_model().maximal_depth()) + return 0.0; + + // Return 1.0 if we are inside the depth range of the slab. + // We use a semi-closed interval so that a slab thickness of 0.0 + // means no slab exists. + const double depth = this->get_geometry_model().depth(position); + if ((depth >= slab_depth) && (depth < slab_depth + slab_thickness)) + return 1.0; + + return 0.0; + } + + + template + const Utilities::AsciiDataBoundary & + SlabModel::get_slab_boundary () const + { + return slab_boundary; + } + + + template + void + SlabModel::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + Utilities::AsciiDataBoundary::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/initial-composition/slab-model/", + "shell_3d.txt", + "Slab model", + /*time dependent = */ false); + } + prm.leave_subsection(); + } + + + template + void + SlabModel::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + slab_boundary.initialize_simulator (this->get_simulator()); + slab_boundary.parse_parameters(prm, "Slab model", /*time dependent = */ false); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialComposition + { + ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(SlabModel, + "slab model", + "An initial composition model that implements subducted " + "slab geometries as a compositional field determined from " + "an input file. The file defines the depth to the top of " + "the slab and the slab thickness. " + "The computed compositional value is 1 within the slabs " + "and zero elsewhere. " + "An example model that is included is Slab2 described in " + "Hayes, G. P., Moore, G. L., Portner, D. E., Hearne, M., " + "Flamme, H., Furtney, M., \\& Smoczyk, G. M. (2018). Slab2, " + "a comprehensive subduction zone geometry model. Science, " + "362(6410), 58-61. The script to convert the Slab2 model " + "into an aspect input data file is available in the directory " + "data/initial-composition/slab-model/. Please note that " + "Slab2 and the example data file assume spherical geometry " + "(latitude, longitude coordinates), however, that is not " + "necessary for this plugin, data files in " + "Cartesian coordinates will work with box geometries.") + } +} diff --git a/source/initial_composition/world_builder.cc.bak b/source/initial_composition/world_builder.cc.bak new file mode 100644 index 00000000000..16695d0841f --- /dev/null +++ b/source/initial_composition/world_builder.cc.bak @@ -0,0 +1,136 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include + +#ifdef ASPECT_WITH_WORLD_BUILDER +#include +#include +#include + +#include + + +namespace aspect +{ + namespace InitialComposition + { + template + void + WorldBuilder:: + initialize() + { + CitationInfo::add("GWB"); + world_builder = this->get_world_builder_pointer(); + } + + + + template + double + WorldBuilder:: + initial_composition (const Point &position, const unsigned int n_comp) const + { + if (relevant_compositions[n_comp] == true) + return world_builder->composition(Utilities::convert_point_to_array(position), + -this->get_geometry_model().height_above_reference_surface(position), + n_comp); + + return 0.0; + } + + + + template + void + WorldBuilder::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + prm.enter_subsection("World builder"); + { + prm.declare_entry ("List of relevant compositions", "", + Patterns::Anything(), + "A list of names of compositional fields for " + "which to determine the initial composition using " + "the World Builder. As World Builder evaluations can " + "be expensive, this parameter allows to only evaluate " + "the fields that are relevant. This plugin returns 0.0 " + "for all compositions that are not selected in the list. " + "By default the list is empty and the world builder is " + "evaluated for all compositional fields."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + WorldBuilder::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial composition model"); + { + prm.enter_subsection("World builder"); + { + const std::vector composition_names = Utilities::split_string_list(prm.get("List of relevant compositions")); + + relevant_compositions.resize(this->n_compositional_fields(),false); + + if (composition_names.size() == 0) + for (unsigned int i=0; in_compositional_fields(); ++i) + relevant_compositions[i] = true; + + for (const auto &composition_name: composition_names) + { + AssertThrow(this->introspection().compositional_name_exists (composition_name), + ExcMessage("All fields in \"List of relevant compositions\" must match names of compositional " + "fields as assigned in the \"Compositional fields/Names of fields\" parameter.")); + + relevant_compositions[this->introspection().compositional_index_for_name(composition_name)] = true; + } + } + + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialComposition + { + ASPECT_REGISTER_INITIAL_COMPOSITION_MODEL(WorldBuilder, + "world builder", + "Specify the initial composition through the World Builder. " + "More information on the World Builder can be found at " + "\\url{https://geodynamicworldbuilder.github.io}. " + "Make sure to specify the location of the World Builder file " + "in the parameter 'World builder file'. It is possible to use " + "the World Builder only for selected compositional fields by " + "specifying the parameter 'List of relevant compositions'.") + } +} +#endif diff --git a/source/initial_temperature/S40RTS_perturbation.cc.bak b/source/initial_temperature/S40RTS_perturbation.cc.bak new file mode 100644 index 00000000000..013c2d83be1 --- /dev/null +++ b/source/initial_temperature/S40RTS_perturbation.cc.bak @@ -0,0 +1,530 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace InitialTemperature + { + namespace internal + { + namespace S40RTS + { + // Read in the spherical harmonics that are located in data/initial-temperature/S40RTS + // and were downloaded from http://www.earth.lsa.umich.edu/~jritsema/research.html + // Ritsema et al. choose real sine and cosine coefficients that follow the normalization + // by Dahlen & Tromp, Theoretical Global Seismology (equations B.58 and B.99). + + // NOTE: There is a factor of sqrt(2) difference between the standard orthonormalized + // spherical harmonics used by Dahlen & Tromp and that used for S40RTS (see PR # 966). + // This might need adjusting if this code is used to read in spherical harmonic + // based tomography models that aren't S40RTS or S20RTS. + + SphericalHarmonicsLookup:: + SphericalHarmonicsLookup(const std::string &filename, + const MPI_Comm comm) + { + std::string temp; + // Read data from disk and distribute among processes + std::istringstream in(Utilities::read_and_distribute_file_content(filename, comm)); + + in >> order; + std::getline(in,temp); // throw away the rest of the line + + const unsigned int num_splines = 21; + const unsigned int maxnumber = num_splines * (order+1)*(order+1); + + // read in all coefficients as a single data vector + std::vector coeffs(maxnumber,0.0); + + for (unsigned int i=0; i> coeffs[i]; + } + + // reorder the coefficients into sin and cos coefficients. a_lm will be the cos coefficients + // and b_lm the sin coefficients. + unsigned int ind = 0; + + a_lm.reserve(maxnumber); + b_lm.reserve(maxnumber); + for (unsigned int j=0; j & + SphericalHarmonicsLookup::cos_coeffs() const + { + return a_lm; + } + + // Declare a function that returns the sine coefficients + const std::vector & + SphericalHarmonicsLookup::sin_coeffs() const + { + return b_lm; + } + + unsigned int + SphericalHarmonicsLookup::maxdegree() const + { + return order; + } + + // Read in the knot points for the spline interpolation. They are located in data/ + // initial-temperature/S40RTS and were taken from the plotting script + // lib/libS20/splhsetup.f which is part of the plotting package downloadable at + // http://www.earth.lsa.umich.edu/~jritsema/research.html + SplineDepthsLookup::SplineDepthsLookup(const std::string &filename, + const MPI_Comm comm) + { + std::string temp; + // Read data from disk and distribute among processes + std::istringstream in(Utilities::read_and_distribute_file_content(filename, comm)); + + std::getline(in,temp); // throw away the rest of the line + std::getline(in,temp); // throw away the rest of the line + + // This is fixed for this tomography model + const unsigned int num_splines = 21; + + depths.resize(num_splines); + for (unsigned int i=0; i> depths[i]; + } + } + + const std::vector & + SplineDepthsLookup::spline_depths() const + { + return depths; + } + } + } + + + template + S40RTSPerturbation::S40RTSPerturbation() + : + vs_to_density_index(numbers::invalid_unsigned_int) + {} + + template + void + S40RTSPerturbation::initialize() + { + spherical_harmonics_lookup + = std::make_unique(data_directory+harmonics_coeffs_file_name, + this->get_mpi_communicator()); + spline_depths_lookup + = std::make_unique(data_directory+spline_depth_file_name, + this->get_mpi_communicator()); + + if (vs_to_density_method == file) + { + profile.initialize(this->get_mpi_communicator()); + vs_to_density_index = profile.get_column_index_from_name("vs_to_density"); + } + } + + + + template + double + S40RTSPerturbation:: + get_Vs (const Point &position) const + { + // get the max degree from the input data file (20 or 40) + const unsigned int max_degree_data_file = spherical_harmonics_lookup->maxdegree(); + + // set the max degree used for the calculation to the max degree from the input data file as default + unsigned int max_degree_to_use = max_degree_data_file; + + // lower the maximum degree of the calculation if needed + if (lower_max_degree) + { + AssertThrow(specified_max_degree <= max_degree_data_file, ExcMessage("Specifying a maximum degree higher than the degree of spherical harmonic data is not allowed")); + max_degree_to_use = specified_max_degree; + } + + // This tomography model is parameterized by 21 layers + const unsigned int num_spline_knots = 21; + + // get the spherical harmonics coefficients + const std::vector &a_lm = spherical_harmonics_lookup->cos_coeffs(); + const std::vector &b_lm = spherical_harmonics_lookup->sin_coeffs(); + + // get spline knots and rescale them from [-1 1] to [CMB Moho] + const std::vector &r = spline_depths_lookup->spline_depths(); + const double rmoho = 6346e3; + const double rcmb = 3480e3; + std::vector depth_values(num_spline_knots, 0); + + for (unsigned int i = 0; i scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(position); + + // Evaluate the spherical harmonics at this position. Since they are the + // same for all depth splines, do it once to avoid multiple evaluations. + // NOTE: there is apparently a factor of sqrt(2) difference + // between the standard orthonormalized spherical harmonics + // and those used for S40RTS (see PR # 966) + std::vector> cosine_components(max_degree_to_use+1, std::vector(max_degree_to_use+1, 0.0)); + std::vector> sine_components(max_degree_to_use+1, std::vector(max_degree_to_use+1, 0.0)); + + for (unsigned int degree_l = 0; degree_l < max_degree_to_use+1; ++degree_l) + { + for (unsigned int order_m = 0; order_m < degree_l+1; ++order_m) + { + const double phi = scoord[1]; + const double theta = (dim == 3) ? scoord[2] : numbers::PI_2; + const std::pair sph_harm_vals = + Utilities::real_spherical_harmonic(degree_l, order_m, theta, phi); + + cosine_components[degree_l][order_m] = sph_harm_vals.first; + sine_components[degree_l][order_m] = sph_harm_vals.second; + } + } + + // iterate over all degrees and orders at each depth and sum them all up. + std::vector spline_values(num_spline_knots, 0.); + double prefact; + unsigned int ind = 0; + + for (unsigned int depth_interp = 0; depth_interp < num_spline_knots; ++depth_interp) + { + for (unsigned int degree_l = 0; degree_l < max_degree_to_use+1; ++degree_l) + { + for (unsigned int order_m = 0; order_m < degree_l+1; ++order_m) + { + if (degree_l == 0) + prefact = (zero_out_degree_0 + ? + 0. + : + 1.); + else if (order_m != 0) + // this removes the sqrt(2) factor difference in normalization (see PR # 966) + prefact = 1./sqrt(2.); + else + prefact = 1.0; + + spline_values[depth_interp] += prefact * (a_lm[ind] * cosine_components[degree_l][order_m] + + b_lm[ind] * sine_components[degree_l][order_m]); + + ++ind; + } + } + // Skip the higher degree spherical harminic coefficients per layer if a lower max degree is used. + // The formula below will calculate the total number of the spherical harmonic coefficients from + // the degree at max_degree_to_use+1 to the degree at max_degree_data_file. + // The formula below will be zero if the spherical harmonics are summed up to the degree at max_degree_data_file. + ind += (max_degree_to_use+max_degree_data_file+3)*(max_degree_data_file-max_degree_to_use)/2; + } + + // We need to reorder the spline_values because the coefficients are given from + // the surface down to the CMB and the interpolation knots range from the CMB up to + // the surface. + std::vector spline_values_inv(num_spline_knots,0); + for (unsigned int i=0; i + double + S40RTSPerturbation:: + initial_temperature (const Point &position) const + { + + // use either the user-input reference temperature as background temperature + // (incompressible model) or the adiabatic temperature profile (compressible model) + const double background_temperature = this->get_material_model().is_compressible() ? + this->get_adiabatic_conditions().temperature(position) : + reference_temperature; + + //Read in Vs perturbation data using function above + const double perturbation = get_Vs (position); + + + // Get the vs to density conversion + const double depth = this->get_geometry_model().depth(position); + + double vs_to_density = 0.0; + if (vs_to_density_method == file) + vs_to_density = profile.get_data_component(Point<1>(depth), vs_to_density_index); + else if (vs_to_density_method == constant) + vs_to_density = vs_to_density_constant; + else + // we shouldn't get here but instead should already have been + // kicked out by the assertion in the parse_parameters() + // function + Assert (false, ExcNotImplemented()); + + // scale the perturbation in seismic velocity into a density perturbation + // vs_to_density is an input parameter + const double density_perturbation = vs_to_density * perturbation; + + double temperature_perturbation; + if (depth > no_perturbation_depth) + { + // scale the density perturbation into a temperature perturbation + // see if we need to ask material model for the thermal expansion coefficient + if (use_material_model_thermal_alpha) + { + MaterialModel::MaterialModelInputs in(1, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(1, this->n_compositional_fields()); + in.position[0] = position; + in.temperature[0] = background_temperature; + in.pressure[0] = this->get_adiabatic_conditions().pressure(position); + in.velocity[0] = Tensor<1,dim> (); + for (unsigned int c=0; cn_compositional_fields(); ++c) + in.composition[0][c] = this->get_initial_composition_manager().initial_composition(position, c); + in.requested_properties = MaterialModel::MaterialProperties::thermal_expansion_coefficient; + + this->get_material_model().evaluate(in, out); + + temperature_perturbation = -1./(out.thermal_expansion_coefficients[0]) * density_perturbation; + } + else + temperature_perturbation = -1./thermal_alpha * density_perturbation; + } + else + // set heterogeneity to zero down to a specified depth + temperature_perturbation = 0.0; + + // add the temperature perturbation to the background temperature + return background_temperature + temperature_perturbation; + } + + + template + void + S40RTSPerturbation::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("S40RTS perturbation"); + { + prm.declare_entry ("Data directory", "$ASPECT_SOURCE_DIR/data/initial-temperature/S40RTS/", + Patterns::DirectoryName (), + "The path to the model data. "); + prm.declare_entry ("Initial condition file name", "S40RTS.sph", + Patterns::Anything(), + "The file name of the spherical harmonics coefficients " + "from Ritsema et al."); + prm.declare_entry ("Spline knots depth file name", "Spline_knots.txt", + Patterns::Anything(), + "The file name of the spline knot locations from " + "Ritsema et al."); + prm.declare_entry ("Vs to density scaling method", "constant", + Patterns::Selection("file|constant"), + "Method that is used to specify how the vs-to-density scaling varies " + "with depth."); + prm.declare_entry ("Vs to density scaling", "0.25", + Patterns::Double (0.), + "This parameter specifies how the perturbation in shear wave velocity " + "as prescribed by S20RTS or S40RTS is scaled into a density perturbation. " + "See the general description of this model for more detailed information."); + prm.declare_entry ("Thermal expansion coefficient in initial temperature scaling", "2e-5", + Patterns::Double (0.), + "The value of the thermal expansion coefficient $\\beta$. " + "Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Use thermal expansion coefficient from material model", "false", + Patterns::Bool (), + "Option to take the thermal expansion coefficient from the " + "material model instead of from what is specified in this " + "section."); + prm.declare_entry ("Remove degree 0 from perturbation","true", + Patterns::Bool (), + "Option to remove the degree zero component from the perturbation, " + "which will ensure that the laterally averaged temperature for a fixed " + "depth is equal to the background temperature."); + prm.declare_entry ("Reference temperature", "1600.0", + Patterns::Double (0.), + "The reference temperature that is perturbed by the spherical " + "harmonic functions. Only used in incompressible models."); + prm.declare_entry ("Remove temperature heterogeneity down to specified depth", + boost::lexical_cast(std::numeric_limits::lowest()), + Patterns::Double (), + "This will set the heterogeneity prescribed by S20RTS or S40RTS to zero " + "down to the specified depth (in meters). Note that your resolution has " + "to be adequate to capture this cutoff. For example if you specify a depth " + "of 660km, but your closest spherical depth layers are only at 500km and " + "750km (due to a coarse resolution) it will only zero out heterogeneities " + "down to 500km. Similar caution has to be taken when using adaptive meshing."); + prm.declare_entry ("Specify a lower maximum degree","false", + Patterns::Bool (), + "Option to use a lower maximum degree when reading the data file of spherical " + "harmonic coefficients. This is probably used for the faster tests or when the " + "users only want to see the spherical harmonic pattern up to a certain degree."); + prm.declare_entry ("Maximum degree","20", + Patterns::Integer (0), + "The maximum degree the users specify when reading the data file of spherical harmonic " + "coefficients, which must be smaller than the maximum degree the data file stored. " + "This parameter will be used only if 'Specify a lower maximum degree' is set to true."); + + aspect::Utilities::AsciiDataProfile::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/initial-temperature/S40RTS/", + "vs_to_density_Steinberger.txt", + "Ascii data vs to density model"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + S40RTSPerturbation::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("S40RTS perturbation"); + { + data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get ("Data directory")); + + if ((data_directory.size() > 0) && (data_directory[data_directory.size()-1] != '/')) + data_directory += "/"; + harmonics_coeffs_file_name = prm.get ("Initial condition file name"); + spline_depth_file_name = prm.get ("Spline knots depth file name"); + vs_to_density_constant = prm.get_double ("Vs to density scaling"); + thermal_alpha = prm.get_double ("Thermal expansion coefficient in initial temperature scaling"); + use_material_model_thermal_alpha = prm.get_bool ("Use thermal expansion coefficient from material model"); + zero_out_degree_0 = prm.get_bool ("Remove degree 0 from perturbation"); + reference_temperature = prm.get_double ("Reference temperature"); + no_perturbation_depth = prm.get_double ("Remove temperature heterogeneity down to specified depth"); + lower_max_degree = prm.get_bool ("Specify a lower maximum degree"); + specified_max_degree = prm.get_integer ("Maximum degree"); + + if (prm.get("Vs to density scaling method") == "file") + vs_to_density_method = file; + else if (prm.get("Vs to density scaling method") == "constant") + vs_to_density_method = constant; + else + { + AssertThrow(false, ExcMessage("Unknown method for vs to density scaling.")); + } + + profile.parse_parameters(prm,"Ascii data vs to density model"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(S40RTSPerturbation, + "S40RTS perturbation", + "An initial temperature field in which the temperature " + "is perturbed following the S20RTS or S40RTS shear wave " + "velocity model by Ritsema and others, which can be downloaded " + "here \\url{http://www.earth.lsa.umich.edu/~jritsema/research.html}. " + "Information on the vs model can be found in Ritsema, J., Deuss, " + "A., van Heijst, H.J. \\& Woodhouse, J.H., 2011. S40RTS: a " + "degree-40 shear-velocity model for the mantle from new Rayleigh " + "wave dispersion, teleseismic traveltime and normal-mode " + "splitting function measurements, Geophys. J. Int. 184, 1223-1236. " + "The scaling between the shear wave perturbation and the " + "density perturbation can be constant and set by the user with the " + "'Vs to density scaling' parameter or depth-dependent and " + "read in from a file. To convert density the user can specify " + "the 'Thermal expansion coefficient in initial temperature scaling' " + "parameter. The scaling is as follows: $\\delta \\ln \\rho " + "(r,\\theta,\\phi) = \\xi \\cdot \\delta \\ln v_s(r,\\theta, " + "\\phi)$ and $\\delta T(r,\\theta,\\phi) = - \\frac{1}{\\alpha} " + "\\delta \\ln \\rho(r,\\theta,\\phi)$. $\\xi$ is the `vs to " + "density scaling' parameter and $\\alpha$ is the 'Thermal " + "expansion coefficient in initial temperature scaling' " + "parameter. The temperature perturbation is added to an " + "otherwise constant temperature (incompressible model) or " + "adiabatic reference profile (compressible model). If a depth " + "is specified in 'Remove temperature heterogeneity down to " + "specified depth', there is no temperature perturbation " + "prescribed down to that depth." + "\n" + "Note the required file format if the vs to density scaling is read in " + "from a file: The first lines may contain any number of comments " + "if they begin with '#', but one of these lines needs to " + "contain the number of points in the reference state as " + "for example '# POINTS: 3'. " + "Following the comment lines there has to be a single line " + "containing the names of all data columns, separated by arbitrarily " + "many spaces. Column names are not allowed to contain spaces. " + "The file can contain unnecessary columns, but for this plugin it " + "needs to at least provide the columns named `depth' and " + "`vs\\_to\\_density'. " + "Note that the data lines in the file need to be sorted in order " + "of increasing depth from 0 to the maximal depth in the model " + "domain. Points in the model that are outside of the provided " + "depth range will be assigned the maximum or minimum depth values, " + "respectively. Points do not need to be equidistant, " + "but the computation of properties is optimized in speed " + "if they are." + "\n" + "If the plugin is used in 2d it will use an equatorial " + "slice of the seismic tomography model.") + } +} diff --git a/source/initial_temperature/SAVANI_perturbation.cc.bak b/source/initial_temperature/SAVANI_perturbation.cc.bak new file mode 100644 index 00000000000..ce8881cbb66 --- /dev/null +++ b/source/initial_temperature/SAVANI_perturbation.cc.bak @@ -0,0 +1,537 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace InitialTemperature + { + namespace internal + { + namespace SAVANI + { + // Read in the spherical harmonics that are located in data/initial-temperature/SAVANI + // and were downloaded from http://n.ethz.ch/~auerl/research.html + // choose real sine and cosine coefficients that follow the normalization + // by Dahlen & Tromp, Theoretical Global Seismology (equations B.58 and B.99). + + class SphericalHarmonicsLookup + { + public: + SphericalHarmonicsLookup(const std::string &filename, + const MPI_Comm comm) + { + std::string temp; + // Read data from disk and distribute among processes + std::istringstream in(Utilities::read_and_distribute_file_content(filename, comm)); + + in >> order; + std::getline(in,temp); // throw away the rest of the line + + const unsigned int num_layers = 28; + + // read in all coefficients as a single data vector + std::vector coeffs; + for (unsigned int i=0; i> new_val; + coeffs.push_back(0.01*new_val); + } + std::getline(in,temp); + } + + // reorder the coefficients into sin and cos coefficients. a_lm will be the cos coefficients + // and b_lm the sin coefficients. + unsigned int ind = 0; + + for (unsigned int j=0; j &cos_coeffs() const + { + return a_lm; + } + + // Declare a function that returns the sine coefficients + const std::vector &sin_coeffs() const + { + return b_lm; + } + + unsigned int maxdegree() + { + return order; + } + + private: + unsigned int order; + std::vector a_lm; + std::vector b_lm; + + }; + + // Read in the knot points for the spline interpolation. They are located in data/ + // initial-temperature/SAVANI and were taken from the 28 spherical layers of SAVANI + // tomography model by a matlab script convert_to_knots.m located in the same directory. + class SplineDepthsLookup + { + public: + SplineDepthsLookup(const std::string &filename, + const MPI_Comm comm) + { + std::string temp; + // Read data from disk and distribute among processes + std::istringstream in(Utilities::read_and_distribute_file_content(filename, comm)); + + std::getline(in,temp); // throw away the rest of the line + std::getline(in,temp); // throw away the rest of the line + + const unsigned int num_splines = 28; + depths.resize(num_splines); + for (unsigned int i=0; i> depths[i]; + } + } + + const std::vector &spline_depths() const + { + return depths; + } + + private: + std::vector depths; + }; + } + } + + template + SAVANIPerturbation::SAVANIPerturbation() + : + vs_to_density_index(numbers::invalid_unsigned_int) + {} + + + template + void + SAVANIPerturbation::initialize() + { + spherical_harmonics_lookup + = std::make_unique(data_directory+harmonics_coeffs_file_name, + this->get_mpi_communicator()); + spline_depths_lookup + = std::make_unique(data_directory+spline_depth_file_name, + this->get_mpi_communicator()); + + if (vs_to_density_method == file) + { + profile.initialize(this->get_mpi_communicator()); + vs_to_density_index = profile.get_column_index_from_name("vs_to_density"); + } + + } + + + template <> + double + SAVANIPerturbation<2>:: + initial_temperature (const Point<2> &) const + { + // we shouldn't get here but instead should already have been + // kicked out by the assertion in the parse_parameters() + // function + Assert (false, ExcNotImplemented()); + return 0; + } + + template <> + double + SAVANIPerturbation<2>:: + get_Vs (const Point<2> &/*position*/) const + { + Assert (false, ExcNotImplemented()); + return 0; + } + + template <> + double + SAVANIPerturbation<3>:: + get_Vs (const Point<3> &position) const + { + const unsigned int dim = 3; + + // get the max degree from the input data file (60) + const unsigned int max_degree_data_file = spherical_harmonics_lookup->maxdegree(); + + // set the max degree used for the calculation to the max degree from the input data file as default + unsigned int max_degree_to_use = max_degree_data_file; + + // lower the maximum degree of the calculation if needed + if (lower_max_degree) + { + AssertThrow(specified_max_degree <= max_degree_data_file, ExcMessage("Specifying a maximum degree higher than the degree of spherical harmonic data is not allowed")); + max_degree_to_use = specified_max_degree; + } + + const int num_spline_knots = 28; // The tomography models are parameterized by 28 layers + + // get the spherical harmonics coefficients + const std::vector &a_lm = spherical_harmonics_lookup->cos_coeffs(); + const std::vector &b_lm = spherical_harmonics_lookup->sin_coeffs(); + + // get spline knots and rescale them from [-1 1], i.e., CMB to Moho. + const std::vector &r = spline_depths_lookup->spline_depths(); + const double rmoho = 6346e3; + const double rcmb = 3480e3; + std::vector depth_values(num_spline_knots, 0.); + + for (unsigned int i = 0; i scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(position); + + // Evaluate the spherical harmonics at this position. Since they are the + // same for all depth splines, do it once to avoid multiple evaluations. + std::vector> cosine_components(max_degree_to_use+1, std::vector(max_degree_to_use+1, 0.0)); + std::vector> sine_components(max_degree_to_use+1, std::vector(max_degree_to_use+1, 0.0)); + + for (unsigned int degree_l = 0; degree_l < max_degree_to_use+1; ++degree_l) + { + for (unsigned int order_m = 0; order_m < degree_l+1; ++order_m) + { + const std::pair sph_harm_vals = Utilities::real_spherical_harmonic( degree_l, order_m, scoord[2], scoord[1] ); + cosine_components[degree_l][order_m] = sph_harm_vals.first; + sine_components[degree_l][order_m] = sph_harm_vals.second; + } + } + + // iterate over all degrees and orders at each depth and sum them all up. + std::vector spline_values(num_spline_knots, 0.); + double prefact; + unsigned int ind = 0; + + for (unsigned int depth_interp = 0; depth_interp < num_spline_knots; ++depth_interp) + { + for (unsigned int degree_l = 0; degree_l < max_degree_to_use+1; ++degree_l) + { + for (unsigned int order_m = 0; order_m < degree_l+1; ++order_m) + { + // normalization after Dahlen and Tromp, 1986, Appendix B.6 + if (degree_l == 0) + prefact = (zero_out_degree_0 + ? + 0. + : + 1.); + else + prefact = 1.0; + + spline_values[depth_interp] += prefact * (a_lm[ind] * cosine_components[degree_l][order_m] + + b_lm[ind] * sine_components[degree_l][order_m]); + + ++ind; + } + } + // Skip the higher degree spherical harminic coefficients per layer if a lower max degree is used. + // The formula below will calculate the total number of the spherical harmonic coefficients from + // the degree at max_degree_to_use+1 to the degree at max_degree_data_file. + // The formula below will be zero if the spherical harmonics are summed up to the degree at max_degree_data_file. + ind += (max_degree_to_use+max_degree_data_file+3)*(max_degree_data_file-max_degree_to_use)/2; + } + + + // The boundary condition for the cubic spline interpolation is that the function is linear + // at the boundary (i.e. Moho and CMB). Values outside the range are linearly + // extrapolated. + aspect::Utilities::tk::spline s; + s.set_points(depth_values, spline_values); + + // Get value at specific depth + return s(scoord[0]); + + } + + + template <> + double + SAVANIPerturbation<3>:: + initial_temperature (const Point<3> &position) const + { + // use either the user-input reference temperature as background temperature + // (incompressible model) or the adiabatic temperature profile (compressible model) + const double background_temperature = this->get_material_model().is_compressible() ? + this->get_adiabatic_conditions().temperature(position) : + reference_temperature; + + //Read in Vs perturbation data using function above + const double perturbation = get_Vs (position); + + // Get the vs to density conversion + const double depth = this->get_geometry_model().depth(position); + + double vs_to_density = 0.0; + if (vs_to_density_method == file) + vs_to_density = profile.get_data_component(Point<1>(depth), vs_to_density_index); + else if (vs_to_density_method == constant) + vs_to_density = vs_to_density_constant; + else + // we shouldn't get here but instead should already have been + // kicked out by the assertion in the parse_parameters() + // function + Assert (false, ExcNotImplemented()); + + // scale the perturbation in seismic velocity into a density perturbation + // vs_to_density is an input parameter + const double density_perturbation = vs_to_density * perturbation; + + double temperature_perturbation; + if (depth > no_perturbation_depth) + { + // scale the density perturbation into a temperature perturbation + // see if we need to ask material model for the thermal expansion coefficient + if (use_material_model_thermal_alpha) + { + MaterialModel::MaterialModelInputs<3> in(1, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs<3> out(1, this->n_compositional_fields()); + in.position[0] = position; + in.temperature[0] = background_temperature; + in.pressure[0] = this->get_adiabatic_conditions().pressure(position); + in.velocity[0] = Tensor<1,3> (); + for (unsigned int c=0; cn_compositional_fields(); ++c) + in.composition[0][c] = this->get_initial_composition_manager().initial_composition(position, c); + in.requested_properties = MaterialModel::MaterialProperties::thermal_expansion_coefficient; + + this->get_material_model().evaluate(in, out); + + temperature_perturbation = -1./(out.thermal_expansion_coefficients[0]) * density_perturbation; + } + else + temperature_perturbation = -1./thermal_alpha * density_perturbation; + } + else + // set heterogeneity to zero down to a specified depth + temperature_perturbation = 0.0; + + // add the temperature perturbation to the background temperature + return background_temperature + temperature_perturbation; + } + + + template + void + SAVANIPerturbation::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("SAVANI perturbation"); + { + prm.declare_entry ("Data directory", "$ASPECT_SOURCE_DIR/data/initial-temperature/SAVANI/", + Patterns::DirectoryName (), + "The path to the model data."); + prm.declare_entry ("Initial condition file name", "savani.dlnvs.60.m.ab", + Patterns::Anything(), + "The file name of the spherical harmonics coefficients " + "from Auer et al."); + prm.declare_entry ("Spline knots depth file name", "Spline_knots.txt", + Patterns::Anything(), + "The file name of the spline knots taken from the 28 spherical layers " + "of SAVANI tomography model."); + prm.declare_entry ("Vs to density scaling method", "constant", + Patterns::Selection("file|constant"), + "Method that is used to specify how the vs-to-density scaling varies " + "with depth."); + prm.declare_entry ("Vs to density scaling", "0.25", + Patterns::Double (0.), + "This parameter specifies how the perturbation in shear wave velocity " + "as prescribed by SAVANI is scaled into a density perturbation. " + "See the general description of this model for more detailed information."); + prm.declare_entry ("Thermal expansion coefficient in initial temperature scaling", "2e-5", + Patterns::Double (0.), + "The value of the thermal expansion coefficient $\\beta$. " + "Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Use thermal expansion coefficient from material model", "false", + Patterns::Bool (), + "Option to take the thermal expansion coefficient from the " + "material model instead of from what is specified in this " + "section."); + prm.declare_entry ("Remove degree 0 from perturbation","true", + Patterns::Bool (), + "Option to remove the degree zero component from the perturbation, " + "which will ensure that the laterally averaged temperature for a fixed " + "depth is equal to the background temperature."); + prm.declare_entry ("Reference temperature", "1600.0", + Patterns::Double (0.), + "The reference temperature that is perturbed by the spherical " + "harmonic functions. Only used in incompressible models."); + prm.declare_entry ("Remove temperature heterogeneity down to specified depth", + boost::lexical_cast(std::numeric_limits::lowest()), + Patterns::Double (), + "This will set the heterogeneity prescribed by SAVANI to zero " + "down to the specified depth (in meters). Note that your resolution has " + "to be adequate to capture this cutoff. For example if you specify a depth " + "of 660km, but your closest spherical depth layers are only at 500km and " + "750km (due to a coarse resolution) it will only zero out heterogeneities " + "down to 500km. Similar caution has to be taken when using adaptive meshing."); + prm.declare_entry ("Specify a lower maximum degree","false", + Patterns::Bool (), + "Option to use a lower maximum degree when reading the data file of spherical " + "harmonic coefficients. This is probably used for the faster tests or when the " + "users only want to see the spherical harmonic pattern up to a certain degree."); + prm.declare_entry ("Maximum degree","20", + Patterns::Integer (0), + "The maximum degree the users specify when reading the data file of spherical harmonic " + "coefficients, which must be smaller than the maximum degree the data file stored. " + "This parameter will be used only if 'Specify a lower maximum degree' is set to true."); + aspect::Utilities::AsciiDataProfile::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/initial-temperature/S40RTS/", + "vs_to_density_Steinberger.txt", + "Ascii data vs to density model"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + SAVANIPerturbation::parse_parameters (ParameterHandler &prm) + { + AssertThrow (dim == 3, + ExcMessage ("The 'SAVANI perturbation' model for the initial " + "temperature is only available for 3d computations.")); + + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("SAVANI perturbation"); + { + data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get ("Data directory")); + if ((data_directory.size() > 0) && (data_directory[data_directory.size()-1] != '/')) + data_directory += "/"; + harmonics_coeffs_file_name = prm.get ("Initial condition file name"); + spline_depth_file_name = prm.get ("Spline knots depth file name"); + vs_to_density_constant = prm.get_double ("Vs to density scaling"); + thermal_alpha = prm.get_double ("Thermal expansion coefficient in initial temperature scaling"); + use_material_model_thermal_alpha = prm.get_bool ("Use thermal expansion coefficient from material model"); + zero_out_degree_0 = prm.get_bool ("Remove degree 0 from perturbation"); + reference_temperature = prm.get_double ("Reference temperature"); + no_perturbation_depth = prm.get_double ("Remove temperature heterogeneity down to specified depth"); + lower_max_degree = prm.get_bool ("Specify a lower maximum degree"); + specified_max_degree = prm.get_integer ("Maximum degree"); + + if (prm.get("Vs to density scaling method") == "file") + vs_to_density_method = file; + else if (prm.get("Vs to density scaling method") == "constant") + vs_to_density_method = constant; + else + { + AssertThrow(false, ExcMessage("Unknown method for vs to density scaling.")); + } + + profile.parse_parameters(prm,"Ascii data vs to density model"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(SAVANIPerturbation, + "SAVANI perturbation", + "An initial temperature field in which the temperature " + "is perturbed following the SAVANI shear wave " + "velocity model by Auer and others, which can be downloaded " + "here \\url{http://n.ethz.ch/~auerl/savani.tar.bz2}. " + "Information on the vs model can be found in Auer, L., Boschi, " + "L., Becker, T.W., Nissen-Meyer, T. \\& Giardini, D., 2014. " + "Savani: A variable resolution whole-mantle model of anisotropic " + "shear velocity variations based on multiple data sets. Journal " + "of Geophysical Research: Solid Earth 119.4 (2014): 3006-3034. " + "The scaling between the shear wave perturbation and the " + "density perturbation can be constant and set by the user with the " + "'Vs to density scaling' parameter or depth-dependent and " + "read in from a file. To convert density the user can specify " + "the 'Thermal expansion coefficient in initial temperature scaling' " + "parameter. The scaling is as follows: $\\delta \\ln \\rho " + "(r,\\theta,\\phi) = \\xi \\cdot \\delta \\ln v_s(r,\\theta, " + "\\phi)$ and $\\delta T(r,\\theta,\\phi) = - \\frac{1}{\\alpha} " + "\\delta \\ln \\rho(r,\\theta,\\phi)$. $\\xi$ is the `vs to " + "density scaling' parameter and $\\alpha$ is the 'Thermal " + "expansion coefficient in initial temperature scaling' " + "parameter. The temperature perturbation is added to an " + "otherwise constant temperature (incompressible model) or " + "adiabatic reference profile (compressible model).If a depth " + "is specified in 'Remove temperature heterogeneity down to " + "specified depth', there is no temperature perturbation " + "prescribed down to that depth." + "\n" + "Note the required file format if the vs to density scaling is read in " + "from a file: The first lines may contain any number of comments " + "if they begin with '#', but one of these lines needs to " + "contain the number of points in the reference state as " + "for example '# POINTS: 3'. " + "Following the comment lines there has to be a single line " + "containing the names of all data columns, separated by arbitrarily " + "many spaces. Column names are not allowed to contain spaces. " + "The file can contain unnecessary columns, but for this plugin it " + "needs to at least provide the columns named `depth' and " + "`vs\\_to\\_density'. " + "Note that the data lines in the file need to be sorted in order " + "of increasing depth from 0 to the maximal depth in the model " + "domain. Points in the model that are outside of the provided " + "depth range will be assigned the maximum or minimum depth values, " + "respectively. Points do not need to be equidistant, " + "but the computation of properties is optimized in speed " + "if they are.") + } +} diff --git a/source/initial_temperature/adiabatic.cc.bak b/source/initial_temperature/adiabatic.cc.bak new file mode 100644 index 00000000000..948475d1cc6 --- /dev/null +++ b/source/initial_temperature/adiabatic.cc.bak @@ -0,0 +1,572 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace InitialTemperature + { + namespace BoundaryLayerAgeModel + { + BoundaryLayerAgeModel::Kind + parse (const std::string ¶meter_name, + const ParameterHandler &prm) + { + BoundaryLayerAgeModel::Kind age_model; + if (prm.get (parameter_name) == "constant") + age_model = constant; + else if (prm.get (parameter_name) == "function") + age_model = function; + else if (prm.get (parameter_name) == "ascii data") + age_model = ascii_data; + else + { + AssertThrow(false, ExcMessage("Not a valid boundary layer age model.")); + + // We will never get here, but we have to return something + // so the compiler does not complain + return constant; + } + + return age_model; + } + } + + template + Adiabatic::Adiabatic () + : + surface_boundary_id(numbers::invalid_unsigned_int) + {} + + + + template + void + Adiabatic::initialize () + { + if (top_boundary_layer_age_model == BoundaryLayerAgeModel::ascii_data) + { + // Find the boundary indicator that represents the surface + surface_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + + // The input ascii table contains one data column (LAB depths(m)) in addition to the coordinate columns. + Utilities::AsciiDataBoundary::initialize({surface_boundary_id}, + 1); + } + } + + + + template + double + Adiabatic:: + top_boundary_layer_age (const Point &position) const + { + // Top boundary layer age in seconds + double age_top = 0.0; + + if (top_boundary_layer_age_model == BoundaryLayerAgeModel::ascii_data) + { + // The input ascii contains the age of the seafloor. User must provide ages in seconds + age_top = Utilities::AsciiDataBoundary::get_data_component(surface_boundary_id, + position, + 0); + } + else if (top_boundary_layer_age_model == BoundaryLayerAgeModel::constant) + { + age_top = (this->convert_output_to_years() + ? + age_top_boundary_layer * year_in_seconds + : + age_top_boundary_layer); + } + else if (top_boundary_layer_age_model == BoundaryLayerAgeModel::function) + { + Utilities::NaturalCoordinate point = + this->get_geometry_model().cartesian_to_other_coordinates(position, + coordinate_system); + + age_top = age_function.value(Utilities::convert_array_to_point(point.get_coordinates())); + if (this->convert_output_to_years()) + age_top *= year_in_seconds; + } + else + { + Assert(false, ExcMessage("Unknown top boundary layer age model.")); + } + + return age_top; + } + + + template + double + Adiabatic:: + initial_temperature (const Point &position) const + { + + const double age_top = top_boundary_layer_age(position); + const double age_bottom = (this->convert_output_to_years() ? age_bottom_boundary_layer * year_in_seconds + : age_bottom_boundary_layer); + + // First, get the temperature of the adiabatic profile at a representative + // point at the top and bottom boundary of the model + // if adiabatic heating is switched off, assume a constant profile + const Point surface_point = this->get_geometry_model().representative_point(0.0); + const Point bottom_point = this->get_geometry_model().representative_point(this->get_geometry_model().maximal_depth()); + const double adiabatic_surface_temperature = this->get_adiabatic_conditions().temperature(surface_point); + const double adiabatic_bottom_temperature = (this->include_adiabatic_heating()) + ? + this->get_adiabatic_conditions().temperature(bottom_point) + : + adiabatic_surface_temperature; + + // then, get the temperature at the top and bottom boundary of the model + // if no boundary temperature is prescribed simply use the adiabatic. + // This implementation assumes that the top and bottom boundaries have + // prescribed temperatures and minimal_temperature() returns the value + // at the surface and maximal_temperature() the value at the bottom. + const double T_surface = (this->has_boundary_temperature() + ? + this->get_boundary_temperature_manager().minimal_temperature( + this->get_fixed_temperature_boundary_indicators()) + : + adiabatic_surface_temperature); + const double T_bottom = (this->has_boundary_temperature() + ? + this->get_boundary_temperature_manager().maximal_temperature( + this->get_fixed_temperature_boundary_indicators()) + : + adiabatic_bottom_temperature); + const double depth = this->get_geometry_model().depth(position); + + // look up material properties + MaterialModel::MaterialModelInputs in(1, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(1, this->n_compositional_fields()); + + // compute the adiabat by referring to the Adiabatic conditions model + in.position[0] = position; + in.temperature[0] = this->get_adiabatic_conditions().temperature(position); + in.pressure[0] = this->get_adiabatic_conditions().pressure(position); + in.velocity[0] = Tensor<1,dim> (); + for (unsigned int c=0; cn_compositional_fields(); ++c) + in.composition[0][c] = function->value(Point<1>(depth),c); + in.requested_properties = MaterialModel::MaterialProperties::equation_of_state_properties | + MaterialModel::MaterialProperties::thermal_conductivity; + this->get_material_model().evaluate(in, out); + + const double kappa = ( (this->get_parameters().formulation_temperature_equation == + Parameters::Formulation::TemperatureEquation::reference_density_profile) + ? + out.thermal_conductivities[0] / + (this->get_adiabatic_conditions().density(in.position[0]) * out.specific_heat[0]) + : + out.thermal_conductivities[0] / (out.densities[0] * out.specific_heat[0]) + ); + + double surface_cooling_temperature = 0; + double bottom_heating_temperature = 0; + + if (cooling_model == "half-space cooling") + { + if (age_top > 0.0 || age_bottom > 0.0) + AssertThrow (kappa > 0.0, + ExcMessage ("The thermal diffusivity needs to be larger than zero " + "for computing thermal boundary layers with the half-space " + "cooling model.")); + + // analytical solution for the thermal boundary layer from half-space cooling model + surface_cooling_temperature = age_top > 0.0 ? + (T_surface - adiabatic_surface_temperature) * + erfc(this->get_geometry_model().depth(position) / + (2 * sqrt(kappa * age_top))) + : 0.0; + bottom_heating_temperature = (age_bottom > 0.0 && this->get_adiabatic_conditions().is_initialized()) ? + (T_bottom - adiabatic_bottom_temperature + subadiabaticity) + * erfc((this->get_geometry_model().maximal_depth() + - this->get_geometry_model().depth(position)) / + (2 * sqrt(kappa * age_bottom))) + : 0.0; + } + + if (cooling_model == "plate cooling") + { + if (depth > lithosphere_thickness) + { + surface_cooling_temperature = 0; + } + else + { + const double exponential = -kappa * std::pow(numbers::PI, 2) * age_top / std::pow(lithosphere_thickness, 2); + double sum_terms = 0.; + for (unsigned int n=1; n<11; ++n) + { + const auto dn = static_cast(n); + sum_terms += 1./dn * std::exp(dn * dn * exponential) * std::sin(dn * depth * numbers::PI / lithosphere_thickness); + surface_cooling_temperature = T_surface - adiabatic_surface_temperature + (adiabatic_surface_temperature - T_surface) * (depth / lithosphere_thickness + 2 / numbers::PI * sum_terms); + } + } + } + + // set the initial temperature perturbation + // first: get the center of the perturbation, then check the distance to the + // evaluation point. the center is supposed to lie at the center of the bottom + // surface. + Point mid_point; + if (perturbation_position == "center") + { + if (Plugins::plugin_type_matches>(this->get_geometry_model())) + { + const GeometryModel::SphericalShell &shell_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + const double inner_radius = shell_geometry_model.inner_radius(); + const double half_opening_angle = constants::degree_to_radians * 0.5 * shell_geometry_model.opening_angle(); + if (dim==2) + { + // choose the center of the perturbation at half angle along the inner radius + mid_point(0) = inner_radius * std::sin(half_opening_angle), + mid_point(1) = inner_radius * std::cos(half_opening_angle); + } + else if (dim==3) + { + // if the opening angle is 90 degrees (an eighth of a full spherical + // shell, then choose the point on the inner surface along the first + // diagonal + if (shell_geometry_model.opening_angle() == 90) + { + mid_point(0) = inner_radius*std::sqrt(1./3), + mid_point(1) = inner_radius*std::sqrt(1./3), + mid_point(2) = inner_radius*std::sqrt(1./3); + } + else + { + // otherwise do the same as in 2d + mid_point(0) = inner_radius * std::sin(half_opening_angle) * std::cos(half_opening_angle), + mid_point(1) = inner_radius * std::sin(half_opening_angle) * std::sin(half_opening_angle), + mid_point(2) = inner_radius * std::cos(half_opening_angle); + } + } + } + else if (Plugins::plugin_type_matches>(this->get_geometry_model())) + { + const GeometryModel::Chunk &chunk_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + const double inner_radius = chunk_geometry_model.inner_radius(); + + const double west_longitude = chunk_geometry_model.west_longitude(); // in radians + const double longitude_range = chunk_geometry_model.longitude_range(); // in radians + const double longitude_midpoint = west_longitude + 0.5 * longitude_range; + + if (dim==2) + { + // choose the center of the perturbation at half angle along the inner radius + mid_point(0) = inner_radius * std::cos(longitude_midpoint), + mid_point(1) = inner_radius * std::sin(longitude_midpoint); + } + else if (dim==3) + { + + const double south_latitude = chunk_geometry_model.south_latitude(); // in radians + const double latitude_range = chunk_geometry_model.latitude_range(); // in radians + const double latitude_midpoint = south_latitude + 0.5 * latitude_range; + mid_point(0) = inner_radius * std::cos(latitude_midpoint) * std::cos(longitude_midpoint); + mid_point(1) = inner_radius * std::cos(latitude_midpoint) * std::sin(longitude_midpoint); + mid_point(2) = inner_radius * std::sin(latitude_midpoint); + } + } + else if (Plugins::plugin_type_matches>(this->get_geometry_model())) + { + const GeometryModel::Box &box_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + // for the box geometry, choose a point at the center of the bottom face. + // (note that the loop only runs over the first dim-1 coordinates, leaving + // the depth variable at zero) + mid_point = box_geometry_model.get_origin(); + for (unsigned int i=0; i> (this->get_geometry_model())) + { + const GeometryModel::TwoMergedBoxes &two_merged_boxes_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + // for the box geometry, choose a point at the center of the bottom face. + // (note that the loop only runs over the first dim-1 coordinates, leaving + // the depth variable at zero) + mid_point = two_merged_boxes_geometry_model.get_origin(); + for (unsigned int i=0; iget_geometry_model().depth(position) / this->get_geometry_model().maximal_depth() - zero_depth) + / (1.0 - zero_depth); + double subadiabatic_T = 0.0; + if (nondimensional_depth > 0) + subadiabatic_T = -subadiabaticity * nondimensional_depth * nondimensional_depth; + + // If adiabatic heating is disabled, apply all perturbations to + // constant adiabatic surface temperature instead of adiabatic profile. + const double temperature_profile = (this->include_adiabatic_heating()) + ? + this->get_adiabatic_conditions().temperature(position) + : + adiabatic_surface_temperature; + + // return sum of the adiabatic profile, the boundary layer temperatures and the initial + // temperature perturbation. + return temperature_profile + surface_cooling_temperature + + (perturbation > 0.0 ? std::max(bottom_heating_temperature + subadiabatic_T,perturbation) + : bottom_heating_temperature + subadiabatic_T); + } + + template + void + Adiabatic::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + Utilities::AsciiDataBase::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/initial-temperature/adiabatic/", + "adiabatic.txt", + "Adiabatic"); + prm.enter_subsection("Adiabatic"); + { + prm.declare_entry ("Age top boundary layer", "0.", + Patterns::Double (0.), + "The age of the upper thermal boundary layer, used for the calculation " + "of the half-space cooling model temperature. Units: years if the " + "'Use years in output instead of seconds' parameter is set; " + "seconds otherwise."); + prm.declare_entry ("Age bottom boundary layer", "0.", + Patterns::Double (0.), + "The age of the lower thermal boundary layer, used for the calculation " + "of the half-space cooling model temperature. Units: years if the " + "'Use years in output instead of seconds' parameter is set; " + "seconds otherwise."); + prm.declare_entry ("Radius", "0.", + Patterns::Double (0.), + "The Radius (in m) of the initial spherical temperature perturbation " + "at the bottom of the model domain."); + prm.declare_entry ("Amplitude", "0.", + Patterns::Double (0.), + "The amplitude (in K) of the initial spherical temperature perturbation " + "at the bottom of the model domain. This perturbation will be added to " + "the adiabatic temperature profile, but not to the bottom thermal " + "boundary layer. Instead, the maximum of the perturbation and the bottom " + "boundary layer temperature will be used."); + prm.declare_entry ("Position", "center", + Patterns::Selection ("center"), + "Where the initial temperature perturbation should be placed. If `center' is " + "given, then the perturbation will be centered along a `midpoint' of some " + "sort of the bottom boundary. For example, in the case of a box geometry, " + "this is the center of the bottom face; in the case of a spherical shell " + "geometry, it is along the inner surface halfway between the bounding " + "radial lines."); + prm.declare_entry ("Subadiabaticity", "0.", + Patterns::Double (0.), + "If this value is larger than 0, the initial temperature profile will " + "not be adiabatic, but subadiabatic. This value gives the maximal " + "deviation from adiabaticity. Set to 0 for an adiabatic temperature " + "profile. Units: \\si{\\kelvin}.\n\n" + "The function object in the Function subsection " + "represents the compositional fields that will be used as a reference " + "profile for calculating the thermal diffusivity. " + "This function is one-dimensional and depends only on depth. The format of this " + "functions follows the syntax understood by the " + "muparser library, see {ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`."); + prm.declare_entry ("Top boundary layer age model", "constant", + Patterns::Selection ("constant|function|ascii data"), + "How to define the age of the top thermal boundary layer. " + "Options are: 'constant' for a constant age specified by the " + "parameter 'Age top boundary layer'; 'function' for an analytical " + "function describing the age as specified in the subsection " + "'Age function'; and 'ascii data' to use an 'ascii data' file " + "specified by the parameter 'Data file name'."); + prm.declare_entry ("Cooling model", "half-space cooling", + Patterns::Selection ("half-space cooling|plate cooling"), + "Whether to use the half space cooling model or the plate cooling model"); + prm.declare_entry ("Lithosphere thickness", "125e3", + Patterns::Double (0.), + "Thickness of the lithosphere for plate cooling model. \\si{\\m}"); + + prm.enter_subsection("Function"); + { + Functions::ParsedFunction<1>::declare_parameters (prm, 1); + } + prm.leave_subsection(); + + prm.enter_subsection("Age function"); + { + /** + * Choose the coordinates to evaluate the age + * function. The function can be declared in dependence of depth, + * cartesian coordinates or spherical coordinates. Note that the order + * of spherical coordinates is r,phi,theta and not r,theta,phi, since + * this allows for dimension independent expressions. + */ + prm.declare_entry ("Coordinate system", "cartesian", + Patterns::Selection ("cartesian|spherical"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `cartesian', `spherical', and `depth'. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle. `depth' " + "will create a function, in which only the first " + "parameter is non-zero, which is interpreted to " + "be the depth of the point."); + + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + Adiabatic::parse_parameters (ParameterHandler &prm) + { + // we need to get the number of compositional fields here to + // initialize the function parser. unfortunately, we can't get it + // via SimulatorAccess from the simulator itself because at the + // current point the SimulatorAccess hasn't been initialized + // yet. so get it from the parameter file directly. + prm.enter_subsection ("Compositional fields"); + const unsigned int n_compositional_fields = prm.get_integer ("Number of fields"); + prm.leave_subsection (); + + prm.enter_subsection ("Initial temperature model"); + { + Utilities::AsciiDataBase::parse_parameters(prm, "Adiabatic"); + + prm.enter_subsection("Adiabatic"); + { + top_boundary_layer_age_model = BoundaryLayerAgeModel::parse("Top boundary layer age model", + prm); + + age_top_boundary_layer = prm.get_double ("Age top boundary layer"); + age_bottom_boundary_layer = prm.get_double ("Age bottom boundary layer"); + + radius = prm.get_double ("Radius"); + amplitude = prm.get_double ("Amplitude"); + perturbation_position = prm.get("Position"); + + subadiabaticity = prm.get_double ("Subadiabaticity"); + + cooling_model = prm.get ("Cooling model"); + lithosphere_thickness = prm.get_double ("Lithosphere thickness"); + + if (n_compositional_fields > 0) + { + prm.enter_subsection("Function"); + try + { + function + = std::make_unique>(n_compositional_fields); + function->parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Initial temperature model.Adiabatic.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + + prm.leave_subsection(); + } + + prm.enter_subsection("Age function"); + { + coordinate_system = Utilities::Coordinates::string_to_coordinate_system(prm.get("Coordinate system")); + } + try + { + age_function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Initial temperature model.Adiabatic.Age Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + + prm.leave_subsection(); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(Adiabatic, + "adiabatic", + "Temperature is prescribed as an adiabatic " + "profile with upper and lower thermal boundary layers, " + "whose ages are given as input parameters. " + "Note that this plugin uses the 'Adiabatic conditions model' " + "to compute the adiabat. Thus, the results depend on variables " + "defined outside of this specific subsection; " + "e.g. the globally defined 'Adiabatic surface temperature', " + "and the variables defined in the 'Material model' section " + "including densities, heat capacities and thermal expansivities.") + } +} diff --git a/source/initial_temperature/adiabatic_boundary.cc.bak b/source/initial_temperature/adiabatic_boundary.cc.bak new file mode 100644 index 00000000000..c9c5e2f17c8 --- /dev/null +++ b/source/initial_temperature/adiabatic_boundary.cc.bak @@ -0,0 +1,136 @@ +/* + Copyright (C) 2016 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + +namespace aspect +{ + namespace InitialTemperature + { + template + AdiabaticBoundary::AdiabaticBoundary () + : + surface_boundary_id(numbers::invalid_unsigned_int) + {} + + template + void + AdiabaticBoundary::initialize () + { + // Find the boundary indicator that represents the surface + surface_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + std::set surface_boundary_set; + surface_boundary_set.insert(surface_boundary_id); + + // The input ascii table contains one data column (LAB depths(m)) in addition to the coordinate columns. + Utilities::AsciiDataBoundary::initialize(surface_boundary_set, + 1); + } + + template + double + AdiabaticBoundary::initial_temperature (const Point &position) const + { + const double depth = this->get_geometry_model().depth(position); + const double isotherm_depth = + Utilities::AsciiDataBoundary::get_data_component(surface_boundary_id, position, 0); + if (depth > isotherm_depth) + return isotherm_temperature + (depth - isotherm_depth) * temperature_gradient; + else + return surface_temperature + (depth/isotherm_depth) * (isotherm_temperature - surface_temperature); + } + + template + void + AdiabaticBoundary::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + Utilities::AsciiDataBase::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/initial-temperature/adiabatic-boundary/", + "adiabatic_boundary.txt", + "Adiabatic boundary"); + prm.enter_subsection("Adiabatic boundary"); + { + prm.declare_entry ("Isotherm temperature", "1673.15", + Patterns::Double (0.), + "The value of the isothermal boundary temperature. Units: \\si{\\kelvin}."); + prm.declare_entry ("Surface temperature", "273.15", + Patterns::Double (0.), + "The value of the surface temperature. Units: \\si{\\kelvin}."); + prm.declare_entry ("Adiabatic temperature gradient", "0.0005", + Patterns::Double (0.), + "The value of the adiabatic temperature gradient. " + "Units: \\si{\\kelvin\\per\\meter}."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + AdiabaticBoundary::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + Utilities::AsciiDataBase::parse_parameters(prm,"Adiabatic boundary"); + + prm.enter_subsection("Adiabatic boundary"); + { + isotherm_temperature = prm.get_double("Isotherm temperature"); + surface_temperature = prm.get_double("Surface temperature"); + temperature_gradient = prm.get_double("Adiabatic temperature gradient"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(AdiabaticBoundary, + "adiabatic boundary", + "An initial temperature condition that allows for discretizing " + "the model domain into two layers separated by a user-defined " + "isothermal boundary. The user includes an input ascii data file " + "that is formatted as 3 columns of `longitude(radians)', " + "`colatitude(radians)', and `isotherm depth(meters)', where `isotherm depth' represents the depth " + "of an initial temperature of 1673.15 K (by default). " + "The first lines in the data file may contain any number of comments if they begin " + "with `#', but one of these lines needs to contain the number of grid points " + "in each dimension as for example `# POINTS: 69 121'. Note that the coordinates need " + "to be sorted in a specific order: the `longitude' coordinate needs to ascend first, " + "followed by the `colatitude' coordinate in order to assign the correct data (isotherm depth) to the " + "prescribed coordinates. " + "The temperature is defined from the surface (273.15 K) to the isotherm depth (1673.15 K) " + "as a linear gradient. Below the isotherm depth the temperature increases " + "approximately adiabatically (0.0005 K per meter). " + "This plugin should work for all geometry models, but is currently only tested for spherical models.") + } +} diff --git a/source/initial_temperature/ascii_data.cc.bak b/source/initial_temperature/ascii_data.cc.bak new file mode 100644 index 00000000000..3af027f8b17 --- /dev/null +++ b/source/initial_temperature/ascii_data.cc.bak @@ -0,0 +1,112 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include + +namespace aspect +{ + namespace InitialTemperature + { + template + AsciiData::AsciiData () + = default; + + + template + void + AsciiData::initialize () + { + Utilities::AsciiDataInitial::initialize(1); + } + + + template + double + AsciiData:: + initial_temperature (const Point &position) const + { + return Utilities::AsciiDataInitial::get_data_component(position,0); + } + + + template + void + AsciiData::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + Utilities::AsciiDataInitial::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/initial-temperature/ascii-data/test/", + "box_2d.txt"); + } + prm.leave_subsection(); + } + + + template + void + AsciiData::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + Utilities::AsciiDataInitial::parse_parameters(prm); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(AsciiData, + "ascii data", + "Implementation of a model in which the initial " + "temperature is derived from files containing data " + "in ascii format. Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example `# POINTS: 3 3'. " + "The order of the data columns " + "has to be `x', `y', `Temperature [K]' in a 2d model and " + " `x', `y', `z', `Temperature [K]' in a 3d model, which means that " + "there has to be a single column " + "containing the temperature. " + "Note that the data in the input " + "files need to be sorted in a specific order: " + "the first coordinate needs to ascend first, " + "followed by the second and the third at last in order to " + "assign the correct data to the prescribed coordinates. " + "If you use a spherical model, " + "then the assumed grid changes. `x' will be replaced by " + "the radial distance of the point to the bottom of the model, " + "`y' by the azimuth angle and `z' by the polar angle measured " + "positive from the north pole. The grid will be assumed to be " + "a latitude-longitude grid. Note that the order " + "of spherical coordinates is `r', `phi', `theta' " + "and not `r', `theta', `phi', since this allows " + "for dimension independent expressions.") + } +} diff --git a/source/initial_temperature/ascii_data_layered.cc.bak b/source/initial_temperature/ascii_data_layered.cc.bak new file mode 100644 index 00000000000..10d687f8821 --- /dev/null +++ b/source/initial_temperature/ascii_data_layered.cc.bak @@ -0,0 +1,124 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include + +namespace aspect +{ + namespace InitialTemperature + { + template + AsciiDataLayered::AsciiDataLayered () + = default; + + + template + void + AsciiDataLayered::initialize () + { + // The ascii data layered class has dim-1 spatial columns + // (which provide the horizontal coordinates of the layer). + // We need another 2 columns; the first for the depth + // of the layer at the given horizontal coordinates, + // and the second for temperature (for cases where + // temperature varies across the layer). + Utilities::AsciiDataLayered::initialize(2); + } + + + template + double + AsciiDataLayered:: + initial_temperature (const Point &position) const + { + // This is where we get the initial temperature + return Utilities::AsciiDataLayered::get_data_component(position,1); + } + + + template + void + AsciiDataLayered::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + Utilities::AsciiDataLayered::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/initial-temperature/ascii-data/test/", + "initial_isotherm_500K_box_3d.txt"); + } + prm.leave_subsection(); + } + + + template + void + AsciiDataLayered::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + Utilities::AsciiDataLayered::parse_parameters(prm); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(AsciiDataLayered, + "ascii data layered", + "Implementation of a model in which the initial " + "temperature is derived from files containing data " + "in ascii format. Each file defines a surface on which " + "temperature is defined. " + "Between the surfaces, the temperatures can be chosen to be " + "constant (with a value defined by the nearest shallower " + "surface), or linearly interpolated between surfaces. " + "Note the required format of the input ascii data file: " + "The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example `# POINTS: 3 3'. " + "The order of the data columns " + "has to be `x', `y', `Temperature [K]' in a 2d model and " + "`x', `y', `z', `Temperature [K]' in a 3d model; i.e. " + "the last two columns always contain the position of the " + "isotherm along the vertical direction, and the temperature " + "at that point. The first column needs to ascend first, " + "followed by the second in order to assign the correct data " + "to the prescribed coordinates. If you use a spherical model, " + "then the assumed grid changes. `x' will be replaced by the " + "azimuth angle and `y' (if 3d) by the polar angle measured " + "positive from the north pole. The last column will be the " + "distance of the point from the origin " + "(i.e. radial position). The grid in this case will be " + "a latitude-longitude grid. Note that the order " + "of spherical coordinates in 3d is `phi', `theta', `r', `T'" + "and not `theta', `phi', `r', `T' as this is " + "more consistent with other ASPECT plugins. Outside of the " + "region defined by the grid, the plugin will use the value " + "at the edge of the region.") + } +} diff --git a/source/initial_temperature/ascii_profile.cc.bak b/source/initial_temperature/ascii_profile.cc.bak new file mode 100644 index 00000000000..49091c317c4 --- /dev/null +++ b/source/initial_temperature/ascii_profile.cc.bak @@ -0,0 +1,112 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include +#include + + +namespace aspect +{ + namespace InitialTemperature + { + template + AsciiProfile::AsciiProfile () + = default; + + + template + void + AsciiProfile::initialize () + { + this->initialize(this->get_mpi_communicator()); + temperature_index = this->get_column_index_from_name("temperature"); + } + + + + template + double AsciiProfile::initial_temperature (const Point &p) const + { + const double depth = this->get_geometry_model().depth(p); + return this->get_data_component(Point<1>(depth),temperature_index); + } + + + template + void + AsciiProfile::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + Utilities::AsciiDataBase::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/initial-temperature/ascii-profile/tests/", + "simple_test.txt", + "Ascii profile"); + } + prm.leave_subsection(); + } + + + template + void + AsciiProfile::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + Utilities::AsciiDataBase::parse_parameters(prm, + "Ascii profile"); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(AsciiProfile, + "ascii profile", + "Implementation of a model in which the initial temperature is " + "read from a file that provides these values as a function of " + "depth. Note the required format of the input data: The first " + "lines may contain any number of comments if they begin with " + "`#', but one of these lines needs to contain the number of " + "points in the temperature profile, for example `# POINTS: 10'. " + "Following the comment lines, there has to be a single line " + "containing the names of all data columns, separated by arbitrarily " + "many spaces. Column names are not allowed to contain spaces. " + "The file can contain unnecessary columns, but for this plugin it " + "needs to at least provide columns named `depth' and" + "`temperature'." + "Note that the data lines in the file need to be sorted in order " + "of increasing depth from 0 to the maximal depth in the model " + "domain. Points in the model that are outside of the provided " + "depth range will be assigned the maximum or minimum depth values, " + "respectively. Points do not need to be equidistant, " + "but the computation of properties is optimized in speed " + "if they are.") + } +} diff --git a/source/initial_temperature/box.cc.bak b/source/initial_temperature/box.cc.bak new file mode 100644 index 00000000000..bdf58376da9 --- /dev/null +++ b/source/initial_temperature/box.cc.bak @@ -0,0 +1,276 @@ +/* + Copyright (C) 2011 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + + +namespace aspect +{ + namespace InitialTemperature + { + template + double + PerturbedBox:: + initial_temperature (const Point &position) const + { + // this initial condition only makes sense if the geometry is a + // Box. verify that it is indeed + AssertThrow (Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage ("This initial condition can only be used if the geometry " + "is a box.")); + + const GeometryModel::Box &geometry + = Plugins::get_plugin_as_type> (this->get_geometry_model()); + + double perturbation = 1; + for (unsigned int d=0; d + double + PolarBox:: + initial_temperature (const Point &position) const + { + // this initial condition only makes sense if the geometry is a + // Box. verify that it is indeed + AssertThrow (Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage ("This initial condition can only be used if the geometry " + "is a box.")); + + const GeometryModel::Box &geometry + = Plugins::get_plugin_as_type> (this->get_geometry_model()); + + Point temporary1, temporary2; + for (int d=0; d + double + MandelBox:: + initial_temperature (const Point &position) const + { + // this initial condition only makes sense if the geometry is a + // box. verify that it is indeed + AssertThrow (Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage ("This initial condition can only be used if the geometry " + "is a box.")); + + const GeometryModel::Box &geometry + = Plugins::get_plugin_as_type> (this->get_geometry_model()); + + double perturbation, ratio; + Point center; + ratio = center[0] = geometry.get_extents()[0]*0.66; + center[1] = geometry.get_extents()[1]*0.5; + if (center[1] < ratio) + ratio = center[1]; + + double zx = (position[0] - geometry.get_origin()[0] - center[0])/ratio; + double zy = (position[1] - geometry.get_origin()[1] - center[1])/ratio; + double x = zx; + double y = zy; + + for (perturbation = 0; perturbation < 50 && (Point<2>(x,y)).norm() <= 2; ++perturbation) + { + x = x*x - y*y + zx; + y = 2 * x*y + zy; + } + return perturbation / 50; + } + + + + template + double + InclusionShapeBox:: + initial_temperature (const Point &position) const + { + // this initial condition only makes sense if the geometry is a + // box. verify that it is indeed + AssertThrow (Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage ("This initial condition can only be used if the geometry " + "is a box.")); + + double perturbation = 0; + Point center; + for (int d=0; d(center_x,center_y,center_z))[d]; + + if (inclusion_shape == "square") + { + if (inclusion_gradient == "gaussian") + { + perturbation = inclusion_temperature - ambient_temperature; + for (int d=0; d= -y) + perturbation = radius - y; + else if (x <= y && x <= -y) + perturbation = radius + x; + else if (x >= y && x >= -y) + perturbation = radius - x; + else if (x >= y && x <= -y) + perturbation = radius + y; + perturbation *= (inclusion_temperature - ambient_temperature) / radius; + } + else if (inclusion_gradient == "constant") + { + perturbation = inclusion_temperature - ambient_temperature; + } + for (int d = 0; d < dim; ++d) + if (abs (center[d] - position[d]) > radius) + perturbation = 0; + } + else if (inclusion_shape == "circle") + { + if (inclusion_gradient == "gaussian") + { + perturbation = inclusion_temperature - ambient_temperature; + perturbation *= exp(-pow(position.distance(center),2) / (2 * pow((radius / 4), 2))) / (2 * radius); + } + else if (inclusion_gradient == "linear") + { + perturbation = ((radius - position.distance(center)) / radius) * (inclusion_temperature - ambient_temperature); + } + else if (inclusion_gradient == "constant") + { + perturbation = inclusion_temperature - ambient_temperature; + } + if (position.distance(center) > radius) + perturbation = 0; + } + + return ambient_temperature + perturbation; + } + + template + void + InclusionShapeBox::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection ("Inclusion shape perturbation"); + { + prm.declare_entry("Inclusion shape", "circle", + Patterns::Selection("square|circle"), + "The shape of the inclusion to be generated."); + prm.declare_entry("Inclusion gradient", "constant", + Patterns::Selection("gaussian|linear|constant"), + "The gradient of the inclusion to be generated."); + prm.declare_entry("Shape radius", "1.0", + Patterns::Double (0.), + "The radius of the inclusion to be generated. For " + "shapes with no radius (e.g. square), this will " + "be the width, and for shapes with no width, this " + "gives a general guideline for the size of the shape."); + prm.declare_entry("Ambient temperature", "1.0", + Patterns::Double (), + "The background temperature for the temperature field."); + prm.declare_entry("Inclusion temperature", "0.0", + Patterns::Double (), + "The temperature of the inclusion shape. This is only " + "the true temperature in the case of the constant " + "gradient. In all other cases, it gives one endpoint " + "of the temperature gradient for the shape."); + prm.declare_entry("Center X", "0.5", + Patterns::Double (), + "The X coordinate for the center of the shape."); + prm.declare_entry("Center Y", "0.5", + Patterns::Double (), + "The Y coordinate for the center of the shape."); + prm.declare_entry("Center Z", "0.5", + Patterns::Double (), + "The Z coordinate for the center of the shape. This " + "is only necessary for three-dimensional fields."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + template + void + InclusionShapeBox::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Inclusion shape perturbation"); + { + inclusion_shape = prm.get ("Inclusion shape"); + inclusion_gradient = prm.get ("Inclusion gradient"); + radius = prm.get_double ("Shape radius"); + ambient_temperature = prm.get_double ("Ambient temperature"); + inclusion_temperature = prm.get_double ("Inclusion temperature"); + center_x = prm.get_double ("Center X"); + center_y = prm.get_double ("Center Y"); + center_z = prm.get_double ("Center Z"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(PerturbedBox, + "perturbed box", + "An initial temperature field in which the temperature " + "is perturbed slightly from an otherwise constant value " + "equal to one. The perturbation is chosen in such a way " + "that the initial temperature is constant to one along " + "the entire boundary.") + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(PolarBox, + "polar box", + "An initial temperature field in which the temperature " + "is perturbed slightly from an otherwise constant value " + "equal to one. The perturbation is such that there are " + "two poles on opposing corners of the box. ") + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(InclusionShapeBox, + "inclusion shape perturbation", + "An initial temperature field in which there is an " + "inclusion in a constant-temperature box field. The size, " + "shape, gradient, position, and temperature of the " + "inclusion are defined by parameters.") + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(MandelBox, + "mandelbox", + "Fractal-shaped temperature field.") + } +} diff --git a/source/initial_temperature/continental_geotherm.cc.bak b/source/initial_temperature/continental_geotherm.cc.bak new file mode 100644 index 00000000000..59c5b4bf941 --- /dev/null +++ b/source/initial_temperature/continental_geotherm.cc.bak @@ -0,0 +1,269 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace InitialTemperature + { + template + ContinentalGeotherm::ContinentalGeotherm () + = default; + + + template + void + ContinentalGeotherm:: + initialize () + { + // Check that the required radioactive heating model ("compositional heating") is used + const std::vector &heating_models = this->get_heating_model_manager().get_active_heating_model_names(); + AssertThrow(std::find(heating_models.begin(), heating_models.end(), "compositional heating") != heating_models.end(), + ExcMessage("The continental geotherm initial temperature plugin requires the compositional heating plugin.")); + + // Check that the required material model ("visco plastic") is used + AssertThrow(Plugins::plugin_type_matches>(this->get_material_model()), + ExcMessage("The continental geotherm initial temperature plugin requires the viscoplastic material model plugin.")); + } + + + template + double + ContinentalGeotherm:: + initial_temperature (const Point &position) const + { + // Get the depth of the point with respect to the reference surface. + const double depth = this->get_geometry_model().depth(position); + + // Compute some constants to calculate the temperatures T1 and T2 at the interfaces + // between the layers upper crust/lower crust (depth y=h1) and lower crust/lithospheric mantle (depth y=h1+h2). + // T1 = (ab + k2/h2 cdb) / (1 - k2^2/h2^2 db) + // T2 = (c + k2/h2 T1) d + // These derivations are based on the assumption that at the boundary between + // the layers, the heat flows of the two layers are equal, so + // at y=h1, q1(h1)=q2(h2)=k1 dT1/dy|h1 = k2 dT2/dy|h2 etc. + const double a = 0.5*densities[0]*heat_productivities[0]*thicknesses[0] + 0.5*densities[1]*heat_productivities[1]*thicknesses[1] + conductivities[0]/thicknesses[0]*T0; + const double b = 1./(conductivities[0]/thicknesses[0]+conductivities[1]/thicknesses[1]); + const double c = 0.5*densities[1]*heat_productivities[1]*thicknesses[1] + conductivities[2]/thicknesses[2]*LAB_isotherm; + const double d = 1./(conductivities[1]/thicknesses[1]+conductivities[2]/thicknesses[2]); + + // Temperature at boundary between layer 1 and 2 + const double T1 = (a*b + conductivities[1]/thicknesses[1]*c*d*b) / (1.-(conductivities[1]*conductivities[1])/(thicknesses[1]*thicknesses[1])*d*b); + // Temperature at boundary between layer 2 and 3 + const double T2 = (c + conductivities[1]/thicknesses[1]*T1) * d; + + // Temperature in layer 1 + if (depth <= thicknesses[0]) + return -0.5*densities[0]*heat_productivities[0]/conductivities[0]*std::pow(depth,2) + (0.5*densities[0]*heat_productivities[0]*thicknesses[0]/conductivities[0] + (T1-T0)/thicknesses[0])*depth + T0; + // Temperature in layer 2 + else if (depth <= thicknesses[0]+thicknesses[1]) + return -0.5*densities[1]*heat_productivities[1]/conductivities[1]*std::pow(depth-thicknesses[0],2.) + (0.5*densities[1]*heat_productivities[1]*thicknesses[1]/conductivities[1] + (T2-T1)/thicknesses[1])*(depth-thicknesses[0]) + T1; + // Temperature in layer 3 + else if (depth <= thicknesses[0]+thicknesses[1]+thicknesses[2]) + return (LAB_isotherm-T2)/thicknesses[2] *(depth-thicknesses[0]-thicknesses[1]) + T2; + // Return an unrealistically high temperature if we're below the lithosphere. + // This way we can combine the continental geotherm with an adiabatic profile from the input file + // using the "minimum" operator on the "List of initial temperature models" + else + return std::numeric_limits::max(); + } + + + + template + void + ContinentalGeotherm::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Continental geotherm"); + { + prm.declare_entry ("Layer thicknesses", "30000.", + Patterns::List(Patterns::Double(0.)), + "List of the 3 thicknesses of the lithospheric layers " + "'upper\\_crust', 'lower\\_crust' and 'mantle\\_lithosphere'. " + "If only one thickness is given, then the same thickness is used " + "for all layers. Units: \\si{meter}."); + prm.declare_entry ("Surface temperature", "273.15", + Patterns::Double (0.), + "The value of the surface temperature. Units: \\si{\\kelvin}."); + prm.declare_entry ("Lithosphere-Asthenosphere boundary isotherm", "1673.15", + Patterns::Double (0.), + "The value of the isotherm that is assumed at the Lithosphere-" + "Asthenosphere boundary. Units: \\si{\\kelvin}."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + ContinentalGeotherm::parse_parameters (ParameterHandler &prm) + { + unsigned int n_fields = 0; + prm.enter_subsection ("Compositional fields"); + { + n_fields = prm.get_integer ("Number of fields"); + } + prm.leave_subsection(); + + + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Continental geotherm"); + { + LAB_isotherm = prm.get_double ("Lithosphere-Asthenosphere boundary isotherm"); + T0 = prm.get_double ("Surface temperature"); + thicknesses = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Layer thicknesses"))), + 3, + "Layer thicknesses"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + + // Retrieve the indices of the fields that represent the lithospheric layers. + AssertThrow(this->introspection().compositional_name_exists("upper_crust"),ExcMessage("We need a compositional field called 'upper_crust' representing the upper crust.")); + AssertThrow(this->introspection().compositional_name_exists("lower_crust"),ExcMessage("We need a compositional field called 'lower_crust' representing the lower crust.")); + AssertThrow(this->introspection().compositional_name_exists("lithospheric_mantle"),ExcMessage("We need a compositional field called 'lithospheric_mantle' representing the lithospheric part of the mantle.")); + + // For now, we assume a 3-layer system with an upper crust, lower crust and lithospheric mantle + const unsigned int id_upper_crust = this->introspection().compositional_index_for_name("upper_crust"); + const unsigned int id_lower_crust = this->introspection().compositional_index_for_name("lower_crust"); + const unsigned int id_lithospheric_mantle = this->introspection().compositional_index_for_name("lithospheric_mantle"); + + // Retrieve other material properties set in different sections such that there + // is no need to set them twice. + + prm.enter_subsection("Heating model"); + { + prm.enter_subsection("Compositional heating"); + { + // The heating model compositional heating prefixes an entry for the background material + const std::vector temp_heat_productivities = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Compositional heating values"))), + n_fields+1, + "Compositional heating values"); + // This sets the heat productivity in W/m3 units + heat_productivities.push_back(temp_heat_productivities[id_upper_crust+1]); + heat_productivities.push_back(temp_heat_productivities[id_lower_crust+1]); + heat_productivities.push_back(temp_heat_productivities[id_lithospheric_mantle+1]); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Visco Plastic"); + { + // The material model viscoplastic prefixes an entry for the background material, hence n_fields+1 + const std::vector temp_densities = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Densities"))), + n_fields+1, + "Densities"); + const std::vector temp_thermal_diffusivities = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Thermal diffusivities"))), + n_fields+1, + "Thermal diffusivities"); + const std::vector temp_heat_capacities = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Heat capacities"))), + n_fields+1, + "Heat capacities"); + + // The material model viscoplastic prefixes an entry for the background material, hence id+1 + densities.push_back(temp_densities[id_upper_crust+1]); + densities.push_back(temp_densities[id_lower_crust+1]); + densities.push_back(temp_densities[id_lithospheric_mantle+1]); + + // Thermal diffusivity kappa = k/(rho*cp), so thermal conductivity k = kappa*rho*cp. + // The densities are already in the right order, so we don't need to use the compositional + // field ids. + conductivities.push_back(temp_thermal_diffusivities[id_upper_crust+1] * densities[0] * temp_heat_capacities[id_upper_crust+1]); + conductivities.push_back(temp_thermal_diffusivities[id_lower_crust+1] * densities[1] * temp_heat_capacities[id_lower_crust+1]); + conductivities.push_back(temp_thermal_diffusivities[id_lithospheric_mantle+1] * densities[2] * temp_heat_capacities[id_lithospheric_mantle+1]); + + // To obtain the radioactive heating rate in W/kg, we divide the volumetric heating rate by density + AssertThrow(heat_productivities.size() == 3 && densities.size() == 3 && conductivities.size() == 3, + ExcMessage("The entries for density, conductivity and heat production do not match with the expected number of layers (3).")); + + for (unsigned int i = 0; i<3; ++i) + heat_productivities[i] /= densities[i]; + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + + +} + + + + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(ContinentalGeotherm, + "continental geotherm", + "This is a temperature initial condition that " + "computes a continental geotherm based on the solution of the " + "steady-state conductive equation $k\\frac{d^2 T}{dy^2}+\\rho H = 0$ " + "as described in e.g. Turcotte and Schubert, " + "Ch. 4.6, or Chapman (1986). As boundary conditions, we take the surface temperature and " + "the temperature of the Lithosphere-Asthenosphere Boundary (LAB). " + "\n" + "The geotherm is computed for a homogeneous lithosphere " + "composed of an upper crust, lower crust and mantle layer. " + "The crustal layers are assumed to have a constant radioactive heating, " + "and all layers are assumed to have a constant thermal conductivity. " + "Layer thicknesses, surface temperature and LAB temperature " + "should be specified by the user. " + "For consistency, the density, heat production and thermal " + "conductivity of each layer are read from the visco plastic material model " + "and the compositional heating model. " + "\n" + "For any depths below the depth of the LAB, a unrealistically high " + "temperature is returned, such that this plugin can be combined with " + "another temperature plugin through the 'minimum' operator. " + "\n" + "Note that the current implementation only works for a 3-layer lithosphere, " + "even though in principle the heat conduction equation can be solved " + "for any number of layers. The naming of the compositional fields " + "that represent the layers is also very specific, namely `upper\\_crust', " + "`lower\\_crust', and `lithospheric\\_mantle'. " + "\n" + "Make sure the top and bottom temperatures of the lithosphere " + "agree with temperatures set in for example the temperature " + "boundary conditions.") + } +} diff --git a/source/initial_temperature/function.cc.bak b/source/initial_temperature/function.cc.bak new file mode 100644 index 00000000000..a02205ca056 --- /dev/null +++ b/source/initial_temperature/function.cc.bak @@ -0,0 +1,129 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace InitialTemperature + { + template + Function::Function () + : + function (1) + {} + + template + double + Function:: + initial_temperature (const Point &position) const + { + const Utilities::NaturalCoordinate point = + this->get_geometry_model().cartesian_to_other_coordinates(position, coordinate_system); + + return function.value(Utilities::convert_array_to_point(point.get_coordinates())); + } + + template + void + Function::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Function"); + { + /** + * Choose the coordinates to evaluate the maximum refinement level + * function. The function can be declared in dependence of depth, + * cartesian coordinates or spherical coordinates. Note that the order + * of spherical coordinates is r,phi,theta and not r,theta,phi, since + * this allows for dimension independent expressions. + */ + prm.declare_entry ("Coordinate system", "cartesian", + Patterns::Selection ("cartesian|spherical|depth"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `cartesian', `spherical', and `depth'. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle. `depth' " + "will create a function, in which only the first " + "parameter is non-zero, which is interpreted to " + "be the depth of the point."); + + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + Function::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Function"); + { + coordinate_system = Utilities::Coordinates::string_to_coordinate_system(prm.get("Coordinate system")); + } + + try + { + function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Initial temperature model.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(Function, + "function", + "Specify the initial temperature in terms of an " + "explicit formula. The format of these " + "functions follows the syntax understood by the " + "muparser library, see {ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") + } +} diff --git a/source/initial_temperature/harmonic_perturbation.cc.bak b/source/initial_temperature/harmonic_perturbation.cc.bak new file mode 100644 index 00000000000..ee78cf82bfe --- /dev/null +++ b/source/initial_temperature/harmonic_perturbation.cc.bak @@ -0,0 +1,234 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include +#include + + +namespace aspect +{ + namespace InitialTemperature + { + template + double + HarmonicPerturbation:: + initial_temperature (const Point &position) const + { + + // use either the user-input reference temperature as background temperature + // (incompressible model) or the adiabatic temperature profile (compressible model) + const double background_temperature = this->include_adiabatic_heating() ? + this->get_adiabatic_conditions().temperature(position) : + reference_temperature; + + // s = fraction of the way from + // the inner to the outer + // boundary; 0<=s<=1 + const double s = this->get_geometry_model().depth(position) / this->get_geometry_model().maximal_depth(); + + const double depth_perturbation = std::sin(vertical_wave_number*s*numbers::PI); + + + double lateral_perturbation = 0.0; + + if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + const GeometryModel::SphericalShell &spherical_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + // In case of spherical shell calculate spherical coordinates + const std::array scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(position); + + if (dim==2) + { + // Use a sine as lateral perturbation that is scaled to the opening angle of the geometry. + // This way the perturbation is always 0 at the model boundaries. + const double opening_angle = spherical_geometry_model.opening_angle() * constants::degree_to_radians; + lateral_perturbation = std::sin(lateral_wave_number_1*scoord[1]*numbers::PI/opening_angle); + } + + else if (dim==3) + { + // Spherical harmonics are only defined for order <= degree + // and degree >= 0. Verify that it is indeed. + Assert ( std::abs(lateral_wave_number_2) <= lateral_wave_number_1, + ExcMessage ("Spherical harmonics can only be computed for " + "order <= degree.")); + Assert ( lateral_wave_number_1 >= 0, + ExcMessage ("Spherical harmonics can only be computed for " + "degree >= 0.")); + // use a spherical harmonic function as lateral perturbation + std::pair sph_harm_vals = Utilities::real_spherical_harmonic( lateral_wave_number_1, lateral_wave_number_2, scoord[2], scoord[1] ); + // For historical reasons, this initial conditions module used an unnormalized real spherical harmonic. + // Here we denormalize the return value of real_spherical_harmonic to keep the original behavior. + lateral_perturbation = sph_harm_vals.first / ( lateral_wave_number_2 == 0 ? 1.0 : std::sqrt(2.) ); + } + } + else if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + const GeometryModel::Chunk &chunk_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + AssertThrow (dim == 2, + ExcMessage ("Harmonic perturbation only implemented in 2d for chunk geometry")); + + // In case of chunk calculate spherical coordinates + const std::array scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(position); + + // Use a sine as lateral perturbation that is scaled to the opening angle of the geometry. + // This way the perturbation is always 0 at the model boundaries. + const double opening_angle = chunk_geometry_model.longitude_range(); // in radians + const double start_angle = chunk_geometry_model.west_longitude(); // in radians + lateral_perturbation = std::sin((lateral_wave_number_1*(scoord[1]-start_angle))*numbers::PI/opening_angle); + + } + else if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + const GeometryModel::Box &box_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + // In case of Box model use a sine as lateral perturbation + // that is scaled to the extent of the geometry. + // This way the perturbation is always 0 at the model borders. + const Point extent = box_geometry_model.get_extents(); + + if (dim==2) + { + lateral_perturbation = std::sin(lateral_wave_number_1*position(0)*numbers::PI/extent(0)); + } + else if (dim==3) + { + lateral_perturbation = std::sin(lateral_wave_number_1*position(0)*numbers::PI/extent(0)) + * std::sin(lateral_wave_number_2*position(1)*numbers::PI/extent(1)); + } + } + else if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + const GeometryModel::TwoMergedBoxes &two_merged_boxes_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + // In case of Box model use a sine as lateral perturbation + // that is scaled to the extent of the geometry. + // This way the perturbation is always 0 at the model borders. + const Point extent = two_merged_boxes_geometry_model.get_extents(); + + if (dim==2) + { + lateral_perturbation = std::sin(lateral_wave_number_1*position(0)*numbers::PI/extent(0)); + } + else if (dim==3) + { + lateral_perturbation = std::sin(lateral_wave_number_1*position(0)*numbers::PI/extent(0)) + * std::sin(lateral_wave_number_2*position(1)*numbers::PI/extent(1)); + } + } + else + AssertThrow (false, + ExcMessage ("Not a valid geometry model for the initial conditions model " + "harmonic perturbation.")); + + return background_temperature + magnitude * depth_perturbation * lateral_perturbation; + } + + template + void + HarmonicPerturbation::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Harmonic perturbation"); + { + prm.declare_entry ("Vertical wave number", "1", + Patterns::Integer (), + "Doubled radial wave number of the harmonic perturbation. " + " One equals half of a sine period over the model domain. " + " This allows for single up-/downswings. Negative numbers " + " reverse the sign of the perturbation."); + prm.declare_entry ("Lateral wave number one", "3", + Patterns::Integer (), + "Doubled first lateral wave number of the harmonic perturbation. " + "Equals the spherical harmonic degree in 3d spherical shells. " + "In all other cases one equals half of a sine period over " + "the model domain. This allows for single up-/downswings. " + "Negative numbers reverse the sign of the perturbation but are " + "not allowed for the spherical harmonic case."); + prm.declare_entry ("Lateral wave number two", "2", + Patterns::Integer (), + "Doubled second lateral wave number of the harmonic perturbation. " + "Equals the spherical harmonic order in 3d spherical shells. " + "In all other cases one equals half of a sine period over " + "the model domain. This allows for single up-/downswings. " + "Negative numbers reverse the sign of the perturbation."); + prm.declare_entry ("Magnitude", "1.0", + Patterns::Double (0.), + "The magnitude of the Harmonic perturbation."); + prm.declare_entry ("Reference temperature", "1600.0", + Patterns::Double (0.), + "The reference temperature that is perturbed by the " + "harmonic function. Only used in incompressible models."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + template + void + HarmonicPerturbation::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Harmonic perturbation"); + { + vertical_wave_number = prm.get_integer ("Vertical wave number"); + lateral_wave_number_1 = prm.get_integer ("Lateral wave number one"); + lateral_wave_number_2 = prm.get_integer ("Lateral wave number two"); + magnitude = prm.get_double ("Magnitude"); + reference_temperature = prm.get_double ("Reference temperature"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(HarmonicPerturbation, + "harmonic perturbation", + "An initial temperature field in which the temperature " + "is perturbed following a harmonic function (spherical " + "harmonic or sine depending on geometry and dimension) " + "in lateral and radial direction from an otherwise " + "constant temperature (incompressible model) or adiabatic " + "reference profile (compressible model).") + } +} diff --git a/source/initial_temperature/interface.cc.bak b/source/initial_temperature/interface.cc.bak new file mode 100644 index 00000000000..c747b7197b8 --- /dev/null +++ b/source/initial_temperature/interface.cc.bak @@ -0,0 +1,264 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + +#include + + +namespace aspect +{ + namespace InitialTemperature + { + // ------------------------------ Manager ----------------------------- + // -------------------------------- Deal with registering initial_temperature models and automating + // -------------------------------- their setup and selection at run time + + template + Manager::~Manager() + = default; + + + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + template + void + Manager::register_initial_temperature (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + template + void + Manager::parse_parameters (ParameterHandler &prm) + { + // find out which plugins are requested and the various other + // parameters we declare here + prm.enter_subsection ("Initial temperature model"); + { + model_names + = Utilities::split_string_list(prm.get("List of model names")); + + AssertThrow(Utilities::has_unique_entries(model_names), + ExcMessage("The list of strings for the parameter " + "'Initial temperature model/List of model names' contains entries more than once. " + "This is not allowed. Please check your parameter file.")); + + const std::string model_name = prm.get ("Model name"); + + AssertThrow (model_name == "unspecified" || model_names.size() == 0, + ExcMessage ("The parameter 'Model name' is only used for reasons" + "of backwards compatibility and can not be used together with " + "the new functionality 'List of model names'. Please add your " + "initial temperature model to the list instead.")); + + if (!(model_name == "unspecified")) + model_names.push_back(model_name); + + // create operator list + const std::vector model_operator_names = + Utilities::possibly_extend_from_1_to_N (Utilities::split_string_list(prm.get("List of model operators")), + model_names.size(), + "List of model operators"); + model_operators = Utilities::create_model_operator_list(model_operator_names); + } + prm.leave_subsection (); + + // go through the list, create objects and let them parse + // their own parameters + for (auto &model_name : model_names) + { + // create initial temperature objects + this->plugin_objects.push_back (std::unique_ptr> + (std::get(registered_plugins) + .create_plugin (model_name, + "Initial temperature model::Model names"))); + + if (SimulatorAccess *sim = dynamic_cast*>(&*this->plugin_objects.back())) + sim->initialize_simulator (this->get_simulator()); + + this->plugin_objects.back()->parse_parameters (prm); + this->plugin_objects.back()->initialize (); + } + } + + + + template + void + Manager::update() + { + for (auto &initial_temperature_object : this->plugin_objects) + initial_temperature_object->update(); + } + + + + template + double + Manager::initial_temperature (const Point &position) const + { + double temperature = 0.0; + int i = 0; + + for (const auto &initial_temperature_object : this->plugin_objects) + { + temperature = model_operators[i](temperature, + initial_temperature_object->initial_temperature(position)); + ++i; + } + return temperature; + } + + + template + const std::vector & + Manager::get_active_initial_temperature_names () const + { + return model_names; + } + + + template + const std::list>> & + Manager::get_active_initial_temperature_conditions () const + { + return this->plugin_objects; + } + + + template + void + Manager::declare_parameters (ParameterHandler &prm) + { + // declare the entry in the parameter file + prm.enter_subsection ("Initial temperature model"); + { + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + + prm.declare_entry("List of model names", + "", + Patterns::MultipleSelection(pattern_of_names), + "A comma-separated list of initial temperature models that " + "will be used to initialize the temperature. " + "These plugins are loaded in the order given, and modify the " + "existing temperature field via the operators listed " + "in 'List of model operators'.\n\n" + "The following initial temperature models are available:\n\n" + + + std::get(registered_plugins).get_description_string()); + + prm.declare_entry("List of model operators", "add", + Patterns::MultipleSelection(Utilities::get_model_operator_options()), + "A comma-separated list of operators that " + "will be used to append the listed temperature models onto " + "the previous models. If only one operator is given, " + "the same operator is applied to all models."); + + prm.declare_entry ("Model name", "unspecified", + Patterns::Selection (pattern_of_names+"|unspecified"), + "Select one of the following models:\n\n" + + + std::get(registered_plugins).get_description_string() + + "\n\n" + + "\\textbf{Warning}: This parameter provides an old and " + "deprecated way of specifying " + "initial temperature models and shouldn't be used. " + "Please use 'List of model names' instead."); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + std::string + get_valid_model_names_pattern () + { + return std::get(registered_plugins).get_pattern_of_names (); + } + + + + template + void + Manager::write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Initial temperature interface", + out); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace InitialTemperature + { +#define INSTANTIATE(dim) \ + template class Interface; \ + template class Manager; \ + \ + template \ + std::string \ + get_valid_model_names_pattern (); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/initial_temperature/lithosphere_mask.cc.bak b/source/initial_temperature/lithosphere_mask.cc.bak new file mode 100644 index 00000000000..e1101048d37 --- /dev/null +++ b/source/initial_temperature/lithosphere_mask.cc.bak @@ -0,0 +1,223 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include +#include + + +namespace aspect +{ + namespace InitialTemperature + { + namespace LABDepth + { + template + LABDepthLookup::LABDepthLookup () + : + lab_depths(1, 1.0) + {} + + + + template + void + LABDepthLookup::initialize () + { + if (LAB_depth_source == File) + { + const std::string filename = data_directory+LAB_file_name; + this->get_pcout() << " Loading Ascii data lookup file " << filename << '.' << std::endl; + + lab_depths.load_file(filename,this->get_mpi_communicator()); + } + } + + + + template + double + LABDepthLookup::get_lab_depth (const Point &position) const + { + if (LAB_depth_source == File) + { + //Get spherical coordinates for model + Assert (dim == 3, ExcNotImplemented()); + std::array scoord = Utilities::Coordinates::cartesian_to_spherical_coordinates(position); + const double phi = scoord[1]; + const double theta = scoord[2 % dim]; // work-around to compile without warnings for dim==2 + const Point<2> phi_theta (phi, theta); + + //Get lab depth for specific phi and theta + const double lab_depth = lab_depths.get_data(phi_theta,0); + return lab_depth; + } + + else if (LAB_depth_source == Value) + { + return max_depth; + } + else + { + Assert( false, ExcMessage("Invalid method for depth specification method") ); + return 0.0; + } + + return 0.0; + } + + + + template + void + LABDepthLookup::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Depth specification method", "Value", + Patterns::Selection("File|Value"), + "Method that is used to specify the depth of the lithosphere-asthenosphere boundary."); + prm.declare_entry ("Maximum lithosphere depth", "200000.0", + Patterns::Double (0.),"Units: \\si{\\meter}." + "The maximum depth of the lithosphere. The model will be " + "NaNs below this depth."); + prm.declare_entry ("Data directory", "$ASPECT_SOURCE_DIR/data/initial-temperature/lithosphere-mask/", + Patterns::DirectoryName (), + "The path to the LAB depth data file"); + prm.declare_entry ("LAB depth filename", + "LAB_CAM2016.txt", + Patterns::FileName (), + "File from which the lithosphere-asthenosphere boundary depth data is read."); + } + + template + void + LABDepthLookup::parse_parameters (ParameterHandler &prm) + { + if ( prm.get("Depth specification method") == "File" ) + { + LAB_depth_source = File; + data_directory = Utilities::expand_ASPECT_SOURCE_DIR (prm.get("Data directory")); + LAB_file_name = prm.get("LAB depth filename"); + } + else if ( prm.get("Depth specification method") == "Value" ) + { + LAB_depth_source = Value; + max_depth = prm.get_double ("Maximum lithosphere depth"); + } + } + } + + + + template + void + LithosphereMask::initialize () + { + lab_depth_lookup.initialize(); + } + + + + template + double + LithosphereMask::initial_temperature (const Point &position) const + { + double temperature; + const double depth = this->SimulatorAccess::get_geometry_model().depth(position); + const double lab_depth = lab_depth_lookup.get_lab_depth(position); + + if (depth <= lab_depth) + temperature = lithosphere_temperature; + else + temperature = std::numeric_limits::quiet_NaN(); + + return temperature; + } + + template + void + LithosphereMask::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection ("Lithosphere Mask"); + { + LABDepth::LABDepthLookup::declare_parameters(prm); + + prm.declare_entry ("Lithosphere temperature", "1600.", + Patterns::Double (0.), + "The initial temperature within lithosphere, applied above" + "the maximum lithosphere depth."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + LithosphereMask::parse_parameters (ParameterHandler &prm) + { + AssertThrow (dim == 3, + ExcMessage ("The 'Lithosphere mask' model for the initial " + "temperature is only available for 3d computations.")); + + prm.enter_subsection("Initial temperature model"); + { + prm.enter_subsection ("Lithosphere Mask"); + { + lab_depth_lookup.initialize_simulator(this->get_simulator()); + lab_depth_lookup.parse_parameters(prm); + lithosphere_temperature = prm.get_double ("Lithosphere temperature"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + template class LABDepth::LABDepthLookup<2>; + template class LABDepth::LABDepthLookup<3>; + + + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(LithosphereMask, + "lithosphere mask", + "Implementation of a model in which the initial " + "temperature is set to a specified lithosphere temperature above the " + "lithosphere-asthenosphere boundary (specified by an ascii file " + "or maximum lithosphere depth value). Below this the initial temperature is set as " + "NaN. Note the required format of the input data file: The first lines may " + "contain any number of comments if they begin with '#', but one of these lines " + "needs to contain the number of grid points in each dimension as for example " + "'# POINTS: 3 3'. For a spherical model, the order of the data columns has to be " + "'phi', 'theta', 'depth (m)', where phi is the azimuth angle and theta is the " + "polar angle measured positive from the north pole. This plug-in can be combined " + "with another using the 'replace if valid' operator. ") + } +} diff --git a/source/initial_temperature/patch_on_S40RTS.cc.bak b/source/initial_temperature/patch_on_S40RTS.cc.bak new file mode 100644 index 00000000000..185cc74d950 --- /dev/null +++ b/source/initial_temperature/patch_on_S40RTS.cc.bak @@ -0,0 +1,212 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace InitialTemperature + { + template + PatchOnS40RTS::PatchOnS40RTS () + = default; + + + template + void + PatchOnS40RTS::initialize () + { + this->Utilities::AsciiDataInitial::initialize(1); + } + + + template + double + PatchOnS40RTS:: + ascii_grid_vs (const Point &position) const + { + const double vs_perturbation = Utilities::AsciiDataInitial::get_data_component(position,0); + return vs_perturbation; + } + + + template + double + PatchOnS40RTS:: + initial_temperature (const Point &position) const + { + const double depth = this->get_geometry_model().depth(position); + + double vs_perturbation; + if (depth <= max_grid_depth - smoothing_length_scale) + { + vs_perturbation = ascii_grid_vs(position); + } + //add smoothing between the two models + else if (depth > max_grid_depth - smoothing_length_scale && depth < max_grid_depth) + { + const double scale_factor = (depth-(max_grid_depth-smoothing_length_scale))/smoothing_length_scale; + vs_perturbation = s40rts.get_Vs(position)*(scale_factor) + ascii_grid_vs(position)*(1.0-scale_factor); + } + else + { + vs_perturbation = s40rts.get_Vs(position); + } + + // use either the user-input reference temperature as background temperature + // (incompressible model) or the adiabatic temperature profile (compressible model) + const double background_temperature = this->get_material_model().is_compressible() ? + this->get_adiabatic_conditions().temperature(position) : + s40rts.reference_temperature; + + // get the Vs to density conversion + double vs_to_density = 0.0; + if (s40rts.vs_to_density_method == s40rts.file) + vs_to_density = s40rts.profile.get_data_component(Point<1>(depth), s40rts.vs_to_density_index); + else if (s40rts.vs_to_density_method == s40rts.constant) + vs_to_density = s40rts.vs_to_density_constant; + else + // we shouldn't get here but instead should already have been + // kicked out when declaring the parameter, as the pattern won't match ("file|constant") + Assert(false, ExcMessage("Unknown method for vs to density scaling.")); + + // scale the perturbation in seismic velocity into a density perturbation + // vs_to_density is read in from input file + const double density_perturbation = vs_to_density * vs_perturbation; + double temperature_perturbation; + if (depth > no_perturbation_depth_patch) + // scale the density perturbation into a temperature perturbation + temperature_perturbation = -1./s40rts.thermal_alpha * density_perturbation; + else + // set heterogeneity to zero down to a specified depth + temperature_perturbation = 0.0; + + return background_temperature + temperature_perturbation; + } + + template + void + PatchOnS40RTS::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection ("Patch on S40RTS"); + { + prm.declare_entry ("Maximum grid depth", "700000.0", + Patterns::Double (0.), + "The maximum depth of the Vs ascii grid. The model will read in " + "Vs from S40RTS below this depth."); + prm.declare_entry ("Smoothing length scale", "200000.0", + Patterns::Double (0.), + "The depth range (above maximum grid depth) over which to smooth. " + "The boundary is smoothed using a depth weighted combination of Vs " + "values from the ascii grid and S40RTS at each point in the region of smoothing."); + prm.declare_entry ("Remove temperature heterogeneity down to specified depth", + boost::lexical_cast(std::numeric_limits::lowest()), + Patterns::Double (), + "This will set the heterogeneity prescribed by the Vs ascii grid and S40RTS to zero " + "down to the specified depth (in meters). Note that your resolution has " + "to be adequate to capture this cutoff. For example if you specify a depth " + "of 660km, but your closest spherical depth layers are only at 500km and " + "750km (due to a coarse resolution) it will only zero out heterogeneities " + "down to 500km. Similar caution has to be taken when using adaptive meshing."); + + Utilities::AsciiDataBase::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/initial-temperature/patch-on-S40RTS/test/", + "upper_shell_3d.txt"); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + PatchOnS40RTS::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Initial temperature model"); + { + prm.enter_subsection ("Patch on S40RTS"); + { + max_grid_depth = prm.get_double ("Maximum grid depth"); + smoothing_length_scale = prm.get_double ("Smoothing length scale"); + no_perturbation_depth_patch = prm.get_double ("Remove temperature heterogeneity down to specified depth"); + + Utilities::AsciiDataBase::parse_parameters(prm); + + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + s40rts.initialize_simulator (this->get_simulator()); + s40rts.parse_parameters(prm); + s40rts.initialize(); + + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(PatchOnS40RTS, + "patch on S40RTS", + "Implementation of a model in which the initial " + "temperature is derived from a file containing shear wave velocity perturbations " + "in ascii format (e.g. a high resolution upper mantle tomography) " + "combined with S40RTS. Note the required format of the " + "input ascii input data: The first lines may contain any number of comments " + "if they begin with '#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example '# POINTS: 3 3 3'. " + "The order of the data columns has to be " + " `x', `y', `z', 'Vs Perturbation' in a 3d model, which means that " + "there has to be a single column " + "containing the temperature. " + "Note that the data in the input " + "files need to be sorted in a specific order: " + "the first coordinate needs to ascend first, " + "followed by the second and the third at last in order to " + "assign the correct data to the prescribed coordinates. " + "In the spherical model data will be handled as Cartesian, " + "however, `x' will be replaced by " + "the radial distance of the point to the bottom of the model, " + "`y' by the azimuth angle and `z' by the polar angle measured " + "positive from the north pole. The grid will be assumed to be " + "a latitude-longitude grid. Note that the order " + "of spherical coordinates is `r', `phi', `theta' " + "and not `r', `theta', `phi', since this allows " + "for dimension independent expressions. " + "See S40RTS documentation for details on input parameters in the " + "S40RTS perturbation subsection. " + "The boundary between the two tomography models is smoothed using a depth weighted " + "combination of Vs values within the region of smoothing. ") + } +} diff --git a/source/initial_temperature/prescribed_temperature.cc.bak b/source/initial_temperature/prescribed_temperature.cc.bak new file mode 100644 index 00000000000..7b5e5149a88 --- /dev/null +++ b/source/initial_temperature/prescribed_temperature.cc.bak @@ -0,0 +1,97 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include +#include + + +namespace aspect +{ + namespace InitialTemperature + { + template + void + PrescribedTemperature::initialize() + { + // Make sure we keep track of the initial composition manager and + // that it continues to live beyond the time when the simulator + // class releases its pointer to it. + initial_composition = this->get_initial_composition_manager_pointer(); + } + + + template + double + PrescribedTemperature:: + initial_temperature (const Point &position) const + { + // Evaluate the material model to get the temperature + MaterialModel::MaterialModelInputs in(1, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(1, this->n_compositional_fields()); + in.requested_properties = MaterialModel::MaterialProperties::additional_outputs; + + in.position[0] = position; + in.temperature[0] = this->get_adiabatic_conditions().temperature(position); + in.pressure[0] = this->get_adiabatic_conditions().pressure(position); + in.velocity[0] = Tensor<1,dim> (); + + for (unsigned int c=0; cn_compositional_fields(); ++c) + in.composition[0][c] = initial_composition->initial_composition(position, c); + + in.strain_rate.resize(0); + + this->get_material_model().create_additional_named_outputs(out); + this->get_material_model().evaluate(in, out); + + // set up variable to interpolate prescribed field outputs onto temperature field + double temperature = in.temperature[0]; + if (MaterialModel::PrescribedTemperatureOutputs *prescribed_temperature_out + = out.template get_additional_output>()) + { + temperature = prescribed_temperature_out->prescribed_temperature_outputs[0]; + } + else + AssertThrow (false, + ExcMessage ("The material model needs to compute precribed temperature outputs, " + "otherwise the initial temperature can not be set to the prescribed " + "temperature.")); + + return temperature; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(PrescribedTemperature, + "prescribed temperature", + "This model fixes the initial temperature to the prescribed " + "temperature outputs computed by the material model. This only " + "works if the material model implements prescribed temperature " + "outputs.") + } +} diff --git a/source/initial_temperature/random_gaussian_perturbation.cc.bak b/source/initial_temperature/random_gaussian_perturbation.cc.bak new file mode 100644 index 00000000000..528caf247d3 --- /dev/null +++ b/source/initial_temperature/random_gaussian_perturbation.cc.bak @@ -0,0 +1,211 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace InitialTemperature + { + template + void + RandomGaussianPerturbation::initialize () + { + // Get dimension of the model from the geometry model. + Point min_coordinates; + Point max_coordinates; + + perturbation_centers.resize(n_perturbations); + perturbation_magnitudes.resize(n_perturbations); + + if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + const GeometryModel::SphericalShell &spherical_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + for (unsigned int d=0; d> (this->get_geometry_model())) + { + const GeometryModel::Sphere &sphere_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + for (unsigned int d=0; d> (this->get_geometry_model())) + { + const GeometryModel::Chunk &chunk_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + for (unsigned int d=0; d> (this->get_geometry_model())) + { + const GeometryModel::Box &box_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + min_coordinates = box_geometry_model.get_origin(); + max_coordinates = min_coordinates + box_geometry_model.get_extents(); + } + else if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + const GeometryModel::TwoMergedBoxes &two_merged_boxes_geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + min_coordinates = two_merged_boxes_geometry_model.get_origin(); + max_coordinates = min_coordinates + two_merged_boxes_geometry_model.get_extents(); + } + else + AssertThrow (false, + ExcMessage ("Not a valid geometry model for the initial conditions model " + "'random Gaussian perturbation'.")); + + // Initialize random locations of perturbations and check they are in the model domain. + // Use a fixed number as seed for random generator. + // This is important if we run the code on more than 1 processor. + std::mt19937 generator(1); + std::uniform_real_distribution random_location(0.0,1.0); + std::uniform_real_distribution random_magnitude(-max_magnitude, max_magnitude); + + for (unsigned int n=0; nget_geometry_model().point_is_in_domain(perturbation_centers[n])); + + perturbation_magnitudes[n] = random_magnitude(generator); + } + } + + + + template + double + RandomGaussianPerturbation:: + initial_temperature (const Point &position) const + { + double temperature_perturbation = 0; + for (unsigned int n=0; n + void + RandomGaussianPerturbation::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Random Gaussian perturbation"); + { + prm.declare_entry ("Number of perturbations", "100", + Patterns::Integer (), + "Total number of perturbations to be introduced into the model. " + "Perturbations will be placed at random locations within the " + "model domain."); + prm.declare_entry ("Maximum magnitude", "25.0", + Patterns::Double (0.), + "The maximum magnitude of the Gaussian perturbation. For each " + "perturbation, a random magnitude between plus and minus the " + "maximum magnitude will be chosen. " + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Width", "1000.0", + Patterns::Double (0.), + "The Gaussian RMS width of the perturbations. " + "Units: \\si{\\meter}."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + + template + void + RandomGaussianPerturbation::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Random Gaussian perturbation"); + { + n_perturbations = prm.get_integer ("Number of perturbations"); + max_magnitude = prm.get_double ("Maximum magnitude"); + width = prm.get_double ("Width"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(RandomGaussianPerturbation, + "random Gaussian perturbation", + "An initial temperature field in which the temperature " + "is perturbed from a temperature of zero following a " + "given number of Gaussian perturbations placed randomly " + "throughout the model domain. The number, width, and " + "maximum magnitude of the perturbations can be chosen " + "as model parameters. " + "This plugin is meant to be used in combination with " + "another initial temperature model that determines the " + "background temperature (such as the 'function' or the " + "'adiabatic' plugin) using the 'add' operator to combine " + "them.") + } +} diff --git a/source/initial_temperature/spherical_shell.cc.bak b/source/initial_temperature/spherical_shell.cc.bak new file mode 100644 index 00000000000..4a43ef19b92 --- /dev/null +++ b/source/initial_temperature/spherical_shell.cc.bak @@ -0,0 +1,378 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + + + +namespace aspect +{ + namespace InitialTemperature + { + template + double + SphericalHexagonalPerturbation:: + initial_temperature (const Point &position) const + { + // s = fraction of the way from the inner to the outer boundary; 0<=s<=1 + const double s = this->get_geometry_model().depth(position) + / this->get_geometry_model().maximal_depth(); + + /* now compute an angular variation of the linear temperature field by + stretching the variable s appropriately. note that the following + formula leaves the end points s=0 and s=1 fixed, but stretches the + region in between depending on the angle phi=atan2(x,y). + + For a plot, see + http://www.wolframalpha.com/input/?i=plot+%28%282*sqrt%28x^2%2By^2%29-1%29%2B0.2*%282*sqrt%28x^2%2By^2%29-1%29*%281-%282*sqrt%28x^2%2By^2%29-1%29%29*sin%286*atan2%28x%2Cy%29%29%29%2C+x%3D-1+to+1%2C+y%3D-1+to+1 + */ + const double scale = ((dim==3) + ? + std::max(0.0, + std::cos(numbers::PI * std::fabs(position(2)/R1))) + : + 1.0); + const double phi = std::atan2(position(0),position(1)); + const double s_mod = s + + + 0.2 * s * (1-s) * std::sin(angular_mode*phi + (90 + 2*rotation_offset) * constants::degree_to_radians ) * scale; + + // Check that a boundary temperature is prescribed + AssertThrow (this->has_boundary_temperature(), + ExcMessage ("This initial condition can only be used if a boundary " + "temperature is prescribed.")); + + return (this->get_boundary_temperature_manager().maximal_temperature()*(s_mod) + + + this->get_boundary_temperature_manager().minimal_temperature()*(1-s_mod)); + } + + + + template + void + SphericalHexagonalPerturbation::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Spherical hexagonal perturbation"); + { + + prm.declare_entry ("Angular mode", "6", + Patterns::Integer (), + "The number of convection cells with which to perturb the system."); + + prm.declare_entry ("Rotation offset", "-45.", + Patterns::Double (), + "Amount of clockwise rotation in degrees to apply to " + "the perturbations. Default is set to -45 in order " + "to provide backwards compatibility."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + + template + void + SphericalHexagonalPerturbation::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Spherical hexagonal perturbation"); + { + angular_mode = prm.get_integer ("Angular mode"); + rotation_offset = prm.get_double ("Rotation offset"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + // This initial condition only makes sense if the geometry is derived from + // a spherical model (i.e. a sphere, spherical shell or chunk) + if (Plugins::plugin_type_matches>(this->get_geometry_model())) + { + R1 = Plugins::get_plugin_as_type> + (this->get_geometry_model()).radius(); + } + else if (Plugins::plugin_type_matches>(this->get_geometry_model())) + { + R1 = Plugins::get_plugin_as_type> + (this->get_geometry_model()).outer_radius(); + } + else if (Plugins::plugin_type_matches>(this->get_geometry_model())) + { + R1 = Plugins::get_plugin_as_type> + (this->get_geometry_model()).outer_radius(); + } + else if (Plugins::plugin_type_matches>(this->get_geometry_model())) + { + const auto &gm = Plugins::get_plugin_as_type> + (this->get_geometry_model()); + // TODO + // If the eccentricity of the EllipsoidalChunk is non-zero, the radius can vary along a boundary, + // but the maximal depth is the same everywhere and we could calculate a representative pressure + // profile. However, it requires some extra logic with ellipsoidal + // coordinates, so for now we only allow eccentricity zero. + // Using the EllipsoidalChunk with eccentricity zero can still be useful, + // because the domain can be non-coordinate parallel. + + AssertThrow(gm.get_eccentricity() == 0.0, + ExcNotImplemented("This plugin cannot be used with a non-zero eccentricity. ")); + + R1 = gm.get_semi_major_axis_a(); + } + else + { + Assert (false, ExcMessage ("This initial condition can only be used if the geometry " + "is a sphere, a spherical shell, a chunk or an " + "ellipsoidal chunk.")); + R1 = numbers::signaling_nan(); + } + } + + + + template + SphericalGaussianPerturbation:: + SphericalGaussianPerturbation() + { + + // Note that the values we read in here have reasonable default values + geotherm.resize(4); + radial_position.resize(4); + geotherm[0] = 1e0; + geotherm[1] = 0.75057142857142856; + geotherm[2] = 0.32199999999999995; + geotherm[3] = 0.0; + radial_position[0] = 0e0-1e-3; + radial_position[1] = 0.16666666666666666; + radial_position[2] = 0.83333333333333337; + radial_position[3] = 1e0+1e-3; + + + } + + template + double + SphericalGaussianPerturbation:: + initial_temperature (const Point &position) const + { + // Check that a boundary temperature is prescribed + AssertThrow (this->has_boundary_temperature(), + ExcMessage ("This initial condition can only be used if a boundary " + "temperature is prescribed.")); + + const double dT = this->get_boundary_temperature_manager().maximal_temperature() + - this->get_boundary_temperature_manager().minimal_temperature(); + const double T0 = this->get_boundary_temperature_manager().maximal_temperature()/dT; + const double T1 = this->get_boundary_temperature_manager().minimal_temperature()/dT; + const double h = R1-R0; + + // s = fraction of the way from + // the inner to the outer + // boundary; 0<=s<=1 + const double r = position.norm(); + const double s = (r-R0)/h; + + const double scale=R1/(R1 - R0); + const float eps = 1e-4; + + int indx = -1; + for (unsigned int i=0; i<3; ++i) + { + if ((radial_position[i] - s) < eps && (radial_position[i+1] - s) > eps) + { + indx = i; + break; + } + } + Assert (indx >= 0, ExcInternalError()); + Assert (indx < 3, ExcInternalError()); + int indx1 = indx + 1; + const float dx = radial_position[indx1] - radial_position[indx]; + const float dy = geotherm[indx1] - geotherm[indx]; + + const double InterpolVal = (( dx > 0.5*eps) + ? + // linear interpolation + std::max(geotherm[3],geotherm[indx] + (s-radial_position[indx]) * (dy/dx)) + : + // evaluate the point in the discontinuity + 0.5*( geotherm[indx] + geotherm[indx1] )); + + const double x = (scale - this->depth)*std::cos(angle); + const double y = (scale - this->depth)*std::sin(angle); + const double Perturbation = (sign * amplitude * + std::exp( -( std::pow((position(0)*scale/R1-x),2) + + + std::pow((position(1)*scale/R1-y),2) ) / sigma)); + + if (r > R1 - 1e-6*R1 || InterpolVal + Perturbation < T1) + return T1*dT; + else if (r < R0 + 1e-6*R0 || InterpolVal + Perturbation > T0 ) + return T0*dT; + else + return (InterpolVal + Perturbation)*dT; + } + + + + template + void + SphericalGaussianPerturbation::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Spherical gaussian perturbation"); + { + prm.declare_entry ("Angle", "0.", + Patterns::Double (0.), + "The angle where the center of the perturbation is placed."); + prm.declare_entry ("Non-dimensional depth", "0.7", + Patterns::Double (0.), + "The non-dimensional radial distance where the center of the " + "perturbation is placed."); + prm.declare_entry ("Amplitude", "0.01", + Patterns::Double (0.), + "The amplitude of the perturbation."); + prm.declare_entry ("Sigma", "0.2", + Patterns::Double (0.), + "The standard deviation of the Gaussian perturbation."); + prm.declare_entry ("Sign", "1.", + Patterns::Double (), + "The sign of the perturbation."); + prm.declare_entry ("Filename for initial geotherm table", "initial-geotherm-table", + Patterns::FileName(), + "The file from which the initial geotherm table is to be read. " + "The format of the file is defined by what is read in " + "source/initial\\_temperature/spherical\\_shell.cc."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + template + void + SphericalGaussianPerturbation::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Initial temperature model"); + { + prm.enter_subsection("Spherical gaussian perturbation"); + { + angle = prm.get_double ("Angle"); + depth = prm.get_double ("Non-dimensional depth"); + amplitude = prm.get_double ("Amplitude"); + sigma = prm.get_double ("Sigma"); + sign = prm.get_double ("Sign"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + // This initial condition only makes sense if the geometry is derived from + // a spherical model + // (i.e. a sphere, spherical shell, chunk or ellipsoidal chunk with zero ellipticity) + + if (Plugins::plugin_type_matches>(this->get_geometry_model())) + { + R0 = 0.; + R1 = Plugins::get_plugin_as_type> + (this->get_geometry_model()).radius(); + } + else if (Plugins::plugin_type_matches>(this->get_geometry_model())) + { + R0 = Plugins::get_plugin_as_type> + (this->get_geometry_model()).inner_radius(); + R1 = Plugins::get_plugin_as_type> + (this->get_geometry_model()).outer_radius(); + } + else if (Plugins::plugin_type_matches>(this->get_geometry_model())) + { + R0 = Plugins::get_plugin_as_type> + (this->get_geometry_model()).inner_radius(); + R1 = Plugins::get_plugin_as_type> + (this->get_geometry_model()).outer_radius(); + } + + else if (Plugins::plugin_type_matches>(this->get_geometry_model())) + { + + // TODO + // If the eccentricity of the EllipsoidalChunk is non-zero, the radius can vary along a boundary, + // but the maximal depth is the same everywhere and we could calculate a representative pressure + // profile. However, it requires some extra logic with ellipsoidal + // coordinates, so for now we only allow eccentricity zero. + // Using the EllipsoidalChunk with eccentricity zero can still be useful, + // because the domain can be non-coordinate parallel. + + const auto &gm = Plugins::get_plugin_as_type>(this->get_geometry_model()); + + AssertThrow(gm.get_eccentricity() == 0.0, + ExcNotImplemented("This plugin cannot be used with a non-zero eccentricity. ")); + + R0 = gm.get_semi_major_axis_a() - gm.maximal_depth(); + R1 = gm.get_semi_major_axis_a(); + } + else + { + Assert (false, ExcMessage ("This initial condition can only be used if the geometry " + "is a sphere, a spherical shell, a chunk or an " + "ellipsoidal chunk.")); + + R0 = numbers::signaling_nan(); + R1 = numbers::signaling_nan(); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(SphericalHexagonalPerturbation, + "spherical hexagonal perturbation", + "An initial temperature field in which the temperature " + "is perturbed following an $N$-fold pattern in a specified " + "direction from an otherwise spherically symmetric " + "state. The class's name comes from previous versions " + "when the only option was $N=6$.") + + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(SphericalGaussianPerturbation, + "spherical gaussian perturbation", + "An initial temperature field in which the temperature " + "is perturbed by a single Gaussian added to an " + "otherwise spherically symmetric state. Additional " + "parameters are read from the parameter file in subsection " + "'Spherical gaussian perturbation'.") + } +} diff --git a/source/initial_temperature/world_builder.cc.bak b/source/initial_temperature/world_builder.cc.bak new file mode 100644 index 00000000000..ae1f5eac2c4 --- /dev/null +++ b/source/initial_temperature/world_builder.cc.bak @@ -0,0 +1,84 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include + +#ifdef ASPECT_WITH_WORLD_BUILDER +#include +#include +#include +#include +#include + +#include + + +namespace aspect +{ + namespace InitialTemperature + { + template + WorldBuilder::WorldBuilder () + = default; + + template + void + WorldBuilder:: + initialize() + { + CitationInfo::add("GWB"); + world_builder = this->get_world_builder_pointer(); + } + + + template + double + WorldBuilder:: + initial_temperature (const Point &position) const + { +#if WORLD_BUILDER_VERSION_MAJOR > 0 || WORLD_BUILDER_VERSION_MINOR >= 5 + return world_builder->temperature(Utilities::convert_point_to_array(position), + -this->get_geometry_model().height_above_reference_surface(position)); +#else + + return world_builder->temperature(Utilities::convert_point_to_array(position), + -this->get_geometry_model().height_above_reference_surface(position), + this->get_gravity_model().gravity_vector(position).norm()); +#endif + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace InitialTemperature + { + ASPECT_REGISTER_INITIAL_TEMPERATURE_MODEL(WorldBuilder, + "world builder", + "Specify the initial temperature through the World Builder. " + "More information on the World Builder can be found at " + "\\url{https://geodynamicworldbuilder.github.io}. " + "Make sure to specify the location of the World Builder file " + "in the parameter 'World builder file'.") + } +} +#endif diff --git a/source/main.cc.bak b/source/main.cc.bak new file mode 100644 index 00000000000..77b38b6890c --- /dev/null +++ b/source/main.cc.bak @@ -0,0 +1,892 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DEBUG +#ifdef ASPECT_USE_FP_EXCEPTIONS +#include +#endif +#endif + +#if ASPECT_USE_SHARED_LIBS==1 +# include +# ifdef ASPECT_HAVE_LINK_H +# include +# endif +#endif + +// This define has to be in exactly one translation unit and sets up the catch testing framework +#define CATCH_CONFIG_RUNNER + +// work-around for clang 6 error: +// "error: no member named 'uncaught_exceptions' in namespace 'std'" +// see https://github.com/catchorg/Catch2/issues/1201 +#define CATCH_INTERNAL_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS +#define CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS + +#include + + +// get the value of a particular parameter from the contents of the input +// file. return an empty string if not found +std::string +get_last_value_of_parameter(const std::string ¶meters, + const std::string ¶meter_name) +{ + std::string return_value; + + std::istringstream x_file(parameters); + while (x_file) + { + // Get one line and then match a regex to it that matches the parameter + // we are looking for. Before we do that, strip spaces from the front + // and back of the line: + std::string line; + std::getline(x_file, line); + + while ((line.size() > 0) && (line[0] == ' ' || line[0] == '\t')) + line.erase(0, 1); + while ((line.size() > 0) + && (line[line.size() - 1] == ' ' || line[line.size() - 1] == '\t')) + line.erase(line.size() - 1, std::string::npos); + + std::match_results matches; + const std::string regex = "set[ \t]+" + parameter_name + "[ \t]*=[ \t]*(.*)"; + if (std::regex_match(line, matches, std::regex(regex))) + { + // Since the line as a whole matched, the 'matches' variable needs to + // contain two entries: [0] denotes the whole string, and [1] the + // one that was matched by the '(.*)' expression. + Assert (matches.size() == 2, dealii::ExcInternalError()); + return_value = std::string(matches[1].first, matches[1].second); + } + } + + return return_value; +} + + +// Extract the dimension in which to run ASPECT from the +// the contents of the parameter file. This is something that +// we need to do before processing the parameter file since we +// need to know whether to use the dim=2 or dim=3 instantiation +// of the main classes. +// +// This function is essentially the first part of ASPECT to look at the input +// file, so if something is wrong with it, this is the place to generate good +// error messages. +unsigned int +get_dimension(const std::string ¶meters) +{ + const std::string dimension = get_last_value_of_parameter(parameters, "Dimension"); + if (dimension.size() > 0) + { + // A common problem is that people have .prm files that were generated + // on Windows, but then run this on Linux where the line endings are + // different. This is pernicious because it means that the conversion + // of a string such as "2\r" to an integer fails, but if we print + // this string, it comes out completely garbled because it contains + // a carriage-return without a newline -- so the error message looks + // like this: + // + // >. While reading the dimension from the input file, ASPECT found a string that can not be converted to an integer: <2 + // + // Note how the end of the error message overwrites the beginning + // of the line. + // + // To avoid this kind of error, specifically test up front that the + // text in question does not contain '\r' characters. If we are on + // linux, then this kind of character would means that the line endings + // are wrong. On the other hand, if we are on windows, then the + // getline command we have used in finding 'dimension' would have + // filtered it out. So its presence points to a problem. + + AssertThrow (dimension.find('\r') == std::string::npos, + dealii::ExcMessage ("It appears that your input file uses Windows-style " + "line endings ('\\r\\n') but you are running on a system where " + "the C++ run time environment expects input files to have " + "Unix-style line endings ('\\n'). You need to convert your " + "input file to use the correct line endings before running " + "ASPECT with it.")); + try + { + return dealii::Utilities::string_to_int (dimension); + } + catch (...) + { + AssertThrow (false, + dealii::ExcMessage("While reading the dimension from the input file, " + "ASPECT found a string that can not be converted to " + "an integer: <" + dimension + ">.")); + return 0; // we should never get here. + } + } + else + return 2; +} + + + +#if ASPECT_USE_SHARED_LIBS==1 + +#ifdef ASPECT_HAVE_LINK_H +// collect the names of the shared libraries linked to by this program. this +// function is a callback for the dl_iterate_phdr() function we call below +int get_names_of_shared_libs (struct dl_phdr_info *info, + size_t, + void *data) +{ + reinterpret_cast*>(data)->insert (info->dlpi_name); + return 0; +} +#endif + + +// make sure the list of shared libraries we currently link with +// has deal.II only once +void validate_shared_lib_list (const bool before_loading_shared_libs) +{ +#ifdef ASPECT_HAVE_LINK_H + // get the list of all shared libs we currently link against + std::set shared_lib_names; + dl_iterate_phdr(get_names_of_shared_libs, &shared_lib_names); + + // find everything that is interesting + std::set dealii_shared_lib_names; + for (const auto &p : shared_lib_names) + if (p.find ("libdeal_II") != std::string::npos || + p.find ("libdeal.ii") != std::string::npos) + dealii_shared_lib_names.insert (p); + + // produce an error if we load deal.II more than once + if (dealii_shared_lib_names.size() != 1) + { + std::ostringstream error; + error << "........................................................\n" + << "ASPECT currently links against different versions of the\n" + << "deal.II library, namely the ones at these locations:\n"; + for (const auto &p : dealii_shared_lib_names) + error << " " << p << '\n'; + error << "This can not work.\n\n"; + + if (before_loading_shared_libs) + error << "Since this is happening already before opening additional\n" + << "shared libraries, this means that something must have gone\n" + << "wrong when you configured deal.II and/or ASPECT. Please\n" + << "contact the forum for help.\n"; + else + error << "Since this is happening after opening additional shared\n" + << "library plugins, this likely means that you have compiled\n" + << "ASPECT in release mode and the plugin in debug mode, or the\n" + << "other way around. Please re-compile the plugin in the same\n" + << "mode as ASPECT.\n"; + + error << "........................................................\n"; + + // if not success, then throw an exception: ExcMessage on processor 0, + // QuietException on the others + if (dealii::Utilities::MPI::this_mpi_process (MPI_COMM_WORLD) == 0) + { + AssertThrow (false, dealii::ExcMessage (error.str())); + } + else + throw aspect::QuietException(); + } +#else + // simply mark the argument as read, to avoid compiler warnings + (void)before_loading_shared_libs; +#endif +} + + +#endif + + +// retrieve a list of shared libraries from the parameter file and +// dlopen them so that we can load plugins declared in them +void possibly_load_shared_libs (const std::string ¶meters) +{ + using namespace dealii; + + + const std::string shared_libs + = get_last_value_of_parameter(parameters, + "Additional shared libraries"); + if (shared_libs.size() > 0) + { +#if ASPECT_USE_SHARED_LIBS==1 + // check up front whether the list of shared libraries is internally + // consistent or whether we link, for whatever reason, with both the + // debug and release versions of deal.II + validate_shared_lib_list (true); + + const std::vector + shared_libs_list = Utilities::split_string_list (shared_libs); + + for (const auto &shared_lib : shared_libs_list) + { + // The user can specify lib{target}.so, lib{target}.debug.so, or lib{target}.release.so but + // we need to load the correct file depending on our compilation mode. We will try to make + // it work regardless of what the users specified: + std::string filename = shared_lib; + + auto delete_if_ends_with = [](std::string &a, const std::string &b) + { + if (a.size()' << std::endl; + + + void *handle = dlopen (filename.c_str(), RTLD_LAZY); + AssertThrow (handle != nullptr, + ExcMessage (std::string("Could not successfully load shared library <") + + filename + ">. The operating system reports " + + "that the error is this: <" + + dlerror() + + ">. Did you call 'cmake' and then compile " + "the plugin library you are trying to load, and did " + "you check the spelling of the library's name? " + "Are you running ASPECT in a directory so that the path " + "to the library in question is as specified in the " + ".prm file?")); + + // check again whether the list of shared libraries is + // internally consistent or whether we link with both the + // debug and release versions of deal.II. this may happen if + // the plugin was compiled against the debug version of + // deal.II but aspect itself against the release version, or + // the other way around + validate_shared_lib_list (false); + + // on systems where we can detect that both libdeal_II.so and + // libdeal_II.g.so is loaded, the test above function above will + // throw an exception and we will terminate. on the other hand, on + // systems where we can't detect this we should at least mitigate + // some of the ill effects -- in particular, make sure that + // deallog is set to use the desired output depth since otherwise + // we get lots of output from the linear solvers + deallog.depth_console(0); + } + + if (Utilities::MPI::this_mpi_process (MPI_COMM_WORLD) == 0) + std::cout << std::endl; +#else + if (Utilities::MPI::this_mpi_process (MPI_COMM_WORLD) == 0) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "You can not load plugins through additional shared libraries " << std::endl + << "on systems where you link ASPECT as a static executable." + << std::endl + << "----------------------------------------------------" + << std::endl; + } + std::exit (1); +#endif + } +} + + +/** + * Read until we reach the end of the given stream, and return the contents + * so obtained in a std::string object that contains the individual + * lines read separated by `\n` characters. + */ +std::string +read_until_end (std::istream &input) +{ + std::string result; + while (input) + { + std::string line; + std::getline(input, line); + + result += line + '\n'; + } + return result; +} + + + +/** + * Take the name of a parameter file and return all parameters in that file + * as a string. If @p parameter_file_name is "--" read the parameters from + * std::cin instead. + */ +std::string +read_parameter_file(const std::string ¶meter_file_name, + MPI_Comm comm) +{ + using namespace dealii; + + std::string input_as_string; + const bool i_am_proc_0 = (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0); + + if (parameter_file_name != "--") + { + if (i_am_proc_0 == true && + aspect::Utilities::fexists(parameter_file_name) == false && + (parameter_file_name=="parameter-file.prm" + || parameter_file_name=="parameter_file.prm")) + { + std::cerr << "*** You should not take everything literally! ***\n" + << "*** Please pass the name of an existing parameter file instead. ***" << std::endl; + exit(1); + } + + input_as_string = aspect::Utilities::read_and_distribute_file_content(parameter_file_name, comm); + } + else + { + // As stated in the help string, treat "--" as special: as is common + // on unix, treat it as a way to read input from stdin. + // Unfortunately, if you do + // echo "abc" | mpirun -np 4 ./aspect + // then only MPI process 0 gets the data. so we have to + // read it there, then broadcast it to the other processors + if (i_am_proc_0) + { + input_as_string = read_until_end (std::cin); + int size = input_as_string.size()+1; + int ierr = MPI_Bcast (&size, + 1, + MPI_INT, + /*root=*/0, MPI_COMM_WORLD); + AssertThrowMPI(ierr); + ierr = MPI_Bcast (const_cast(input_as_string.c_str()), + size, + MPI_CHAR, + /*root=*/0, MPI_COMM_WORLD); + AssertThrowMPI(ierr); + } + else + { + // on this side, read what processor zero has broadcast about + // the size of the input file. then create a buffer to put the + // text in, get it from processor 0, and copy it to + // input_as_string + int size; + int ierr = MPI_Bcast (&size, 1, + MPI_INT, + /*root=*/0, MPI_COMM_WORLD); + AssertThrowMPI(ierr); + + std::vector p (size); + ierr = MPI_Bcast (p.data(), size, + MPI_CHAR, + /*root=*/0, MPI_COMM_WORLD); + AssertThrowMPI(ierr); + input_as_string = p.data(); + } + } + + return input_as_string; +} + + + +/** + * Let ParameterHandler parse the input file, here given as a string. + * Since ParameterHandler unconditionally writes to the screen when it + * finds something it doesn't like, we get massive amounts of output + * in parallel computations since every processor writes the same + * stuff to screen. To avoid this, let processor 0 parse the input + * first and, if necessary, produce its output. Only if this + * succeeds, also let the other processors read their input. + * + * In case of an error, we need to abort all processors without them + * having read their data. This is done by throwing an exception of the + * special class aspect::QuietException that we can catch in main() and terminate + * the program quietly without generating other output. + */ +void +parse_parameters (const std::string &input_as_string, + dealii::ParameterHandler &prm) +{ + // try reading on processor 0 + bool success = true; + if (dealii::Utilities::MPI::this_mpi_process (MPI_COMM_WORLD) == 0) + try + { + prm.parse_input_from_string(input_as_string); + } + catch (const dealii::ExceptionBase &e) + { + success = false; + e.print_info(std::cerr); + std::cerr << std::endl; + } + + + // broadcast the result. we'd like to do this with a bool + // data type but MPI_C_BOOL is not part of old MPI standards. + // so, do the broadcast in integers + { + int isuccess = (success ? 1 : 0); + const int ierr = MPI_Bcast (&isuccess, 1, MPI_INT, 0, MPI_COMM_WORLD); + AssertThrowMPI(ierr); + success = (isuccess == 1); + } + + // if not success, then throw an exception: ExcMessage on processor 0, + // QuietException on the others + if (success == false) + { + if (dealii::Utilities::MPI::this_mpi_process (MPI_COMM_WORLD) == 0) + { + AssertThrow(false, dealii::ExcMessage ("Invalid input parameter file.")); + } + else + throw aspect::QuietException(); + } + + // otherwise, processor 0 was ok reading the data, so we can expect the + // other processors will be ok as well + if (dealii::Utilities::MPI::this_mpi_process (MPI_COMM_WORLD) != 0) + { + prm.parse_input_from_string(input_as_string); + } +} + + + +/** + * Print help text + */ +void print_help() +{ + std::cout << "Usage: ./aspect [args] (to read from an input file)\n" + << " or ./aspect [args] -- (to read parameters from stdin)\n" + << std::endl; + std::cout << " optional arguments [args]:\n" + << " -h, --help (for this usage help)\n" + << " -v, --version (for information about library versions)\n" + << " -j, --threads (to use multi-threading)\n" + << " --output-json (print parameters in JSON format to standard output and exit)\n" + << " --output-xml (print parameters in XML format to standard output and exit)\n" + << " --output-plugin-graph (write a representation of all plugins to standard output and exit)\n" + << " --validate (parse parameter file and exit or report errors)\n" + << " --test (run the unit tests from unit_tests/, run --test -h for more info)\n" + << std::endl; +} + + + +// hook into SIGABRT/SIGFPE and kill off the program +void signal_handler(int signal) +{ + if (signal == SIGABRT) + { + std::cerr << "SIGABRT received\n"; + } + else if (signal == SIGFPE) + { + std::cerr << "SIGFPE received\n"; + } + else + { + std::cerr << "Unexpected signal " << signal << " received\n"; + } + + // Kill the program without performing any other cleanup, which would likely + // lead to a deadlock. + std::_Exit(EXIT_FAILURE); +} + + + +template +void +run_simulator(const std::string &raw_input_as_string, + const std::string &input_as_string, + const bool output_json, + const bool output_xml, + const bool output_plugin_graph, + const bool validate_only) +{ + using namespace dealii; + + ParameterHandler prm; + const bool i_am_proc_0 = (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0); + aspect::Simulator::declare_parameters(prm); + + if (validate_only) + { + try + { + parse_parameters (input_as_string, prm); + } + catch (...) + { + throw aspect::QuietException(); + } + if (i_am_proc_0) + std::cout << "The provided parameter file is valid." + "\n\n" + "Note: This validation only checks parameter file syntax errors, like typos\n" + "in keywords or parameter names, and that each parameter value satisfies a\n" + "basic check by itself. However, it may miss more nuanced errors that\n" + "are only checked when the model actually begins running. In particular,\n" + "checks that involve two or more parameters can not be verified at this\n" + "stage of an ASPECT run. Examples for such errors that can not already\n" + "be reported here are: (i) That every boundary is assigned exactly one type\n" + "of boundary condition; (ii) that parameters that take a list with values for\n" + "each composition field receive a list of the correct size." + << std::endl; + return; + } + + parse_parameters (input_as_string, prm); + + if (output_json) + { + if (i_am_proc_0) + prm.print_parameters(std::cout, ParameterHandler::JSON); + } + else if (output_xml) + { + if (i_am_proc_0) + prm.print_parameters(std::cout, ParameterHandler::XML); + } + else if (output_plugin_graph) + { + aspect::Simulator simulator(MPI_COMM_WORLD, prm); + if (i_am_proc_0) + simulator.write_plugin_graph (std::cout); + } + else + { + aspect::Simulator simulator(MPI_COMM_WORLD, prm); + if (i_am_proc_0) + { + // write create output/original.prm containing exactly what we got + // started with: + std::string output_directory = prm.get ("Output directory"); + if (output_directory.size() == 0) + output_directory = "./"; + else if (output_directory[output_directory.size()-1] != '/') + output_directory += "/"; + + std::ofstream file(output_directory + "original.prm"); + file << raw_input_as_string; + } + + simulator.run(); + } +} + + + +int main (int argc, char *argv[]) +{ + using namespace dealii; + +#ifdef DEBUG +#ifdef ASPECT_USE_FP_EXCEPTIONS + // Some implementations seem to not initialize the floating point exception + // bits to zero. Make sure we start from a clean state. + feclearexcept(FE_DIVBYZERO|FE_INVALID); + + // enable floating point exceptions + feenableexcept(FE_DIVBYZERO|FE_INVALID); +#endif +#endif + + std::string prm_name = ""; + bool output_json = false; + bool output_xml = false; + bool output_plugin_graph = false; + bool output_version = false; + bool output_help = false; + bool use_threads = false; + bool run_unittests = false; + bool validate_only = false; + int current_argument = 1; + + // Loop over all command line arguments. Handle a number of special ones + // starting with a dash, and then take the first non-special one as the + // name of the input file. We will later check that there are no further + // arguments left after that. + while (current_argument 0) ? &argv[current_argument] : nullptr; + + try + { + // Note: we initialize this class inside the try/catch block and not + // before, so that the destructor of this instance can react if we are + // currently unwinding the stack if an unhandled exception is being + // thrown to avoid MPI deadlocks. + Utilities::MPI::MPI_InitFinalize mpi_initialization(n_remaining_arguments, + remaining_arguments, + (use_threads ? + numbers::invalid_unsigned_int : + 1)); + + if (run_unittests) + { + // Construct new_argc, new_argv from argc, argv for catch without + // the "--test" arg, so we can control catch from the command + // line. It turns out catch needs argv[0] to be the executable name + // so we can not use remaining_arguments from above. + int new_argc = n_remaining_arguments + 1; + std::vector args; // use to construct a new argv of type char ** + args.emplace_back(argv[0]); + for (int i=0; i(raw_input_as_string,input_as_string,output_json,output_xml,output_plugin_graph,validate_only); + break; + } + case 3: + { + run_simulator<3>(raw_input_as_string,input_as_string,output_json,output_xml,output_plugin_graph,validate_only); + break; + } + default: + AssertThrow((dim >= 2) && (dim <= 3), + ExcMessage ("ASPECT can only be run in 2d and 3d but a " + "different space dimension is given in the parameter file.")); + } + } + catch (ExceptionBase &exc) + { + // report name of the deal.II exception: + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception '" << exc.get_exc_name() << "'" + << " on rank " << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) + << " on processing: " << std::endl + << exc.what() << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + MPI_Abort(MPI_COMM_WORLD, 1); + return 1; + } + catch (std::exception &exc) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception" + << " on rank " << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) + << " on processing: " << std::endl + << exc.what() << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + MPI_Abort(MPI_COMM_WORLD, 1); + return 1; + } + catch (aspect::QuietException &) + { + // Quietly treat an exception used on processors other than root + // when we already know that processor 0 will generate an + // exception. We do this to avoid creating too much (duplicate) + // screen output. Note that QuietException is not derived from + // std::exception, so the order of this and the previous 'catch' + // block does not matter. + // + // Sleep a few seconds before aborting. This allows text output from + // other ranks to be printed before the MPI implementation might kill + // the computation. + std::this_thread::sleep_for(std::chrono::seconds(5)); + + MPI_Abort(MPI_COMM_WORLD, 1); + return 1; + } + catch (...) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Unknown exception!" << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + MPI_Abort(MPI_COMM_WORLD, 1); + return 1; + } + + return 0; +} diff --git a/source/material_model/ascii_reference_profile.cc.bak b/source/material_model/ascii_reference_profile.cc.bak new file mode 100644 index 00000000000..d43d40df713 --- /dev/null +++ b/source/material_model/ascii_reference_profile.cc.bak @@ -0,0 +1,280 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + AsciiReferenceProfile::AsciiReferenceProfile() + : + density_index(numbers::invalid_unsigned_int), + thermal_expansivity_index(numbers::invalid_unsigned_int), + specific_heat_index(numbers::invalid_unsigned_int), + compressibility_index(numbers::invalid_unsigned_int), + seismic_vp_index(numbers::invalid_unsigned_int), + seismic_vs_index(numbers::invalid_unsigned_int), + seismic_dvp_dT_index(numbers::invalid_unsigned_int), + seismic_dvs_dT_index(numbers::invalid_unsigned_int) + {} + + template + void + AsciiReferenceProfile::initialize () + { + profile.initialize(this->get_mpi_communicator()); + + density_index = profile.get_column_index_from_name("density"); + thermal_expansivity_index = profile.get_column_index_from_name("thermal_expansivity"); + specific_heat_index = profile.get_column_index_from_name("specific_heat"); + compressibility_index = profile.get_column_index_from_name("compressibility"); + + // these are only optional entries in the data file, read them in if they exist, + // but keep the invalid unsigned int entry if the columns do not exist + // the strings have to be all lower case for the lookup class to find them + seismic_vp_index = profile.maybe_get_column_index_from_name("seismic_vp"); + seismic_vs_index = profile.maybe_get_column_index_from_name("seismic_vs"); + seismic_dvp_dT_index = profile.maybe_get_column_index_from_name("seismic_dvp_dt"); + seismic_dvs_dT_index = profile.maybe_get_column_index_from_name("seismic_dvs_dt"); + } + + template + void + AsciiReferenceProfile:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const Point position = in.position[i]; + const double temperature_deviation = in.temperature[i] - this->get_adiabatic_conditions().temperature(position); + const double pressure_deviation = in.pressure[i] - this->get_adiabatic_conditions().pressure(position); + + const double depth = this->get_geometry_model().depth(position); + const Point<1> profile_position(depth); + + double visc_temperature_dependence = std::max(std::min(std::exp(-thermal_viscosity_exponent*temperature_deviation/this->get_adiabatic_conditions().temperature(position)),1e3),1e-3); + if (std::isnan(visc_temperature_dependence)) + visc_temperature_dependence = 1.0; + + double visc_depth_dependence = viscosity_prefactors[0]; + for (unsigned int j=0; j < transition_depths.size(); ++j) + { + if (depth>transition_depths[j]) + visc_depth_dependence = viscosity_prefactors[j+1]; + } + + out.viscosities[i] = viscosity * visc_temperature_dependence * visc_depth_dependence; + + out.thermal_conductivities[i] = thermal_conductivity; + + out.thermal_expansion_coefficients[i] = profile.get_data_component(profile_position,thermal_expansivity_index); + out.specific_heat[i] = profile.get_data_component(profile_position,specific_heat_index); + out.compressibilities[i] = profile.get_data_component(profile_position,compressibility_index); + + out.densities[i] = profile.get_data_component(profile_position,density_index) + * (1.0 - out.thermal_expansion_coefficients[i] * temperature_deviation) + * (tala ? 1.0 : (1.0 + out.compressibilities[i] * pressure_deviation)); + + out.entropy_derivative_pressure[i] = 0.0; + out.entropy_derivative_temperature[i] = 0.0; + + for (unsigned int c=0; c *seismic_out = out.template get_additional_output>()) + { + if (seismic_vp_index != numbers::invalid_unsigned_int) + seismic_out->vp[i] = profile.get_data_component(profile_position,seismic_vp_index); + if (seismic_vs_index != numbers::invalid_unsigned_int) + seismic_out->vs[i] = profile.get_data_component(profile_position,seismic_vs_index); + if (seismic_dvp_dT_index != numbers::invalid_unsigned_int) + seismic_out->vp[i] += profile.get_data_component(profile_position,seismic_dvp_dT_index) + * temperature_deviation; + if (seismic_dvs_dT_index != numbers::invalid_unsigned_int) + seismic_out->vs[i] += profile.get_data_component(profile_position,seismic_dvs_dT_index) + * temperature_deviation; + } + } + } + + + + template + bool + AsciiReferenceProfile:: + is_compressible () const + { + return true; + } + + + + template + void + AsciiReferenceProfile::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Ascii reference profile"); + { + prm.declare_entry ("Thermal conductivity", "4.0", + Patterns::Double (0.), + "Reference conductivity"); + prm.declare_entry ("Viscosity", "1e21", + Patterns::Double (0.), + "Viscosity"); + prm.declare_entry ("Use TALA", "false", + Patterns::Bool (), + "Whether to use the TALA instead of the ALA " + "approximation."); + prm.declare_entry ("Thermal viscosity exponent", "0.", + Patterns::Double (0.), + "The temperature dependence of viscosity. Dimensionless exponent."); + prm.declare_entry ("Transition depths", "1.5e5, 4.1e5, 6.6e5", + Patterns::List (Patterns::Double(0.)), + "A list of depths where the viscosity changes. Values must " + "monotonically increase. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Viscosity prefactors", "10., 0.1, 1., 10.", + Patterns::List (Patterns::Double(0.)), + "A list of prefactors for the viscosity that determine the viscosity " + "profile. Each prefactor is applied in a depth range specified by the " + "list of `Transition depths', i.e. the first prefactor is applied above " + "the first transition depth, the second one between the first and second " + "transition depth, and so on. " + "To compute the viscosity profile, this prefactor is multiplied by the " + "reference viscosity specified through the parameter `Viscosity'. " + "List must have one more entry than Transition depths. " + "Units: non-dimensional."); + + aspect::Utilities::AsciiDataProfile::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/adiabatic-conditions/ascii-data/", + ""); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + AsciiReferenceProfile::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Ascii reference profile"); + { + tala = prm.get_bool ("Use TALA"); + thermal_conductivity = prm.get_double ("Thermal conductivity"); + viscosity = prm.get_double ("Viscosity"); + thermal_viscosity_exponent = prm.get_double ("Thermal viscosity exponent"); + transition_depths = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Transition depths"))); + viscosity_prefactors = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Viscosity prefactors"))); + + // make sure to check against the depth lists for size errors, since using depth + if (viscosity_prefactors.size() != transition_depths.size()+1) + AssertThrow(false, ExcMessage("Error: The list of Viscosity prefactors needs to have exactly " + "one more entry than the list of Transition depths. ")); + + profile.parse_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::none; + this->model_dependence.density = NonlinearDependence::pressure | NonlinearDependence::temperature; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + + } + + + + template + void + AsciiReferenceProfile::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (out.template get_additional_output>() == nullptr + && seismic_vp_index != numbers::invalid_unsigned_int + && seismic_vs_index != numbers::invalid_unsigned_int) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(AsciiReferenceProfile, + "ascii reference profile", + "A material model that reads in a reference " + "state for density, thermal expansivity, compressibility " + "and specific heat from a text file. " + "\n" + "Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of points in the reference state as " + "for example `# POINTS: 3'. " + "Following the comment lines there has to be a single line " + "containing the names of all data columns, separated by arbitrarily " + "many spaces. Column names are not allowed to contain spaces. " + "The file can contain unnecessary columns, but for this plugin it " + "needs to at least provide the columns named `density', " + "`thermal\\_expansivity', `specific\\_heat', and `compressibility'. " + "Note that the data lines in the file need to be sorted in order " + "of increasing depth from 0 to the maximal depth in the model " + "domain. Points in the model that are outside of the provided " + "depth range will be assigned the maximum or minimum depth values, " + "respectively. Points do not need to be equidistant, " + "but the computation of properties is optimized in speed " + "if they are." + "\n" + "\n" + "The viscosity $\\eta$ is computed as " + "$\\eta(z,T) = \\eta_r(z) \\eta_0 \\exp\\left(-A \\frac{T - T_{\\text{adi}}}{T_{\\text{adi}}}\\right)$, " + "where $\\eta_r(z)$ is the depth-dependence, which is a " + "piecewise constant function computed according to the " + "list of ``Viscosity prefactors'' and ``Transition depths'', " + "$\\eta_0$ is the reference viscosity specified by the parameter ``Viscosity'' " + "and $A$ describes the dependence on temperature and corresponds to " + "the parameter ``Thermal viscosity exponent''.") + } +} diff --git a/source/material_model/averaging.cc.bak b/source/material_model/averaging.cc.bak new file mode 100644 index 00000000000..d9ad5a02ea4 --- /dev/null +++ b/source/material_model/averaging.cc.bak @@ -0,0 +1,464 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + + template + AveragingOperation + Averaging::parse_averaging_operation_name (const std::string &s) + { + if (s == "none") + return none; + else if (s == "arithmetic average") + return arithmetic_average; + else if (s == "harmonic average") + return harmonic_average; + else if (s == "geometric average") + return geometric_average; + else if (s == "pick largest") + return pick_largest; + else if (s == "log average") + return log_average; + else if (s == "nwd arithmetic average") + return nwd_arithmetic_average; + else if (s == "nwd harmonic average") + return nwd_harmonic_average; + else if (s == "nwd geometric average") + return nwd_geometric_average; + else + AssertThrow (false, + ExcMessage ("The value <" + s + "> for a material " + "averaging operation is not one of the " + "valid values.")); + + return none; + } + + // Do the requested averaging operation for one array. + template + void + Averaging::average (const AveragingOperation averaging_operation, + const std::vector> &position, + std::vector &values_out) const + { + // if an output field has not been filled (because it was + // not requested), then simply do nothing -- no harm no foul + if (values_out.size() == 0) + return; + + const unsigned int N = values_out.size(); + + // alfad is a constant which is dependent on the dimension and is used to define the shape of the bell shape. + const double alfad = (dim == 2 ? 5/(numbers::PI * bell_shape_limit * bell_shape_limit) : 106/(numbers::PI * bell_shape_limit * bell_shape_limit * bell_shape_limit)); + + // perform the requested averaging + switch (averaging_operation) + { + case none: + { + break; + } + case arithmetic_average: + { + double sum = 0; + for (unsigned int i=0; i= 0, + ExcMessage ("Computing the geometric average " + "only makes sense for non-negative " + "quantities.")); + prod *= values_out[i]; + } + + const double average = std::pow (prod, 1./N); + for (unsigned int i=0; i::lowest(); + for (unsigned int i=0; i= 0, + ExcMessage ("Computing the log average " + "only makes sense for non-negative " + "quantities.")); + sum += std::log10(values_out[i]); + } + const double log_value_average = std::pow (10.,sum/N); + for (unsigned int i=0; i temp_values(N,0); + + // determine the maximum distance between all the points + double max_distance = 0; + for (unsigned int i=0; i 1) + weight = 0; + sum_value += weight * values_out[j]; + sum_weights += weight; + } + + const double average = sum_value / sum_weights; + + temp_values[i] = average; + }; + for (unsigned int i = 0; i temp_values(N,0); + + // determine the maximum distance between all the points + double max_distance = 0; + for (unsigned int i=0; i bell_shape_limit ) + weight = 0; + if (values_out[j] != 0) + { + sum_value += weight / values_out[j]; + } + sum_weights += weight; + } + const double average = sum_weights / sum_value; + + temp_values[i] = average; + }; + for (unsigned int i = 0; i temp_values(N,0); + + // determine the maximum distance between all the points + double max_distance = 0; + for (unsigned int i=0; i= 0, + ExcMessage ("Computing the geometric average " + "only makes sense for non-negative " + "quantities.")); + + for (unsigned int j=0; j bell_shape_limit ) + weight = 0; + + /** + * If the value is zero to begin with the log of that value will return nan. + * To prevent this from happening nothing is added to sum_value in this case. + */ + if (values_out[j] != 0) + { + sum_value += weight*log(values_out[j]); + } + + sum_weights += weight; + + } + const double average = std::exp (sum_value/sum_weights); + + + temp_values[i] = average; + }; + for (unsigned int i = 0; i + void + Averaging::evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const + { + // fill variable out with the results form the base material model + base_model -> evaluate(in,out); + + /** + * Check if the size of the densities (and thereby all the other vectors) is larger + * than one. Averaging over one or zero points does not make a difference anyway, + * and the normalized weighted distance averaging schemes need the distance between + * the points and can not handle a distance of zero. + */ + if (out.n_evaluation_points() > 1) + { + /* Average the base model values based on the chosen average */ + average (averaging_operation,in.position,out.viscosities); + average (averaging_operation,in.position,out.densities); + average (averaging_operation,in.position,out.thermal_expansion_coefficients); + average (averaging_operation,in.position,out.specific_heat); + average (averaging_operation,in.position,out.thermal_conductivities); + average (averaging_operation,in.position,out.compressibilities); + average (averaging_operation,in.position,out.entropy_derivative_pressure); + average (averaging_operation,in.position,out.entropy_derivative_temperature); + } + } + + template + void + Averaging::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Averaging"); + { + prm.declare_entry("Base model","simple", + Patterns::Selection(MaterialModel::get_valid_model_names_pattern()), + "The name of a material model that will be modified by an " + "averaging operation. Valid values for this parameter " + "are the names of models that are also valid for the " + "``Material models/Model name'' parameter. See the documentation for " + "that for more information."); + prm.declare_entry ("Averaging operation", "none", + Patterns::Selection ("none|arithmetic average|harmonic average|geometric average|pick largest|log average|nwd arithmetic average|nwd harmonic average|nwd geometric average"), + "Choose the averaging operation to use."); + prm.declare_entry ("Bell shape limit", "1.", + Patterns::Double(0.), + "The limit normalized distance between 0 and 1 where the bell shape becomes zero. See the manual for a more information."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + Averaging::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Averaging"); + { + Assert( prm.get("Base model") != "averaging", + ExcMessage("You may not use ``averaging'' as the base model for " + "a averaging model.") ); + + // create the base model and initialize its SimulatorAccess base + // class; it will get a chance to read its parameters below after we + // leave the current section + base_model = create_material_model(prm.get("Base model")); + if (SimulatorAccess *sim = dynamic_cast*>(base_model.get())) + sim->initialize_simulator (this->get_simulator()); + + averaging_operation = Averaging::parse_averaging_operation_name(prm.get ("Averaging operation")); + bell_shape_limit = prm.get_double ("Bell shape limit"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + /* After parsing the parameters for averaging, it is essential to parse + parameters related to the base model. */ + base_model->parse_parameters(prm); + this->model_dependence = base_model->get_model_dependence(); + } + + template + bool + Averaging:: + is_compressible () const + { + return base_model->is_compressible(); + } + + template + void + Averaging::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + base_model->create_additional_named_outputs(out); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(Averaging, + "averaging", + "The ``averaging'' Material model applies an averaging of the quadrature points " + "within a cell. The values to average are supplied by any of the other available " + "material models. In other words, it is a ``compositing material model''. " + "Parameters related to the average model are read from a subsection " + "``Material model/Averaging''." + "\n\n" + "The user must specify a ``Base model'' from which material properties are " + "derived. Furthermore an averaging operation must be selected, where the " + "Choice should be from the list none|arithmetic average|harmonic average|" + "geometric average|pick largest|log average|NWD arithmetic average|NWD harmonic average" + "|NWD geometric average." + "\n\n" + "NWD stands for Normalized Weighed Distance. The models with this in front " + "of their name work with a weighed average, which means each quadrature point " + "requires an individual weight. The weight is determined by the distance, where " + "the exact relation is determined by a bell shaped curve. A bell shaped curve is " + "a continuous function which is one at its maximum and exactly zero at and beyond " + "its limit. This bell shaped curve is spanned around each quadrature point to " + "determine the weighting map for each quadrature point. The used bell shape comes " + "from Lucy (1977). The distance is normalized so the largest distance becomes one. " + "This means that if variable ''Bell shape limit'' is exactly one, the farthest " + "quadrature point is just on the limit and its weight will be exactly zero. In " + "this plugin it is not implemented as larger and equal than the limit, but larger " + "than, to ensure the quadrature point at distance zero is always included." + ) + } +} diff --git a/source/material_model/compositing.cc.bak b/source/material_model/compositing.cc.bak new file mode 100644 index 00000000000..c091017a1be --- /dev/null +++ b/source/material_model/compositing.cc.bak @@ -0,0 +1,259 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include + +namespace aspect +{ + namespace MaterialModel + { + namespace Property + { + namespace + { + const std::pair property_map_pairs[] + = + { + {"Viscosity", viscosity}, + {"Density", density}, + {"Thermal expansion coefficient", thermal_expansion_coefficient}, + {"Specific heat", specific_heat}, + {"Thermal conductivity", thermal_conductivity}, + {"Compressibility", compressibility}, + {"Entropy derivative pressure", entropy_derivative_pressure}, + {"Entropy derivative temperature", entropy_derivative_temperature}, + {"Reaction terms", reaction_terms} + }; + + + const std::map + property_map (std::begin(property_map_pairs), + std::end(property_map_pairs)); + } + } + + + template + void + Compositing::copy_required_properties(const unsigned int model_index, + const typename Interface::MaterialModelOutputs &base_output, + typename Interface::MaterialModelOutputs &out) const + { + if (model_property_map.find(Property::viscosity)->second == model_index) + out.viscosities = base_output.viscosities; + if (model_property_map.find(Property::density)->second == model_index) + out.densities = base_output.densities; + if (model_property_map.find(Property::thermal_expansion_coefficient)->second == model_index) + out.thermal_expansion_coefficients = base_output.thermal_expansion_coefficients; + if (model_property_map.find(Property::specific_heat)->second == model_index) + out.specific_heat = base_output.specific_heat; + if (model_property_map.find(Property::thermal_conductivity)->second == model_index) + out.thermal_conductivities = base_output.thermal_conductivities; + if (model_property_map.find(Property::compressibility)->second == model_index) + out.compressibilities = base_output.compressibilities; + if (model_property_map.find(Property::entropy_derivative_pressure)->second == model_index) + out.entropy_derivative_pressure = base_output.entropy_derivative_pressure; + if (model_property_map.find(Property::entropy_derivative_temperature)->second == model_index) + out.entropy_derivative_temperature = base_output.entropy_derivative_temperature; + if (model_property_map.find(Property::reaction_terms)->second == model_index) + out.reaction_terms = base_output.reaction_terms; + } + + + + template + void + Compositing::initialize () + { + // initialize all models + for (auto &model : models) + model->initialize(); + } + + + template + void + Compositing::evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const + { + typename Interface::MaterialModelOutputs base_output(out.n_evaluation_points(), + this->introspection().n_compositional_fields); + + // Move the additional outputs to base_output so that our models can fill them if desired: + base_output.move_additional_outputs_from(out); + + for (unsigned int i=0; ievaluate(in, base_output); + copy_required_properties(i, base_output, out); + } + + // Finally, we move the additional outputs back into place: + out.move_additional_outputs_from(base_output); + } + + + + template + void + Compositing:: + create_additional_named_outputs (typename Interface::MaterialModelOutputs &outputs) const + { + for (unsigned int i=0; icreate_additional_named_outputs(outputs); + } + } + + + + template + void + Compositing::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Compositing"); + { + std::map::const_iterator prop_it = Property::property_map.begin(); + for (; prop_it != Property::property_map.end(); ++prop_it) + { + prm.declare_entry(prop_it->first, "unspecified", + Patterns::Selection( + MaterialModel::get_valid_model_names_pattern()+"|unspecified" + ), + "Material model to use for " + prop_it->first +". Valid values for this " + "parameter are the names of models that are also valid for the " + "``Material models/Model name'' parameter. See the documentation for " + "that for more information."); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + Compositing::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Compositing"); + { + model_names.clear(); + std::map::const_iterator prop_it = Property::property_map.begin(); + for (; prop_it != Property::property_map.end(); ++prop_it) + { + const Property::MaterialProperty prop = prop_it->second; + const std::string model_name = prm.get(prop_it->first); + + AssertThrow(model_name != "averaging", + ExcMessage("You may not use ``averaging'' as the base model for the " + + prop_it->first +" property of a compositing material model.")); + AssertThrow(model_name != "compositing", + ExcMessage("You may not use ``compositing'' as the base model for the " + + prop_it->first +" property of a compositing material model.")); + + // see if we've encountered this base model before. If not, + // otherwise put it into a new slot. otherwise + // record its number for the current coefficient. + std::vector::iterator model_position + = std::find(model_names.begin(), model_names.end(), model_name); + if ( model_position == model_names.end() ) + { + model_property_map[prop] = model_names.size(); + model_names.push_back(model_name); + } + else + model_property_map[prop] = std::distance(model_names.begin(), model_position); + } + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // create the models and initialize their SimulatorAccess base + // After parsing the parameters for averaging, it is essential to parse + // parameters related to the base models + models.resize(model_names.size()); + for (unsigned int i=0; i(model_names[i]); + if (SimulatorAccess *sim = dynamic_cast*>(models[i].get())) + sim->initialize_simulator (this->get_simulator()); + models[i]->parse_parameters(prm); + // All models will need to compute all quantities, so do so + this->model_dependence.viscosity |= models[i]->get_model_dependence().viscosity; + this->model_dependence.density |= models[i]->get_model_dependence().density; + this->model_dependence.compressibility |= models[i]->get_model_dependence().compressibility; + this->model_dependence.specific_heat |= models[i]->get_model_dependence().specific_heat; + this->model_dependence.thermal_conductivity |= models[i]->get_model_dependence().thermal_conductivity; + } + } + + + + template + bool + Compositing:: + is_compressible () const + { + const unsigned int ind = model_property_map.find(Property::compressibility)->second; + return models[ind]->is_compressible(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(Compositing, + "compositing", + "The ``compositing'' Material model selects material model properties from a " + "given set of other material models, and is intended to make mixing different " + "material models easier. This is useful, for example, when wanting to " + "use the melting parameterization of the ``melt simple'' model (which has " + "a relatively simple viscosity model that only allows for a " + "temperature- but not strain rate-dependent viscosity) with a more " + "realistic viscosity model such as that provided by the " + "``diffusion dislocation'' model." + "\n\n" + "Specifically, this material model works by allowing to specify " + "the name of another material model for each coefficient that material " + "models are asked for (such as the viscosity, density, etc.). Whenever " + "the material model is asked for the values of coefficients, it then " + "evaluates all of the ``base models'' that were listed for the various " + "coefficients, and copies the values returned by these base models " + "into the output structure." + "\n\n" + "The implementation of this material model is somewhat expensive " + "because it has to evaluate all material coefficients of all underlying " + "material models. Consequently, if performance of assembly and postprocessing " + "is important, then implementing a separate material model is " + "a better choice than using this material model." + ) + } +} diff --git a/source/material_model/composition_reaction.cc.bak b/source/material_model/composition_reaction.cc.bak new file mode 100644 index 00000000000..71f4fdd01ce --- /dev/null +++ b/source/material_model/composition_reaction.cc.bak @@ -0,0 +1,250 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + + template + void + CompositionReaction:: + evaluate(const MaterialModelInputs &in, + MaterialModelOutputs &out) const + { + ReactionRateOutputs *reaction_rate_out = out.template get_additional_output>(); + + // The Composition reaction model has up to two compositional fields (plus one background field) + // that can influence the density + const unsigned int n_compositions_for_eos = std::min(this->n_compositional_fields()+1, 3u); + EquationOfStateOutputs eos_outputs (n_compositions_for_eos); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const double temperature = in.temperature[i]; + const std::vector &composition = in.composition[i]; + const double delta_temp = temperature-reference_T; + double temperature_dependence = std::max(std::min(std::exp(-thermal_viscosity_exponent*delta_temp/reference_T),1e2),1e-2); + + if (std::isnan(temperature_dependence)) + temperature_dependence = 1.0; + + switch (composition.size()) + { + case 0: + out.viscosities[i] = temperature_dependence * eta; + break; + case 1: + // geometric interpolation + out.viscosities[i] = (pow(10, ((1-composition[0]) * log10(eta*temperature_dependence) + + composition[0] * log10(eta*composition_viscosity_prefactor_1*temperature_dependence)))); + break; + default: + out.viscosities[i] = (pow(10, ((1 - 0.5*composition[0] - 0.5*composition[1]) * log10(eta*temperature_dependence) + + 0.5 * composition[0] * log10(eta*composition_viscosity_prefactor_1*temperature_dependence) + + 0.5 * composition[1] * log10(eta*composition_viscosity_prefactor_2*temperature_dependence)))); + break; + } + + equation_of_state.evaluate(in, i, eos_outputs); + + std::vector volume_fractions (n_compositions_for_eos, 1.0); + for (unsigned int c=0; cget_geometry_model().depth(in.position[i]); + for (unsigned int c=0; cn_compositional_fields(); ++c) + { + double delta_C = 0.0; + switch (c) + { + case 0: + if (depth < reaction_depth) delta_C = -composition[0]; + break; + case 1: + if (depth < reaction_depth) delta_C = composition[0]; + break; + default: + delta_C = 0.0; + break; + } + out.reaction_terms[i][c] = delta_C; + + // Fill reaction rate outputs instead of the reaction terms if we use operator splitting + // (and then set the latter to zero). + if (this->get_parameters().use_operator_splitting) + { + if (reaction_rate_out != nullptr) + reaction_rate_out->reaction_rates[i][c] = (this->get_timestep_number() > 0 + ? + out.reaction_terms[i][c] / this->get_timestep() + : + 0.0); + out.reaction_terms[i][c] = 0.0; + } + } + + out.thermal_expansion_coefficients[i] = eos_outputs.thermal_expansion_coefficients[0]; + out.specific_heat[i] = eos_outputs.specific_heat_capacities[0]; + out.thermal_conductivities[i] = k_value; + out.compressibilities[i] = eos_outputs.compressibilities[0]; + } + } + + + + template + bool + CompositionReaction:: + is_compressible () const + { + return false; + } + + + + template + void + CompositionReaction::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Composition reaction model"); + { + EquationOfState::LinearizedIncompressible::declare_parameters (prm, 2); + + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. Units: \\si{\\kelvin}."); + prm.declare_entry ("Viscosity", "5e24", + Patterns::Double (0.), + "The value of the constant viscosity. Units: \\si{\\kilogram\\per\\meter\\per\\second}."); + prm.declare_entry ("Composition viscosity prefactor 1", "1.0", + Patterns::Double (0.), + "A linear dependency of viscosity on the first compositional field. " + "Dimensionless prefactor. With a value of 1.0 (the default) the " + "viscosity does not depend on the composition."); + prm.declare_entry ("Composition viscosity prefactor 2", "1.0", + Patterns::Double (0.), + "A linear dependency of viscosity on the second compositional field. " + "Dimensionless prefactor. With a value of 1.0 (the default) the " + "viscosity does not depend on the composition."); + prm.declare_entry ("Thermal viscosity exponent", "0.0", + Patterns::Double (0.), + "The temperature dependence of viscosity. Dimensionless exponent."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Reaction depth", "0.", + Patterns::Double (0.), + "Above this depth the compositional fields react: " + "The first field gets converted to the second field. " + "Units: \\si{\\meter}."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + CompositionReaction::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Composition reaction model"); + { + equation_of_state.parse_parameters (prm, 2); + + reference_T = prm.get_double ("Reference temperature"); + eta = prm.get_double ("Viscosity"); + composition_viscosity_prefactor_1 = prm.get_double ("Composition viscosity prefactor 1"); + composition_viscosity_prefactor_2 = prm.get_double ("Composition viscosity prefactor 2"); + thermal_viscosity_exponent = prm.get_double ("Thermal viscosity exponent"); + k_value = prm.get_double ("Thermal conductivity"); + reaction_depth = prm.get_double ("Reaction depth"); + + if (thermal_viscosity_exponent!=0.0 && reference_T == 0.0) + AssertThrow(false, ExcMessage("Error: Material model composition reaction with Thermal viscosity exponent can not have reference_T=0.")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::none; + this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + + if (thermal_viscosity_exponent != 0) + this->model_dependence.viscosity |= NonlinearDependence::temperature; + if ((composition_viscosity_prefactor_1 != 1.0) || + (composition_viscosity_prefactor_2 != 1.0)) + this->model_dependence.viscosity |= NonlinearDependence::compositional_fields; + } + + + template + void + CompositionReaction::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (this->get_parameters().use_operator_splitting + && out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points, + this->n_compositional_fields())); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(CompositionReaction, + "composition reaction", + "A material model that behaves in the same way as " + "the simple material model, but includes two compositional " + "fields and a reaction between them. Above a depth given " + "in the input file, the first fields gets converted to the " + "second field. ") + } +} diff --git a/source/material_model/depth_dependent.cc.bak b/source/material_model/depth_dependent.cc.bak new file mode 100644 index 00000000000..9efd80cd564 --- /dev/null +++ b/source/material_model/depth_dependent.cc.bak @@ -0,0 +1,350 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include + +#include + +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + void + DepthDependent::initialize() + { + base_model->initialize(); + } + + + + template + void + DepthDependent::update() + { + base_model->update(); + + // we get time passed as seconds (always) but may want + // to reinterpret it in years + if (this->convert_output_to_years()) + viscosity_function.set_time (this->get_time() / year_in_seconds); + else + viscosity_function.set_time (this->get_time()); + } + + + + template + bool + DepthDependent:: + is_compressible () const + { + return base_model->is_compressible(); + } + + + + template + double + DepthDependent::calculate_depth_dependent_prefactor(const double &depth) const + { + if (viscosity_source == file) + { + return depth_dependent_rheology->compute_viscosity(depth) / reference_viscosity; + } + else if (viscosity_source == function) + { + const Point<1> dpoint(depth); + const double viscosity = viscosity_function.value(dpoint); + Assert (viscosity > 0.0, ExcMessage("Viscosity depth function should be larger than zero")); + return viscosity / reference_viscosity; + } + else if (viscosity_source == list) + { + const unsigned int nlayers = depth_values.size()-1; + unsigned int i=0; + /* find the layer containing the specified depth and return the corresponding viscosity */ + while (depth > depth_values[i] && i + void + DepthDependent::evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const + { + base_model->evaluate(in,out); + if (in.requests_property(MaterialProperties::viscosity)) + { + // Scale the base model viscosity value by the depth dependent prefactor + for (unsigned int i=0; i < out.n_evaluation_points(); ++i) + { + const double depth = this->get_geometry_model().depth(in.position[i]); + out.viscosities[i] *= calculate_depth_dependent_prefactor(depth); + } + } + } + + + + template + void + DepthDependent::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + // Depth-dependent parameters from the rheology plugin + Rheology::AsciiDepthProfile::declare_parameters(prm, + "Depth dependent model"); + + prm.enter_subsection("Depth dependent model"); + { + prm.declare_entry("Base model","simple", + Patterns::Selection(MaterialModel::get_valid_model_names_pattern()), + "The name of a material model that will be modified by a depth " + "dependent viscosity. Valid values for this parameter " + "are the names of models that are also valid for the " + "``Material models/Model name'' parameter. See the documentation for " + "that for more information."); + prm.declare_entry ("Depth dependence method", "None", + Patterns::Selection("Function|File|List|None"), + "Method that is used to specify how the viscosity should vary with depth."); + prm.declare_entry("Depth list", "", Patterns::List(Patterns::Double ()), + "A comma-separated list of depth values for use with the ``List'' " + "``Depth dependence method''. The list must be provided in order of " + "increasing depth, and the last value must be greater than or equal to " + "the maximal depth of the model. The depth list is interpreted as a layered " + "viscosity structure and the depth values specify the maximum depths of each " + "layer."); + prm.declare_entry("Viscosity list", "", Patterns::List(Patterns::Double ()), + "A comma-separated list of viscosity values, corresponding to the depth values " + "provided in ``Depth list''. The number of viscosity values specified here must " + "be the same as the number of depths provided in ``Depth list''."); + + prm.declare_entry ("Reference viscosity", + boost::lexical_cast(std::numeric_limits::max()), + Patterns::Double (0.), + "The value of the constant reference viscosity $\\eta_r$ that is used to scale " + "the non-dimensional depth-dependent viscosity prefactor. " + "Units: \\si{\\pascal\\second}."); + + prm.declare_alias ("Data file name","Viscosity depth file"); + + prm.enter_subsection("Viscosity depth function"); + { + Functions::ParsedFunction<1>::declare_parameters(prm,1); + prm.declare_entry("Function expression","1.0e21"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + DepthDependent::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Depth dependent model"); + { + AssertThrow( prm.get("Base model") != "depth dependent", + ExcMessage("You may not use ``depth dependent'' as the base model for " + "a depth-dependent model.") ); + + // create the base model and initialize its SimulatorAccess base + // class; it will get a chance to read its parameters below after we + // leave the current section + base_model = create_material_model(prm.get("Base model")); + if (SimulatorAccess *sim = dynamic_cast*>(base_model.get())) + sim->initialize_simulator (this->get_simulator()); + + if (prm.get("Depth dependence method") == "Function") + viscosity_source = function; + else if (prm.get("Depth dependence method") == "File") + viscosity_source = file; + else if (prm.get("Depth dependence method") == "List") + viscosity_source = list; + else if (prm.get("Depth dependence method") == "None") + viscosity_source = none; + else + { + AssertThrow(false, ExcMessage("Unknown method for depth dependence.")); + } + + depth_values = Utilities::string_to_double(Utilities::split_string_list(prm.get("Depth list"))); + viscosity_values = Utilities::string_to_double(Utilities::split_string_list(prm.get("Viscosity list"))); + /* + * check sanity of viscosity list values and depth list values input + */ + if (viscosity_source == list) + { + /* check that length of depth values and viscosity values are compatible */ + AssertThrow( depth_values.size() == viscosity_values.size() , + ExcMessage("Depth list must be same size as Viscosity list")); + /* check that list is in ascending order */ + for (unsigned int i=1; i depth_values[i-1], + ExcMessage("Viscosity depth values must be strictly ascending")); + /* check that last layer includes base of model */ + AssertThrow( *(depth_values.end()-1) >= this->get_geometry_model().maximal_depth(), + ExcMessage("Last value in Depth list must be greater than or equal to maximal depth of domain")); + } + + prm.enter_subsection("Viscosity depth function"); + { + try + { + viscosity_function.parse_parameters(prm); + } + catch (...) + { + std::cerr << "FunctionParser failed to parse\n" + << "\t Viscosity depth function\n" + << "with expression \n" + << "\t' " << prm.get("Function expression") << "'"; + throw; + } + } + prm.leave_subsection(); + + reference_viscosity = prm.get_double("Reference viscosity"); + + AssertThrow(reference_viscosity != std::numeric_limits::max(), + ExcMessage("You have to set a reference viscosity for the depth dependent model.")); + } + prm.leave_subsection(); + + if (viscosity_source == file) + { + depth_dependent_rheology = std::make_unique>(); + depth_dependent_rheology->initialize_simulator (this->get_simulator()); + depth_dependent_rheology->parse_parameters(prm, "Depth dependent model"); + depth_dependent_rheology->initialize(); + } + } + prm.leave_subsection(); + + /* After parsing the parameters for depth dependent, it is essential to parse + parameters related to the base model. */ + base_model->parse_parameters(prm); + this->model_dependence = base_model->get_model_dependence(); + } + + + + template + void + DepthDependent::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + base_model->create_additional_named_outputs(out); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(DepthDependent, + "depth dependent", + "The ``depth dependent'' Material model applies a depth-dependent scaling " + "to the viscosity of any other available material models. In other words, it " + "is a ``compositing material model''." + "\n\n" + "Parameters related to the depth dependent model are read from a subsection " + "``Material model/Depth dependent model''. " + "The user must specify a ``Base model'' from which material properties are " + "derived. Currently the depth dependent model only allows depth dependence of " + "viscosity - other material properties are taken from the ``Base model''. " + "Viscosity $\\eta$ at depth $z$ is calculated according to:" + "$ \\eta(z,p,T,X,...) = \\eta(z) \\eta_b(p,T,X,..)/\\eta_{r}$ " + "where $\\eta(z)$ is the depth-dependence specified by the depth dependent " + "model, $\\eta_b(p,T,X,...)$ is the viscosity calculated from the base model, " + "and $\\eta_{r}$ is the reference viscosity. " + "In addition to the specification of the ``Base model'', the user must specify " + "the method to be used to calculate the depth-dependent viscosity $\\eta(z)$ as " + "``Material model/Depth dependent model/Depth dependence method'', which can be " + "chosen among ``None|Function|File|List''. Each method and the associated parameters " + "are as follows:" + "\n" + "\n" + "``Function'': read a user-specified parsed function from the input file in a " + "subsection ``Material model/Depth dependent model/Viscosity depth function''. " + "By default, this function is uniformly equal to 1.0e21. Specifying a function " + "that returns a value less than or equal to 0.0 anywhere in the model domain will " + "produce an error. " + "\n" + "\n" + "``File'': read a user-specified file containing viscosity values at specified " + "depths. The file containing depth-dependent viscosities is read from a " + "directory specified by the user as " + "``Material model/Depth dependent model/Data directory'', from a file with name " + "specified as ``Material model/Depth dependent model/Viscosity depth file''. " + "The format of this file is ascii text and contains two columns with one header line:" + "\n" + "\n" + "example Viscosity depth file:\\\\" + "Depth (m) Viscosity (Pa-s)\\\\" + "0.0000000e+00 1.0000000e+21\\\\" + "6.7000000e+05 1.0000000e+22\\\\" + "\n" + "\n" + "Viscosity is interpolated from this file using linear interpolation. " + "``None'': no depth-dependence. Viscosity is taken directly from ``Base model''" + "\n" + "\n" + "``List:'': read a comma-separated list of depth values corresponding to the maximum " + "depths of layers having constant depth-dependence $\\eta(z)$. The layers must be " + "specified in order of increasing depth, and the last layer in the list must have a depth " + "greater than or equal to the maximal depth of the model. The list of layer depths is " + "specified as ``Material model/Depth dependent model/Depth list'' and the corresponding " + "list of layer viscosities is specified as " + "``Material model/Depth dependent model/Viscosity list''" + ) + } +} diff --git a/source/material_model/diffusion_dislocation.cc.bak b/source/material_model/diffusion_dislocation.cc.bak new file mode 100644 index 00000000000..70c3147579b --- /dev/null +++ b/source/material_model/diffusion_dislocation.cc.bak @@ -0,0 +1,219 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + template + void + DiffusionDislocation:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + for (unsigned int i = 0; i < in.n_evaluation_points(); ++i) + { + // const Point position = in.position[i]; + const double temperature = in.temperature[i]; + const double pressure= in.pressure[i]; + const std::vector composition = in.composition[i]; + const std::vector volume_fractions = MaterialUtilities::compute_only_composition_fractions(composition, + this->introspection().chemical_composition_field_indices()); + + // densities + double density = 0.0; + for (unsigned int j=0; j < volume_fractions.size(); ++j) + { + // not strictly correct if thermal expansivities are different, since we are interpreting + // these compositions as volume fractions, but the error introduced should not be too bad. + const double temperature_factor= (1.0 - thermal_expansivities[j] * (temperature - reference_T)); + density += volume_fractions[j] * densities[j] * temperature_factor; + } + + // thermal expansivities + double thermal_expansivity = 0.0; + for (unsigned int j=0; j < volume_fractions.size(); ++j) + thermal_expansivity += volume_fractions[j] * thermal_expansivities[j]; + + // calculate effective viscosity + if (in.requests_property(MaterialProperties::viscosity)) + { + Assert(std::isfinite(in.strain_rate[i].norm()), + ExcMessage("Invalid strain_rate in the MaterialModelInputs. This is likely because it was " + "not filled by the caller.")); + out.viscosities[i] = diffusion_dislocation.compute_viscosity(pressure, temperature, volume_fractions, in.strain_rate[i]); + } + + out.densities[i] = density; + out.thermal_expansion_coefficients[i] = thermal_expansivity; + // Specific heat at the given positions. + out.specific_heat[i] = heat_capacity; + // Thermal conductivity at the given positions. If the temperature equation uses + // the reference density profile formulation, use the reference density to + // calculate thermal conductivity. Otherwise, use the real density. If the adiabatic + // conditions are not yet initialized, the real density will still be used. + if (this->get_parameters().formulation_temperature_equation == + Parameters::Formulation::TemperatureEquation::reference_density_profile && + this->get_adiabatic_conditions().is_initialized()) + out.thermal_conductivities[i] = thermal_diffusivity * heat_capacity * + this->get_adiabatic_conditions().density(in.position[i]); + else + out.thermal_conductivities[i] = thermal_diffusivity * heat_capacity * density; + // Compressibility at the given positions. + // The compressibility is given as + // $\frac 1\rho \frac{\partial\rho}{\partial p}$. + out.compressibilities[i] = 0.0; + // Pressure derivative of entropy at the given positions. + out.entropy_derivative_pressure[i] = 0.0; + // Temperature derivative of entropy at the given positions. + out.entropy_derivative_temperature[i] = 0.0; + // Change in composition due to chemical reactions at the + // given positions. The term reaction_terms[i][c] is the + // change in compositional field c at point i. + for (unsigned int c=0; c + bool + DiffusionDislocation:: + is_compressible () const + { + return false; + } + + template + void + DiffusionDislocation::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection ("Diffusion dislocation"); + { + Rheology::DiffusionDislocation::declare_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + DiffusionDislocation::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection ("Diffusion dislocation"); + { + reference_T = prm.get_double("Reference temperature"); + + // Retrieve the list of composition names + std::vector compositional_field_names = this->introspection().get_composition_names(); + // Establish that a background field is required here + compositional_field_names.insert(compositional_field_names.begin(),"background"); + + // Make options file for parsing maps to double arrays + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + + // Establish that a background field is required here + chemical_field_names.insert(chemical_field_names.begin(),"background"); + + Utilities::MapParsing::Options options(chemical_field_names, "Densities"); + options.list_of_allowed_keys = compositional_field_names; + + densities = Utilities::MapParsing::parse_map_to_double_array (prm.get("Densities"), + options); + + options.property_name = "Thermal expansivities"; + thermal_expansivities = Utilities::MapParsing::parse_map_to_double_array (prm.get("Thermal expansivities"), + options); + + // Phenomenological parameters + thermal_diffusivity = prm.get_double("Thermal diffusivity"); + heat_capacity = prm.get_double("Heat capacity"); + + diffusion_dislocation.initialize_simulator (this->get_simulator()); + diffusion_dislocation.parse_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::strain_rate | NonlinearDependence::compositional_fields; + this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(DiffusionDislocation, + "diffusion dislocation", + "An implementation of a viscous rheology including diffusion " + "and dislocation creep. " + "Compositional fields can each be assigned individual " + "activation energies, reference densities, thermal expansivities, " + "and stress exponents. The effective viscosity is defined as " + "\n\n" + "$\\eta_{\\text{eff}} = \\left(\\frac{1}{\\eta_{\\text{eff}}^\\text{diff}}+ " + "\\frac{1}{\\eta_{\\text{eff}}^\\text{dis}}\\right)^{-1}$ " + "where " + "$\\eta_{\\text{i}} = \\frac{1}{2} A^{-\\frac{1}{n_i}} d^\\frac{m_i}{n_i} " + "\\dot{\\varepsilon_i}^{\\frac{1-n_i}{n_i}} " + "\\exp\\left(\\frac{E_i^\\ast + PV_i^\\ast}{n_iRT}\\right)$ " + "\n\n" + "where $d$ is grain size, $i$ corresponds to diffusion or dislocation creep, " + "$\\dot{\\varepsilon}$ is the square root of the second invariant of the " + "strain rate tensor, $R$ is the gas constant, $T$ is temperature, " + "and $P$ is pressure. " + "$A_i$ are prefactors, $n_i$ and $m_i$ are stress and grain size exponents " + "$E_i$ are the activation energies and $V_i$ are the activation volumes. " + "\n\n" + "This form of the viscosity equation is commonly used in geodynamic simulations " + "See, for example, Billen and Hirth (2007), G3, 8, Q08012. Significantly, " + "other studies may use slightly different forms of the viscosity equation " + "leading to variations in how specific terms are defined or combined. For " + "example, the grain size exponent should always be positive in the diffusion " + "viscosity equation used here, while other studies place the grain size term " + "in the denominator and invert the sign of the grain size exponent. When " + "examining previous work, one should carefully check how the viscous " + "prefactor and grain size terms are defined. " + " \n\n" + "The ratio of diffusion to dislocation strain rate is found by Newton's " + "method, iterating to find the stress which satisfies the above equations. " + "The value for the components of this formula and additional " + "parameters are read from the parameter file in subsection " + "'Material model/DiffusionDislocation'.") + } +} diff --git a/source/material_model/drucker_prager.cc.bak b/source/material_model/drucker_prager.cc.bak new file mode 100644 index 00000000000..e59c6808b7a --- /dev/null +++ b/source/material_model/drucker_prager.cc.bak @@ -0,0 +1,323 @@ +/* + Copyright (C) 2015 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + + template + void + DruckerPrager:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + // set up additional output for the derivatives + MaterialModel::MaterialModelDerivatives *derivatives; + derivatives = out.template get_additional_output>(); + + EquationOfStateOutputs eos_outputs (1); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + // To avoid negative yield strengths and eventually viscosities, + // we make sure the pressure is not negative + const double pressure=std::max(in.pressure[i],0.0); + + // calculate effective viscosity + if (in.requests_property(MaterialProperties::viscosity)) + { + Assert(std::isfinite(in.strain_rate[i].norm()), + ExcMessage("Invalid strain_rate in the MaterialModelInputs. This is likely because it was " + "not filled by the caller.")); + const SymmetricTensor<2,dim> strain_rate_deviator = deviator(in.strain_rate[i]); + + // For the very first time this function is called + // (the first iteration of the first timestep), this function is called + // with a zero input strain rate. We provide a representative reference + // strain rate for this case, which avoids division by zero and produces + // a representative first guess of the viscosities. + // + // In later iterations and timesteps we calculate the second moment + // invariant of the deviatoric strain rate tensor. + // This is equal to the negative of the second principle + // invariant of the deviatoric strain rate (calculated with the function second_invariant), + // as shown in Appendix A of Zienkiewicz and Taylor (Solid Mechanics, 2000). + // + // The negative of the second principle invariant is equal to 0.5 e_dot_dev_ij e_dot_dev_ji, + // where e_dot_dev is the deviatoric strain rate tensor. The square root of this quantity + // gives the common definition of effective strain rate. + const double edot_ii_strict = (this->simulator_is_past_initialization() == false + ? + // no simulator object available via + // the SimulatorAccess base class, or the + // Simulator itself has not been completely + // initialized. This might mean that we are + // in a unit test, or at least that we can't + // rely on any simulator information + std::fabs(second_invariant(strain_rate_deviator)) + : + // simulator object is available, but we need to treat the + // first time step separately + ((this->get_timestep_number() == 0) + && + (in.strain_rate[i].norm() <= std::numeric_limits::min()) + ? + reference_strain_rate * reference_strain_rate + : + std::fabs(second_invariant(strain_rate_deviator)))); + + const double strain_rate_effective = edot_ii_strict; + + // In later time steps, we still need to care about cases of very small + // strain rates. We expect the viscosity to approach the maximum_viscosity + // in these cases. This check prevents a division-by-zero. + if (std::sqrt(strain_rate_effective) <= std::numeric_limits::min()) + { + out.viscosities[i] = maximum_viscosity; + + if (derivatives != nullptr) + { + derivatives->viscosity_derivative_wrt_strain_rate[i] = 0.0; + derivatives->viscosity_derivative_wrt_pressure[i] = 0.0; + } + } + else + { + // plasticity + const double eta_plastic = drucker_prager_plasticity.compute_viscosity(cohesion, + angle_of_internal_friction, + pressure, + std::sqrt(strain_rate_effective), + std::numeric_limits::infinity()); + + const double viscosity_pressure_derivative = drucker_prager_plasticity.compute_derivative(angle_of_internal_friction,std::sqrt(strain_rate_effective)); + + // Cut off the viscosity between a minimum and maximum value to avoid + // a numerically unfavourable large viscosity range. + const double effective_viscosity = 1.0 / ( ( 1.0 / ( eta_plastic + minimum_viscosity ) ) + ( 1.0 / maximum_viscosity ) ); + + Assert(dealii::numbers::is_finite(effective_viscosity), ExcMessage ("Error: Viscosity is not finite.")); + + out.viscosities[i] = effective_viscosity; + + Assert(dealii::numbers::is_finite(out.viscosities[i]), + ExcMessage ("Error: Averaged viscosity is not finite.")); + + if (derivatives != nullptr) + { + const double averaging_factor = maximum_viscosity * maximum_viscosity + / ((eta_plastic + minimum_viscosity + maximum_viscosity) * (eta_plastic + minimum_viscosity + maximum_viscosity)); + const SymmetricTensor<2,dim> effective_viscosity_strain_rate_derivatives + = -0.5 * averaging_factor * (eta_plastic / edot_ii_strict) * strain_rate_deviator; + const double effective_viscosity_pressure_derivatives = averaging_factor * viscosity_pressure_derivative; + + derivatives->viscosity_derivative_wrt_strain_rate[i] = deviator_tensor() * effective_viscosity_strain_rate_derivatives; + + derivatives->viscosity_derivative_wrt_pressure[i] = effective_viscosity_pressure_derivatives; + + Assert(dealii::numbers::is_finite(derivatives->viscosity_derivative_wrt_pressure[i]), + ExcMessage ("Error: Averaged viscosity_derivative_wrt_pressure is not finite.")); + for (int x = 0; x < dim; ++x) + for (int y = 0; y < dim; ++y) + Assert(dealii::numbers::is_finite(derivatives->viscosity_derivative_wrt_strain_rate[i][x][y]), + ExcMessage ("Error: Averaged viscosity_derivative_wrt_strain_rate is not finite.")); + + } + } + } + + equation_of_state.evaluate(in, i, eos_outputs); + + out.densities[i] = eos_outputs.densities[0]; + out.thermal_expansion_coefficients[i] = eos_outputs.thermal_expansion_coefficients[0]; + out.specific_heat[i] = eos_outputs.specific_heat_capacities[0]; + out.thermal_conductivities[i] = thermal_conductivities; + out.compressibilities[i] = eos_outputs.compressibilities[0]; + out.entropy_derivative_pressure[i] = eos_outputs.entropy_derivative_pressure[0]; + out.entropy_derivative_temperature[i] = eos_outputs.entropy_derivative_temperature[0]; + + for (unsigned int c=0; c < in.composition[i].size(); ++c) + out.reaction_terms[i][c] = 0.0; + } + } + + + + template + bool + DruckerPrager:: + is_compressible () const + { + return false; + } + + + + template + void + DruckerPrager::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Drucker Prager"); + { + EquationOfState::LinearizedIncompressible::declare_parameters (prm); + + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. The reference temperature is used " + "in the density calculation. Units: \\si{\\kelvin}."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.enter_subsection ("Viscosity"); + { + + prm.declare_entry ("Minimum viscosity", "1e19", + Patterns::Double (0.), + "The value of the minimum viscosity cutoff $\\eta_min$. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Maximum viscosity", "1e24", + Patterns::Double (0.), + "The value of the maximum viscosity cutoff $\\eta_max$. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Reference strain rate", "1e-15", + Patterns::Double (0.), + "The value of the initial strain rate prescribed during the " + "first nonlinear iteration $\\dot{\\epsilon}_ref$. Units: \\si{\\per\\second}."); + prm.declare_entry ("Angle of internal friction", "0.", + Patterns::Double (0.), + "The value of the angle of internal friction $\\phi$. " + "For a value of zero, in 2d the von Mises " + "criterion is retrieved. Angles higher than 30 degrees are " + "harder to solve numerically. Units: degrees."); + prm.declare_entry ("Cohesion", "2e7", + Patterns::Double (0.), + "The value of the cohesion $C$. Units: \\si{\\pascal}."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + DruckerPrager::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Drucker Prager"); + { + equation_of_state.parse_parameters (prm); + + reference_T = prm.get_double ("Reference temperature"); + thermal_conductivities = prm.get_double ("Thermal conductivity"); + prm.enter_subsection ("Viscosity"); + { + minimum_viscosity = prm.get_double ("Minimum viscosity"); + maximum_viscosity = prm.get_double ("Maximum viscosity"); + reference_strain_rate = prm.get_double ("Reference strain rate"); + // Convert degrees to radians + angle_of_internal_friction = prm.get_double ("Angle of internal friction") * constants::degree_to_radians; + cohesion = prm.get_double ("Cohesion"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + this->model_dependence.viscosity = NonlinearDependence::strain_rate; + this->model_dependence.density = NonlinearDependence::temperature; + + if (angle_of_internal_friction==0.0) + this->model_dependence.viscosity |= NonlinearDependence::pressure; + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(DruckerPrager, + "drucker prager", + "A material model that has constant values " + "for all coefficients but the density and viscosity. The defaults for all " + "coefficients are chosen to be similar to what is believed to be correct " + "for Earth's mantle. All of the values that define this model are read " + "from a section ``Material model/Drucker Prager'' in the input file, see " + "Section~\\ref{parameters:Material_20model/Drucker_20Prager}. " + "Note that the model does not take into account any dependencies of " + "material properties on compositional fields. " + "\n\n" + "The viscosity is computed according to the Drucker Prager frictional " + "plasticity criterion (non-associative) based on a user-defined " + "internal friction angle $\\phi$ and cohesion $C$. In 3d: " + " $\\sigma_y = \\frac{6 C \\cos(\\phi)}{\\sqrt{3} (3+\\sin(\\phi))} + " + "\\frac{6 P \\sin(\\phi)}{\\sqrt{3} (3+\\sin(\\phi))}$, " + "where $P$ is the pressure. " + "See for example Zienkiewicz, O. C., Humpheson, C. and Lewis, R. W. (1975), " + "G\\'{e}otechnique 25, No. 4, 671-689. " + "With this formulation we circumscribe instead of inscribe the Mohr Coulomb " + "yield surface. " + "In 2d the Drucker Prager yield surface is the same " + "as the Mohr Coulomb surface: " + " $\\sigma_y = P \\sin(\\phi) + C \\cos(\\phi)$. " + "Note that in 2d for $\\phi=0$, these criteria " + "revert to the von Mises criterion (no pressure dependence). " + "See for example \\cite{thieulot:2011}. " + "\n\n" + "Note that we enforce the pressure to be positive to prevent negative " + "yield strengths and viscosities. " + "\n\n" + "We then use the computed yield strength to scale back the viscosity on " + "to the yield surface using the Viscosity Rescaling Method described in " + "Kachanov, L. M. (2004), Fundamentals of the Theory of Plasticity, " + "Dover Publications, Inc. (Not Radial Return.)" + "A similar implementation can be found in GALE " + "(). " + "\n\n" + "To avoid numerically unfavourably large (or even negative) viscosity ranges, " + "we cut off the viscosity with a user-defined minimum and maximum viscosity: " + "$\\eta_{eff} = \\frac{1}{\\frac{1}{\\eta_{min} + \\eta}+ " + "\\frac{1}{\\eta_{max}}}$. " + "\n\n" + "Note that this model uses the formulation that assumes an incompressible " + "medium despite the fact that the density follows the law " + "$\\rho(T)=\\rho_0(1-\\beta(T-T_{\\text{ref}}))$. ") + } +} diff --git a/source/material_model/entropy_model.cc.bak b/source/material_model/entropy_model.cc.bak new file mode 100644 index 00000000000..9a4089a3358 --- /dev/null +++ b/source/material_model/entropy_model.cc.bak @@ -0,0 +1,577 @@ +/* + Copyright (C) 2016 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + namespace + { + template + bool solver_scheme_is_supported(const Parameters ¶meters) + { + // If we solve advection equations, we need to iterate them, because this material + // models splits temperature diffusion from entropy advection. + switch (parameters.nonlinear_solver) + { + case Parameters::NonlinearSolver::Kind::iterated_Advection_and_Stokes: + case Parameters::NonlinearSolver::Kind::iterated_Advection_and_defect_correction_Stokes: + case Parameters::NonlinearSolver::Kind::iterated_Advection_and_Newton_Stokes: + case Parameters::NonlinearSolver::Kind::no_Advection_no_Stokes: + case Parameters::NonlinearSolver::Kind::no_Advection_iterated_defect_correction_Stokes: + case Parameters::NonlinearSolver::Kind::no_Advection_iterated_Stokes: + case Parameters::NonlinearSolver::Kind::no_Advection_single_Stokes: + case Parameters::NonlinearSolver::Kind::first_timestep_only_single_Stokes: + return true; + + case Parameters::NonlinearSolver::Kind::single_Advection_single_Stokes: + case Parameters::NonlinearSolver::Kind::single_Advection_iterated_Stokes: + case Parameters::NonlinearSolver::Kind::single_Advection_iterated_defect_correction_Stokes: + case Parameters::NonlinearSolver::Kind::single_Advection_iterated_Newton_Stokes: + case Parameters::NonlinearSolver::Kind::single_Advection_no_Stokes: + return false; + } + Assert(false, ExcNotImplemented()); + return false; + } + } + + + + template + void + EntropyModel::initialize() + { + AssertThrow (this->get_parameters().formulation_mass_conservation == + Parameters::Formulation::MassConservation::projected_density_field, + ExcMessage("The 'entropy model' material model was only tested with the " + "'projected density field' approximation " + "for the mass conservation equation, which is not selected.")); + + AssertThrow (this->introspection().composition_type_exists(CompositionalFieldDescription::Type::entropy), + ExcMessage("The 'entropy model' material model requires the existence of a compositional field " + "named 'entropy'. This field does not exist.")); + + AssertThrow(solver_scheme_is_supported(this->get_parameters()) == true, + ExcMessage("The 'entropy model' material model requires the use of a solver scheme that " + "iterates over the advection equations but a non iterating solver scheme was selected. " + "Please check the consistency of your solver scheme.")); + + AssertThrow(material_file_names.size() == 1 || SimulatorAccess::get_end_time () == 0, + ExcMessage("The 'entropy model' material model can only handle one composition, " + "and can therefore only read one material lookup table.")); + + + + for (unsigned int i = 0; i < material_file_names.size(); ++i) + { + entropy_reader.push_back(std::make_unique()); + entropy_reader[i]->initialize(this->get_mpi_communicator(), data_directory, material_file_names[i]); + } + + lateral_viscosity_prefactor_lookup = std::make_unique(data_directory+lateral_viscosity_file_name, + this->get_mpi_communicator()); + } + + + + template + bool + EntropyModel:: + is_compressible () const + { + return true; + } + + + + template + double + EntropyModel:: + thermal_conductivity (const double temperature, + const double pressure, + const Point &position) const + { + if (conductivity_formulation == constant) + return thermal_conductivity_value; + + else if (conductivity_formulation == p_T_dependent) + { + // Find the conductivity layer that corresponds to the depth of the evaluation point. + const double depth = this->get_geometry_model().depth(position); + unsigned int layer_index = std::distance(conductivity_transition_depths.begin(), + std::lower_bound(conductivity_transition_depths.begin(),conductivity_transition_depths.end(), depth)); + + const double p_dependence = reference_thermal_conductivities[layer_index] + conductivity_pressure_dependencies[layer_index] * pressure; + + // Make reasonably sure we will not compute any invalid values due to the temperature-dependence. + // Since both the temperature-dependence and the saturation time scale with (Tref/T), we have to + // make sure we can compute the square of this number. If the temperature is small enough to + // be close to yielding NaN values, the conductivity will be set to the maximum value anyway. + const double T = std::max(temperature, std::sqrt(std::numeric_limits::min()) * conductivity_reference_temperatures[layer_index]); + const double T_dependence = std::pow(conductivity_reference_temperatures[layer_index] / T, conductivity_exponents[layer_index]); + + // Function based on the theory of Roufosse and Klemens (1974) that accounts for saturation. + // For the Tosi formulation, the scaling should be zero so that this term is 1. + double saturation_function = 1.0; + if (1./T_dependence > 1.) + saturation_function = (1. - saturation_scaling[layer_index]) + + saturation_scaling[layer_index] * (2./3. * std::sqrt(T_dependence) + 1./3. * 1./T_dependence); + + return std::min(p_dependence * saturation_function * T_dependence, maximum_conductivity); + } + else + { + AssertThrow(false, ExcNotImplemented()); + return numbers::signaling_nan(); + } + } + + + + template + void + EntropyModel::evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + const unsigned int projected_density_index = this->introspection().compositional_index_for_name("density_field"); + //TODO : need to make it work for more than one field + const std::vector &entropy_indices = this->introspection().get_indices_for_fields_of_type(CompositionalFieldDescription::entropy); + const unsigned int entropy_index = entropy_indices[0]; + const std::vector &composition_indices = this->introspection().get_indices_for_fields_of_type(CompositionalFieldDescription::chemical_composition); + + AssertThrow(composition_indices.size() == material_file_names.size() - 1, + ExcMessage("The 'entropy model' material model assumes that there exists a background field in addition to the compositional fields, " + "and therefore it requires one more lookup table than there are chemical compositional fields.")); + + EquationOfStateOutputs eos_outputs (material_file_names.size()); + std::vector volume_fractions (material_file_names.size()); + std::vector mass_fractions (material_file_names.size()); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + // Use the adiabatic pressure instead of the real one, + // to stabilize against pressure oscillations in phase transitions. + // This is a requirement of the projected density approximation for + // the Stokes equation and not related to the entropy formulation. + // Also convert pressure from Pa to bar, bar is used in the table. + const double entropy = in.composition[i][entropy_index]; + const double pressure = this->get_adiabatic_conditions().pressure(in.position[i]) / 1.e5; + + // Loop over all material files, and store the looked-up values for all compositions. + for (unsigned int j=0; jdensity(entropy, pressure); + eos_outputs.thermal_expansion_coefficients[j] = entropy_reader[j]->thermal_expansivity(entropy,pressure); + eos_outputs.specific_heat_capacities[j] = entropy_reader[j]->specific_heat(entropy,pressure); + + const Tensor<1, 2> pressure_unit_vector({0.0, 1.0}); + eos_outputs.compressibilities[j] = ((entropy_reader[j]->density_gradient(entropy,pressure)) * pressure_unit_vector) / eos_outputs.densities[j]; + } + + // Calculate volume fractions from mass fractions + // If there is only one lookup table, set the mass and volume fractions to 1 + if (material_file_names.size() == 1) + mass_fractions [0] = 1.0; + + else + { + // We only want to compute mass/volume fractions for fields that are chemical compositions. + mass_fractions = MaterialUtilities::compute_only_composition_fractions(in.composition[i], this->introspection().chemical_composition_field_indices()); + } + + volume_fractions = MaterialUtilities::compute_volumes_from_masses(mass_fractions, + eos_outputs.densities, + true); + + out.densities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.densities, MaterialUtilities::arithmetic); + out.thermal_expansion_coefficients[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.thermal_expansion_coefficients, MaterialUtilities::arithmetic); + + out.specific_heat[i] = MaterialUtilities::average_value (mass_fractions, eos_outputs.specific_heat_capacities, MaterialUtilities::arithmetic); + + out.compressibilities[i] = MaterialUtilities::average_value (mass_fractions, eos_outputs.compressibilities, MaterialUtilities::arithmetic); + + // Thermal conductivity can be pressure temperature dependent + const double temperature_lookup = entropy_reader[0]->temperature(entropy,pressure); + out.thermal_conductivities[i] = thermal_conductivity(temperature_lookup, in.pressure[i], in.position[i]); + + out.entropy_derivative_pressure[i] = 0.; + out.entropy_derivative_temperature[i] = 0.; + for (unsigned int c=0; c *prescribed_field_out = out.template get_additional_output>()) + { + prescribed_field_out->prescribed_field_outputs[i][projected_density_index] = out.densities[i]; + } + + // set up variable to interpolate prescribed field outputs onto temperature field + if (PrescribedTemperatureOutputs *prescribed_temperature_out = out.template get_additional_output>()) + { + prescribed_temperature_out->prescribed_temperature_outputs[i] = temperature_lookup; + } + + // Calculate Viscosity + if (in.requests_property(MaterialProperties::viscosity)) + { + // read in the viscosity profile + const double depth = this->get_geometry_model().depth(in.position[i]); + const double viscosity_profile = depth_dependent_rheology->compute_viscosity(depth); + + // lateral viscosity variations + const double reference_temperature = this->get_adiabatic_conditions().is_initialized() + ? + this->get_adiabatic_conditions().temperature(in.position[i]) + : + this->get_parameters().adiabatic_surface_temperature; + + const double delta_temperature = temperature_lookup-reference_temperature; + + // Steinberger & Calderwood viscosity + if (temperature_lookup*reference_temperature == 0) + out.viscosities[i] = max_eta; + else + { + double vis_lateral = std::exp(-lateral_viscosity_prefactor_lookup->lateral_viscosity(depth)*delta_temperature/(temperature_lookup*reference_temperature)); + // lateral vis variation + vis_lateral = std::max(std::min((vis_lateral),max_lateral_eta_variation),1/max_lateral_eta_variation); + + if (std::isnan(vis_lateral)) + vis_lateral = 1.0; + + double effective_viscosity = vis_lateral * viscosity_profile; + + const double strain_rate_effective = std::fabs(second_invariant(deviator(in.strain_rate[i]))); + + if (std::sqrt(strain_rate_effective) >= std::numeric_limits::min()) + { + const double pressure = this->get_adiabatic_conditions().pressure(in.position[i]); + const double eta_plastic = drucker_prager_plasticity.compute_viscosity(cohesion, + angle_of_internal_friction, + pressure, + std::sqrt(strain_rate_effective), + std::numeric_limits::infinity()); + + effective_viscosity = 1.0 / ( ( 1.0 / eta_plastic ) + ( 1.0 / (vis_lateral * viscosity_profile) ) ); + + PlasticAdditionalOutputs *plastic_out = out.template get_additional_output>(); + if (plastic_out != nullptr) + { + plastic_out->cohesions[i] = cohesion; + plastic_out->friction_angles[i] = angle_of_internal_friction; + plastic_out->yielding[i] = eta_plastic < (vis_lateral * viscosity_profile) ? 1 : 0; + } + } + out.viscosities[i] = std::max(std::min(effective_viscosity,max_eta),min_eta); + } + } + + // fill seismic velocities outputs if they exist + if (SeismicAdditionalOutputs *seismic_out = out.template get_additional_output>()) + { + + std::vector vp (material_file_names.size()); + std::vector vs (material_file_names.size()); + for (unsigned int j=0; jseismic_vp(entropy,pressure); + vs[j] = entropy_reader[j]->seismic_vs(entropy,pressure); + } + seismic_out->vp[i] = MaterialUtilities::average_value (volume_fractions, vp, MaterialUtilities::arithmetic); + seismic_out->vs[i] = MaterialUtilities::average_value (volume_fractions, vs, MaterialUtilities::arithmetic); + } + } + } + + + + template + void + EntropyModel::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Entropy model"); + { + prm.declare_entry ("Data directory", "$ASPECT_SOURCE_DIR/data/material-model/entropy-table/opxtable/", + Patterns::DirectoryName (), + "The path to the model data. The path may also include the special " + "text '$ASPECT_SOURCE_DIR' which will be interpreted as the path " + "in which the ASPECT source files were located when ASPECT was " + "compiled. This interpretation allows, for example, to reference " + "files located in the `data/' subdirectory of ASPECT."); + prm.declare_entry ("Material file name", "material_table.txt", + Patterns::List (Patterns::Anything()), + "The file name of the material data. The first material data file is intended for the background composition. "); + prm.declare_entry ("Reference viscosity", "1e22", + Patterns::Double(0), + "The viscosity that is used in this model. " + "\n\n" + "Units: \\si{\\pascal\\second}"); + prm.declare_entry ("Lateral viscosity file name", "temp-viscosity-prefactor.txt", + Patterns::Anything (), + "The file name of the lateral viscosity prefactor."); + prm.declare_entry ("Minimum viscosity", "1e19", + Patterns::Double (0.), + "The minimum viscosity that is allowed in the viscosity " + "calculation. Smaller values will be cut off."); + prm.declare_entry ("Maximum viscosity", "1e23", + Patterns::Double (0.), + "The maximum viscosity that is allowed in the viscosity " + "calculation. Larger values will be cut off."); + prm.declare_entry ("Maximum lateral viscosity variation", "1e2", + Patterns::Double (0.), + "The relative cutoff value for lateral viscosity variations " + "caused by temperature deviations. The viscosity may vary " + "laterally by this factor squared."); + prm.declare_entry ("Angle of internal friction", "0.", + Patterns::Double (0.), + "The value of the angle of internal friction, $\\phi$." + "For a value of zero, in 2D the von Mises criterion is retrieved. " + "Angles higher than 30 degrees are harder to solve numerically." + "Units: degrees."); + prm.declare_entry ("Cohesion", "1e20", + Patterns::Double (0.), + "The value of the cohesion, $C$. The extremely large default" + "cohesion value (1e20 Pa) prevents the viscous stress from " + "exceeding the yield stress. Units: \\si{\\pascal}."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Thermal conductivity formulation", "constant", + Patterns::Selection("constant|p-T-dependent"), + "Which law should be used to compute the thermal conductivity. " + "The 'constant' law uses a constant value for the thermal " + "conductivity. The 'p-T-dependent' formulation uses equations " + "from Stackhouse et al. (2015): First-principles calculations " + "of the lattice thermal conductivity of the lower mantle " + "(https://doi.org/10.1016/j.epsl.2015.06.050), and Tosi et al. " + "(2013): Mantle dynamics with pressure- and temperature-dependent " + "thermal expansivity and conductivity " + "(https://doi.org/10.1016/j.pepi.2013.02.004) to compute the " + "thermal conductivity in dependence of temperature and pressure. " + "The thermal conductivity parameter sets can be chosen in such a " + "way that either the Stackhouse or the Tosi relations are used. " + "The conductivity description can consist of several layers with " + "different sets of parameters. Note that the Stackhouse " + "parametrization is only valid for the lower mantle (bridgmanite)."); + prm.declare_entry ("Thermal conductivity transition depths", "410000, 520000, 660000", + Patterns::List(Patterns::Double (0.)), + "A list of depth values that indicate where the transitions between " + "the different conductivity parameter sets should occur in the " + "'p-T-dependent' Thermal conductivity formulation (in most cases, " + "this will be the depths of major mantle phase transitions). " + "Units: \\si{\\meter}."); + prm.declare_entry ("Reference thermal conductivities", "2.47, 3.81, 3.52, 4.9", + Patterns::List(Patterns::Double (0.)), + "A list of base values of the thermal conductivity for each of the " + "horizontal layers in the 'p-T-dependent' thermal conductivity " + "formulation. Pressure- and temperature-dependence will be applied" + "on top of this base value, according to the parameters 'Pressure " + "dependencies of thermal conductivity' and 'Reference temperatures " + "for thermal conductivity'. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}"); + prm.declare_entry ("Pressure dependencies of thermal conductivity", "3.3e-10, 3.4e-10, 3.6e-10, 1.05e-10", + Patterns::List(Patterns::Double ()), + "A list of values that determine the linear scaling of the " + "thermal conductivity with the pressure in the 'p-T-dependent' " + "thermal conductivity formulation. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin\\per\\pascal}."); + prm.declare_entry ("Reference temperatures for thermal conductivity", "300, 300, 300, 1200", + Patterns::List(Patterns::Double (0.)), + "A list of values of reference temperatures used to determine " + "the temperature-dependence of the thermal conductivity in the " + "'p-T-dependent' thermal conductivity formulation. " + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Thermal conductivity exponents", "0.48, 0.56, 0.61, 1.0", + Patterns::List(Patterns::Double (0.)), + "A list of exponents in the temperature-dependent term of the " + "'p-T-dependent' thermal conductivity formulation. Note that this " + "exponent is not used (and should have a value of 1) in the " + "formulation of Stackhouse et al. (2015). " + "Units: none."); + prm.declare_entry ("Saturation prefactors", "0, 0, 0, 1", + Patterns::List(Patterns::Double (0., 1.)), + "A list of values that indicate how a given layer in the " + "conductivity formulation should take into account the effects " + "of saturation on the temperature-dependence of the thermal " + "conducitivity. This factor is multiplied with a saturation function " + "based on the theory of Roufosse and Klemens, 1974. A value of 1 " + "reproduces the formulation of Stackhouse et al. (2015), a value of " + "0 reproduces the formulation of Tosi et al., (2013). " + "Units: none."); + prm.declare_entry ("Maximum thermal conductivity", "1000", + Patterns::Double (0.), + "The maximum thermal conductivity that is allowed in the " + "model. Larger values will be cut off."); + prm.leave_subsection(); + } + + // Depth-dependent parameters from the rheology plugin + Rheology::AsciiDepthProfile::declare_parameters(prm, + "Depth dependent viscosity"); + + prm.leave_subsection(); + } + } + + + + template + void + EntropyModel::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Entropy model"); + { + data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get ("Data directory")); + material_file_names = Utilities::split_string_list(prm.get ("Material file name")); + lateral_viscosity_file_name = prm.get ("Lateral viscosity file name"); + min_eta = prm.get_double ("Minimum viscosity"); + max_eta = prm.get_double ("Maximum viscosity"); + max_lateral_eta_variation = prm.get_double ("Maximum lateral viscosity variation"); + thermal_conductivity_value = prm.get_double ("Thermal conductivity"); + + if (prm.get ("Thermal conductivity formulation") == "constant") + conductivity_formulation = constant; + else if (prm.get ("Thermal conductivity formulation") == "p-T-dependent") + conductivity_formulation = p_T_dependent; + else + AssertThrow(false, ExcMessage("Not a valid thermal conductivity formulation")); + + conductivity_transition_depths = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Thermal conductivity transition depths"))); + const unsigned int n_conductivity_layers = conductivity_transition_depths.size() + 1; + AssertThrow (std::is_sorted(conductivity_transition_depths.begin(), conductivity_transition_depths.end()), + ExcMessage("The list of 'Thermal conductivity transition depths' must " + "be sorted such that the values increase monotonically.")); + + reference_thermal_conductivities = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Reference thermal conductivities"))), + n_conductivity_layers, + "Reference thermal conductivities"); + conductivity_pressure_dependencies = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Pressure dependencies of thermal conductivity"))), + n_conductivity_layers, + "Pressure dependencies of thermal conductivity"); + conductivity_reference_temperatures = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Reference temperatures for thermal conductivity"))), + n_conductivity_layers, + "Reference temperatures for thermal conductivity"); + conductivity_exponents = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Thermal conductivity exponents"))), + n_conductivity_layers, + "Thermal conductivity exponents"); + saturation_scaling = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Saturation prefactors"))), + n_conductivity_layers, + "Saturation prefactors"); + maximum_conductivity = prm.get_double ("Maximum thermal conductivity"); + + angle_of_internal_friction = prm.get_double ("Angle of internal friction") * constants::degree_to_radians; + cohesion = prm.get_double("Cohesion"); + + prm.leave_subsection(); + } + + depth_dependent_rheology = std::make_unique>(); + depth_dependent_rheology->initialize_simulator (this->get_simulator()); + depth_dependent_rheology->parse_parameters(prm, "Depth dependent viscosity"); + depth_dependent_rheology->initialize(); + + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::temperature; + this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + this->model_dependence.specific_heat = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + } + } + + + + template + void + EntropyModel::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> + (n_points, this->n_compositional_fields())); + } + + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> + (n_points)); + } + + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + } + + } +} + + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(EntropyModel, + "entropy model", + "A material model that is designed to use pressure and entropy (rather " + "than pressure and temperature) as independent variables. " + "It requires a thermodynamic data table that contains " + "all relevant properties in a specific format as illustrated in " + "the data/material-model/entropy-table/opxtable example folder. " + "The material model requires the use of the projected density " + "approximation for compressibility, and the existence of a " + "compositional field called 'entropy'.") + } +} diff --git a/source/material_model/equation_of_state/interface.cc.bak b/source/material_model/equation_of_state/interface.cc.bak new file mode 100644 index 00000000000..d414d108ca0 --- /dev/null +++ b/source/material_model/equation_of_state/interface.cc.bak @@ -0,0 +1,85 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + EquationOfStateOutputs::EquationOfStateOutputs(const unsigned int n_individual_compositions_and_phases) + : + densities(n_individual_compositions_and_phases, numbers::signaling_nan()), + thermal_expansion_coefficients(n_individual_compositions_and_phases, numbers::signaling_nan()), + specific_heat_capacities(n_individual_compositions_and_phases, numbers::signaling_nan()), + compressibilities(n_individual_compositions_and_phases, numbers::signaling_nan()), + entropy_derivative_pressure(n_individual_compositions_and_phases, numbers::signaling_nan()), + entropy_derivative_temperature(n_individual_compositions_and_phases, numbers::signaling_nan()) + {} + + + + template + void + phase_average_equation_of_state_outputs(const EquationOfStateOutputs &eos_outputs_all_phases, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition, + EquationOfStateOutputs &eos_outputs) + { + for (unsigned int c=0; c; \ + template void phase_average_equation_of_state_outputs (const EquationOfStateOutputs &, \ + const std::vector &phase_function_values, \ + const std::vector &n_phase_transitions_per_composition, \ + EquationOfStateOutputs &); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/equation_of_state/linearized_incompressible.cc.bak b/source/material_model/equation_of_state/linearized_incompressible.cc.bak new file mode 100644 index 00000000000..93459dbb073 --- /dev/null +++ b/source/material_model/equation_of_state/linearized_incompressible.cc.bak @@ -0,0 +1,160 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace EquationOfState + { + template + void + LinearizedIncompressible:: + evaluate(const MaterialModel::MaterialModelInputs &in, + const unsigned int q, + MaterialModel::EquationOfStateOutputs &out) const + { + + Assert(maximum_number_of_compositions+1 >= out.densities.size(), + ExcMessage("Error: You are trying to evaluate the equation of state with " + + Utilities::to_string(out.densities.size()-1) + + " compositional fields, which is larger than " + + Utilities::to_string(maximum_number_of_compositions) + + ", the number of fields the equation of state was set up with.")); + + + for (unsigned int c=0; c < out.densities.size(); ++c) + { + out.densities[c] = reference_rho * (1 - thermal_alpha * (in.temperature[q] - reference_T)); + if (c>0) + out.densities[c] += compositional_delta_rhos[c-1]; + + out.thermal_expansion_coefficients[c] = thermal_alpha; + out.specific_heat_capacities[c] = reference_specific_heat; + out.compressibilities[c] = 0.0; + out.entropy_derivative_pressure[c] = 0.0; + out.entropy_derivative_temperature[c] = 0.0; + } + } + + + + template + bool + LinearizedIncompressible:: + is_compressible () const + { + return false; + } + + + + template + void + LinearizedIncompressible::declare_parameters (ParameterHandler &prm, + const unsigned int n_compositions) + { + prm.declare_entry ("Reference density", "3300.", + Patterns::Double (0.), + "Reference density $\\rho_0$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. The reference temperature is used " + "in both the density and viscosity formulas. Units: \\si{\\kelvin}."); + prm.declare_entry ("Reference specific heat", "1250.", + Patterns::Double (0.), + "The value of the specific heat $C_p$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Thermal expansion coefficient", "2e-5", + Patterns::Double (0.), + "The value of the thermal expansion coefficient $\\alpha$. " + "Units: \\si{\\per\\kelvin}."); + if (n_compositions > 0) + prm.declare_entry ("Density differential for compositional field 1", "0.", + Patterns::Double(), + "If compositional fields are used, then one would frequently want " + "to make the density depend on these fields. In this simple material " + "model, we make the following assumptions: if no compositional fields " + "are used in the current simulation, then the density is simply the usual " + "one with its linear dependence on the temperature. If there are compositional " + "fields, then the material model determines how many of them influence the density. " + "The composition-dependence adds a term of the kind $+\\Delta \\rho \\; c_1(\\mathbf x)$. " + "This parameter describes the value of $\\Delta \\rho$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}/unit change in composition."); + if (n_compositions > 1) + prm.declare_entry ("Density differential for compositional field 2", "0.", + Patterns::Double(), + "If compositional fields are used, then one would frequently want " + "to make the density depend on these fields. In this simple material " + "model, we make the following assumptions: if no compositional fields " + "are used in the current simulation, then the density is simply the usual " + "one with its linear dependence on the temperature. If there are compositional " + "fields, then the material model determines how many of them influence the density. " + "The composition-dependence adds a term of the kind $+\\Delta \\rho \\; c_2(\\mathbf x)$. " + "This parameter describes the value of $\\Delta \\rho$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}/unit change in composition."); + } + + + + template + void + LinearizedIncompressible::parse_parameters (ParameterHandler &prm, + const unsigned int n_compositions) + { + reference_rho = prm.get_double ("Reference density"); + reference_T = prm.get_double ("Reference temperature"); + reference_specific_heat = prm.get_double ("Reference specific heat"); + thermal_alpha = prm.get_double ("Thermal expansion coefficient"); + + maximum_number_of_compositions = n_compositions; + compositional_delta_rhos.resize(maximum_number_of_compositions); + if (maximum_number_of_compositions > 0) + compositional_delta_rhos[0] = prm.get_double ("Density differential for compositional field 1"); + if (maximum_number_of_compositions > 1) + compositional_delta_rhos[1] = prm.get_double ("Density differential for compositional field 2"); + } + + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + namespace EquationOfState + { +#define INSTANTIATE(dim) \ + template class LinearizedIncompressible; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + } +} diff --git a/source/material_model/equation_of_state/multicomponent_compressible.cc.bak b/source/material_model/equation_of_state/multicomponent_compressible.cc.bak new file mode 100644 index 00000000000..a7652424cd4 --- /dev/null +++ b/source/material_model/equation_of_state/multicomponent_compressible.cc.bak @@ -0,0 +1,177 @@ +/* + Copyright (C) 2011 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace EquationOfState + { + template + void + MulticomponentCompressible:: + evaluate(const MaterialModel::MaterialModelInputs &in, + const unsigned int q, + MaterialModel::EquationOfStateOutputs &out) const + { + + const double pressure = in.pressure[q]; + const double temperature = std::max(in.temperature[q], 1.); // temperature can't be zero for correct evaluation + + for (unsigned int c=0; c < out.densities.size(); ++c) + { + const double ak = reference_thermal_expansivities[c]/reference_isothermal_compressibilities[c]; + const double f = (1. + (pressure - ak*(temperature - reference_temperatures[c])) * + isothermal_bulk_modulus_pressure_derivatives[c] * + reference_isothermal_compressibilities[c]); + + out.densities[c] = reference_densities[c]*std::pow(f, 1./isothermal_bulk_modulus_pressure_derivatives[c]); + out.thermal_expansion_coefficients[c] = reference_thermal_expansivities[c] / f; + out.specific_heat_capacities[c] = (isochoric_specific_heats[c] + + (temperature*reference_thermal_expansivities[c] * + ak * std::pow(f, -1.-(1./isothermal_bulk_modulus_pressure_derivatives[c])) + / reference_densities[c])); + out.compressibilities[c] = reference_isothermal_compressibilities[c]/f; + out.entropy_derivative_pressure[c] = 0.; + out.entropy_derivative_temperature[c] = 0.; + } + } + + + + template + bool + MulticomponentCompressible:: + is_compressible () const + { + return true; + } + + + + template + void + MulticomponentCompressible::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Reference temperatures", "298.15", + Patterns::List(Patterns::Double (0.)), + "List of reference temperatures $T_0$ for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. Units: \\si{\\kelvin}."); + prm.declare_entry ("Reference densities", "3300.", + Patterns::List(Patterns::Double (0.)), + "List of densities for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference isothermal compressibilities", "4e-12", + Patterns::List(Patterns::Double (0.)), + "List of isothermal compressibilities for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("Isothermal bulk modulus pressure derivatives", "4.", + Patterns::List(Patterns::Double (0.)), + "List of isothermal pressure derivatives of the bulk moduli for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. " + "Units: []."); + prm.declare_entry ("Reference thermal expansivities", "4.e-5", + Patterns::List(Patterns::Double (0.)), + "List of thermal expansivities for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Isochoric specific heats", "1250.", + Patterns::List(Patterns::Double (0.)), + "List of isochoric specific heats $C_v$ for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + } + + + + template + void + MulticomponentCompressible::parse_parameters (ParameterHandler &prm) + { + // Establish that a background field is required here + const bool has_background_field = true; + + // Retrieve the list of composition names + const std::vector list_of_composition_names = this->introspection().get_composition_names(); + + // Parse multicomponent properties + reference_temperatures = Utilities::parse_map_to_double_array (prm.get("Reference temperatures"), + list_of_composition_names, + has_background_field, + "Reference temperatures"); + + reference_densities = Utilities::parse_map_to_double_array (prm.get("Reference densities"), + list_of_composition_names, + has_background_field, + "Reference densities"); + + reference_isothermal_compressibilities = Utilities::parse_map_to_double_array (prm.get("Reference isothermal compressibilities"), + list_of_composition_names, + has_background_field, + "Reference isothermal compressibilities"); + + isothermal_bulk_modulus_pressure_derivatives = Utilities::parse_map_to_double_array (prm.get("Isothermal bulk modulus pressure derivatives"), + list_of_composition_names, + has_background_field, + "Isothermal bulk modulus pressure derivatives"); + + reference_thermal_expansivities = Utilities::parse_map_to_double_array (prm.get("Reference thermal expansivities"), + list_of_composition_names, + has_background_field, + "Reference thermal expansivities"); + + isochoric_specific_heats = Utilities::parse_map_to_double_array (prm.get("Isochoric specific heats"), + list_of_composition_names, + has_background_field, + "Isochoric specific heats"); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + namespace EquationOfState + { +#define INSTANTIATE(dim) \ + template class MulticomponentCompressible; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + } +} diff --git a/source/material_model/equation_of_state/multicomponent_incompressible.cc.bak b/source/material_model/equation_of_state/multicomponent_incompressible.cc.bak new file mode 100644 index 00000000000..3e8c0066e8d --- /dev/null +++ b/source/material_model/equation_of_state/multicomponent_incompressible.cc.bak @@ -0,0 +1,156 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace EquationOfState + { + template + void + MulticomponentIncompressible:: + evaluate(const MaterialModel::MaterialModelInputs &in, + const unsigned int input_index, + MaterialModel::EquationOfStateOutputs &out) const + { + + + // If adiabatic heating is used, the reference temperature used to calculate density should be the adiabatic + // temperature at the current position. This definition is consistent with the Extended Boussinesq Approximation. + const double reference_temperature = (this->include_adiabatic_heating() + ? + this->get_adiabatic_conditions().temperature(in.position[input_index]) + : + reference_T); + + for (unsigned int c=0; c < out.densities.size(); ++c) + { + out.densities[c] = densities[c] * (1 - thermal_expansivities[c] * (in.temperature[input_index] - reference_temperature)); + out.thermal_expansion_coefficients[c] = thermal_expansivities[c]; + out.specific_heat_capacities[c] = specific_heats[c]; + out.compressibilities[c] = 0.0; + out.entropy_derivative_pressure[c] = 0.0; + out.entropy_derivative_temperature[c] = 0.0; + } + } + + + + template + bool + MulticomponentIncompressible:: + is_compressible () const + { + return false; + } + + + + template + void + MulticomponentIncompressible::declare_parameters (ParameterHandler &prm, + const double default_thermal_expansion) + { + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. Units: \\si{\\kelvin}."); + prm.declare_entry ("Densities", "3300.", + Patterns::Anything(), + "List of densities for background mantle and compositional fields," + "for a total of N+M+1 values, where N is the number of compositional fields and M is the number of phases. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Thermal expansivities", std::to_string(default_thermal_expansion), + Patterns::Anything(), + "List of thermal expansivities for background mantle and compositional fields," + "for a total of N+M+1 values, where N is the number of compositional fields and M is the number of phases. " + "If only one value is given, then all use the same value. Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Heat capacities", "1250.", + Patterns::Anything(), + "List of specific heats $C_p$ for background mantle and compositional fields," + "for a total of N+M+1 values, where N is the number of compositional fields and M is the number of phases. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_alias ("Heat capacities", "Specific heats"); + } + + + + template + void + MulticomponentIncompressible::parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition) + { + reference_T = prm.get_double ("Reference temperature"); + + // Make options file for parsing maps to double arrays + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + chemical_field_names.insert(chemical_field_names.begin(),"background"); + + std::vector compositional_field_names = this->introspection().get_composition_names(); + compositional_field_names.insert(compositional_field_names.begin(),"background"); + + Utilities::MapParsing::Options options(chemical_field_names, "Densities"); + options.list_of_allowed_keys = compositional_field_names; + options.allow_multiple_values_per_key = true; + if (expected_n_phases_per_composition) + { + options.n_values_per_key = *expected_n_phases_per_composition; + + // check_values_per_key is required to be true to duplicate single values + // if they are to be used for all phases associated with a given key. + options.check_values_per_key = true; + } + + // Parse multicomponent properties + densities = Utilities::MapParsing::parse_map_to_double_array(prm.get("Densities"), options); + options.property_name = "Thermal expansivities"; + thermal_expansivities = Utilities::MapParsing::parse_map_to_double_array(prm.get("Thermal expansivities"), options); + options.property_name = "Heat capacities"; + specific_heats = Utilities::MapParsing::parse_map_to_double_array (prm.get("Heat capacities"), options); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + namespace EquationOfState + { +#define INSTANTIATE(dim) \ + template class MulticomponentIncompressible; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + } +} diff --git a/source/material_model/equation_of_state/thermodynamic_table_lookup.cc.bak b/source/material_model/equation_of_state/thermodynamic_table_lookup.cc.bak new file mode 100644 index 00000000000..40ebfaac66e --- /dev/null +++ b/source/material_model/equation_of_state/thermodynamic_table_lookup.cc.bak @@ -0,0 +1,579 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace EquationOfState + { + template + void + ThermodynamicTableLookup::initialize() + { + // This model allows the user to provide several PerpleX or HeFESTo + // P-T lookup files, each of which corresponds to a different material. + // The thermodynamic properties and stable mineral phases within each material + // will in general be different, and must be averaged in a reasonable way. + + // In the following, we populate the material_lookups. + // We also populate the unique_phase_names vector, which is used to + // calculate the phase volumes if they are provided by the lookup. + // This equation of state sums the volume fractions of + // phases from different lookups if they have the same phase name. + std::set set_phase_volume_column_names; + + unique_phase_indices.resize(n_material_lookups, std::vector()); + global_index_of_lookup_phase.resize (n_material_lookups, std::vector()); + + for (unsigned i = 0; i < n_material_lookups; ++i) + { + if (material_file_format == perplex) + material_lookup + .push_back(std::make_unique(data_directory+material_file_names[i], + use_bilinear_interpolation, + this->get_mpi_communicator())); + else if (material_file_format == hefesto) + material_lookup + .push_back(std::make_unique(data_directory+material_file_names[i], + data_directory+derivatives_file_names[i], + use_bilinear_interpolation, + this->get_mpi_communicator())); + else + AssertThrow (false, ExcNotImplemented()); + + // Here we look up all of the column names and insert + // unique names into the unique_phase_names vector and + // filling the unique_phase_indices object. + std::vector phase_volume_column_names = material_lookup[i]->phase_volume_column_names(); + for (const auto &phase_volume_column_name : phase_volume_column_names) + { + // iterate over the present unique_phase_names object + // to find phase_volume_column_name. + std::vector::iterator it = std::find(unique_phase_names.begin(), + unique_phase_names.end(), + phase_volume_column_name); + + // If phase_volume_column_name already exists in unique_phase_names, + // std::distance finds its index. Otherwise, std::distance will return + // the size of the present object, which is the index where we are + // about to push the new name. Either way, this is the index we want + // to add to the unique_phase_indices[i] vector. + unsigned int i_unique = std::distance(unique_phase_names.begin(), it); + unique_phase_indices[i].push_back(i_unique); + + // If phase_volume_column_name did not already exist + // in unique_phase_names, we add it here. + if (it == unique_phase_names.end()) + unique_phase_names.push_back(phase_volume_column_name); + } + + // Do the same for the dominant phases + std::vector phase_names_one_lookup = material_lookup[i]->get_dominant_phase_names(); + for (const auto &phase_name : phase_names_one_lookup) + { + std::vector::iterator it = std::find(list_of_dominant_phases.begin(), + list_of_dominant_phases.end(), + phase_name); + + // Each lookup only stores the index for the individual lookup, so we have to know + // how to convert from the indices of the individual lookup to the index in the + // list_of_dominant_phases vector. Here we fill the global_index_of_lookup_phase + // object to contain the global indices. + global_index_of_lookup_phase[i].push_back(std::distance(list_of_dominant_phases.begin(), it)); + + if (it == list_of_dominant_phases.end()) + list_of_dominant_phases.push_back(phase_name); + } + + // Make sure that either all or none of the tables have a column with the dominant phase. + AssertThrow(material_lookup[0]->has_dominant_phase() == material_lookup[i]->has_dominant_phase(), + ExcMessage("Some of the lookup tables you read in contain outputs for the dominant phase, " + "as indicated by the column 'phase', but in at least of of the tables you use " + "this column is missing.")); + } + + // Since the visualization output can only contain numbers and not strings + // we have to output the index instead of the name of the phase. + // We write out a data file that contains the list of dominant phases so + // that it is clear which index corresponds to which phase from the table. + const std::string filename = (this->get_output_directory() + + "thermodynamic_lookup_table_phases.txt"); + + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0 + && list_of_dominant_phases.size() > 0) + { + std::ofstream file; + file.open(filename); + file << "# " << std::endl; + for (unsigned int p=0; p did not succeed in the `phase outputs' additional names outputs " + "visualization postprocessor.")); + file.close(); + } + } + + + + template + unsigned int + ThermodynamicTableLookup::number_of_lookups() const + { + return n_material_lookups; + } + + + + template + bool + ThermodynamicTableLookup:: + is_compressible () const + { + return true; + } + + + + template + void + ThermodynamicTableLookup:: + fill_seismic_velocities (const MaterialModel::MaterialModelInputs &in, + const std::vector &composite_densities, + const std::vector> &volume_fractions, + SeismicAdditionalOutputs *seismic_out) const + { + // This function returns the Voigt-Reuss-Hill averages of the + // seismic velocities of the different materials. + + // Now we calculate the averaged moduli. + // mu = rho*Vs^2; K_s = rho*Vp^2 - 4./3.*mu + // The Voigt average is an arithmetic volumetric average, + // while the Reuss average is a harmonic volumetric average. + for (unsigned int i = 0; i < in.n_evaluation_points(); ++i) + { + if (material_lookup.size() == 1) + { + seismic_out->vs[i] = material_lookup[0]->seismic_Vs(in.temperature[i],in.pressure[i]); + seismic_out->vp[i] = material_lookup[0]->seismic_Vp(in.temperature[i],in.pressure[i]); + } + else + { + double k_voigt = 0.; + double mu_voigt = 0.; + double invk_reuss = 0.; + double invmu_reuss = 0.; + + for (unsigned int j = 0; j < material_lookup.size(); ++j) + { + const double mu = material_lookup[j]->density(in.temperature[i],in.pressure[i])*std::pow(material_lookup[j]->seismic_Vs(in.temperature[i],in.pressure[i]), 2.); + const double k = material_lookup[j]->density(in.temperature[i],in.pressure[i])*std::pow(material_lookup[j]->seismic_Vp(in.temperature[i],in.pressure[i]), 2.) - 4./3.*mu; + + k_voigt += volume_fractions[i][j] * k; + mu_voigt += volume_fractions[i][j] * mu; + invk_reuss += volume_fractions[i][j] / k; + invmu_reuss += volume_fractions[i][j] / mu; + } + + const double k_VRH = (k_voigt + 1./invk_reuss)/2.; + const double mu_VRH = (mu_voigt + 1./invmu_reuss)/2.; + seismic_out->vp[i] = std::sqrt((k_VRH + 4./3.*mu_VRH)/composite_densities[i]); + seismic_out->vs[i] = std::sqrt(mu_VRH/composite_densities[i]); + } + } + } + + + + template + void + ThermodynamicTableLookup:: + fill_phase_volume_fractions (const MaterialModel::MaterialModelInputs &in, + const std::vector> &volume_fractions, + NamedAdditionalMaterialOutputs *phase_volume_fractions_out) const + { + // Each call to material_lookup[j]->phase_volume_fraction(k,temperature,pressure) + // returns the volume fraction of the kth phase which is present in that material lookup + // at the requested temperature and pressure. + // The total volume fraction of each phase at each evaluation point is equal to + // sum_j (volume_fraction_of_material_j * phase_volume_fraction_in_material_j). + // In the following function, + // the index i corresponds to the ith evaluation point + // the index j corresponds to the jth compositional field + // the index k corresponds to the kth phase in the lookup + std::vector> phase_volume_fractions(unique_phase_names.size(), + std::vector(in.n_evaluation_points(), 0.)); + for (unsigned int i = 0; i < in.n_evaluation_points(); ++i) + for (unsigned j = 0; j < material_lookup.size(); ++j) + for (unsigned int k = 0; k < unique_phase_indices[j].size(); ++k) + phase_volume_fractions[unique_phase_indices[j][k]][i] += volume_fractions[i][j] * material_lookup[j]->phase_volume_fraction(k,in.temperature[i],in.pressure[i]); + + phase_volume_fractions_out->output_values = phase_volume_fractions; + } + + + + template + void + ThermodynamicTableLookup:: + fill_dominant_phases (const MaterialModel::MaterialModelInputs &in, + const std::vector> &volume_fractions, + PhaseOutputs &dominant_phases_out) const + { + Assert(material_lookup[0]->has_dominant_phase(), + ExcMessage("You are trying to fill in outputs for the dominant phase, " + "but these values do not exist in the material lookup.")); + + // Each call to material_lookup[j]->dominant_phase(temperature,pressure) + // returns the phase with the largest volume fraction in that material lookup + // at the requested temperature and pressure. + // In the following function, + // the index i corresponds to the ith evaluation point + // the index j corresponds to the jth compositional field + std::vector> dominant_phase_indices(1, std::vector(in.n_evaluation_points(), + std::numeric_limits::quiet_NaN())); + for (unsigned int i = 0; i < in.n_evaluation_points(); ++i) + { + const unsigned int dominant_material_index = std::distance(volume_fractions[i].begin(), std::max_element(volume_fractions[i].begin(), volume_fractions[i].end())); + const unsigned int dominant_phase_in_material = material_lookup[dominant_material_index]->dominant_phase(in.temperature[i],in.pressure[i]); + dominant_phase_indices[0][i] = global_index_of_lookup_phase[dominant_material_index][dominant_phase_in_material]; + } + dominant_phases_out.output_values = dominant_phase_indices; + } + + + + template + std::array,2> + ThermodynamicTableLookup:: + enthalpy_derivatives (const typename Interface::MaterialModelInputs &in) const + { + std::array,2> derivative; + + // get the pressures and temperatures at the vertices of the cell + const QTrapezoid quadrature_formula; + + const unsigned int n_q_points = quadrature_formula.size(); + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values); + + std::vector temperatures(n_q_points), pressures(n_q_points); + fe_values.reinit (in.current_cell); + + fe_values[this->introspection().extractors.temperature] + .get_function_values (this->get_current_linearization_point(), temperatures); + fe_values[this->introspection().extractors.pressure] + .get_function_values (this->get_current_linearization_point(), pressures); + + AssertThrow (n_material_lookups == 1, + ExcMessage("This formalism is only implemented for one material " + "table.")); + + // We have to take into account here that the p,T spacing of the table of material properties + // we use might be on a finer grid than our model. Because of that we compute the enthalpy + // derivatives by using finite differences that average over the whole temperature and + // pressure range that is used in this cell. This way we should not miss any phase transformation. + derivative = material_lookup[0]->enthalpy_derivatives(temperatures, + pressures, + max_latent_heat_substeps); + + return derivative; + } + + + + template + void + ThermodynamicTableLookup:: + evaluate(const MaterialModel::MaterialModelInputs &in, + std::vector> &eos_outputs) const + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const double pressure = in.pressure[i]; + const double temperature = in.temperature[i]; + + for (unsigned int j=0; jdensity(temperature, pressure); + eos_outputs[i].compressibilities[j] = material_lookup[j]->dRhodp(temperature, pressure)/eos_outputs[i].densities[j]; + + // Only calculate the non-reactive specific heat and + // thermal expansivity if latent heat is to be ignored. + if (!latent_heat) + { + eos_outputs[i].thermal_expansion_coefficients[j] = material_lookup[j]->thermal_expansivity(temperature, pressure); + eos_outputs[i].specific_heat_capacities[j] = material_lookup[j]->specific_heat(temperature, pressure); + } + + eos_outputs[i].entropy_derivative_pressure[j] = 0.; + eos_outputs[i].entropy_derivative_temperature[j] = 0.; + } + } + // Calculate the specific heat and thermal expansivity + // including the effects of reaction. + if (latent_heat) + { + evaluate_thermal_enthalpy_derivatives(in, eos_outputs); + } + } + + + + template + void + ThermodynamicTableLookup:: + evaluate_thermal_enthalpy_derivatives(const MaterialModel::MaterialModelInputs &in, + std::vector> &eos_outputs) const + { + // The second derivatives of the thermodynamic potentials (compressibility, thermal expansivity, specific heat) + // are dependent not only on the phases present in the assemblage at the given temperature and pressure, + // but also on any reactions between phases in the assemblage. PerpleX and HeFESTo output only "static" properties + // (properties not including any reaction effects), and so do not capture the latent heat of reaction. + + // In this material model, we always use a compressibility which includes the effects of reaction, + // but we allow the user the option to switch on or off thermal (latent heat) effects. + // If the latent_heat bool is set to true, thermal expansivity and specific heat are calculated from + // the change in enthalpy with pressure and temperature. + + // There are alternative ways to capture the latent heat effect (by preprocessing the P-T table, for example), + // which may be a more appropriate approach in some cases, but the latent heat should always be considered if + // thermodynamic self-consistency is intended. + + // The affected properties are computed using the partial derivatives of the enthalpy + // with respect to pressure and temperature: + // thermal expansivity = (1 - rho * (dH/dp)_T) / T + // specific heat capacity = (dH/dT)_P + // where the subscript indicates the natural variable which is held constant. + double average_temperature(0.0); + double average_density(0.0); + std::array,2> dH; + + for (unsigned int i = 0; i < in.n_evaluation_points(); ++i) + { + average_temperature += in.temperature[i]; + average_density += eos_outputs[i].densities[0]; + } + average_temperature /= in.n_evaluation_points(); + average_density /= in.n_evaluation_points(); + + if (in.current_cell.state() == IteratorState::valid) + dH = enthalpy_derivatives(in); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + // Use the adiabatic pressure instead of the real one, + // to stabilize against pressure oscillations in phase transitions + const double pressure = this->get_adiabatic_conditions().pressure(in.position[i]); + + if ((in.current_cell.state() == IteratorState::valid) + && (dH[0].second > 0) && (dH[1].second > 0)) + { + eos_outputs[i].thermal_expansion_coefficients[0] = (1 - average_density * dH[1].first) / average_temperature; + eos_outputs[i].specific_heat_capacities[0] = dH[0].first; + } + else + { + eos_outputs[i].thermal_expansion_coefficients[0] = (1 - eos_outputs[i].densities[0] * material_lookup[0]->dHdp(in.temperature[i],pressure)) / in.temperature[i]; + eos_outputs[i].specific_heat_capacities[0] = material_lookup[0]->dHdT(in.temperature[i],pressure); + } + } + } + + + + template + void + ThermodynamicTableLookup::fill_additional_outputs (const MaterialModel::MaterialModelInputs &in, + const std::vector> &volume_fractions, + MaterialModel::MaterialModelOutputs &out) const + { + // fill seismic velocity outputs if they exist + if (SeismicAdditionalOutputs *seismic_out = out.template get_additional_output>()) + fill_seismic_velocities(in, out.densities, volume_fractions, seismic_out); + + // fill phase volume outputs if they exist + if (NamedAdditionalMaterialOutputs *phase_volume_fractions_out = out.template get_additional_output>()) + fill_phase_volume_fractions(in, volume_fractions, phase_volume_fractions_out); + + if (PhaseOutputs *dominant_phases_out = out.template get_additional_output>()) + fill_dominant_phases(in, volume_fractions, *dominant_phases_out); + } + + + + template + void + ThermodynamicTableLookup::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Data directory", "$ASPECT_SOURCE_DIR/data/material-model/steinberger/", + Patterns::DirectoryName (), + "The path to the model data. The path may also include the special " + "text '$ASPECT_SOURCE_DIR' which will be interpreted as the path " + "in which the ASPECT source files were located when ASPECT was " + "compiled. This interpretation allows, for example, to reference " + "files located in the `data/' subdirectory of ASPECT. "); + prm.declare_entry ("Material file names", "pyr-ringwood88.txt", + Patterns::List (Patterns::Anything()), + "The file names of the material data (material " + "data is assumed to be in order with the ordering " + "of the compositional fields). Note that there are " + "three options on how many files need to be listed " + "here: 1. If only one file is provided, it is used " + "for the whole model domain, and compositional fields " + "are ignored. 2. If there is one more file name than the " + "number of compositional fields, then the first file is " + "assumed to define a `background composition' that is " + "modified by the compositional fields. If there are " + "exactly as many files as compositional fields, the fields are " + "assumed to represent the fractions of different materials " + "and the average property is computed as a sum of " + "the value of the compositional field times the " + "material property of that field."); + prm.declare_entry ("Derivatives file names", "", + Patterns::List (Patterns::Anything()), + "The file names of the enthalpy derivatives data. " + "List with as many components as active " + "compositional fields (material data is assumed to " + "be in order with the ordering of the fields)."); + prm.declare_entry ("Material file format", "perplex", + Patterns::Selection ("perplex|hefesto"), + "The material file format to be read in the property " + "tables."); + prm.declare_entry ("Bilinear interpolation", "true", + Patterns::Bool (), + "Whether to use bilinear interpolation to compute " + "material properties (slower but more accurate). "); + prm.declare_entry ("Latent heat", "false", + Patterns::Bool (), + "Whether to include latent heat effects in the " + "calculation of thermal expansivity and specific heat. " + "If true, ASPECT follows the approach of Nakagawa et al. 2009, " + "using pressure and temperature derivatives of the enthalpy " + "to calculate the thermal expansivity and specific heat. " + "If false, ASPECT uses the thermal expansivity and " + "specific heat values from the material properties table."); + prm.declare_entry ("Maximum latent heat substeps", "1", + Patterns::Integer (1), + "The maximum number of substeps over the temperature pressure range " + "to calculate the averaged enthalpy gradient over a cell."); + } + + + + template + void + ThermodynamicTableLookup::parse_parameters (ParameterHandler &prm) + { + data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get ("Data directory")); + material_file_names = Utilities::split_string_list(prm.get ("Material file names")); + n_material_lookups = material_file_names.size(); + + derivatives_file_names = Utilities::split_string_list(prm.get ("Derivatives file names")); + use_bilinear_interpolation = prm.get_bool ("Bilinear interpolation"); + latent_heat = prm.get_bool ("Latent heat"); + max_latent_heat_substeps = prm.get_integer ("Maximum latent heat substeps"); + + if (prm.get ("Material file format") == "perplex") + material_file_format = perplex; + else if (prm.get ("Material file format") == "hefesto") + material_file_format = hefesto; + else + AssertThrow (false, ExcNotImplemented()); + + if (latent_heat) + AssertThrow (n_material_lookups == 1, + ExcMessage("Isochemical latent heat calculations are only implemented for a single material lookup.")); + + } + + + + template + void + ThermodynamicTableLookup::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (unique_phase_names, n_points)); + } + + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + + if (out.template get_additional_output>() == nullptr + && material_lookup[0]->has_dominant_phase()) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + } + + + + template + const MaterialModel::MaterialUtilities::Lookup::MaterialLookup & + ThermodynamicTableLookup::get_material_lookup (unsigned int lookup_index) const + { + return *material_lookup[lookup_index].get(); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + namespace EquationOfState + { +#define INSTANTIATE(dim) \ + template class ThermodynamicTableLookup; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + } +} diff --git a/source/material_model/grain_size.cc.bak b/source/material_model/grain_size.cc.bak new file mode 100644 index 00000000000..5f807ffa1ad --- /dev/null +++ b/source/material_model/grain_size.cc.bak @@ -0,0 +1,1687 @@ +/* + Copyright (C) 2014 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +using namespace dealii; + +namespace aspect +{ + namespace MaterialModel + { + namespace + { + std::vector make_dislocation_viscosity_outputs_names() + { + std::vector names; + names.emplace_back("dislocation_viscosity"); + names.emplace_back("diffusion_viscosity"); + return names; + } + } + + + + template + DislocationViscosityOutputs::DislocationViscosityOutputs (const unsigned int n_points) + : + NamedAdditionalMaterialOutputs(make_dislocation_viscosity_outputs_names()), + dislocation_viscosities(n_points, numbers::signaling_nan()), + diffusion_viscosities(n_points, numbers::signaling_nan()) + {} + + + + template + std::vector + DislocationViscosityOutputs::get_nth_output(const unsigned int idx) const + { + AssertIndexRange (idx, 2); + switch (idx) + { + case 0: + return dislocation_viscosities; + + case 1: + return diffusion_viscosities; + + default: + AssertThrow(false, ExcInternalError()); + } + // we will never get here, so just return something + return dislocation_viscosities; + } + + + + template + void + GrainSize::initialize() + { + n_material_data = material_file_names.size(); + for (unsigned i = 0; i < n_material_data; ++i) + { + if (material_file_format == perplex) + material_lookup + .push_back(std::make_unique(datadirectory+material_file_names[i], + use_bilinear_interpolation, + this->get_mpi_communicator())); + else if (material_file_format == hefesto) + material_lookup + .push_back(std::make_unique(datadirectory+material_file_names[i], + datadirectory+derivatives_file_names[i], + use_bilinear_interpolation, + this->get_mpi_communicator())); + else + AssertThrow (false, ExcNotImplemented()); + } + + AssertThrow( (grain_size_evolution_formulation != Formulation::paleopiezometer || !this->get_heating_model_manager().shear_heating_enabled()), + ExcMessage("Shear heating output should not be used with the Paleopiezometer grain damage formulation.")); + } + + + + template + unsigned int + GrainSize:: + get_phase_index (const MaterialUtilities::PhaseFunctionInputs &in) const + { + Assert(grain_growth_activation_energy.size()>0, + ExcMessage("Error: No grain evolution parameters are given!")); + + // Since phase transition depth increases monotonically, we only need + // to check for the first phase that has not yet undergone the transition + // (phase function value lower than 0.5). + for (unsigned int j=0; j phase_inputs(in.temperature, + in.pressure, + in.depth, + in.pressure_depth_derivative, + j); + + if (phase_function.compute_value(phase_inputs) < 0.5) + return j; + } + + return n_phase_transitions; + } + + + + template + double + GrainSize:: + compute_partitioning_fraction (const double temperature) const + { + const double power_term_base = maximum_grain_size_reduction_work_fraction/minimum_grain_size_reduction_work_fraction; + + const double power_term_numerator = temperature_minimum_partitioning_power - + std::pow (temperature, grain_size_reduction_work_fraction_exponent); + + const double power_term_denominator = temperature_minimum_partitioning_power - + temperature_maximum_partitioning_power; + + // We have to ensure the power term exponent is between 0 and 1, otherwise the partitioning fraction + // will be outside the set bounds for the work fraction. + const double power_term_exponent = std::max(std::min(power_term_numerator / power_term_denominator, 1.0), 0.0); + + const double power_term = std::pow(power_term_base, + power_term_exponent); + + return minimum_grain_size_reduction_work_fraction * power_term; + } + + + + namespace + { + double moment_of_grain_size_distribution (const unsigned int n) + { + // This function normalizes the grain size distribution using the nth moment. + // Description can be found in eq 8 of Bercovici and Richard (2012) + // This is the variance of the log-normal distribution + const double sigma = 0.8; + + return std::exp(n * n * sigma * sigma / 2.); + } + + + + double phase_distribution_function (const double volume_fraction_phase_one) + { + // This factor is used in pinned state grain damage formulation. + const double volume_fraction_phase_two = 1. - volume_fraction_phase_one; + + return (volume_fraction_phase_one * volume_fraction_phase_two); + } + + + + double + roughness_to_grain_size_factor (const double volume_fraction_phase_one) + { + // This factor is used to convert from an interface roughness equation to a mean grain size + // Refer to Appendix H.1, eqs 8, F.28 in Bercovici and Richard (2012) for more details. + const double b1 = 1./20 ; + const double c1 = 3.0 * b1 * moment_of_grain_size_distribution(4) / (8.0 * moment_of_grain_size_distribution (2)); + + const double volume_fraction_phase_two = 1. - volume_fraction_phase_one; + + const double h1 = c1 * (1 - volume_fraction_phase_one); + const double h2 = c1 * (1 - volume_fraction_phase_two); + + const double one_over_sqrt_h = volume_fraction_phase_one / std::sqrt(h1) + volume_fraction_phase_two / std::sqrt(h2); + + return (1./one_over_sqrt_h); + } + } + + + + template + std::vector> + GrainSize:: + grain_size_change (const typename Interface::MaterialModelInputs &in, + const std::vector &pressures, + const std::vector &phase_indices) const + { + // We want to iterate over the grain size evolution here, as we solve in fact an ordinary differential equation + // and it is not correct to use the starting grain size (and it introduces instabilities). + // We assume that the strain rate is constant across all substeps for the ODE (within one advection step). + // Even though this assumption may not always be the most accurate (compared to assuming a constant stress), + // it leads to a more stable behavior because it implies that a reduction in grain size leads to less work + // being done by dislocation creep, so that the grain size reduction rate is lower in the next substep. + std::vector> reaction_terms (in.n_evaluation_points(), std::vector(this->n_compositional_fields(), 0.0)); + + // Set up a vector that tells us which phase transition has been crossed for each point we are evaluating. + std::vector crossed_transitions (in.n_evaluation_points(), -1); + + using VectorType = Vector; + VectorType grain_sizes(in.n_evaluation_points()); + for (unsigned int i=0; isimulator_is_past_initialization() + ? + this->get_timestep() + : + 0.0; + + if (std::all_of(grain_sizes.begin(), grain_sizes.end(), [](double gs) + { + return gs != gs || gs < std::numeric_limits::min(); + }) + || timestep == 0.0) + return reaction_terms; + + SUNDIALS::ARKode::AdditionalData data; + + data.initial_time = 0.0; + data.final_time = this->get_timestep(); + + // TODO: make this an input parameter. + data.initial_step_size = 0.001 * this->get_timestep(); + data.output_period = this->get_timestep(); + data.minimum_step_size = 1.e-6*this->get_timestep(); + data.maximum_order = 3; + data.maximum_non_linear_iterations = 30; + + // Because both tolerances are added, we set the absolute + // tolerance to 0. + data.relative_tolerance = 1e-3; + data.absolute_tolerance = 0; + + SUNDIALS::ARKode ode(data); + ode.explicit_function = [&] (const double /*time*/, + const VectorType &y, + VectorType &grain_size_rates_of_change) + { + for (unsigned int i=0; iget_adiabatic_conditions().is_initialized() + ? + this->get_adiabatic_conditions().temperature(in.position[i]) + : + in.temperature[i]; + + + + // grain size growth due to Ostwald ripening + const double m = grain_growth_exponent[phase_indices[i]]; + + double grain_size_growth_rate = grain_growth_rate_constant[phase_indices[i]] / (m * std::pow(grain_size,m-1)) + * std::exp(- (grain_growth_activation_energy[phase_indices[i]] + pressures[i] * grain_growth_activation_volume[phase_indices[i]]) + / (constants::gas_constant * in.temperature[i])); + + // in the two-phase damage model grain growth depends on the proportion of the two phases + if (grain_size_evolution_formulation == Formulation::pinned_grain_damage) + grain_size_growth_rate *= geometric_constant[phase_indices[i]] * phase_distribution / + std::pow(roughness_to_grain_size, m); + + // grain size reduction in dislocation creep regime + const SymmetricTensor<2,dim> shear_strain_rate = in.strain_rate[i] - 1./dim * trace(in.strain_rate[i]) * unit_symmetric_tensor(); + const double second_strain_rate_invariant = std::sqrt(std::max(-second_invariant(shear_strain_rate), 0.)); + + const double current_diffusion_viscosity = diffusion_viscosity(in.temperature[i], adiabatic_temperature, pressures[i], grain_size, second_strain_rate_invariant, phase_indices[i]); + current_dislocation_viscosity = dislocation_viscosity(in.temperature[i], adiabatic_temperature, pressures[i], in.strain_rate[i], phase_indices[i], current_diffusion_viscosity, current_dislocation_viscosity); + + double current_viscosity; + if (std::abs(second_strain_rate_invariant) > 1e-30) + current_viscosity = current_dislocation_viscosity * current_diffusion_viscosity / (current_dislocation_viscosity + current_diffusion_viscosity); + else + current_viscosity = current_diffusion_viscosity; + + const double dislocation_strain_rate = second_strain_rate_invariant + * current_viscosity / current_dislocation_viscosity; + + double grain_size_reduction_rate = 0.0; + + if (grain_size_evolution_formulation == Formulation::paleowattmeter) + { + // paleowattmeter: Austin and Evans (2007): Paleowattmeters: A scaling relation for dynamically recrystallized grain size. Geology 35, 343-346 + const double stress = 2.0 * second_strain_rate_invariant * std::min(std::max(min_eta,current_viscosity),max_eta); + grain_size_reduction_rate = 2.0 * stress * boundary_area_change_work_fraction[phase_indices[i]] * dislocation_strain_rate * grain_size * grain_size + / (geometric_constant[phase_indices[i]] * grain_boundary_energy[phase_indices[i]]); + } + else if (grain_size_evolution_formulation == Formulation::pinned_grain_damage) + { + // pinned_grain_damage: Mulyukova and Bercovici (2018) Collapse of passive margins by lithospheric damage and plunging grain size. Earth and Planetary Science Letters, 484, 341-352. + const double stress = 2.0 * second_strain_rate_invariant * std::min(std::max(min_eta,current_viscosity),max_eta); + grain_size_reduction_rate = 2.0 * stress * partitioning_fraction * second_strain_rate_invariant * grain_size * grain_size + * roughness_to_grain_size + / (geometric_constant[phase_indices[i]] * grain_boundary_energy[phase_indices[i]] * phase_distribution); + } + else if (grain_size_evolution_formulation == Formulation::paleopiezometer) + { + // paleopiezometer: Hall and Parmentier (2003): Influence of grain size evolution on convective instability. Geochem. Geophys. Geosyst., 4(3). + grain_size_reduction_rate = reciprocal_required_strain[phase_indices[i]] * dislocation_strain_rate * grain_size; + } + else + AssertThrow(false, ExcNotImplemented()); + + grain_size_rates_of_change[i] = grain_size_growth_rate - grain_size_reduction_rate; + } + }; + + + const unsigned int iteration_count = ode.solve_ode(grain_sizes); + this->get_signals().post_ARKode_solve(*this, iteration_count); + + for (unsigned int i=0; i 0, + ExcMessage("The grain size became smaller than zero. This is not valid, " + "and likely an effect of a too large sub-timestep, or unrealistic " + "input parameters.")); + + // reduce grain size to recrystallized_grain_size when crossing phase transitions + // if the distance in radial direction a grain moved compared to the last time step + // is crossing a phase transition, reduce grain size + + const double gravity_norm = this->get_gravity_model().gravity_vector(in.position[i]).norm(); + Tensor<1,dim> vertical_direction = this->get_gravity_model().gravity_vector(in.position[i]); + if (gravity_norm > 0.0) + vertical_direction /= gravity_norm; + + int crossed_transition = -1; + + // Figure out if the material in the current cell underwent a phase change. + // To do so, check if a grain has moved further than the distance from the phase transition and + // if the velocity is in the direction of the phase change. After the check 'crossed_transition' will + // be -1 if we crossed no transition, or the index of the phase transition, if we crossed it. + for (unsigned int phase=0; phaseget_geometry_model().depth(in.position[i]) - phase_function.get_transition_depth(phase); + const double distance_moved = in.velocity[i] * vertical_direction * timestep; + + // If we are close to the phase boundary (closer than the distance a grain has moved + // within one time step) and the velocity points away from the phase transition, + // then the material has crossed the transition. + // To make sure we actually reset the grain size of all the material passing through + // the transition, we take 110% of the distance a grain has moved for the check. + if (std::abs(distance_moved) * 1.1 > std::abs(distance_from_transition) + && + distance_moved * distance_from_transition >= 0) + crossed_transition = phase; + } + + // TODO: recrystallize first, and then do grain size growth/reduction for grains that crossed the transition + // in dependence of the distance they have moved + double phase_grain_size_reduction = 0.0; + if (this->get_timestep_number() > 0) + { + // check if material has crossed any phase transition, if yes, reset grain size + if (crossed_transition != -1) + if (recrystallized_grain_size[crossed_transition] > 0.0) + phase_grain_size_reduction = grain_sizes[i] - recrystallized_grain_size[crossed_transition]; + } + + grain_sizes[i] = std::max(grain_sizes[i], minimum_grain_size); + const double grain_size_change = grain_sizes[i] - in.composition[i][grain_size_index] - phase_grain_size_reduction; + + reaction_terms[i][grain_size_index] = grain_size_change; + // We do not have to fill the other fields because we have initialized them with zero. + } + + return reaction_terms; + } + + + + template + double + GrainSize:: + diffusion_viscosity (const double temperature, + const double adiabatic_temperature, + const double adiabatic_pressure, + const double grain_size, + const double second_strain_rate_invariant, + const unsigned int phase_index) const + { + double energy_term = std::exp((diffusion_activation_energy[phase_index] + diffusion_activation_volume[phase_index] * adiabatic_pressure) + / (diffusion_creep_exponent[phase_index] * constants::gas_constant * temperature)); + + // If the adiabatic profile is already calculated we can use it to limit + // variations in viscosity due to temperature. + if (this->get_adiabatic_conditions().is_initialized()) + { + const double adiabatic_energy_term + = std::exp((diffusion_activation_energy[phase_index] + diffusion_activation_volume[phase_index] * adiabatic_pressure) + / (diffusion_creep_exponent[phase_index] * constants::gas_constant * adiabatic_temperature)); + + const double temperature_dependence = energy_term / adiabatic_energy_term; + if (temperature_dependence > max_temperature_dependence_of_eta) + energy_term = adiabatic_energy_term * max_temperature_dependence_of_eta; + if (temperature_dependence < 1.0 / max_temperature_dependence_of_eta) + energy_term = adiabatic_energy_term / max_temperature_dependence_of_eta; + } + + const double strain_rate_dependence = (1.0 - diffusion_creep_exponent[phase_index]) / diffusion_creep_exponent[phase_index]; + + return diffusion_creep_prefactor[phase_index] + * std::pow(second_strain_rate_invariant,strain_rate_dependence) + * std::pow(grain_size, diffusion_creep_grain_size_exponent[phase_index]/diffusion_creep_exponent[phase_index]) + * energy_term; + } + + + + template + double + GrainSize:: + dislocation_viscosity (const double temperature, + const double adiabatic_temperature, + const double adiabatic_pressure, + const SymmetricTensor<2,dim> &strain_rate, + const unsigned int phase_index, + const double diffusion_viscosity, + const double viscosity_guess) const + { + // find out in which phase we are + double energy_term = std::exp((dislocation_activation_energy[phase_index] + dislocation_activation_volume[phase_index] * adiabatic_pressure) + / (dislocation_creep_exponent[phase_index] * constants::gas_constant * temperature)); + + // If we are past the initialization of the adiabatic profile, use it to + // limit viscosity variations due to temperature. + if (this->get_adiabatic_conditions().is_initialized()) + { + const double adiabatic_energy_term + = std::exp((dislocation_activation_energy[phase_index] + dislocation_activation_volume[phase_index] * adiabatic_pressure) + / (dislocation_creep_exponent[phase_index] * constants::gas_constant * adiabatic_temperature)); + + const double temperature_dependence = energy_term / adiabatic_energy_term; + if (temperature_dependence > max_temperature_dependence_of_eta) + energy_term = adiabatic_energy_term * max_temperature_dependence_of_eta; + if (temperature_dependence < 1.0 / max_temperature_dependence_of_eta) + energy_term = adiabatic_energy_term / max_temperature_dependence_of_eta; + } + + const double strain_rate_dependence = (1.0 - dislocation_creep_exponent[phase_index]) / dislocation_creep_exponent[phase_index]; + const SymmetricTensor<2,dim> shear_strain_rate = strain_rate - 1./dim * trace(strain_rate) * unit_symmetric_tensor(); + const double second_strain_rate_invariant = std::sqrt(std::max(-second_invariant(shear_strain_rate), 0.)); + + // If the strain rate is zero, the dislocation viscosity is infinity. + if (second_strain_rate_invariant <= std::numeric_limits::min()) + return std::numeric_limits::min(); + + // Start the iteration with the full strain rate + double dis_viscosity; + if (viscosity_guess == 0) + dis_viscosity = dislocation_creep_prefactor[phase_index] + * std::pow(second_strain_rate_invariant,strain_rate_dependence) + * energy_term; + else + dis_viscosity = viscosity_guess; + + double dis_viscosity_old = 0; + unsigned int i = 0; + while ((std::abs((dis_viscosity-dis_viscosity_old) / dis_viscosity) > dislocation_viscosity_iteration_threshold) + && (i < dislocation_viscosity_iteration_number)) + { + const SymmetricTensor<2,dim> dislocation_strain_rate = diffusion_viscosity + / (diffusion_viscosity + dis_viscosity) * shear_strain_rate; + const double dislocation_strain_rate_invariant = std::sqrt(std::max(-second_invariant(dislocation_strain_rate), 0.)); + + dis_viscosity_old = dis_viscosity; + dis_viscosity = dislocation_creep_prefactor[phase_index] + * std::pow(dislocation_strain_rate_invariant,strain_rate_dependence) + * energy_term; + ++i; + } + + Assert(i + double + GrainSize:: + enthalpy (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &/*position*/) const + { + AssertThrow ((reference_compressibility != 0.0) || use_table_properties, + ExcMessage("Currently only compressible models are supported.")); + + double enthalpy = 0.0; + if (n_material_data == 1) + enthalpy = material_lookup[0]->enthalpy(temperature,pressure); + else + { + for (unsigned i = 0; i < n_material_data; ++i) + enthalpy += compositional_fields[i] * material_lookup[i]->enthalpy(temperature,pressure); + } + return enthalpy; + } + + + + template + double + GrainSize:: + seismic_Vp (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &/*position*/) const + { + AssertThrow ((reference_compressibility != 0.0) || use_table_properties, + ExcMessage("Currently only compressible models are supported.")); + + double vp = 0.0; + if (n_material_data == 1) + vp = material_lookup[0]->seismic_Vp(temperature,pressure); + else + { + for (unsigned i = 0; i < n_material_data; ++i) + vp += compositional_fields[i] * material_lookup[i]->seismic_Vp(temperature,pressure); + } + return vp; + } + + + + template + double + GrainSize:: + seismic_Vs (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &/*position*/) const + { + AssertThrow ((reference_compressibility != 0.0) || use_table_properties, + ExcMessage("Currently only compressible models are supported.")); + + double vs = 0.0; + if (n_material_data == 1) + vs = material_lookup[0]->seismic_Vs(temperature,pressure); + else + { + for (unsigned i = 0; i < n_material_data; ++i) + vs += compositional_fields[i] * material_lookup[i]->seismic_Vs(temperature,pressure); + } + return vs; + } + + + + template + double + GrainSize:: + density (const double temperature, + const double pressure, + const std::vector &compositional_fields, /*composition*/ + const Point &) const + { + if (!use_table_properties) + { + return reference_rho * std::exp(reference_compressibility * (pressure - this->get_surface_pressure())) + * (1 - thermal_alpha * (temperature - reference_T)); + } + else + { + double rho = 0.0; + if (n_material_data == 1) + { + rho = material_lookup[0]->density(temperature,pressure); + } + else + { + for (unsigned i = 0; i < n_material_data; ++i) + rho += compositional_fields[i] * material_lookup[i]->density(temperature,pressure); + } + + return rho; + } + } + + + + template + bool + GrainSize:: + is_compressible () const + { + return (reference_compressibility != 0) + || use_table_properties; + } + + + + template + double + GrainSize:: + compressibility (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position) const + { + if (!use_table_properties) + return reference_compressibility; + + double dRhodp = 0.0; + if (n_material_data == 1) + dRhodp = material_lookup[0]->dRhodp(temperature,pressure); + else + { + for (unsigned i = 0; i < n_material_data; ++i) + dRhodp += compositional_fields[i] * material_lookup[i]->dRhodp(temperature,pressure); + } + const double rho = density(temperature,pressure,compositional_fields,position); + return (1/rho)*dRhodp; + } + + + + template + double + GrainSize:: + thermal_expansion_coefficient (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &/*position*/) const + { + double alpha = 0.0; + if (!use_table_properties) + return thermal_alpha; + else + { + if (n_material_data == 1) + alpha = material_lookup[0]->thermal_expansivity(temperature,pressure); + else + { + for (unsigned i = 0; i < n_material_data; ++i) + alpha += compositional_fields[i] * material_lookup[i]->thermal_expansivity(temperature,pressure); + } + } + alpha = std::max(std::min(alpha,max_thermal_expansivity),min_thermal_expansivity); + return alpha; + } + + + + template + double + GrainSize:: + specific_heat (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &/*position*/) const + { + double cp = 0.0; + if (!use_table_properties) + return reference_specific_heat; + else + { + if (n_material_data == 1) + cp = material_lookup[0]->specific_heat(temperature,pressure); + else + { + for (unsigned i = 0; i < n_material_data; ++i) + cp += compositional_fields[i] * material_lookup[i]->specific_heat(temperature,pressure); + } + } + cp = std::max(std::min(cp,max_specific_heat),min_specific_heat); + return cp; + } + + + + template + std::array,2> + GrainSize:: + enthalpy_derivative (const typename Interface::MaterialModelInputs &in) const + { + std::array,2> derivative; + + if (in.current_cell.state() == IteratorState::valid) + { + // get the pressures and temperatures at the vertices of the cell + const QTrapezoid quadrature_formula; + + std::vector solution_values(this->get_fe().dofs_per_cell); + in.current_cell->get_dof_values(this->get_current_linearization_point(), + solution_values.begin(), + solution_values.end()); + + // Only create the evaluator the first time we get here + if (!temperature_evaluator) + temperature_evaluator + = std::make_unique>(this->get_mapping(), + this->get_fe(), + update_values, + this->introspection().component_indices.temperature); + if (!pressure_evaluator) + pressure_evaluator + = std::make_unique>(this->get_mapping(), + this->get_fe(), + update_values, + this->introspection().component_indices.pressure); + + + // Initialize the evaluator for the temperature + temperature_evaluator->reinit(in.current_cell, quadrature_formula.get_points()); + temperature_evaluator->evaluate(solution_values, + EvaluationFlags::values); + + // Initialize the evaluator for the pressure + pressure_evaluator->reinit(in.current_cell, quadrature_formula.get_points()); + pressure_evaluator->evaluate(solution_values, + EvaluationFlags::values); + + std::vector temperatures(quadrature_formula.size()); + std::vector pressures(quadrature_formula.size()); + + for (unsigned int i=0; iget_value(i); + pressures[i] = pressure_evaluator->get_value(i); + } + + AssertThrow (material_lookup.size() == 1, + ExcMessage("This formalism is only implemented for one material " + "table.")); + + // We have to take into account here that the p,T spacing of the table of material properties + // we use might be on a finer grid than our model. Because of that we compute the enthalpy + // derivatives by using finite differences that average over the whole temperature and + // pressure range that is used in this cell. This way we should not miss any phase transformation. + derivative = material_lookup[0]->enthalpy_derivatives(temperatures, + pressures, + max_latent_heat_substeps); + } + + return derivative; + } + + + + template + void + GrainSize:: + evaluate(const typename Interface::MaterialModelInputs &in, typename Interface::MaterialModelOutputs &out) const + { + std::vector adiabatic_pressures (in.n_evaluation_points()); + std::vector phase_indices (in.n_evaluation_points()); + + for (unsigned int i=0; iget_adiabatic_conditions().is_initialized()) + ? + this->get_adiabatic_conditions().pressure(in.position[i]) + : + in.pressure[i]; + + const double gravity_norm = this->get_gravity_model().gravity_vector(in.position[i]).norm(); + + out.densities[i] = density(in.temperature[i], adiabatic_pressures[i], in.composition[i], in.position[i]); + out.thermal_conductivities[i] = k_value; + out.compressibilities[i] = compressibility(in.temperature[i], adiabatic_pressures[i], in.composition[i], in.position[i]); + + // We do not fill the phase function index, because that will be done internally in the get_phase_index() function + const double depth = this->get_geometry_model().depth(in.position[i]); + const double rho_g = out.densities[i] * gravity_norm; + MaterialUtilities::PhaseFunctionInputs phase_inputs(in.temperature[i], adiabatic_pressures[i], depth, rho_g, numbers::invalid_unsigned_int); + phase_indices[i] = get_phase_index(phase_inputs); + + if (in.requests_property(MaterialProperties::viscosity)) + { + double effective_viscosity; + double disl_viscosity = std::numeric_limits::max(); + Assert(std::isfinite(in.strain_rate[i].norm()), + ExcMessage("Invalid strain_rate in the MaterialModelInputs. This is likely because it was " + "not filled by the caller.")); + const SymmetricTensor<2,dim> shear_strain_rate = deviator(in.strain_rate[i]); + const double second_strain_rate_invariant = std::sqrt(std::max(-second_invariant(shear_strain_rate), 0.)); + + const double adiabatic_temperature = this->get_adiabatic_conditions().is_initialized() + ? + this->get_adiabatic_conditions().temperature(in.position[i]) + : + in.temperature[i]; + + // Make sure grain size is not negative/too small. + std::vector composition (in.composition[i]); + composition[grain_size_index] = std::max(min_grain_size,composition[grain_size_index]); + + const double diff_viscosity = diffusion_viscosity(in.temperature[i], + adiabatic_temperature, + adiabatic_pressures[i], + composition[grain_size_index], + second_strain_rate_invariant, + phase_indices[i]); + + if (std::abs(second_strain_rate_invariant) > 1e-30) + { + disl_viscosity = dislocation_viscosity(in.temperature[i], adiabatic_temperature, adiabatic_pressures[i], in.strain_rate[i], phase_indices[i], diff_viscosity); + effective_viscosity = disl_viscosity * diff_viscosity / (disl_viscosity + diff_viscosity); + } + else + effective_viscosity = diff_viscosity; + + if (enable_drucker_prager_rheology) + { + // Calculate non-yielding (viscous) stress magnitude. + const double non_yielding_stress = 2. * effective_viscosity * second_strain_rate_invariant; + + // The following handles phases + std::vector n_phases = {n_phase_transitions+1}; + std::vector phase_function_values(n_phase_transitions, 0.0); + + for (unsigned int k=0; k= yield_stress) + { + effective_viscosity = drucker_prager_plasticity.compute_viscosity(drucker_prager_parameters.cohesion, + drucker_prager_parameters.angle_internal_friction, + pressure_for_yielding, + second_strain_rate_invariant, + drucker_prager_parameters.max_yield_stress, + effective_viscosity); + } + + PlasticAdditionalOutputs *plastic_out = out.template get_additional_output>(); + + if (plastic_out != nullptr) + { + plastic_out->cohesions[i] = drucker_prager_parameters.cohesion; + plastic_out->friction_angles[i] = drucker_prager_parameters.angle_internal_friction; + plastic_out->yield_stresses[i] = yield_stress; + plastic_out->yielding[i] = non_yielding_stress >= yield_stress ? 1 : 0; + } + } + + out.viscosities[i] = std::min(std::max(min_eta,effective_viscosity),max_eta); + + if (DislocationViscosityOutputs *disl_viscosities_out = out.template get_additional_output>()) + { + disl_viscosities_out->dislocation_viscosities[i] = std::min(std::max(min_eta,disl_viscosity),1e300); + disl_viscosities_out->diffusion_viscosities[i] = std::min(std::max(min_eta,diff_viscosity),1e300); + } + + if (HeatingModel::ShearHeatingOutputs *shear_heating_out = out.template get_additional_output>()) + { + if (grain_size_evolution_formulation == Formulation::paleowattmeter) + { + const double f = boundary_area_change_work_fraction[phase_indices[i]]; + shear_heating_out->shear_heating_work_fractions[i] = 1. - f * out.viscosities[i] / std::min(std::max(min_eta,disl_viscosity),1e300); + } + else if (grain_size_evolution_formulation == Formulation::pinned_grain_damage) + { + const double f = compute_partitioning_fraction(in.temperature[i]); + shear_heating_out->shear_heating_work_fractions[i] = 1. - f; + } + else + AssertThrow(false, ExcNotImplemented()); + } + } + + // fill seismic velocities outputs if they exist + if (use_table_properties) + if (SeismicAdditionalOutputs *seismic_out = out.template get_additional_output>()) + { + seismic_out->vp[i] = seismic_Vp(in.temperature[i], in.pressure[i], in.composition[i], in.position[i]); + seismic_out->vs[i] = seismic_Vs(in.temperature[i], in.pressure[i], in.composition[i], in.position[i]); + } + } + + if (in.requests_property(MaterialProperties::reaction_terms)) + out.reaction_terms = grain_size_change(in, adiabatic_pressures, phase_indices); + + + /* We separate the calculation of specific heat and thermal expansivity, + * because they depend on cell-wise averaged values that are only available + * here + */ + double average_temperature(0.0); + double average_density(0.0); + for (unsigned int i = 0; i < in.n_evaluation_points(); ++i) + { + average_temperature += in.temperature[i]; + average_density += out.densities[i]; + } + average_temperature /= in.n_evaluation_points(); + average_density /= in.n_evaluation_points(); + + std::array,2> dH; + + if (use_table_properties && use_enthalpy) + dH = enthalpy_derivative(in); + + for (unsigned int i = 0; i < in.n_evaluation_points(); ++i) + { + if (!use_table_properties) + { + out.thermal_expansion_coefficients[i] = thermal_alpha; + out.specific_heat[i] = reference_specific_heat; + } + else if (use_enthalpy) + { + if (this->get_adiabatic_conditions().is_initialized() + && (in.current_cell.state() == IteratorState::valid) + && (dH[0].second > 0) + && (dH[1].second > 0)) + { + out.thermal_expansion_coefficients[i] = (1 - average_density * dH[1].first) / average_temperature; + out.specific_heat[i] = dH[0].first; + } + else + { + if (material_lookup.size() == 1) + { + out.thermal_expansion_coefficients[i] = (1 - out.densities[i] * material_lookup[0]->dHdp(in.temperature[i],adiabatic_pressures[i])) / in.temperature[i]; + out.specific_heat[i] = material_lookup[0]->dHdT(in.temperature[i],adiabatic_pressures[i]); + } + else + { + ExcNotImplemented(); + } + } + } + else + { + out.thermal_expansion_coefficients[i] = thermal_expansion_coefficient(in.temperature[i], adiabatic_pressures[i], in.composition[i], in.position[i]); + out.specific_heat[i] = specific_heat(in.temperature[i], adiabatic_pressures[i], in.composition[i], in.position[i]); + } + + out.thermal_expansion_coefficients[i] = std::max(std::min(out.thermal_expansion_coefficients[i],max_thermal_expansivity),min_thermal_expansivity); + out.specific_heat[i] = std::max(std::min(out.specific_heat[i],max_specific_heat),min_specific_heat); + } + } + + + + template + void + GrainSize::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Grain size model"); + { + prm.declare_entry ("Reference density", "3300", + Patterns::Double (0.), + "The reference density $\\rho_0$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. Units: \\si{\\kelvin}."); + prm.declare_entry ("Viscosity", "5e24", + Patterns::Double (0.), + "The value of the constant viscosity. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Reference specific heat", "1250.", + Patterns::Double (0.), + "The value of the specific heat $cp$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Thermal expansion coefficient", "2e-5", + Patterns::Double (0.), + "The value of the thermal expansion coefficient $\\alpha$. " + "Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Reference compressibility", "4e-12", + Patterns::Double (0.), + "The value of the reference compressibility. " + "Units: \\si{\\per\\pascal}."); + + MaterialUtilities::PhaseFunction::declare_parameters(prm); + + prm.declare_entry ("Grain growth activation energy", "3.5e5", + Patterns::List (Patterns::Double (0.)), + "The activation energy for grain growth $E_g$. " + "List must have one more entry than the Phase transition depths. " + "Units: \\si{\\joule\\per\\mole}."); + prm.declare_entry ("Grain growth activation volume", "8e-6", + Patterns::List (Patterns::Double (0.)), + "The activation volume for grain growth $V_g$. " + "List must have one more entry than the Phase transition depths. " + "Units: \\si{\\meter\\cubed\\per\\mole}."); + prm.declare_entry ("Grain growth exponent", "3.", + Patterns::List (Patterns::Double (0.)), + "The exponent of the grain growth law $p_g$. This is an experimentally determined " + "grain growth constant. " + "List must have one more entry than the Phase transition depths. " + "Units: none."); + prm.declare_entry ("Grain growth rate constant", "1.5e-5", + Patterns::List (Patterns::Double (0.)), + "The prefactor for the Ostwald ripening grain growth law $G_0$. " + "This is dependent on water content, which is assumed to be " + "50 H/$10^6$ Si for the default value. " + "List must have one more entry than the Phase transition depths. " + "Units: \\si{\\meter}$^{p_g}$\\si{\\per\\second}."); + prm.declare_entry ("Minimum grain size", "5e-6", + Patterns::Double (0.), + "The minimum allowable grain size. The grain size will be limited to be " + "larger than this value. This can be used to damp out oscillations, or " + "to limit the viscosity variation due to grain size. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Reciprocal required strain", "10.", + Patterns::List (Patterns::Double (0.)), + "This parameter ($\\lambda$) gives an estimate of the strain necessary " + "to achieve a new grain size. " + "List must have one more entry than the Phase transition depths."); + prm.declare_entry ("Recrystallized grain size", "", + Patterns::List (Patterns::Double (0.)), + "The grain size $d_{ph}$ to that a phase will be reduced to when crossing a phase transition. " + "When set to zero, grain size will not be reduced. " + "List must have the same number of entries as Phase transition depths. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Phase volume fraction", "0.4", + Patterns::Double (0., 1.), + "The volume fraction of one of the phases in the two-phase damage model of Bercovici and Ricard (2012). " + "The volume fraction of the other phase can be simply calculated by subtracting from one. " + "This parameter is only used in the pinned state grain damage formulation." + "Units: none."); + prm.declare_entry ("Grain size evolution formulation", "paleowattmeter", + Patterns::Selection ("paleowattmeter|paleopiezometer|pinned grain damage"), + "A flag indicating whether the material model should use the " + "paleowattmeter approach of Austin and Evans (2007) for grain size reduction " + "in the dislocation creep regime, the paleopiezometer approach " + "from Hall and Parmetier (2003), or the pinned grain damage approach " + "from Mulyukova and Bercovici (2018)."); + prm.declare_entry ("Use paleowattmeter", "default", + Patterns::Selection ("true|false|default"), + "A flag indicating whether the computation should use the " + "paleowattmeter approach of Austin and Evans (2007) for grain size reduction " + "in the dislocation creep regime (if true) or the paleopiezometer approach " + "from Hall and Parmetier (2003) (if false). This parameter has been removed. " + "Use 'Grain size evolution formulation' instead."); + prm.declare_entry ("Average specific grain boundary energy", "1.0", + Patterns::List (Patterns::Double (0.)), + "The average specific grain boundary energy $\\gamma$. " + "List must have one more entry than the Phase transition depths. " + "Units: \\si{\\joule\\per\\meter\\squared}."); + prm.declare_entry ("Work fraction for boundary area change", "0.1", + Patterns::List (Patterns::Double (0.)), + "The fraction $\\chi$ of work done by dislocation creep to change the grain boundary area. " + "List must have one more entry than the Phase transition depths. " + "Units: \\si{\\joule\\per\\meter\\squared}."); + prm.declare_entry ("Geometric constant", "3.", + Patterns::List (Patterns::Double (0.)), + "The geometric constant $c$ used in the paleowattmeter grain size reduction law. " + "List must have one more entry than the Phase transition depths. " + "Units: none."); + prm.declare_entry ("Dislocation viscosity iteration threshold", "1e-3", + Patterns::Double (0.), + "We need to perform an iteration inside the computation " + "of the dislocation viscosity, because it depends on the " + "dislocation strain rate, which depends on the dislocation " + "viscosity itself. This number determines the termination " + "accuracy, i.e. if the dislocation viscosity changes by less " + "than this factor we terminate the iteration."); + prm.declare_entry ("Dislocation viscosity iteration number", "100", + Patterns::Integer(0), + "We need to perform an iteration inside the computation " + "of the dislocation viscosity, because it depends on the " + "dislocation strain rate, which depends on the dislocation " + "viscosity itself. This number determines the maximum " + "number of iterations that are performed. "); + prm.declare_entry ("Dislocation creep exponent", "3.5", + Patterns::List (Patterns::Double (0.)), + "The power-law exponent $n_{dis}$ for dislocation creep. " + "List must have one more entry than the Phase transition depths. " + "Units: none."); + prm.declare_entry ("Dislocation activation energy", "4.8e5", + Patterns::List (Patterns::Double (0.)), + "The activation energy for dislocation creep $E_{dis}$. " + "List must have one more entry than the Phase transition depths. " + "Units: \\si{\\joule\\per\\mole}."); + prm.declare_entry ("Dislocation activation volume", "1.1e-5", + Patterns::List (Patterns::Double (0.)), + "The activation volume for dislocation creep $V_{dis}$. " + "List must have one more entry than the Phase transition depths. " + "Units: \\si{\\meter\\cubed\\per\\mole}."); + prm.declare_entry ("Dislocation creep prefactor", "4.5e-15", + Patterns::List (Patterns::Double (0.)), + "The prefactor for the dislocation creep law $A_{dis}$. " + "List must have one more entry than the Phase transition depths. " + "Units: \\si{\\pascal}$^{-n_{dis}}$\\si{\\per\\second}."); + prm.declare_entry ("Diffusion creep exponent", "1.", + Patterns::List (Patterns::Double (0.)), + "The power-law exponent $n_{diff}$ for diffusion creep. " + "List must have one more entry than the Phase transition depths. " + "Units: none."); + prm.declare_entry ("Diffusion activation energy", "3.35e5", + Patterns::List (Patterns::Double (0.)), + "The activation energy for diffusion creep $E_{diff}$. " + "List must have one more entry than the Phase transition depths. " + "Units: \\si{\\joule\\per\\mole}."); + prm.declare_entry ("Diffusion activation volume", "4e-6", + Patterns::List (Patterns::Double (0.)), + "The activation volume for diffusion creep $V_{diff}$. " + "List must have one more entry than the Phase transition depths. " + "Units: \\si{\\meter\\cubed\\per\\mole}."); + prm.declare_entry ("Diffusion creep prefactor", "7.4e-15", + Patterns::List (Patterns::Double (0.)), + "The prefactor for the diffusion creep law $A_{diff}$. " + "List must have one more entry than the Phase transition depths. " + "Units: \\si{\\meter}$^{p_{diff}}$\\si{\\pascal}$^{-n_{diff}}$\\si{\\per\\second}."); + prm.declare_entry ("Diffusion creep grain size exponent", "3.", + Patterns::List (Patterns::Double (0.)), + "The diffusion creep grain size exponent $p_{diff}$ that determines the " + "dependence of viscosity on grain size. " + "List must have one more entry than the Phase transition depths. " + "Units: none."); + prm.declare_entry ("Maximum temperature dependence of viscosity", "100.", + Patterns::Double (0.), + "The factor by which viscosity at adiabatic temperature and ambient temperature " + "are allowed to differ (a value of x means that the viscosity can be x times higher " + "or x times lower compared to the value at adiabatic temperature. This parameter " + "is introduced to limit local viscosity contrasts, but still allow for a widely " + "varying viscosity over the whole mantle range. " + "Units: none."); + prm.declare_entry ("Minimum viscosity", "1e18", + Patterns::Double (0.), + "The minimum viscosity that is allowed in the whole model domain. " + "Units: Pa \\, s."); + prm.declare_entry ("Maximum viscosity", "1e26", + Patterns::Double (0.), + "The maximum viscosity that is allowed in the whole model domain. " + "Units: Pa \\, s."); + prm.declare_entry ("Minimum specific heat", "500.", + Patterns::Double (0.), + "The minimum specific heat that is allowed in the whole model domain. " + "Units: J/kg/K."); + prm.declare_entry ("Maximum specific heat", "6000.", + Patterns::Double (0.), + "The maximum specific heat that is allowed in the whole model domain. " + "Units: J/kg/K."); + prm.declare_entry ("Minimum thermal expansivity", "1e-5", + Patterns::Double (), + "The minimum thermal expansivity that is allowed in the whole model domain. " + "Units: 1/K."); + prm.declare_entry ("Maximum thermal expansivity", "1e-3", + Patterns::Double (), + "The maximum thermal expansivity that is allowed in the whole model domain. " + "Units: 1/K."); + prm.declare_entry ("Maximum latent heat substeps", "1", + Patterns::Integer (1), + "The maximum number of substeps over the temperature pressure range " + "to calculate the averaged enthalpy gradient over a cell."); + prm.declare_entry ("Minimum grain size", "1e-5", + Patterns::Double (0.), + "The minimum grain size that is used for the material model. This parameter " + "is introduced to limit local viscosity contrasts, but still allows for a widely " + "varying viscosity over the whole mantle range. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Lower mantle grain size scaling", "1.0", + Patterns::Double (0.), + "This option does not exist any more."); + prm.declare_entry ("Advect logarithm of grain size", "false", + Patterns::Bool (), + "This option does not exist any more."); + prm.declare_entry ("Data directory", "$ASPECT_SOURCE_DIR/data/material-model/steinberger/", + Patterns::DirectoryName (), + "The path to the model data. The path may also include the special " + "text '$ASPECT_SOURCE_DIR' which will be interpreted as the path " + "in which the ASPECT source files were located when ASPECT was " + "compiled. This interpretation allows, for example, to reference " + "files located in the 'data/' subdirectory of ASPECT. "); + prm.declare_entry ("Material file names", "pyr-ringwood88.txt", + Patterns::List (Patterns::Anything()), + "The file names of the material data. " + "List with as many components as active " + "compositional fields (material data is assumed to " + "be in order with the ordering of the fields). "); + prm.declare_entry ("Derivatives file names", "", + Patterns::List (Patterns::Anything()), + "The file names of the enthalpy derivatives data. " + "List with as many components as active " + "compositional fields (material data is assumed to " + "be in order with the ordering of the fields). "); + prm.declare_entry ("Use table properties", "false", + Patterns::Bool(), + "This parameter determines whether to use the table properties " + "also for density, thermal expansivity and specific heat. " + "If false the properties are generated as in the " + "simple compressible plugin."); + prm.declare_entry ("Material file format", "perplex", + Patterns::Selection ("perplex|hefesto"), + "The material file format to be read in the property " + "tables."); + prm.declare_entry ("Use enthalpy for material properties", "true", + Patterns::Bool(), + "This parameter determines whether to use the enthalpy to calculate " + "the thermal expansivity and specific heat (if true) or use the " + "thermal expansivity and specific heat values from " + "the material properties table directly (if false)."); + prm.declare_entry ("Bilinear interpolation", "true", + Patterns::Bool (), + "This parameter determines whether to use bilinear interpolation " + "to compute material properties (slower but more accurate)."); + + prm.enter_subsection("Grain damage partitioning"); + { + prm.declare_entry ("Temperature for minimum grain damage partitioning", "1600", + Patterns::Double (0.), + "This parameter determines the temperature at which the computed coefficient of shear energy " + "partitioned into grain damage is minimum. This is used in the pinned state limit of the grain " + "size evolution. One choice of this parameter is the mantle temperature at the ridge axis, " + "see Mulyukova and Bercovici (2018) for details."); + prm.declare_entry ("Temperature for maximum grain damage partitioning", "283", + Patterns::Double (0.), + "This parameter determines the temperature at which the computed coefficient of shear energy " + "partitioned into grain damage is maximum. This is used in the pinned state limit of the grain " + "size evolution. One choice of this parameter is the surface temperature of the seafloor, see " + "Mulyukova and Bercovici (2018) for details."); + prm.declare_entry ("Minimum grain size reduction work fraction", "1e-12", + Patterns::Double (0., 1.), + "This parameter determines the minimum value of the partitioning coefficient, which governs " + "the amount of shear heating partitioned into grain damage in the pinned state limit."); + prm.declare_entry ("Maximum grain size reduction work fraction", "1e-1", + Patterns::Double (0., 1.), + "This parameter determines the maximum value of the partitioning coefficient, which governs " + "the amount of shear heating partitioned into grain damage in the pinned state limit."); + prm.declare_entry ("Grain size reduction work fraction exponent", "10", + Patterns::Double (0.), + "This parameter determines the variability in how much shear heating is partitioned into " + "grain damage. A higher value suggests a wider temperature range over which the partitioning " + "coefficient is high."); + } + prm.leave_subsection(); + + // Drucker Prager plasticity parameters + prm.declare_entry ("Use Drucker-Prager rheology", "false", + Patterns::Bool(), + "This parameter determines whether to apply plastic yielding " + "according to a Drucker-Prager rheology after computing the viscosity " + "from the (grain-size dependent) visous creep flow laws (if true) " + "or not (if false)."); + prm.declare_entry ("Use adiabatic pressure for yield stress", "false", + Patterns::Bool (), + "Whether to use the adiabatic pressure (if true) instead of the full " + "(non-negative) pressure (if false) when calculating the yield stress. " + "Using the adiabatic pressure (which is analogous to the depth-dependent " + "von Mises model) can be useful to avoid the strong non-linearity associated " + "with dynamic pressure variations affecting the yield strength, which can " + "make the problem ill-posed. However, dynamic pressure can affect the " + "localization of the strain rate and the resulting deformation, and neglecting " + "it therefore changes the solution."); + Rheology::DruckerPrager::declare_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + GrainSize::parse_parameters (ParameterHandler &prm) + { + AssertThrow (this->introspection().compositional_name_exists("grain_size"), + ExcMessage("The 'grain size' material model only works if a compositional " + "field with name 'grain_size' is present. Please use another material " + "model or add such a field.")); + grain_size_index = this->introspection().compositional_index_for_name("grain_size"); + + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Grain size model"); + { + reference_rho = prm.get_double ("Reference density"); + reference_T = prm.get_double ("Reference temperature"); + eta = prm.get_double ("Viscosity"); + k_value = prm.get_double ("Thermal conductivity"); + reference_specific_heat = prm.get_double ("Reference specific heat"); + thermal_alpha = prm.get_double ("Thermal expansion coefficient"); + reference_compressibility = prm.get_double ("Reference compressibility"); + + // Phase transition parameters + phase_function.initialize_simulator (this->get_simulator()); + phase_function.parse_parameters (prm); + + std::vector n_phases_for_each_composition = phase_function.n_phases_for_each_composition(); + n_phase_transitions = n_phases_for_each_composition[0] - 1; + + recrystallized_grain_size = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Recrystallized grain size"))); + + if (recrystallized_grain_size.size() != n_phase_transitions) + AssertThrow(false, + ExcMessage("Error: The list of recrystallized grain sizes has to have as many entries as there are phases.")); + + for (unsigned int i=1; i 0. && maximum_grain_size_reduction_work_fraction < 1., + ExcMessage("Maximum grain size reduction work fraction cannot be smaller or equal to 0 or larger or equal to 1.")); + AssertThrow(minimum_grain_size_reduction_work_fraction > 0. && minimum_grain_size_reduction_work_fraction < 1., + ExcMessage("Minimum grain size reduction work fraction cannot be smaller or equal to 0 or larger or equal to 1.")); + AssertThrow(maximum_grain_size_reduction_work_fraction >= minimum_grain_size_reduction_work_fraction, + ExcMessage("Maximum grain size reduction work fraction must be larger than minimum grain size reduction work fraction.")); + + const double temperature_minimum_partition = prm.get_double ("Temperature for minimum grain damage partitioning"); + const double temperature_maximum_partition = prm.get_double ("Temperature for maximum grain damage partitioning"); + + AssertThrow(temperature_minimum_partition > temperature_maximum_partition, + ExcMessage("Temperature for minimum grain damage partitioning must be larger than Temperature for maximum grain damage partitioning.")); + + temperature_minimum_partitioning_power = std::pow(temperature_minimum_partition,grain_size_reduction_work_fraction_exponent); + temperature_maximum_partitioning_power = std::pow(temperature_maximum_partition,grain_size_reduction_work_fraction_exponent); + } + prm.leave_subsection(); + } + + // rheology parameters + dislocation_viscosity_iteration_threshold = prm.get_double("Dislocation viscosity iteration threshold"); + dislocation_viscosity_iteration_number = prm.get_integer("Dislocation viscosity iteration number"); + dislocation_creep_exponent = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Dislocation creep exponent"))); + dislocation_activation_energy = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Dislocation activation energy"))); + dislocation_activation_volume = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Dislocation activation volume"))); + dislocation_creep_prefactor = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Dislocation creep prefactor"))); + diffusion_creep_exponent = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Diffusion creep exponent"))); + diffusion_activation_energy = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Diffusion activation energy"))); + diffusion_activation_volume = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Diffusion activation volume"))); + diffusion_creep_prefactor = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Diffusion creep prefactor"))); + diffusion_creep_grain_size_exponent = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Diffusion creep grain size exponent"))); + max_temperature_dependence_of_eta = prm.get_double ("Maximum temperature dependence of viscosity"); + min_eta = prm.get_double ("Minimum viscosity"); + max_eta = prm.get_double ("Maximum viscosity"); + min_specific_heat = prm.get_double ("Minimum specific heat"); + max_specific_heat = prm.get_double ("Maximum specific heat"); + min_thermal_expansivity = prm.get_double ("Minimum thermal expansivity"); + max_thermal_expansivity = prm.get_double ("Maximum thermal expansivity"); + max_latent_heat_substeps = prm.get_integer ("Maximum latent heat substeps"); + min_grain_size = prm.get_double ("Minimum grain size"); + + // scale recrystallized grain size, diffusion creep and grain growth prefactor accordingly + diffusion_creep_prefactor[diffusion_creep_prefactor.size()-1] *= std::pow(1.0,diffusion_creep_grain_size_exponent[diffusion_creep_grain_size_exponent.size()-1]); + grain_growth_rate_constant[grain_growth_rate_constant.size()-1] *= std::pow(1.0,grain_growth_exponent[grain_growth_exponent.size()-1]); + + // prefactors never appear without their exponents. perform some calculations here to save time later + for (unsigned int i=0; i 1) + { + AssertThrow(grain_size_index >= material_file_names.size(), + ExcMessage("The compositional fields indicating the major element composition need to be first in the " + "list of compositional fields, but the grain size field seems to have a lower index than the number " + "of provided data files. This is likely inconsistent. Please check the number of provided data " + "files and the order of compositional fields.")); + } + + if (prm.get ("Material file format") == "perplex") + material_file_format = perplex; + else if (prm.get ("Material file format") == "hefesto") + material_file_format = hefesto; + else + AssertThrow (false, ExcNotImplemented()); + + use_bilinear_interpolation = prm.get_bool ("Bilinear interpolation"); + + // Plasticity parameters + enable_drucker_prager_rheology = prm.get_bool ("Use Drucker-Prager rheology"); + use_adiabatic_pressure_for_yielding = prm.get_bool ("Use adiabatic pressure for yield stress"); + drucker_prager_plasticity.initialize_simulator (this->get_simulator()); + + std::vector n_phases = {n_phase_transitions+1}; + drucker_prager_plasticity.parse_parameters(prm, std::make_unique> (n_phases)); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + + // Declare dependencies on solution variables + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + + this->model_dependence.viscosity = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::strain_rate + | NonlinearDependence::compositional_fields; + + this->model_dependence.density = NonlinearDependence::none; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + + if (use_table_properties) + { + this->model_dependence.density |= NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + this->model_dependence.specific_heat = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + } + else + { + if (thermal_alpha != 0) + this->model_dependence.density |=NonlinearDependence::temperature; + if (reference_compressibility != 0) + this->model_dependence.density |=NonlinearDependence::pressure; + } + } + + + + template + void + GrainSize::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + // These properties are useful as output. + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + + // These properties will be used by the heating model to reduce + // shear heating by the amount of work done to reduce grain size. + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + + // These properties are only output properties. + if (use_table_properties && out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + + if (enable_drucker_prager_rheology && out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(GrainSize, + "grain size", + "A material model that relies on compositional " + "fields that correspond to the average grain sizes of a " + "mineral phase and source terms that determine the grain " + "size evolution in terms of the strain rate, " + "temperature, phase transitions, and the creep regime. " + "This material model only works if a compositional field " + "named 'grain_size' is present. " + "In the diffusion creep regime, the viscosity depends " + "on this grain size field. " + "We use the grain size evolution laws described in Behn " + "et al., 2009. Implications of grain size evolution on the " + "seismic structure of the oceanic upper mantle, " + "Earth Planet. Sci. Letters, 282, 178–189. " + "Other material parameters are either prescribed similar " + "to the 'simple' material model, or read from data files " + "that were generated by the Perplex or Hefesto software. " + "This material model " + "is described in more detail in Dannberg, J., Z. Eilon, " + "U. Faul, R. Gassmoeller, P. Moulik, and R. Myhill (2017), " + "The importance of grain size to mantle dynamics and " + "seismological observations, Geochem. Geophys. Geosyst., " + "18, 3034–3061, doi:10.1002/2017GC006944.") + +#define INSTANTIATE(dim) \ + template class DislocationViscosityOutputs; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/interface.cc.bak b/source/material_model/interface.cc.bak new file mode 100644 index 00000000000..11ffbae6d08 --- /dev/null +++ b/source/material_model/interface.cc.bak @@ -0,0 +1,1239 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef DEBUG +#ifdef ASPECT_USE_FP_EXCEPTIONS +#include +#endif +#endif + +namespace aspect +{ + namespace MaterialModel + { + namespace NonlinearDependence + { + bool + identifies_single_variable(const Dependence dependence) + { + Assert (dependence != uninitialized, + ExcMessage ("You cannot call this function on an uninitialized dependence value!")); + return ((dependence == temperature) + || + (dependence == pressure) + || + (dependence == strain_rate) + || + (dependence == compositional_fields)); + } + + + + ModelDependence::ModelDependence () + : + viscosity (uninitialized), + density (uninitialized), + compressibility (uninitialized), + specific_heat (uninitialized), + thermal_conductivity (uninitialized) + {} + } + + + +// -------------------------------- Deal with registering material models and automating +// -------------------------------- their setup and selection at run time + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + register_material_model (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + template + std::unique_ptr> + create_material_model (const std::string &model_name) + { + return std::get(registered_plugins).create_plugin (model_name, "Material model::Model name"); + } + + + + template + std::unique_ptr> + create_material_model (ParameterHandler &prm) + { + std::string model_name; + prm.enter_subsection ("Material model"); + { + model_name = prm.get ("Model name"); + } + prm.leave_subsection (); + + // If one sets the model name to an empty string in the input file, + // ParameterHandler produces an error while reading the file. However, + // if one omits specifying any model name at all (not even setting it to + // the empty string) then the value we get here is the empty string. If + // we don't catch this case here, we end up with awkward downstream + // errors because the value obviously does not conform to the Pattern. + AssertThrow(model_name != "unspecified", + ExcMessage("You need to select a material model " + "(`set Model name' in `subsection Material model').")); + + return create_material_model (model_name); + } + + + + template + const NonlinearDependence::ModelDependence & + Interface:: + get_model_dependence() const + { + return model_dependence; + } + + + + template + void + Interface:: + create_additional_named_outputs (MaterialModelOutputs &/*outputs*/) const + { + // by default we do nothing! + } + + + + template + void + Interface:: + fill_additional_material_model_inputs(MaterialModel::MaterialModelInputs &input, + const LinearAlgebra::BlockVector &solution, + const FEValuesBase &fe_values, + const Introspection &introspection) const + { + // go through the list of additional inputs and fill them + for (unsigned int i=0; ifill(solution, fe_values, introspection); + } + + + + template + std::string + get_valid_model_names_pattern () + { + return std::get(registered_plugins).get_pattern_of_names (); + } + + + template + void + declare_parameters (ParameterHandler &prm) + { + // declare the actual entry in the parameter file + prm.enter_subsection ("Material model"); + { + const std::string pattern_of_names = get_valid_model_names_pattern(); + prm.declare_entry ("Model name", "unspecified", + Patterns::Selection (pattern_of_names+"|unspecified"), + "The name of the material model to be used in " + "this simulation. There are many material models " + "you can choose from, as listed below. They generally " + "fall into two category: (i) models that implement " + "a particular case of material behavior, (ii) models " + "that modify other models in some way. We sometimes " + "call the latter ``compositing models''. An example " + "of a compositing model is the ``depth dependent'' model " + "below in that it takes another, freely choosable " + "model as its base and then modifies that model's " + "output in some way." + "\n\n" + "You can select one of the following models:\n\n" + + + std::get(registered_plugins).get_description_string()); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Material model interface", + out); + } + + + template + MaterialModelInputs::MaterialModelInputs(const unsigned int n_points, + const unsigned int n_comp) + : + position(n_points, Point(numbers::signaling_nan>())), + temperature(n_points, numbers::signaling_nan()), + pressure(n_points, numbers::signaling_nan()), + pressure_gradient(n_points, numbers::signaling_nan>()), + velocity(n_points, numbers::signaling_nan>()), + composition(n_points, std::vector(n_comp, numbers::signaling_nan())), + strain_rate(n_points, numbers::signaling_nan>()), + current_cell(), + requested_properties(MaterialProperties::all_properties) + {} + + + + template + MaterialModelInputs::MaterialModelInputs(const DataPostprocessorInputs::Vector &input_data, + const Introspection &introspection, + const bool compute_strain_rate) + : + position(input_data.evaluation_points), + temperature(input_data.solution_values.size(), numbers::signaling_nan()), + pressure(input_data.solution_values.size(), numbers::signaling_nan()), + pressure_gradient(input_data.solution_values.size(), numbers::signaling_nan>()), + velocity(input_data.solution_values.size(), numbers::signaling_nan>()), + composition(input_data.solution_values.size(), std::vector(introspection.n_compositional_fields, numbers::signaling_nan())), + strain_rate(input_data.solution_values.size(), numbers::signaling_nan>()), + current_cell(input_data.template get_cell()), + requested_properties(MaterialProperties::all_properties) + { + AssertThrow (compute_strain_rate == true, + ExcMessage ("The option to not compute the strain rate is no longer supported.")); + + for (unsigned int q=0; q grad_u; + for (unsigned int d=0; dvelocity[q][d] = input_data.solution_values[q][introspection.component_indices.velocities[d]]; + this->pressure_gradient[q][d] = input_data.solution_gradients[q][introspection.component_indices.pressure][d]; + } + + this->strain_rate[q] = symmetrize (grad_u); + this->pressure[q] = input_data.solution_values[q][introspection.component_indices.pressure]; + this->temperature[q] = input_data.solution_values[q][introspection.component_indices.temperature]; + + for (unsigned int c=0; ccomposition[q][c] = input_data.solution_values[q][introspection.component_indices.compositional_fields[c]]; + } + } + + + + template + MaterialModelInputs::MaterialModelInputs(const FEValuesBase &fe_values, + const typename DoFHandler::active_cell_iterator &cell_x, + const Introspection &introspection, + const LinearAlgebra::BlockVector &solution_vector, + const bool compute_strain_rate) + : + position(fe_values.get_quadrature_points()), + temperature(fe_values.n_quadrature_points, numbers::signaling_nan()), + pressure(fe_values.n_quadrature_points, numbers::signaling_nan()), + pressure_gradient(fe_values.n_quadrature_points, numbers::signaling_nan>()), + velocity(fe_values.n_quadrature_points, numbers::signaling_nan>()), + composition(fe_values.n_quadrature_points, std::vector(introspection.n_compositional_fields, numbers::signaling_nan())), + strain_rate(fe_values.n_quadrature_points, numbers::signaling_nan>()), + current_cell (cell_x), + requested_properties(MaterialProperties::all_properties) + { + // Call the function reinit to populate the new arrays. + this->reinit(fe_values, current_cell, introspection, solution_vector, compute_strain_rate); + } + + + + template + MaterialModelInputs::MaterialModelInputs(const MaterialModelInputs &source) + : + position(source.position), + temperature(source.temperature), + pressure(source.pressure), + pressure_gradient(source.pressure_gradient), + velocity(source.velocity), + composition(source.composition), + strain_rate(source.strain_rate), + current_cell(source.current_cell), + requested_properties(source.requested_properties) + { + Assert (source.additional_inputs.size() == 0, + ExcMessage ("You can not copy MaterialModelInputs objects that have " + "additional input objects attached")); + } + + + + template + void + MaterialModelInputs::reinit(const FEValuesBase &fe_values, + const typename DoFHandler::active_cell_iterator &cell_x, + const Introspection &introspection, + const LinearAlgebra::BlockVector &solution_vector, + const bool compute_strain_rate) + { + AssertThrow (compute_strain_rate == true, + ExcMessage ("The option to not compute the strain rate is no longer supported.")); + + // Populate the arrays that hold solution values and gradients + fe_values[introspection.extractors.temperature].get_function_values (solution_vector, this->temperature); + fe_values[introspection.extractors.velocities].get_function_values (solution_vector, this->velocity); + fe_values[introspection.extractors.pressure].get_function_values (solution_vector, this->pressure); + fe_values[introspection.extractors.pressure].get_function_gradients (solution_vector, this->pressure_gradient); + fe_values[introspection.extractors.velocities].get_function_symmetric_gradients (solution_vector, this->strain_rate); + + // Vectors for evaluating the compositional field parts of the finite element solution + std::vector> composition_values (introspection.n_compositional_fields, + std::vector (fe_values.n_quadrature_points)); + for (unsigned int c=0; ccomposition[q][c] = composition_values[c][q]; + } + + // Finally also record quadrature point positions and the cell + this->position = fe_values.get_quadrature_points(); + this->current_cell = cell_x; + } + + + + template + unsigned int + MaterialModelInputs::n_evaluation_points() const + { + return position.size(); + } + + + + template + bool + MaterialModelInputs::requests_property(const MaterialProperties::Property &property) const + { + // Note that this means 'requested_properties' can include other properties than + // just 'property', but in any case it at least requests 'property'. + return (requested_properties & property) != 0; + } + + + + template + MaterialModelOutputs::MaterialModelOutputs(const unsigned int n_points, + const unsigned int n_comp) + : + viscosities(n_points, numbers::signaling_nan()), + densities(n_points, numbers::signaling_nan()), + thermal_expansion_coefficients(n_points, numbers::signaling_nan()), + specific_heat(n_points, numbers::signaling_nan()), + thermal_conductivities(n_points, numbers::signaling_nan()), + compressibilities(n_points, numbers::signaling_nan()), + entropy_derivative_pressure(n_points, numbers::signaling_nan()), + entropy_derivative_temperature(n_points, numbers::signaling_nan()), + reaction_terms(n_points, std::vector(n_comp, numbers::signaling_nan())) + {} + + + template + MaterialModelOutputs::MaterialModelOutputs(const MaterialModelOutputs &source) + : + viscosities(source.viscosities), + densities(source.densities), + thermal_expansion_coefficients(source.thermal_expansion_coefficients), + specific_heat(source.specific_heat), + thermal_conductivities(source.thermal_conductivities), + compressibilities(source.compressibilities), + entropy_derivative_pressure(source.entropy_derivative_pressure), + entropy_derivative_temperature(source.entropy_derivative_temperature), + reaction_terms(source.reaction_terms), + additional_outputs() + { + Assert (source.additional_outputs.size() == 0, + ExcMessage ("You can not copy MaterialModelOutputs objects that have " + "additional output objects attached")); + } + + + + template + unsigned int + MaterialModelOutputs::n_evaluation_points() const + { + return densities.size(); + } + + + + namespace MaterialAveraging + { + std::string get_averaging_operation_names () + { + return "none|default averaging|arithmetic average|harmonic average|geometric average|pick largest|project to Q1|log average|harmonic average only viscosity|geometric average only viscosity|project to Q1 only viscosity"; + } + + + AveragingOperation parse_averaging_operation_name (const std::string &s) + { + if (s == "none") + return none; + else if (s == "arithmetic average") + return arithmetic_average; + else if (s == "harmonic average") + return harmonic_average; + else if (s == "geometric average") + return geometric_average; + else if (s == "pick largest") + return pick_largest; + else if (s == "project to Q1") + return project_to_Q1; + else if (s == "log average") + return log_average; + else if (s == "harmonic average only viscosity") + return harmonic_average_only_viscosity; + else if (s == "geometric average only viscosity") + return geometric_average_only_viscosity; + else if (s == "project to Q1 only viscosity") + return project_to_Q1_only_viscosity; + else if (s == "default averaging") + return default_averaging; + else + AssertThrow (false, + ExcMessage ("The value <" + s + "> for a material " + "averaging operation is not one of the " + "valid values.")); + + return none; + } + + + + namespace + { + bool + all_entries_NaN (const std::vector &values) + { + for (const double value : values) + if (std::isnan(value) == false) + return false; + + return true; + } + } + + + + // Do the requested averaging operation for one array. The + // projection matrix argument is only used if the operation + // chosen is project_to_Q1. + void average_property (const AveragingOperation operation, + const FullMatrix &projection_matrix, + const FullMatrix &expansion_matrix, + std::vector &values_out) + { +#ifdef DEBUG +#ifdef ASPECT_USE_FP_EXCEPTIONS + // disable floating point exceptions while averaging. Errors will be reported + // as soon as somebody will try to use the averaged values later. + fedisableexcept(FE_DIVBYZERO|FE_INVALID); +#endif +#endif + + // if an output field has not been filled (because it was + // not requested), then simply do nothing -- no harm no foul + // note that it is still an error if only some entries are NaN + if (values_out.size() == 0 || all_entries_NaN(values_out) == true) + return; + + const unsigned int N = values_out.size(); + const unsigned int P = expansion_matrix.n(); + Assert ((P==0) || (/*dim=2*/ P==4) || (/*dim=3*/ P==8), + ExcInternalError()); + Assert (((operation == project_to_Q1) && + (projection_matrix.m() == P) && + (projection_matrix.n() == N) && + (expansion_matrix.m() == N) && + (expansion_matrix.n() == P)) + || + ((projection_matrix.m() == 0) && + (projection_matrix.n() == 0)), + ExcInternalError()); + + // otherwise do as instructed + switch (operation) + { + case none: + { + break; + } + + case arithmetic_average: + { + double sum = 0; + for (unsigned int i=0; i= 0, + ExcMessage ("Computing the geometric average " + "only makes sense for non-negative " + "quantities.")); + average *= std::pow (values_out[i], 1./N); + } + + for (unsigned int i=0; i::lowest(); + for (unsigned int i=0; i::max(); + for (unsigned int i=0; i::lowest(); + for (unsigned int i=0; i x (N), z(P), y(N); + for (unsigned int i=0; i::infinity(); + break; + } + Assert (values_out[i] > 0.0, + ExcMessage ("Computing the log average " + "only makes sense for positive " + "quantities.")); + sum += std::log10(values_out[i]); + } + const double log_value_average = std::pow (10., sum/N); + for (unsigned int i=0; i + void compute_projection_matrix (const typename DoFHandler::active_cell_iterator &cell, + const Quadrature &quadrature_formula, + const Mapping &mapping, + FullMatrix &projection_matrix, + FullMatrix &expansion_matrix) + { + static const FE_Q fe(1); + FEValues fe_values (mapping, fe, quadrature_formula, + update_values | update_JxW_values); + + const unsigned int P = fe.dofs_per_cell; + const unsigned int N = quadrature_formula.size(); + + FullMatrix F (P, N); + FullMatrix M (P, P); + + projection_matrix.reinit (P, N); + expansion_matrix.reinit (N, P); + + // reinitialize the fe_values object with the current cell. we get a + // DoFHandler cell, but we are not going to use it with the + // finite element associated with that DoFHandler, so cast it back + // to just a tria iterator (all we need anyway is the geometry) + fe_values.reinit (typename Triangulation::active_cell_iterator(cell)); + + // compute the matrices F, M, E + for (unsigned int i=0; i(); + + case arithmetic_average: + return one_over_Nq; + + case harmonic_average: + case harmonic_average_only_viscosity: + return Utilities::fixed_power<2,double>(average_viscosity / viscosity_before_averaging) + * one_over_Nq; + + case geometric_average: + case geometric_average_only_viscosity: + case log_average: + return (average_viscosity / viscosity_before_averaging) + * one_over_Nq; + + default: + AssertThrow(false, + ExcMessage("The Newton method currently only works if the material " + "averaging scheme is ``none'', ``arithmetic average'', " + "``harmonic average (only viscosity)'', ``geometric " + "average (only viscosity)'' or ``log average''.")); + } + } + + + template + void average (const AveragingOperation operation, + const typename DoFHandler::active_cell_iterator &cell, + const Quadrature &quadrature_formula, + const Mapping &mapping, + const MaterialProperties::Property &requested_properties, + MaterialModelOutputs &values_out) + { + if (operation == none) + return; + + FullMatrix projection_matrix; + FullMatrix expansion_matrix; + + const bool average_viscosity = requested_properties & MaterialProperties::Property::viscosity; + + if (operation == project_to_Q1 + || + operation == project_to_Q1_only_viscosity) + { + Assert (quadrature_formula.size() == values_out.n_evaluation_points(), + ExcMessage("When asking for a Q1-type averaging operation, " + "this function requires to know the locations of " + "the evaluation points.")); + projection_matrix.reinit (quadrature_formula.size(), + quadrature_formula.size()); + compute_projection_matrix (cell, + quadrature_formula, + mapping, + projection_matrix, + expansion_matrix); + } + + // store the original viscosities if we need to compute the + // system jacobian later on + MaterialModelDerivatives *derivatives = + values_out.template get_additional_output>(); + + std::vector viscosity_before_averaging; + if (derivatives != nullptr) + viscosity_before_averaging = values_out.viscosities; + + // compute the average of viscosity + if (average_viscosity) + { + if (operation == harmonic_average_only_viscosity) + average_property (harmonic_average, projection_matrix, expansion_matrix, + values_out.viscosities); + + else if (operation == geometric_average_only_viscosity) + average_property (geometric_average, projection_matrix, expansion_matrix, + values_out.viscosities); + + else if (operation == project_to_Q1_only_viscosity) + average_property (project_to_Q1, projection_matrix, expansion_matrix, + values_out.viscosities); + + else + average_property (operation, projection_matrix, expansion_matrix, + values_out.viscosities); + + // calculate the weight of viscosity derivative at each + // quadrature point + if (derivatives != nullptr) + { + for (unsigned int q = 0; q < values_out.n_evaluation_points(); ++q) + derivatives->viscosity_derivative_averaging_weights[q] = + compute_viscosity_derivative_averaging_weight( + operation, values_out.viscosities[q], viscosity_before_averaging[q], + 1. / values_out.n_evaluation_points()); + } + } + + if (operation == harmonic_average_only_viscosity || + operation == geometric_average_only_viscosity || + operation == project_to_Q1_only_viscosity) + return; + + average_property (operation, projection_matrix, expansion_matrix, + values_out.densities); + average_property (operation, projection_matrix, expansion_matrix, + values_out.thermal_expansion_coefficients); + average_property (operation, projection_matrix, expansion_matrix, + values_out.specific_heat); + average_property (operation, projection_matrix, expansion_matrix, + values_out.thermal_conductivities); + average_property (operation, projection_matrix, expansion_matrix, + values_out.compressibilities); + average_property (operation, projection_matrix, expansion_matrix, + values_out.entropy_derivative_pressure); + average_property (operation, projection_matrix, expansion_matrix, + values_out.entropy_derivative_temperature); + + // The reaction terms are unfortunately stored in reverse + // indexing. It's also not quite clear whether these should + // really be averaged, so avoid this for now. + + // average all additional outputs + for (unsigned int i=0; iaverage (operation, projection_matrix, expansion_matrix); + } + } + + + + template + NamedAdditionalMaterialOutputs:: + NamedAdditionalMaterialOutputs(const std::vector &output_names) + : + names(output_names) + {} + + + + template + NamedAdditionalMaterialOutputs:: + NamedAdditionalMaterialOutputs(const std::vector &output_names, + const unsigned int n_points) + : + output_values(output_names.size(), std::vector(n_points, numbers::signaling_nan())), + names(output_names) + {} + + + + template + NamedAdditionalMaterialOutputs:: + ~NamedAdditionalMaterialOutputs() + = default; + + + + template + const std::vector & + NamedAdditionalMaterialOutputs::get_names() const + { + return names; + } + + + + template + std::vector + NamedAdditionalMaterialOutputs::get_nth_output(const unsigned int idx) const + { + // In this function we extract the values for the nth output + // The number of outputs is the outer vector + Assert (output_values.size() > idx, + ExcMessage ("The requested output index is out of range for output_values.")); + Assert (output_values[idx].size() > 0, + ExcMessage ("There must be one or more points for the nth output.")); + return output_values[idx]; + } + + + + template + PrescribedPlasticDilation::PrescribedPlasticDilation (const unsigned int n_points) + : NamedAdditionalMaterialOutputs(std::vector(1, "prescribed_dilation")), + dilation(n_points, numbers::signaling_nan()) + {} + + + + template + std::vector PrescribedPlasticDilation::get_nth_output(const unsigned int idx) const + { + (void)idx; + Assert(idx==0, ExcInternalError()); + return dilation; + } + + + + namespace + { + std::vector make_seismic_additional_outputs_names() + { + std::vector names; + names.emplace_back("seismic_Vs"); + names.emplace_back("seismic_Vp"); + return names; + } + } + + + + template + SeismicAdditionalOutputs::SeismicAdditionalOutputs (const unsigned int n_points) + : + NamedAdditionalMaterialOutputs(make_seismic_additional_outputs_names()), + vs(n_points, numbers::signaling_nan()), + vp(n_points, numbers::signaling_nan()) + {} + + + + template + std::vector + SeismicAdditionalOutputs::get_nth_output(const unsigned int idx) const + { + AssertIndexRange (idx, 2); + switch (idx) + { + case 0: + return vs; + + case 1: + return vp; + + default: + AssertThrow(false, ExcInternalError()); + } + // we will never get here, so just return something + return vs; + } + + + + namespace + { + std::vector make_reaction_rate_outputs_names(const unsigned int n_comp) + { + std::vector names; + for (unsigned int c=0; c make_prescribed_field_output_names(const unsigned int n_comp) + { + std::vector names; + for (unsigned int c=0; c + ReactionRateOutputs::ReactionRateOutputs (const unsigned int n_points, + const unsigned int n_comp) + : + NamedAdditionalMaterialOutputs(make_reaction_rate_outputs_names(n_comp)), + reaction_rates(n_points, std::vector(n_comp, std::numeric_limits::quiet_NaN())) + {} + + + + template + std::vector + ReactionRateOutputs::get_nth_output(const unsigned int idx) const + { + // we have to extract the reaction rate outputs for one particular compositional + // field, but the vector in the material model outputs is sorted so that the + // number of evaluation points (and not the compositional fields) is the outer + // vector + std::vector cth_reaction_rates(reaction_rates.size()); + for (unsigned int q=0; q make_phase_outputs_names() + { + std::vector names; + names.emplace_back("phase"); + return names; + } + } + + + + template + PhaseOutputs::PhaseOutputs (const unsigned int n_points) + : + NamedAdditionalMaterialOutputs(make_phase_outputs_names(), n_points) + {} + + + + template + PrescribedFieldOutputs::PrescribedFieldOutputs (const unsigned int n_points, + const unsigned int n_comp) + : + NamedAdditionalMaterialOutputs(make_prescribed_field_output_names(n_comp)), + prescribed_field_outputs(n_points, std::vector(n_comp, std::numeric_limits::quiet_NaN())) + {} + + + + template + std::vector + PrescribedFieldOutputs::get_nth_output(const unsigned int idx) const + { + // we have to extract the prescribed field outputs for one particular compositional + // field, but the vector in the material model outputs is sorted so that the + // number of evaluation points (and not the compositional fields) is the outer + // vector + std::vector nth_prescribed_field_output(prescribed_field_outputs.size()); + for (unsigned int q=0; q + PrescribedTemperatureOutputs::PrescribedTemperatureOutputs (const unsigned int n_points) + : + NamedAdditionalMaterialOutputs(std::vector(1,"prescribed_temperature")), + prescribed_temperature_outputs(n_points, std::numeric_limits::quiet_NaN()) + {} + + + + template + std::vector + PrescribedTemperatureOutputs::get_nth_output(const unsigned int idx) const + { + (void)idx; + AssertIndexRange (idx, 1); + return prescribed_temperature_outputs; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + template class Interface; \ + \ + template \ + void \ + register_material_model (const std::string &, \ + const std::string &, \ + void ( *) (ParameterHandler &), \ + std::unique_ptr>( *) ()); \ + \ + template \ + std::string \ + get_valid_model_names_pattern (); \ + \ + template \ + void \ + declare_parameters (ParameterHandler &); \ + \ + template \ + std::unique_ptr> \ + create_material_model (const std::string &model_name); \ + \ + template \ + void \ + write_plugin_graph (std::ostream &); \ + \ + template \ + std::unique_ptr> \ + create_material_model (ParameterHandler &prm); \ + \ + template class MaterialModelInputs; \ + \ + template class MaterialModelOutputs; \ + \ + template class AdditionalMaterialOutputs; \ + \ + template class NamedAdditionalMaterialOutputs; \ + \ + template class SeismicAdditionalOutputs; \ + \ + template class ReactionRateOutputs; \ + \ + template class PhaseOutputs; \ + \ + template class PrescribedPlasticDilation; \ + \ + template class PrescribedFieldOutputs; \ + \ + template class PrescribedTemperatureOutputs; \ + \ + namespace MaterialAveraging \ + { \ + template \ + void average (const AveragingOperation operation, \ + const DoFHandler::active_cell_iterator &cell, \ + const Quadrature &quadrature_formula, \ + const Mapping &mapping, \ + const MaterialProperties::Property &requested_properties, \ + MaterialModelOutputs &values_out); \ + } + + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/latent_heat.cc.bak b/source/material_model/latent_heat.cc.bak new file mode 100644 index 00000000000..dd4a69ccac8 --- /dev/null +++ b/source/material_model/latent_heat.cc.bak @@ -0,0 +1,422 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + void + LatentHeat:: + evaluate(const MaterialModelInputs &in, + MaterialModelOutputs &out) const + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const double temperature = in.temperature[i]; + const double pressure = in.pressure[i]; + const std::vector composition = in.composition[i]; + const Point position = in.position[i]; + + // Assign constant material properties + { + out.specific_heat[i] = reference_specific_heat; + out.thermal_conductivities[i] = k_value; + out.thermal_expansion_coefficients[i] = thermal_alpha; + out.compressibilities[i] = reference_compressibility; + } + + // Calculate Viscosity + { + const double reference_temperature = (this->include_adiabatic_heating() + ? + this->get_adiabatic_conditions().temperature(in.position[i]) + : + reference_T); + + const double delta_temp = temperature-reference_temperature; + const double T_dependence = ( thermal_viscosity_exponent == 0.0 + ? + 0.0 + : + thermal_viscosity_exponent * delta_temp / reference_temperature ); + + double visc_temperature_dependence = std::max(std::min(std::exp(-T_dependence),1e2),1e-2); + + if (std::isnan(visc_temperature_dependence)) + visc_temperature_dependence = 1.0; + + double visc_composition_dependence = 1.0; + if ((composition_viscosity_prefactor != 1.0) && (composition.size() > 0)) + { + // geometric interpolation + out.viscosities[i] = (pow(10, ((1-composition[0]) * log10(eta*visc_temperature_dependence) + + composition[0] * log10(eta*composition_viscosity_prefactor*visc_temperature_dependence)))); + } + else + out.viscosities[i] = visc_composition_dependence * visc_temperature_dependence * eta; + } + + // Calculate density + // and phase dependence of viscosity + { + // first, calculate temperature dependence of density + // temperature dependence is 1 - alpha * (T - T(adiabatic)) + const double density_temperature_dependence = 1.0 - (temperature - this->get_adiabatic_conditions().temperature(position)) + * thermal_alpha; + + // second, calculate composition dependence of density + // constant density difference between peridotite and eclogite + const double density_composition_dependence = composition.size()>0 + ? + compositional_delta_rho * composition[0] + : + 0.0; + + // third, calculate the density (and viscosity) differences due to phase + // transitions (temperature- and pressure dependence included). + // the phase function gives the percentage of material that has + // already undergone the phase transition to the higher-pressure material + // (this is done individual for each transitions and summed up + // in the end) + // this means, that there are no actual density or viscosity "jumps", but + // gradual transitions between the materials + double phase_dependence = 0.0; + double viscosity_phase_dependence = 1.0; + + // Loop through phase transitions + for (unsigned int phase=0; phaseget_geometry_model().depth(position); + const double pressure_depth_derivative = (depth > 0.0) + ? + this->get_adiabatic_conditions().pressure(position) / depth + : + this->get_gravity_model().gravity_vector(position).norm() * reference_rho; + + const MaterialUtilities::PhaseFunctionInputs phase_in(temperature, + pressure, + depth, + pressure_depth_derivative, + phase); + + const double phaseFunction = phase_function.compute_value(phase_in); + + // Note that for the densities we have a list of jumps, so the index used + // in the loop corresponds to the index of the phase transition. For the + // viscosities we have a list of prefactors, which has one more entry + // for the first layer, so we have to use phase+1 as the index. + if (composition.size()==0) + { + phase_dependence += phaseFunction * density_jumps[phase]; + viscosity_phase_dependence *= 1. + phaseFunction * (phase_prefactors[phase+1]-1.); + } + else if (composition.size()>0) + { + if (transition_phases[phase] == 0) // 1st compositional field + phase_dependence += phaseFunction * density_jumps[phase] * (1.0 - composition[0]); + else if (transition_phases[phase] == 1) // 2nd compositional field + phase_dependence += phaseFunction * density_jumps[phase] * composition[0]; + + viscosity_phase_dependence *= 1. + phaseFunction * (phase_prefactors[phase]-1.); + } + } + + // fourth, pressure dependence of density + const double kappa = reference_compressibility; + const double pressure_dependence = reference_rho * kappa * (pressure - this->get_surface_pressure()); + + // In the end, all the influences are added up. + // In the non-Boussinesq case, we chose to add the composition-, pressure-, and phase-dependent terms + // first, before applying the density changes due to thermal expansion, because they can be relatively + // large and should be taken into account for the temperature dependence (for example, if the material + // has a different density because it is in a new phase, we should take the density of that new phase + // to compute thermal expansion effects). + out.densities[i] = (reference_rho + density_composition_dependence + pressure_dependence + phase_dependence) + * density_temperature_dependence; + + // For the Boussinesq approximation, all terms are linearized and added separately (that is simply how + // the Boussinesq approximation is defined). This means we have to apply the temperature term first + // since it is (1 - alpha T). + if (this->get_parameters().formulation == Parameters::Formulation::boussinesq_approximation) + out.densities[i] = (reference_rho * density_temperature_dependence + density_composition_dependence + phase_dependence); + + out.viscosities[i] = std::max(minimum_viscosity, std::min(maximum_viscosity, out.viscosities[i] * viscosity_phase_dependence)); + } + + // Calculate entropy derivative + { + double entropy_gradient_pressure = 0.0; + double entropy_gradient_temperature = 0.0; + const double rho = out.densities[i]; + + if (this->get_adiabatic_conditions().is_initialized() && this->include_latent_heat()) + for (unsigned int phase=0; phaseget_geometry_model().depth(in.position[i]); + const double pressure_depth_derivative = (this->get_adiabatic_conditions().pressure(position) > 0) + ? + depth / this->get_adiabatic_conditions().pressure(position) + : + this->get_gravity_model().gravity_vector(in.position[i]).norm() * reference_rho; + + const MaterialUtilities::PhaseFunctionInputs phase_in(temperature, + pressure, + depth, + pressure_depth_derivative, + phase); + + const double PhaseFunctionDerivative = phase_function.compute_derivative(phase_in); + const double clapeyron_slope = phase_function.get_transition_slope(phase); + + double entropy_change = 0.0; + if (composition.size()==0) // only one compositional field + entropy_change = clapeyron_slope * density_jumps[phase] / (rho * rho); + else + { + if (transition_phases[phase] == 0) // 1st compositional field + entropy_change = clapeyron_slope * density_jumps[phase] / (rho * rho) * (1.0 - composition[0]); + else if (transition_phases[phase] == 1) // 2nd compositional field + entropy_change = clapeyron_slope * density_jumps[phase] / (rho * rho) * composition[0]; + } + // we need DeltaS * DX/Dpressure_deviation for the pressure derivative + // and - DeltaS * DX/Dpressure_deviation * gamma for the temperature derivative + entropy_gradient_pressure += PhaseFunctionDerivative * entropy_change; + entropy_gradient_temperature -= PhaseFunctionDerivative * entropy_change * clapeyron_slope; + } + + out.entropy_derivative_pressure[i] = entropy_gradient_pressure; + out.entropy_derivative_temperature[i] = entropy_gradient_temperature; + } + + // Assign reaction terms + for (unsigned int c=0; c + bool + LatentHeat:: + is_compressible () const + { + if (reference_compressibility > 0) + return true; + else + return false; + } + + + + template + void + LatentHeat::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Latent heat"); + { + prm.declare_entry ("Reference density", "3300.", + Patterns::Double (0.), + "Reference density $\\rho_0$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. Units: \\si{\\kelvin}."); + prm.declare_entry ("Viscosity", "5e24", + Patterns::Double (0.), + "The value of the constant viscosity. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Composition viscosity prefactor", "1.0", + Patterns::Double (0.), + "A linear dependency of viscosity on composition. Dimensionless prefactor."); + prm.declare_entry ("Thermal viscosity exponent", "0.0", + Patterns::Double (0.), + "The temperature dependence of viscosity. Dimensionless exponent."); + prm.declare_entry ("Thermal conductivity", "2.38", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Reference specific heat", "1250.", + Patterns::Double (0.), + "The value of the specific heat $C_p$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Thermal expansion coefficient", "4e-5", + Patterns::Double (0.), + "The value of the thermal expansion coefficient $\\beta$. " + "Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Compressibility", "5.124e-12", + Patterns::Double (0.), + "The value of the compressibility $\\kappa$. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("Density differential for compositional field 1", "0.", + Patterns::Double(), + "If compositional fields are used, then one would frequently want " + "to make the density depend on these fields. In this simple material " + "model, we make the following assumptions: if no compositional fields " + "are used in the current simulation, then the density is simply the usual " + "one with its linear dependence on the temperature. If there are compositional " + "fields, then the density only depends on the first one in such a way that " + "the density has an additional term of the kind $+\\Delta \\rho \\; c_1(\\mathbf x)$. " + "This parameter describes the value of $\\Delta \\rho$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}/unit change in composition."); + prm.declare_entry ("Phase transition density jumps", "", + Patterns::List (Patterns::Double (0.)), + "A list of density jumps at each phase transition. A positive value means " + "that the density increases with depth. The corresponding entry in " + "Corresponding phase for density jump determines if the density jump occurs " + "in peridotite, eclogite or none of them." + "List must have the same number of entries as Phase transition depths. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Corresponding phase for density jump", "", + Patterns::List (Patterns::Integer(0)), + "A list of phases, which correspond to the Phase transition density jumps. " + "The density jumps occur only in the phase that is given by this phase value. " + "0 stands for the 1st compositional fields, 1 for the second compositional field " + "and -1 for none of them. " + "List must have the same number of entries as Phase transition depths. " + "Units: \\si{\\pascal\\per\\kelvin}."); + prm.declare_entry ("Viscosity prefactors", "", + Patterns::List (Patterns::Double (0.)), + "A list of prefactors for the viscosity for each phase. The reference " + "viscosity will be multiplied by this factor to get the corresponding " + "viscosity for each phase. " + "List must have one more entry than Phase transition depths. " + "Units: non-dimensional."); + prm.declare_entry ("Minimum viscosity", "1e19", + Patterns::Double (0.), + "Limit for the minimum viscosity in the model. " + "Units: Pa \\, s."); + prm.declare_entry ("Maximum viscosity", "1e24", + Patterns::Double (0.), + "Limit for the maximum viscosity in the model. " + "Units: Pa \\, s."); + + MaterialUtilities::PhaseFunction::declare_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + LatentHeat::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Latent heat"); + { + reference_rho = prm.get_double ("Reference density"); + reference_T = prm.get_double ("Reference temperature"); + eta = prm.get_double ("Viscosity"); + composition_viscosity_prefactor = prm.get_double ("Composition viscosity prefactor"); + thermal_viscosity_exponent = prm.get_double ("Thermal viscosity exponent"); + k_value = prm.get_double ("Thermal conductivity"); + reference_specific_heat = prm.get_double ("Reference specific heat"); + thermal_alpha = prm.get_double ("Thermal expansion coefficient"); + reference_compressibility = prm.get_double ("Compressibility"); + compositional_delta_rho = prm.get_double ("Density differential for compositional field 1"); + minimum_viscosity = prm.get_double ("Minimum viscosity"); + maximum_viscosity = prm.get_double ("Maximum viscosity"); + + phase_function.initialize_simulator (this->get_simulator()); + phase_function.parse_parameters (prm); + + density_jumps = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Phase transition density jumps"))); + transition_phases = Utilities::string_to_int + (Utilities::split_string_list(prm.get ("Corresponding phase for density jump"))); + phase_prefactors = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Viscosity prefactors"))); + + const unsigned int n_transitions = phase_function.n_phase_transitions(); + if (density_jumps.size() != n_transitions || + transition_phases.size() != n_transitions || + phase_prefactors.size() != n_transitions+1) + AssertThrow(false, ExcMessage("Error: At least one list that provides input parameters for phase " + "transitions has the wrong size. The phase function object reports that " + "there are " + std::to_string(n_transitions) + " transitions, " + "therefore the material model expects " + std::to_string(n_transitions) + + " density jumps and corresponding phases, and " + + std::to_string(n_transitions+1) + " viscosity prefactors.")); + + // as the phase viscosity prefactors are all applied multiplicatively on top of each other, + // we have to scale them here so that they are relative factors in comparison to the product + // of the prefactors of all phase above the current one + for (unsigned int phase=1; phasemodel_dependence.viscosity = NonlinearDependence::temperature | NonlinearDependence::compositional_fields; + this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(LatentHeat, + "latent heat", + "A material model that includes phase transitions " + "and the possibility that latent heat is released " + "or absorbed when material crosses one of the " + "phase transitions of up to two different materials " + "(compositional fields). " + "This model implements a standard approximation " + "of the latent heat terms following Christensen \\& Yuen, 1985 \\cite{christensen:yuen:1985}. " + "The change of entropy is calculated as " + "$\\Delta S = \\gamma \\frac{\\Delta\\rho}{\\rho^2}$ with the " + "Clapeyron slope $\\gamma$ and the density change $\\Delta\\rho$ " + "of the phase transition being input parameters. " + "The model employs an analytic phase function in the form " + "$X=\\frac{1}{2} \\left( 1 + \\tanh \\left( \\frac{\\Delta p}{\\Delta p_0} \\right) \\right)$ " + "with $\\Delta p = p - p_{\\text{transition}} - \\gamma \\left( T - T_{\\text{transition}} \\right)$ " + "and $\\Delta p_0$ being the pressure difference over the width " + "of the phase transition (specified as input parameter).") + } +} diff --git a/source/material_model/latent_heat_melt.cc.bak b/source/material_model/latent_heat_melt.cc.bak new file mode 100644 index 00000000000..1cfab292052 --- /dev/null +++ b/source/material_model/latent_heat_melt.cc.bak @@ -0,0 +1,660 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + void + LatentHeatMelt:: + + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + + out.entropy_derivative_pressure[i] = 0; + out.entropy_derivative_temperature[i] = 0; + + for (unsigned int c=0; c < in.composition[i].size(); ++c ) + { + out.reaction_terms[i][c] = 0; + } + + std::vector composition = in.composition[i]; + + const double reference_temperature = (this->include_adiabatic_heating() + ? + this->get_adiabatic_conditions().temperature(in.position[i]) + : + reference_T); + + const double delta_temp = in.temperature[i] - reference_temperature; + const double T_dependence = ( thermal_viscosity_exponent == 0.0 + ? + 0.0 + : + thermal_viscosity_exponent * delta_temp / reference_temperature ); + + + double temperature_dependence = std::max (std::min ( std::exp( - T_dependence ), 1e2 ), 1e-2 ); + + if (std::isnan(temperature_dependence)) + temperature_dependence = 1.0; + + double composition_dependence = 1.0; + if ((composition_viscosity_prefactor != 1.0) && (composition.size() > 0)) + { + //geometric interpolation + out.viscosities[i] = (pow (10, ( (1 - composition[0] ) * log10 ( eta * temperature_dependence ) + + composition[0] * log10 ( eta * composition_viscosity_prefactor * temperature_dependence)))); + } + else + { + out.viscosities[i] = composition_dependence * temperature_dependence * eta; + } + + out.specific_heat[i] = reference_specific_heat; + out.thermal_conductivities[i] = k_value; + out.thermal_expansion_coefficients[i] = thermal_alpha; + out.compressibilities[i] = reference_compressibility; + + temperature_dependence = 1.0; + + if (this->include_adiabatic_heating ()) + { + // temperature dependence is 1 - alpha * (T - T(adiabatic)) + temperature_dependence -= (in.temperature[i] - this->get_adiabatic_conditions().temperature(in.position[i])) * thermal_alpha; + } + else + { + temperature_dependence -= in.temperature[i] * thermal_alpha; + } + // second, calculate composition dependence of density + // constant density difference between peridotite and eclogite + composition_dependence = composition.size()>0 + ? + compositional_delta_rho * composition[0] + : + 0.0; + + // third, pressure dependence of density + const double kappa = reference_compressibility; + const double pressure_dependence = reference_rho * kappa * (in.pressure[i] - this->get_surface_pressure()); + + // fourth, melt fraction dependence + double melt_dependence = (1.0 - relative_melt_density) + * melt_fraction(in.temperature[i], in.pressure[i], in.composition[i], in.position[i]); + + // in the end, all the influences are added up + out.densities[i] = (reference_rho + composition_dependence + pressure_dependence) * temperature_dependence + * (1.0 - melt_dependence); + + + out.entropy_derivative_pressure[i] = entropy_derivative (in.temperature[i], in.pressure[i], composition, + in.position[i], NonlinearDependence::pressure) ; // for pressure dependence + + out.entropy_derivative_temperature[i] = entropy_derivative (in.temperature[i], in.pressure[i], composition, + in.position[i], NonlinearDependence::temperature) ; // for temperature dependence + + } + } + + + + template + double + LatentHeatMelt:: + entropy_derivative (const double temperature, + const double pressure, + const std::vector &compositional_fields, + const Point &position, + const NonlinearDependence::Dependence dependence) const + { + double entropy_gradient = 0.0; + + // calculate latent heat of melting + // we need the change of melt fraction in dependence of pressure and temperature + + // for peridotite after Katz, 2003 + const double T_solidus = A1 + 273.15 + + A2 * pressure + + A3 * pressure * pressure; + const double T_lherz_liquidus = B1 + 273.15 + + B2 * pressure + + B3 * pressure * pressure; + const double T_liquidus = C1 + 273.15 + + C2 * pressure + + C3 * pressure * pressure; + + const double dT_solidus_dp = A2 + 2 * A3 * pressure; + const double dT_lherz_liquidus_dp = B2 + 2 * B3 * pressure; + const double dT_liquidus_dp = C2 + 2 * C3 * pressure; + + const double peridotite_fraction = (this->n_compositional_fields()>0 + ? + 1.0 - compositional_fields[0] + : + 1.0); + + if (temperature > T_solidus && temperature < T_liquidus && pressure < 1.3e10) + { + // melt fraction when clinopyroxene is still present + double melt_fraction_derivative_temperature + = beta * pow((temperature - T_solidus)/(T_lherz_liquidus - T_solidus),beta-1) + / (T_lherz_liquidus - T_solidus); + + double melt_fraction_derivative_pressure + = beta * pow((temperature - T_solidus)/(T_lherz_liquidus - T_solidus),beta-1) + * (dT_solidus_dp * (temperature - T_lherz_liquidus) + + dT_lherz_liquidus_dp * (T_solidus - temperature)) + / pow(T_lherz_liquidus - T_solidus,2); + + // melt fraction after melting of all clinopyroxene + const double R_cpx = r1 + r2 * pressure; + const double F_max = M_cpx / R_cpx; + + if (peridotite_melt_fraction(temperature, pressure, compositional_fields, position) > F_max) + { + const double T_max = std::pow(F_max,1.0/beta) * (T_lherz_liquidus - T_solidus) + T_solidus; + const double dF_max_dp = - M_cpx * std::pow(r1 + r2 * pressure,-2) * r2; + const double dT_max_dp = dT_solidus_dp + + 1.0/beta * std::pow(F_max,1.0/beta - 1.0) * dF_max_dp * (T_lherz_liquidus - T_solidus) + + std::pow(F_max,1.0/beta) * (dT_lherz_liquidus_dp - dT_solidus_dp); + + melt_fraction_derivative_temperature + = (1.0 - F_max) * beta * std::pow((temperature - T_max)/(T_liquidus - T_max),beta-1) + / (T_liquidus - T_max); + + melt_fraction_derivative_pressure + = dF_max_dp + - dF_max_dp * std::pow((temperature - T_max)/(T_liquidus - T_max),beta) + + (1.0 - F_max) * beta * std::pow((temperature - T_max)/(T_liquidus - T_max),beta-1) + * (dT_max_dp * (T_max - T_liquidus) - (dT_liquidus_dp - dT_max_dp) * (temperature - T_max)) / std::pow(T_liquidus - T_max, 2); + } + + double melt_fraction_derivative = 0; + if (dependence == NonlinearDependence::temperature) + melt_fraction_derivative = melt_fraction_derivative_temperature; + else if (dependence == NonlinearDependence::pressure) + melt_fraction_derivative = melt_fraction_derivative_pressure; + else + AssertThrow(false, ExcMessage("Error in calculating melt fraction derivative: not implemented")); + + entropy_gradient += melt_fraction_derivative * peridotite_melting_entropy_change * peridotite_fraction; + } + + + // for melting of pyroxenite after Sobolev et al., 2011 + if (this->n_compositional_fields()>0) + { + // calculate change of entropy for melting all material + const double X = pyroxenite_melt_fraction(temperature, pressure, compositional_fields, position); + + // calculate change of melt fraction in dependence of pressure and temperature + const double T_melting = D1 + 273.15 + + D2 * pressure + + D3 * pressure * pressure; + const double dT_melting_dp = 2*D3*pressure + D2; + const double discriminant = E1*E1/(E2*E2*4) + (temperature-T_melting)/E2; + + double melt_fraction_derivative = 0.0; + if (temperature > T_melting && X < F_px_max && pressure < 1.3e10) + { + if (dependence == NonlinearDependence::temperature) + melt_fraction_derivative = -1.0/(2*E2 * sqrt(discriminant)); + else if (dependence == NonlinearDependence::pressure) + melt_fraction_derivative = (dT_melting_dp)/(2*E2 * sqrt(discriminant)); + else + AssertThrow(false, ExcMessage("Error in calculating melt fraction derivative: not implemented")); + } + + entropy_gradient += melt_fraction_derivative * pyroxenite_melting_entropy_change * compositional_fields[0]; + } + + return entropy_gradient; + } + + + template + void + LatentHeatMelt:: + melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const + { + for (unsigned int q=0; q + double + LatentHeatMelt:: + peridotite_melt_fraction (const double temperature, + const double pressure, + const std::vector &, + const Point &) const + { + // anhydrous melting of peridotite after Katz, 2003 + const double T_solidus = A1 + 273.15 + + A2 * pressure + + A3 * pressure * pressure; + const double T_lherz_liquidus = B1 + 273.15 + + B2 * pressure + + B3 * pressure * pressure; + const double T_liquidus = C1 + 273.15 + + C2 * pressure + + C3 * pressure * pressure; + + // melt fraction for peridotite with clinopyroxene + double peridotite_melt_fraction; + if (temperature < T_solidus || pressure > 1.3e10) + peridotite_melt_fraction = 0.0; + else if (temperature > T_lherz_liquidus) + peridotite_melt_fraction = 1.0; + else + peridotite_melt_fraction = std::pow((temperature - T_solidus) / (T_lherz_liquidus - T_solidus),beta); + + // melt fraction after melting of all clinopyroxene + const double R_cpx = r1 + r2 * pressure; + const double F_max = M_cpx / R_cpx; + + if (peridotite_melt_fraction > F_max && temperature < T_liquidus) + { + const double T_max = std::pow(F_max,1/beta) * (T_lherz_liquidus - T_solidus) + T_solidus; + peridotite_melt_fraction = F_max + (1 - F_max) * pow((temperature - T_max) / (T_liquidus - T_max),beta); + } + return peridotite_melt_fraction; + + } + + template + double + LatentHeatMelt:: + pyroxenite_melt_fraction (const double temperature, + const double pressure, + const std::vector &, + const Point &) const + { + // melting of pyroxenite after Sobolev et al., 2011 + const double T_melting = D1 + 273.15 + + D2 * pressure + + D3 * pressure * pressure; + + const double discriminant = E1*E1/(E2*E2*4) + (temperature-T_melting)/E2; + + double pyroxenite_melt_fraction; + if (temperature < T_melting || pressure > 1.3e10) + pyroxenite_melt_fraction = 0.0; + else if (discriminant < 0) + pyroxenite_melt_fraction = F_px_max; + else + pyroxenite_melt_fraction = -E1/(2*E2) - std::sqrt(discriminant); + + return pyroxenite_melt_fraction; + } + + template + double + LatentHeatMelt:: + melt_fraction (const double temperature, + const double pressure, + const std::vector &composition, /*composition*/ + const Point &position) const + { + return (this->n_compositional_fields()>0 + ? + pyroxenite_melt_fraction(temperature, pressure, composition, position) + * composition[0] + + + peridotite_melt_fraction(temperature, pressure, composition, position) + * (1.0 - composition[0]) + : + peridotite_melt_fraction(temperature, pressure, composition, position)); + + } + + + + template + bool + LatentHeatMelt:: + is_compressible () const + { + if (reference_compressibility > 0) + return true; + else + return false; + } + + + + template + void + LatentHeatMelt::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Latent heat melt"); + { + prm.declare_entry ("Reference density", "3300.", + Patterns::Double (0.), + "Reference density $\\rho_0$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. Units: \\si{\\kelvin}."); + prm.declare_entry ("Viscosity", "5e24", + Patterns::Double (0.), + "The value of the constant viscosity. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Composition viscosity prefactor", "1.0", + Patterns::Double (0.), + "A linear dependency of viscosity on composition. Dimensionless prefactor."); + prm.declare_entry ("Thermal viscosity exponent", "0.0", + Patterns::Double (0.), + "The temperature dependence of viscosity. Dimensionless exponent."); + prm.declare_entry ("Thermal conductivity", "2.38", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Reference specific heat", "1250.", + Patterns::Double (0.), + "The value of the specific heat $C_p$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Thermal expansion coefficient", "4e-5", + Patterns::Double (0.), + "The value of the thermal expansion coefficient $\\alpha_s$. " + "Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Thermal expansion coefficient of melt", "6.8e-5", + Patterns::Double (0.), + "The value of the thermal expansion coefficient $\\alpha_f$. " + "Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Compressibility", "5.124e-12", + Patterns::Double (0.), + "The value of the compressibility $\\kappa$. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("Density differential for compositional field 1", "0.", + Patterns::Double(), + "If compositional fields are used, then one would frequently want " + "to make the density depend on these fields. In this simple material " + "model, we make the following assumptions: if no compositional fields " + "are used in the current simulation, then the density is simply the usual " + "one with its linear dependence on the temperature. If there are compositional " + "fields, then the density only depends on the first one in such a way that " + "the density has an additional term of the kind $+\\Delta \\rho \\; c_1(\\mathbf x)$. " + "This parameter describes the value of $\\Delta \\rho$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}/unit change in composition."); + prm.declare_entry ("A1", "1085.7", + Patterns::Double (), + "Constant parameter in the quadratic " + "function that approximates the solidus " + "of peridotite. " + "Units: \\si{\\degreeCelsius}."); + prm.declare_entry ("A2", "1.329e-7", + Patterns::Double (), + "Prefactor of the linear pressure term " + "in the quadratic function that approximates " + "the solidus of peridotite. " + "Units: \\si{\\degreeCelsius\\per\\pascal}."); + prm.declare_entry ("A3", "-5.1e-18", + Patterns::Double (), + "Prefactor of the quadratic pressure term " + "in the quadratic function that approximates " + "the solidus of peridotite. " + "Units: \\si{\\degreeCelsius\\per\\pascal\\squared}."); + prm.declare_entry ("B1", "1475.0", + Patterns::Double (), + "Constant parameter in the quadratic " + "function that approximates the lherzolite " + "liquidus used for calculating the fraction " + "of peridotite-derived melt. " + "Units: \\si{\\degreeCelsius}."); + prm.declare_entry ("B2", "8.0e-8", + Patterns::Double (), + "Prefactor of the linear pressure term " + "in the quadratic function that approximates " + "the lherzolite liquidus used for " + "calculating the fraction of peridotite-" + "derived melt. " + "Units: \\si{\\degreeCelsius\\per\\pascal}."); + prm.declare_entry ("B3", "-3.2e-18", + Patterns::Double (), + "Prefactor of the quadratic pressure term " + "in the quadratic function that approximates " + "the lherzolite liquidus used for " + "calculating the fraction of peridotite-" + "derived melt. " + "Units: \\si{\\degreeCelsius\\per\\pascal\\squared}."); + prm.declare_entry ("C1", "1780.0", + Patterns::Double (), + "Constant parameter in the quadratic " + "function that approximates the liquidus " + "of peridotite. " + "Units: \\si{\\degreeCelsius}."); + prm.declare_entry ("C2", "4.50e-8", + Patterns::Double (), + "Prefactor of the linear pressure term " + "in the quadratic function that approximates " + "the liquidus of peridotite. " + "Units: \\si{\\degreeCelsius\\per\\pascal}."); + prm.declare_entry ("C3", "-2.0e-18", + Patterns::Double (), + "Prefactor of the quadratic pressure term " + "in the quadratic function that approximates " + "the liquidus of peridotite. " + "Units: \\si{\\degreeCelsius\\per\\pascal\\squared}."); + prm.declare_entry ("r1", "0.5", + Patterns::Double (), + "Constant in the linear function that " + "approximates the clinopyroxene reaction " + "coefficient. " + "Units: non-dimensional."); + prm.declare_entry ("r2", "8e-11", + Patterns::Double (), + "Prefactor of the linear pressure term " + "in the linear function that approximates " + "the clinopyroxene reaction coefficient. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("beta", "1.5", + Patterns::Double (), + "Exponent of the melting temperature in " + "the melt fraction calculation. " + "Units: non-dimensional."); + prm.declare_entry ("Peridotite melting entropy change", "-300.", + Patterns::Double (), + "The entropy change for the phase transition " + "from solid to melt of peridotite. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Mass fraction cpx", "0.15", + Patterns::Double (), + "Mass fraction of clinopyroxene in the " + "peridotite to be molten. " + "Units: non-dimensional."); + prm.declare_entry ("D1", "976.0", + Patterns::Double (), + "Constant parameter in the quadratic " + "function that approximates the solidus " + "of pyroxenite. " + "Units: \\si{\\degreeCelsius}."); + prm.declare_entry ("D2", "1.329e-7", + Patterns::Double (), + "Prefactor of the linear pressure term " + "in the quadratic function that approximates " + "the solidus of pyroxenite. " + "Note that this factor is different from the " + "value given in Sobolev, 2011, because they use " + "the potential temperature whereas we use the " + "absolute temperature. " + "Units: \\si{\\degreeCelsius\\per\\pascal}."); + prm.declare_entry ("D3", "-5.1e-18", + Patterns::Double (), + "Prefactor of the quadratic pressure term " + "in the quadratic function that approximates " + "the solidus of pyroxenite. " + "Units: \\si{\\degreeCelsius\\per\\pascal\\squared}."); + prm.declare_entry ("E1", "663.8", + Patterns::Double (), + "Prefactor of the linear depletion term " + "in the quadratic function that approximates " + "the melt fraction of pyroxenite. " + "Units: \\si{\\degreeCelsius\\per\\pascal}."); + prm.declare_entry ("E2", "-611.4", + Patterns::Double (), + "Prefactor of the quadratic depletion term " + "in the quadratic function that approximates " + "the melt fraction of pyroxenite. " + "Units: \\si{\\degreeCelsius\\per\\pascal\\squared}."); + prm.declare_entry ("Pyroxenite melting entropy change", "-400.", + Patterns::Double (), + "The entropy change for the phase transition " + "from solid to melt of pyroxenite. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Maximum pyroxenite melt fraction", "0.5429", + Patterns::Double (), + "Maximum melt fraction of pyroxenite " + "in this parameterization. At higher " + "temperatures peridotite begins to melt."); + prm.declare_entry ("Relative density of melt", "0.9", + Patterns::Double (), + "The relative density of melt compared to the " + "solid material. This means, the density change " + "upon melting is this parameter times the density " + "of solid material." + "Units: non-dimensional."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + LatentHeatMelt::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Latent heat melt"); + { + reference_rho = prm.get_double ("Reference density"); + reference_T = prm.get_double ("Reference temperature"); + eta = prm.get_double ("Viscosity"); + composition_viscosity_prefactor = prm.get_double ("Composition viscosity prefactor"); + thermal_viscosity_exponent = prm.get_double ("Thermal viscosity exponent"); + k_value = prm.get_double ("Thermal conductivity"); + reference_specific_heat = prm.get_double ("Reference specific heat"); + thermal_alpha = prm.get_double ("Thermal expansion coefficient"); + melt_thermal_alpha = prm.get_double ("Thermal expansion coefficient of melt"); + reference_compressibility = prm.get_double ("Compressibility"); + compositional_delta_rho = prm.get_double ("Density differential for compositional field 1"); + + if (thermal_viscosity_exponent!=0.0 && reference_T == 0.0) + AssertThrow(false, ExcMessage("Error: Material model latent heat with Thermal viscosity exponent can not have reference_T=0.")); + + A1 = prm.get_double ("A1"); + A2 = prm.get_double ("A2"); + A3 = prm.get_double ("A3"); + B1 = prm.get_double ("B1"); + B2 = prm.get_double ("B2"); + B3 = prm.get_double ("B3"); + C1 = prm.get_double ("C1"); + C2 = prm.get_double ("C2"); + C3 = prm.get_double ("C3"); + r1 = prm.get_double ("r1"); + r2 = prm.get_double ("r2"); + beta = prm.get_double ("beta"); + peridotite_melting_entropy_change + = prm.get_double ("Peridotite melting entropy change"); + + M_cpx = prm.get_double ("Mass fraction cpx"); + D1 = prm.get_double ("D1"); + D2 = prm.get_double ("D2"); + D3 = prm.get_double ("D3"); + E1 = prm.get_double ("E1"); + E2 = prm.get_double ("E2"); + pyroxenite_melting_entropy_change + = prm.get_double ("Pyroxenite melting entropy change"); + + F_px_max = prm.get_double ("Maximum pyroxenite melt fraction"); + relative_melt_density = prm.get_double ("Relative density of melt"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::temperature | NonlinearDependence::compositional_fields; + this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(LatentHeatMelt, + "latent heat melt", + "A material model that includes the latent heat of melting " + "for two materials: peridotite and pyroxenite. The melting model " + "for peridotite is taken from Katz et al., 2003 (A new " + "parameterization of hydrous mantle melting) and the one for " + "pyroxenite from Sobolev et al., 2011 (Linking mantle plumes, " + "large igneous provinces and environmental catastrophes). " + "The model assumes a constant entropy change for melting 100\\% " + "of the material, which can be specified in the input file. " + "The partial derivatives of entropy with respect to temperature " + "and pressure required for calculating the latent heat consumption " + "are then calculated as product of this constant entropy change, " + "and the respective derivative of the function the describes the " + "melt fraction. This is linearly averaged with respect to the " + "fractions of the two materials present. " + "If no compositional fields are specified in the input file, the " + "model assumes that the material is peridotite. If compositional " + "fields are specified, the model assumes that the first compositional " + "field is the fraction of pyroxenite and the rest of the material " + "is peridotite. " + "\n\n" + "Otherwise, this material model has a temperature- and pressure-" + "dependent density and viscosity and the density and thermal " + "expansivity depend on the melt fraction present. " + "It is possible to extent this model to include a melt fraction " + "dependence of all the material parameters by calling the " + "function melt_fraction in the calculation of the respective " + "parameter. " + "However, melt and solid move with the same velocity and " + "melt extraction is not taken into account (batch melting). ") + } +} diff --git a/source/material_model/melt_boukare.cc b/source/material_model/melt_boukare.cc index 2e0b0ab91c2..4022c8161ae 100644 --- a/source/material_model/melt_boukare.cc +++ b/source/material_model/melt_boukare.cc @@ -508,7 +508,7 @@ namespace aspect const unsigned int n_endmembers = endmember_names.size(); EndmemberProperties endmembers(n_endmembers); - for (unsigned int q=0; q endmember_mole_fractions_per_phase(n_endmembers); @@ -627,7 +627,7 @@ namespace aspect const unsigned int n_endmembers = endmember_names.size(); EndmemberProperties endmembers(n_endmembers); - for (unsigned int q=0; q endmember_mole_fractions_per_phase(n_endmembers); std::vector endmember_mole_fractions_in_composite(n_endmembers); diff --git a/source/material_model/melt_boukare.cc.bak b/source/material_model/melt_boukare.cc.bak new file mode 100644 index 00000000000..2e0b0ab91c2 --- /dev/null +++ b/source/material_model/melt_boukare.cc.bak @@ -0,0 +1,1314 @@ +/* + Copyright (C) 2015 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace + { + std::vector make_boukare_additional_outputs_names() + { + std::vector names; + names.emplace_back("bulk_composition"); + names.emplace_back("molar_volatiles_in_melt"); + return names; + } + } + + + + template + BoukareOutputs::BoukareOutputs (const unsigned int n_points) + : + NamedAdditionalMaterialOutputs(make_boukare_additional_outputs_names()), + bulk_composition(n_points, numbers::signaling_nan()), + molar_volatiles_in_melt(n_points, numbers::signaling_nan()) + {} + + + + template + std::vector + BoukareOutputs::get_nth_output(const unsigned int idx) const + { + AssertIndexRange (idx, 2); + if (idx == 0) + return bulk_composition; + else + return molar_volatiles_in_melt; + } + + + + template + void + MeltBoukare::initialize() + { + // Compute parameters for the modified Tait equation of state for the different endmembers + // derived from the isothermal bulk modulus and its two first pressure derivatives. + // This corresponds to Equation 4 from Holland and Powell, 2011 (https://doi.org/10.1111/j.1525-1314.2010.00923.x). + + const unsigned int n_endmembers = reference_bulk_moduli.size(); + + tait_parameters_a.resize(n_endmembers); + tait_parameters_b.resize(n_endmembers); + tait_parameters_c.resize(n_endmembers); + + for (unsigned int i=0; i + double + MeltBoukare:: + reference_darcy_coefficient () const + { + // 0.01 = 1% melt + return reference_permeability * std::pow(0.01,3.0) / eta_f; + } + + template + bool + MeltBoukare:: + is_compressible () const + { + return true; + } + + + template + MeltBoukare:: + EndmemberProperties::EndmemberProperties(const unsigned int n_endmembers) + : + volumes(n_endmembers, numbers::signaling_nan()), + gibbs_energies(n_endmembers, numbers::signaling_nan()), + entropies(n_endmembers, numbers::signaling_nan()), + thermal_expansivities(n_endmembers, numbers::signaling_nan()), + bulk_moduli(n_endmembers, numbers::signaling_nan()), + heat_capacities(n_endmembers, numbers::signaling_nan()) + {} + + + + template + void + MeltBoukare:: + fill_endmember_properties (const typename Interface::MaterialModelInputs &in, + const unsigned int q, + EndmemberProperties &properties) const + { + const double n_endmembers = properties.volumes.size(); + + for (unsigned int i=0; iget_adiabatic_conditions().pressure(in.position[q]); + + if (pressure != reference_pressure && pressure > 0.0) + { + intVdP = reference_volumes[i] + * ((pressure - reference_pressure) * (1. - a) + + (a * (std::pow((1. + b * (reference_pressure - Pth)), 1. - c) - std::pow((1. + b * (pressure - Pth)), 1. - c)) / (b * (c - 1.)))); + + const double prefactor = reference_volumes[i] * reference_thermal_expansivities[i] * reference_bulk_moduli[i] * a * heat_capacity_ratio; + dintVdpdT = prefactor * (std::pow(1. + b * (pressure - Pth), -c) - std::pow(1. + b * (reference_pressure - Pth), -c)); + } + + properties.gibbs_energies[i] = G_Pref_Tf + intVdP; + properties.entropies[i] = reference_entropies[i] + endmember_entropy_thermal_addition(in.temperature[q], i) + dintVdpdT; + properties.volumes[i] = reference_volumes[i] * (1 - a * (1. - std::pow(1. + b * (pressure - Pth), -c))); + + properties.bulk_moduli[i] = reference_bulk_moduli[i] * (1. + b * (pressure - Pth)) + * (a + (1. - a) * std::pow(1. + b * (pressure - Pth), c)); + + const double C_V0 = endmember_molar_heat_capacity(reference_temperature, i); + const double C_V = endmember_molar_heat_capacity(in.temperature[q], i); + properties.thermal_expansivities[i] = reference_thermal_expansivities[i] * (C_V / C_V0) * + 1. / ((1. + b * (pressure - Pth)) * + (a + (1. - a) * std::pow(1 + b * (pressure - Pth), c))); + + const double Cp_ref = reference_specific_heats[i] + specific_heat_linear_coefficients[i] * in.temperature[q] + + specific_heat_second_coefficients[i] * std::pow(in.temperature[q], -2.) + + specific_heat_third_coefficients[i] * std::pow(in.temperature[q], -0.5); + + const long double dSdT0 = reference_volumes[i] * reference_bulk_moduli[i] * std::pow(heat_capacity_ratio * reference_thermal_expansivities[i], 2.0) + * (std::pow(1. + b * (pressure - Pth), -1.-c) - std::pow(1. + b * (reference_pressure - Pth), -1.- c)); + + const double relative_T = Einstein_temperatures[i] / in.temperature[q]; + const double dSdT = dSdT0 + dintVdpdT * (1 - 2./relative_T + 2./(std::exp(relative_T) - 1.)) * relative_T/in.temperature[q]; + + properties.heat_capacities[i] = Cp_ref + in.temperature[q] * dSdT; + } + } + + + + template + double + MeltBoukare:: + endmember_thermal_energy (const double temperature, + const unsigned int endmember_index) const + { + AssertThrow(temperature > 0.0, + ExcMessage("The temperature has to be larger than 0, but it is " + + std::to_string(temperature) + " for endmember " + std::to_string(endmember_index) + ".")); + + const double relative_T = Einstein_temperatures[endmember_index] / temperature; + const double energy = 3. * number_of_atoms[endmember_index] * constants::gas_constant * Einstein_temperatures[endmember_index] + * (0.5 + 1. / (std::exp(relative_T) - 1.0)); + + return energy; + } + + + + template + double + MeltBoukare:: + endmember_molar_heat_capacity (const double temperature, + const unsigned int endmember_index) const + { + AssertThrow(temperature > 0.0, + ExcMessage("The temperature has to be larger than 0!")); + + const double relative_T = Einstein_temperatures[endmember_index] / temperature; + const double heat_capacity = 3. * number_of_atoms[endmember_index] * constants::gas_constant * std::pow(relative_T, 2) + * std::exp(relative_T) / std::pow(std::exp(relative_T) - 1.0, 2); + + return heat_capacity; + } + + + + template + double + MeltBoukare:: + endmember_thermal_pressure (const double temperature, + const unsigned int endmember_index) const + { + const double thermal_energy = endmember_thermal_energy(temperature, endmember_index); + const double heat_capacity = endmember_molar_heat_capacity(reference_temperature, endmember_index); + const double thermal_pressure = reference_thermal_expansivities[endmember_index] * reference_bulk_moduli[endmember_index] / heat_capacity * thermal_energy; + + return thermal_pressure; + } + + + + template + double + MeltBoukare:: + endmember_enthalpy_thermal_addition (const double temperature, + const unsigned int i) const + { + const double addition = reference_specific_heats[i] * temperature + + 0.5 * specific_heat_linear_coefficients[i] * std::pow(temperature, 2.) + - specific_heat_second_coefficients[i] / temperature + + 2. * specific_heat_third_coefficients[i] * std::sqrt(temperature) + - (reference_specific_heats[i] * reference_temperature + + 0.5 * specific_heat_linear_coefficients[i] * std::pow(reference_temperature, 2.) + - specific_heat_second_coefficients[i] / reference_temperature + + 2.0 * specific_heat_third_coefficients[i] * std::sqrt(reference_temperature)); + + return addition; + } + + + + template + double + MeltBoukare:: + endmember_entropy_thermal_addition (const double temperature, + const unsigned int i) const + { + const double addition = reference_specific_heats[i] * std::log(temperature) + + specific_heat_linear_coefficients[i] * temperature + - 0.5 * specific_heat_second_coefficients[i] / std::pow(temperature, 2.) + - 2.0 * specific_heat_third_coefficients[i] / std::sqrt(temperature) + - (reference_specific_heats[i] * std::log(reference_temperature) + + specific_heat_linear_coefficients[i] * reference_temperature + - 0.5 * specific_heat_second_coefficients[i] / std::pow(reference_temperature, 2.) + - 2.0 * specific_heat_third_coefficients[i] / std::sqrt(reference_temperature)); + + return addition; + } + + + + template + void + MeltBoukare:: + convert_composition_to_fraction_of_endmembers (const double temperature, + const double molar_Fe_in_solid, + const double molar_Fe_in_melt, + const std::vector &endmember_gibbs_energies, + std::vector &endmember_mole_fractions_per_phase, + double &molar_bridgmanite_in_solid) const + { + const double x_FeO = molar_Fe_in_solid * molar_FeO_in_Fe_mantle_endmember; + const double x_MgO = (1. - molar_Fe_in_solid) * molar_MgO_in_Mg_mantle_endmember; + const double x_SiO2 = molar_Fe_in_solid * molar_SiO2_in_Fe_mantle_endmember + (1. - molar_Fe_in_solid) * molar_SiO2_in_Mg_mantle_endmember; + + const double molar_fraction_FeO = x_FeO/(x_MgO + x_FeO); + const double molar_fraction_SiO2 = x_SiO2/(x_MgO + x_FeO); + molar_bridgmanite_in_solid = molar_fraction_SiO2; + + const double gibbs_energy_of_reaction = endmember_gibbs_energies[mgbdg_idx] + endmember_gibbs_energies[wus_idx] + - endmember_gibbs_energies[febdg_idx] - endmember_gibbs_energies[per_idx]; + const double partition_coefficient = std::exp(gibbs_energy_of_reaction / (constants::gas_constant * temperature)); + + // Solving equation 6 in Nakajima et al., 2012 for X_Fe_fp and X_Fe_pv + // Solved using the definition of the distribution coefficient to define X_Fe_fp as a function of X_Fe_pv + + const double num_to_sqrt = -4. * molar_fraction_FeO * (partition_coefficient - 1.) * partition_coefficient * molar_fraction_SiO2 + + std::pow(1. + (molar_fraction_FeO + molar_fraction_SiO2) * (partition_coefficient - 1.0), 2.); + + endmember_mole_fractions_per_phase[febdg_idx] = (-1. + molar_fraction_FeO - (molar_fraction_FeO * partition_coefficient) + molar_fraction_SiO2 - (molar_fraction_SiO2 * partition_coefficient) + std::sqrt(num_to_sqrt)) / + (2. * molar_fraction_SiO2 * (1. - partition_coefficient)); + + endmember_mole_fractions_per_phase[wus_idx] = endmember_mole_fractions_per_phase[febdg_idx] / (((1. - endmember_mole_fractions_per_phase[febdg_idx]) * partition_coefficient) + endmember_mole_fractions_per_phase[febdg_idx]); + + endmember_mole_fractions_per_phase[mgbdg_idx] = 1.0 - endmember_mole_fractions_per_phase[febdg_idx]; + endmember_mole_fractions_per_phase[per_idx] = 1.0 - endmember_mole_fractions_per_phase[wus_idx]; + + endmember_mole_fractions_per_phase[mgmelt_idx] = 1. - molar_Fe_in_melt; + endmember_mole_fractions_per_phase[femelt_idx] = molar_Fe_in_melt; + + return; + } + + + + template + double + MeltBoukare:: + compute_melt_molar_fraction (const double porosity, + const double bridgmanite_molar_fraction_in_solid, + EndmemberProperties &endmembers, + const std::vector &endmember_mole_fractions_per_phase) const + { + double melt_molar_volume = 0.0; + double solid_molar_volume = 0.0; + for (unsigned int i=0; i 0.0) + { + const double n_moles_total = bounded_porosity / melt_molar_volume + (1.0 - bounded_porosity) / solid_molar_volume; + melt_molar_fraction = bounded_porosity / (melt_molar_volume * n_moles_total); + } + + return melt_molar_fraction; + } + + + + template + double + MeltBoukare:: + assert_update_is_within_0_and_1 (const double old_value, + const double change_of_value) const + { + if (old_value + change_of_value < 0.0) + { + AssertThrow (false, ExcMessage("Update below 0. Proposed update: " + std::to_string(old_value + change_of_value))); + return -old_value; + } + else if (old_value + change_of_value > 1.0) + { + AssertThrow (false, ExcMessage("Update above 1. Proposed update: " + std::to_string(old_value + change_of_value))); + return 1.0 - old_value; + } + else + return change_of_value; + } + + + + template + double + MeltBoukare:: + melt_fraction (const double temperature, + const double pressure, + const double molar_composition_of_bulk, + double &molar_volatiles_in_melt, + double &new_molar_composition_of_solid, + double &new_molar_composition_of_melt) const + { + if (temperature == 0.0) + return 0.0; + + const double molar_volatiles_in_bulk = 1.e-4; + { + // after Phipps Morgan, Jason. "Thermodynamics of pressure release melting of a veined plum pudding mantle." + // Geochemistry, Geophysics, Geosystems 2.4 (2001). + // See also Appendix B of Dannberg et al., 2021. "The morphology, evolution and seismic visibility of partial + // melt at the core-mantle boundary: Implications for ULVZs". + const double P = pressure; // pressure in Pa + const double T = temperature; // temperature in K + const double R = constants::gas_constant; // Ideal Gas Constant + + // Free Energy Change Delta_G due to melting as a function of temperature and pressure + const double dG_Fe_mantle = (Fe_mantle_melting_temperature - T) * Fe_mantle_melting_entropy + + (P - melting_reference_pressure) * Fe_mantle_melting_volume; + const double dG_Mg_mantle = (Mg_mantle_melting_temperature - T) * Mg_mantle_melting_entropy + + (P - melting_reference_pressure) * Mg_mantle_melting_volume; + + // Equations (B.13) and (B.14) in Appendix B of Dannberg et al., 2021. + const double c_Fe_endmember = std::exp(dG_Fe_mantle/(Fe_number_of_moles*R*T)); + const double c_Mg_endmember = std::exp(dG_Mg_mantle/(Mg_number_of_moles*R*T)); + + // Mole composition of the solid and liquid (corresponds to the molar fraction of X_Fe, the iron-bearing endmember). + // In addition to the Phipps Morgan model, we also include volatiles here. + // Equations (B.8) and (B.10) to (B.12) in Appendix B of Dannberg et al., 2021. + const double q0 = (c_Fe_endmember - c_Mg_endmember) * c_Fe_endmember/c_Mg_endmember; + const double q1 = c_Fe_endmember * (1. - 1./c_Mg_endmember) - molar_composition_of_bulk * (c_Fe_endmember - c_Mg_endmember)/c_Mg_endmember + molar_volatiles_in_bulk * (1. - c_Fe_endmember); + const double q2 = -molar_composition_of_bulk * (1. - 1./c_Mg_endmember); + const double molar_composition_of_melt = (-q1 + std::sqrt(q1*q1 - 4.*q0*q2))/(2.*q0); + + const double T_Fe_mantle = dG_Fe_mantle / Fe_mantle_melting_entropy; + const double T_Mg_mantle = dG_Mg_mantle / Mg_mantle_melting_entropy; + + double melt_molar_fraction; + + if (molar_composition_of_bulk < std::numeric_limits::min()) + { + melt_molar_fraction = T_Mg_mantle < 0.0 ? 1.0 : molar_volatiles_in_bulk; + new_molar_composition_of_melt = 0.0; + new_molar_composition_of_solid = 0.0; + } + else if (molar_composition_of_melt <= molar_composition_of_bulk + && std::min(T_Fe_mantle, T_Mg_mantle) < 0.0) // above the liquidus + { + melt_molar_fraction = 1.0; + new_molar_composition_of_melt = molar_composition_of_bulk; + new_molar_composition_of_solid = molar_composition_of_bulk; + + molar_volatiles_in_melt = molar_volatiles_in_bulk; + } + else + { + // Equations (B.9) in Appendix B of Dannberg et al., 2021. + const double molar_composition_of_solid = molar_composition_of_melt * c_Fe_endmember; + + new_molar_composition_of_solid = std::max(std::min(molar_composition_of_solid, molar_composition_of_bulk), 0.0); + new_molar_composition_of_melt = std::min(std::max(molar_composition_of_melt, molar_composition_of_bulk), 1.0); + + if (std::abs(molar_composition_of_melt - molar_composition_of_solid) > std::numeric_limits::min()) + melt_molar_fraction = std::min(std::max((molar_composition_of_bulk - molar_composition_of_solid) / (molar_composition_of_melt - molar_composition_of_solid), 0.0), 1.0); + // If solid and melt composition are the same, there is no two-phase region. + // If we are not above the liquidus, we are below the solidus. + else + melt_molar_fraction = molar_volatiles_in_bulk; + + if (molar_volatiles_in_bulk > 0.0 && std::abs(molar_composition_of_bulk - molar_composition_of_solid) > std::numeric_limits::min()) + molar_volatiles_in_melt = molar_volatiles_in_bulk*(molar_composition_of_melt - molar_composition_of_solid)/(molar_composition_of_bulk - molar_composition_of_solid); + } + + return melt_molar_fraction; + } + } + + + + template + void + MeltBoukare:: + melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const + { + const unsigned int Fe_solid_idx = this->introspection().compositional_index_for_name("molar_Fe_in_solid"); + unsigned int Fe_melt_idx = numbers::invalid_unsigned_int; + unsigned int porosity_idx = numbers::invalid_unsigned_int; + + if (this->include_melt_transport()) + { + Fe_melt_idx = this->introspection().compositional_index_for_name("molar_Fe_in_melt"); + porosity_idx = this->introspection().compositional_index_for_name("porosity"); + } + + const unsigned int n_endmembers = endmember_names.size(); + EndmemberProperties endmembers(n_endmembers); + + for (unsigned int q=0; q endmember_mole_fractions_per_phase(n_endmembers); + + fill_endmember_properties(in, q, endmembers); + + // We need the compositions of all phases. + double solid_composition = in.composition[q][Fe_solid_idx]; + double melt_composition = 0.0, melt_molar_fraction = 0.0; + double bridgmanite_molar_fraction_in_solid; + + if (this->include_melt_transport()) + melt_composition = in.composition[q][Fe_melt_idx]; + + convert_composition_to_fraction_of_endmembers(in.temperature[q], + solid_composition, + melt_composition, + endmembers.gibbs_energies, + endmember_mole_fractions_per_phase, + bridgmanite_molar_fraction_in_solid); + + + if (this->include_melt_transport()) + melt_molar_fraction = compute_melt_molar_fraction(in.composition[q][porosity_idx], + bridgmanite_molar_fraction_in_solid, + endmembers, + endmember_mole_fractions_per_phase); + + const double solid_molar_fraction = 1.0 - melt_molar_fraction; + const double bulk_composition = melt_composition * melt_molar_fraction + solid_composition * solid_molar_fraction; + double molar_volatiles_in_melt = 0.0; + + const double eq_melt_molar_fraction = this->melt_fraction(in.temperature[q], + this->get_adiabatic_conditions().pressure(in.position[q]), + bulk_composition, + molar_volatiles_in_melt, + solid_composition, + melt_composition); + + // We have to compute the endmember fractions again here because the porosity is now different. + convert_composition_to_fraction_of_endmembers(in.temperature[q], + solid_composition, + melt_composition, + endmembers.gibbs_energies, + endmember_mole_fractions_per_phase, + bridgmanite_molar_fraction_in_solid); + + + // convert from melt molar fraction to porosity + const double solid_molar_volume = bridgmanite_molar_fraction_in_solid * endmember_mole_fractions_per_phase[febdg_idx] * endmembers.volumes[febdg_idx] + + bridgmanite_molar_fraction_in_solid * endmember_mole_fractions_per_phase[mgbdg_idx] * endmembers.volumes[mgbdg_idx] + + (1. - bridgmanite_molar_fraction_in_solid) * endmember_mole_fractions_per_phase[per_idx] * endmembers.volumes[per_idx] + + (1. - bridgmanite_molar_fraction_in_solid) * endmember_mole_fractions_per_phase[wus_idx] * endmembers.volumes[wus_idx]; + const double melt_molar_volume = endmember_mole_fractions_per_phase[mgmelt_idx] * endmembers.volumes[mgmelt_idx] + + endmember_mole_fractions_per_phase[femelt_idx] * endmembers.volumes[femelt_idx]; + + melt_fractions[q] = eq_melt_molar_fraction * melt_molar_volume + / (eq_melt_molar_fraction * melt_molar_volume + (1.0 - eq_melt_molar_fraction) * solid_molar_volume); + } + return; + } + + + + template + void + MeltBoukare:: + evaluate(const typename Interface::MaterialModelInputs &in, typename Interface::MaterialModelOutputs &out) const + { + ReactionRateOutputs *reaction_rate_out = out.template get_additional_output>(); + MeltOutputs *melt_out = out.template get_additional_output>(); + BoukareOutputs *boukare_out = out.template get_additional_output>(); + EnthalpyOutputs *enthalpy_out = out.template get_additional_output>(); + + const unsigned int Fe_solid_idx = this->introspection().compositional_index_for_name("molar_Fe_in_solid"); + unsigned int Fe_melt_idx = numbers::invalid_unsigned_int; + unsigned int porosity_idx = numbers::invalid_unsigned_int; + + if (this->include_melt_transport()) + { + Fe_melt_idx = this->introspection().compositional_index_for_name("molar_Fe_in_melt"); + porosity_idx = this->introspection().compositional_index_for_name("porosity"); + } + + // If the temperature or pressure are zero, this model does not work. + // This should only happen when setting the melt constraints before we have the initial temperature. + // In this case, just fill the permeabilities and fluid viscosities and return. + const unsigned int n_points = in.n_evaluation_points(); + for (unsigned int q=0; qfluid_viscosities[q] = eta_f; + melt_out->permeabilities[q] = reference_permeability * std::pow(porosity,3) * std::pow(1.0-porosity,2); + } + } + return; + } + } + + // We need the reaction step here to conserve bulk composition. + double reaction_time_step_size = 1.0; + double reaction_fraction = 0.0; + if (this->simulator_is_past_initialization()) + { + const unsigned int number_of_reaction_steps = std::max(static_cast(this->get_timestep() / this->get_parameters().reaction_time_step), + std::max(this->get_parameters().reaction_steps_per_advection_step,1U)); + reaction_time_step_size = this->get_timestep() / static_cast(number_of_reaction_steps); + reaction_fraction = reaction_time_step_size / melting_time_scale; + } + + const unsigned int n_endmembers = endmember_names.size(); + EndmemberProperties endmembers(n_endmembers); + + for (unsigned int q=0; q endmember_mole_fractions_per_phase(n_endmembers); + std::vector endmember_mole_fractions_in_composite(n_endmembers); + + fill_endmember_properties(in, q, endmembers); + + // We need the compositions of all phases. + const double solid_composition = in.composition[q][Fe_solid_idx]; + double melt_composition = 0.0; + double melt_molar_fraction = 0.0; + double bridgmanite_molar_fraction_in_solid; + + if (this->include_melt_transport()) + melt_composition = in.composition[q][Fe_melt_idx]; + + convert_composition_to_fraction_of_endmembers(in.temperature[q], + solid_composition, + melt_composition, + endmembers.gibbs_energies, + endmember_mole_fractions_per_phase, + bridgmanite_molar_fraction_in_solid); + + if (this->include_melt_transport()) + melt_molar_fraction = compute_melt_molar_fraction(in.composition[q][porosity_idx], + bridgmanite_molar_fraction_in_solid, + endmembers, + endmember_mole_fractions_per_phase); + + const double solid_molar_fraction = 1.0 - melt_molar_fraction; + + // Compute endmember molar fractions in the composite. + std::vector phase_mole_fractions_in_composite(n_endmembers); + double solid_molar_mass = 0.0; + double melt_molar_mass = 0.0; + double melt_molar_volume = 0.0; + double solid_molar_volume = 0.0; + + for (unsigned int i=0; i 0.0) + { + out.compressibilities[q] += (endmember_mole_fractions_in_composite[i] * endmembers.volumes[i]) + / (solid_molar_volume * endmembers.bulk_moduli[i]); + } + } + + if (solid_molar_volume > 0.0) + out.densities[q] = solid_molar_mass / solid_molar_volume; + else + out.densities[q] = melt_molar_mass / melt_molar_volume; + + if (melt_out != nullptr) + { + double melt_compressiblity = 0.0; + for (unsigned int i=0; i 0.0) + melt_compressiblity += (endmember_mole_fractions_in_composite[i] * endmembers.volumes[i]) / (melt_molar_volume * endmembers.bulk_moduli[i]); + + if (melt_molar_volume > 0.0) + melt_out->fluid_densities[q] = melt_molar_mass / melt_molar_volume; + else + { + // make sure we have a useful melt density even if there is no melt to avoid density jumps + double mass = 0.0; + double volume = 0.0; + for (unsigned int i=0; ifluid_densities[q] = mass/volume; + } + + // This does not take into account the volume change due to thermal expansion of melt + melt_out->fluid_density_gradients[q] = melt_out->fluid_densities[q] * melt_out->fluid_densities[q] + * melt_compressiblity + * this->get_gravity_model().gravity_vector(in.position[q]); + } + + + if (this->include_melt_transport()) + { + // TODO: Alternatively, this could also be done by summing over endmember_mole_fractions_in_composite + const double old_porosity = in.composition[q][porosity_idx]; + const double old_solid_composition = in.composition[q][Fe_solid_idx]; + const double old_melt_composition = in.composition[q][Fe_melt_idx]; + const double old_melt_molar_fraction = melt_molar_fraction; + + // in this simple model, the bulk composition is just one number, namely + // the molar fraction of the combined iron endmembers + const double bulk_composition = old_melt_composition * melt_molar_fraction + old_solid_composition * solid_molar_fraction; + double molar_volatiles_in_melt = 0.0; + double solid_composition, melt_composition; + + // calculate the melting rate as difference between the equilibrium melt fraction + // and the solution of the previous time step, and also update melt and solid composition + melt_molar_fraction = melt_fraction(in.temperature[q], + this->get_adiabatic_conditions().pressure(in.position[q]), + bulk_composition, + molar_volatiles_in_melt, + solid_composition, + melt_composition); + + if (boukare_out != nullptr) + { + boukare_out->bulk_composition[q] = bulk_composition; + boukare_out->molar_volatiles_in_melt[q] = molar_volatiles_in_melt; + } + + // We have to compute the update to the melt fraction in such a way that the bulk composition is conserved. + const double change_of_melt_composition = reaction_fraction * assert_update_is_within_0_and_1(old_melt_composition, melt_composition - old_melt_composition); + const double change_of_melt_fraction = reaction_fraction * assert_update_is_within_0_and_1(old_melt_molar_fraction, melt_molar_fraction - old_melt_molar_fraction); + + melt_composition = old_melt_composition + change_of_melt_composition; + melt_molar_fraction = old_melt_molar_fraction + change_of_melt_fraction; + + if (melt_molar_fraction > 0.0 && melt_molar_fraction < 1.0) + solid_composition = (bulk_composition - melt_molar_fraction * melt_composition) + / (1.0 - melt_molar_fraction); + const double change_of_solid_composition = solid_composition - old_solid_composition; + + + // We have to compute the endmember fractions again here because the porosity is now different. + convert_composition_to_fraction_of_endmembers(in.temperature[q], + solid_composition, + melt_composition, + endmembers.gibbs_energies, + endmember_mole_fractions_per_phase, + bridgmanite_molar_fraction_in_solid); + + + // convert from melt molar fraction to porosity + const double solid_molar_volume = bridgmanite_molar_fraction_in_solid * endmember_mole_fractions_per_phase[febdg_idx] * endmembers.volumes[febdg_idx] + + bridgmanite_molar_fraction_in_solid * endmember_mole_fractions_per_phase[mgbdg_idx] * endmembers.volumes[mgbdg_idx] + + (1. - bridgmanite_molar_fraction_in_solid) * endmember_mole_fractions_per_phase[per_idx] * endmembers.volumes[per_idx] + + (1. - bridgmanite_molar_fraction_in_solid) * endmember_mole_fractions_per_phase[wus_idx] * endmembers.volumes[wus_idx]; + const double melt_molar_volume = endmember_mole_fractions_per_phase[mgmelt_idx] * endmembers.volumes[mgmelt_idx] + + endmember_mole_fractions_per_phase[femelt_idx] * endmembers.volumes[femelt_idx]; + + const double new_porosity = melt_molar_fraction * melt_molar_volume + / (melt_molar_fraction * melt_molar_volume + (1.0 - melt_molar_fraction) * solid_molar_volume); + const double porosity_change = new_porosity - old_porosity; + + // For this simple model, we only track the iron in the solid (bridgmanite) and the iron in the melt + for (unsigned int c=0; creaction_rates[q][c] = 0.0; + else if (c == Fe_solid_idx && this->get_timestep_number() > 0) + reaction_rate_out->reaction_rates[q][c] = change_of_solid_composition / reaction_time_step_size; + else if (c == Fe_melt_idx && this->get_timestep_number() > 0) + reaction_rate_out->reaction_rates[q][c] = change_of_melt_composition / reaction_time_step_size; + else if (c == porosity_idx && this->get_timestep_number() > 0) + reaction_rate_out->reaction_rates[q][c] = porosity_change / reaction_time_step_size; + else + reaction_rate_out->reaction_rates[q][c] = 0.0; + } + out.reaction_terms[q][c] = 0.0; + } + + if (enthalpy_out != nullptr) + { + const double melt_molar_mass = endmember_mole_fractions_per_phase[mgmelt_idx] * molar_masses[mgmelt_idx] + + endmember_mole_fractions_per_phase[femelt_idx] * molar_masses[femelt_idx]; + const double Fe_enthalpy_of_fusion = Fe_mantle_melting_temperature * Fe_mantle_melting_entropy + + (this->get_adiabatic_conditions().pressure(in.position[q]) - melting_reference_pressure) * Fe_mantle_melting_volume; + const double Mg_enthalpy_of_fusion = Mg_mantle_melting_temperature * Mg_mantle_melting_entropy + + (this->get_adiabatic_conditions().pressure(in.position[q]) - melting_reference_pressure) * Mg_mantle_melting_volume; + double enthalpy_of_fusion = Fe_enthalpy_of_fusion * bulk_composition + Mg_enthalpy_of_fusion * (1.0-bulk_composition); + enthalpy_of_fusion /= melt_molar_mass; + + enthalpy_out->enthalpies_of_fusion[q] = enthalpy_of_fusion; + } + + // cutoff for viscosity at 30% + const double porosity = std::min(0.3, std::max(in.composition[q][porosity_idx],0.0)); + out.viscosities[q] = (1.0 - porosity) * eta_0 * std::exp(- alpha_phi * porosity); + } + else + { + out.viscosities[q] = eta_0; + + // no melting/freezing is used in the model --> set all reactions to zero + for (unsigned int c=0; creaction_rates[q][c] = 0.0; + } + } + + out.entropy_derivative_pressure[q] = 0.0; + out.entropy_derivative_temperature[q] = 0.0; + out.thermal_conductivities[q] = thermal_conductivity; + + for (unsigned int c=0; cget_adiabatic_conditions().temperature(in.position[q]); + const double viscosity_bound = 1.e8; + const double visc_temperature_dependence = std::max(std::min(std::exp(-thermal_viscosity_exponent*delta_temp/this->get_adiabatic_conditions().temperature(in.position[q])),viscosity_bound),1./viscosity_bound); + out.viscosities[q] *= visc_temperature_dependence; + } + + // fill melt outputs if they exist + if (melt_out != nullptr) + { + const unsigned int n_points = in.n_evaluation_points(); + for (unsigned int q=0; qfluid_viscosities[q] = eta_f; + melt_out->permeabilities[q] = reference_permeability * std::pow(porosity,3) * std::pow(1.0-porosity,2); + + // limit porosity to disaggregation threshold + porosity = std::min(0.3, porosity); + + const double porosity_threshold = 0.01 * std::pow(this->get_melt_handler().melt_parameters.melt_scaling_factor_threshold, 1./3.); + melt_out->compaction_viscosities[q] = (1.0 - porosity) * xi_0 / std::max(porosity, porosity_threshold); + + const double delta_temp = in.temperature[q]-this->get_adiabatic_conditions().temperature(in.position[q]); + const double compaction_viscosity_bound = 1.e4; + const double visc_temperature_dependence = std::max(std::min(std::exp(-thermal_bulk_viscosity_exponent*delta_temp/this->get_adiabatic_conditions().temperature(in.position[q])),compaction_viscosity_bound),1./compaction_viscosity_bound); + + melt_out->compaction_viscosities[q] *= visc_temperature_dependence; + } + } + } + + + + template + void + MeltBoukare::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Melt boukare"); + { + prm.declare_entry ("Reference shear viscosity", "5e20", + Patterns::Double (0), + "The value of the constant viscosity $\\eta_0$ of the solid matrix. " + "This viscosity may be modified by both temperature and porosity " + "dependencies. Units: $Pa \\, s$."); + prm.declare_entry ("Reference bulk viscosity", "1e22", + Patterns::Double (0), + "The value of the constant bulk viscosity $\\xi_0$ of the solid matrix. " + "This viscosity may be modified by both temperature and porosity " + "dependencies. Units: $Pa \\, s$."); + prm.declare_entry ("Reference melt viscosity", "10", + Patterns::Double (0), + "The value of the constant melt viscosity $\\eta_f$. Units: $Pa \\, s$."); + prm.declare_entry ("Exponential melt weakening factor", "27", + Patterns::Double (), + "The porosity dependence of the viscosity. Units: dimensionless."); + prm.declare_entry ("Thermal viscosity exponent", "0.0", + Patterns::Double (0), + "The temperature dependence of the shear viscosity. Dimensionless exponent. " + "See the general documentation " + "of this model for a formula that states the dependence of the " + "viscosity on this factor, which is called $\\beta$ there."); + prm.declare_entry ("Thermal bulk viscosity exponent", "0.0", + Patterns::Double (0), + "The temperature dependence of the bulk viscosity. Dimensionless exponent. " + "See the general documentation " + "of this model for a formula that states the dependence of the " + "viscosity on this factor, which is called $\\beta$ there."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0), + "The value of the thermal conductivity $k$. " + "Units: $W/m/K$."); + prm.declare_entry ("Reference permeability", "1e-8", + Patterns::Double(), + "Reference permeability of the solid host rock." + "Units: $m^2$."); + prm.declare_entry ("Include melting and freezing", "true", + Patterns::Bool (), + "Whether to include melting and freezing (according to a simplified " + "linear melting approximation in the model (if true), or not (if " + "false)."); + prm.declare_entry ("Melting time scale for operator splitting", "1e3", + Patterns::Double (0), + "In case the operator splitting scheme is used, the porosity field can not " + "be set to a new equilibrium melt fraction instantly, but the model has to " + "provide a melting time scale instead. This time scale defines how fast melting " + "happens, or more specifically, the parameter defines the time after which " + "the deviation of the porosity from the equilibrium melt fraction will be " + "reduced to a fraction of $1/e$. So if the melting time scale is small compared " + "to the time step size, the reaction will be so fast that the porosity is very " + "close to the equilibrium melt fraction after reactions are computed. Conversely, " + "if the melting time scale is large compared to the time step size, almost no " + "melting and freezing will occur." + "\n\n" + "Also note that the melting time scale has to be larger than or equal to the reaction " + "time step used in the operator splitting scheme, otherwise reactions can not be " + "computed. If the model does not use operator splitting, this parameter is not used. " + "Units: yr or s, depending on the ``Use years " + "in output instead of seconds'' parameter."); + prm.declare_entry ("Fe mantle melting temperature", "3424.5", + Patterns::Double(), + "The melting temperature of one of the components in the melting " + "model, the Fe mantle endmember." + "Units: K."); + prm.declare_entry ("Mg mantle melting temperature", "4821.2", + Patterns::Double(), + "The melting temperature of one of the components in the melting " + "model, the Mg mantle endmember." + "Units: K."); + prm.declare_entry ("Fe number of moles", "0.48", + Patterns::Double(), + "The number of moles of Fe atoms mixing on a pseudosite in the " + "mantle lattice, This is needed because we use an empirical model " + "fitting the full Boukare model, and can be changed to reflect " + "partition coefficients from other sources." + "Units: none."); + prm.declare_entry ("Mg number of moles", "0.62", + Patterns::Double(), + "The number of moles of Mg atoms mixing on a pseudosite in the " + "mantle lattice, This is needed because we use an empirical model " + "fitting the full Boukare model, and can be changed to reflect " + "partition coefficients from other sources." + "Units: none."); + prm.declare_entry ("Reference temperature", "298.15", + Patterns::Double(), + "Reference temperature used to compute the material properties" + "of the different endmember components." + "Units: K."); + prm.declare_entry ("Reference pressure", "1e11", + Patterns::Double(), + "Reference pressure used to compute the material properties" + "of the different endmember components." + "Units: Pa."); + + prm.declare_entry ("Endmember names", "FeSiO3_bridgmanite, MgSiO3_bridgmanite, FeO_periclase, MgO_periclase, FeO_melt, MgO_melt, SiO2_melt", + Patterns::List(Patterns::MultipleSelection("MgSiO3_bridgmanite|FeSiO3_bridgmanite|MgO_periclase|FeO_periclase|MgO_melt|FeO_melt|SiO2_melt")), + "Names of the endmember components used in the equation of state and the melting model, " + "and whose parameters are determined by the other input parameters of this material model. " + "The order the parameters are given in has to be the same as the order the endmember names " + "are given in. " + "Units: none."); + prm.declare_entry ("Endmember states", "solid, solid, solid, solid, melt, melt, melt", + Patterns::List(Patterns::MultipleSelection("solid|melt")), + "States of the endmember components used in the equation of state and the melting model. " + "For each endmember, this list has to define if they belong to the melt or to the solid. " + "The order the states are given in has to be the same as the order the 'Endmember names' " + "are given in. " + "Units: none."); + + prm.declare_entry ("Molar masses", "0.1319287, 0.1003887, 0.0718444, 0.0403044, 0.0707624708, 0.048592178, 0.048592178", + Patterns::List(Patterns::Double(0)), + "Molar masses of the different endmembers" + "Units: kg/mol."); + prm.declare_entry ("Number of atoms", "5.0, 5.0, 2.0, 2.0, 2.092, 2.419, 2.419", + Patterns::List(Patterns::Double(0)), + "Number of atoms per in the formula of each endmember." + "Units: none."); + prm.declare_entry ("Reference volumes", "2.534e-05, 2.445e-05, 1.206e-05, 1.125e-05, 1.2325484447664221e-05, 1.218e-05, 1.218e-05", + Patterns::List(Patterns::Double(0)), + "Reference volumes of the different endmembers." + "Units: $m^3$."); + prm.declare_entry ("Reference thermal expansivities", "1.87e-05, 1.87e-05, 3.22e-05, 3.11e-05, 2.9614332469401705e-05, 2.06e-05, 2.06e-05", + Patterns::List(Patterns::Double(0)), + "List of thermal expansivities for each different endmember at the reference temperature " + "and reference pressure." + "Units: 1/K."); + prm.declare_entry ("Reference bulk moduli", "2.81e11, 2.51e+11, 1.52e11, 1.616e11, 166652774642.11273, 2.317e11, 2.317e11", + Patterns::List(Patterns::Double(0)), + "List of bulk moduli for each different endmember at the reference temperature " + "and reference pressure." + "Units: Pa."); + prm.declare_entry ("First derivatives of the bulk modulus", "4.14, 4.14, 4.9, 3.95, 5.0802472229003905, 4.25, 4.25", + Patterns::List(Patterns::Double()), + "The pressure derivative of the bulk modulus at the reference temperature and reference " + "pressure for each different endmember component." + "Units: none."); + prm.declare_entry ("Second derivatives of the bulk modulus", "-1.6e-11, -1.6e-11, -3.2e-11, -2.4e-11, -3.9742163085937504e-11, -2.14e-11, -2.14e-11", + Patterns::List(Patterns::Double()), + "The second pressure derivative of the bulk modulus at the reference temperature and reference " + "pressure for each different endmember component." + "Units: 1/Pa."); + prm.declare_entry ("Einstein temperatures", "418.1, 561.0, 297.6, 540.2, 505.75, 558.1, 558.1", + Patterns::List(Patterns::Double(0)), + "List of Einstein temperatures for each different endmember." + "Units: K."); + prm.declare_entry ("Reference enthalpies", "-1082910.0, -1442310.0, -262240.0, -601570.0, -195245.49100022088, -538009.8, -538009.8", + Patterns::List(Patterns::Double()), + "List of enthalpies at the reference temperature and reference " + "pressure for each different endmember component." + "Units: J/mol."); + prm.declare_entry ("Reference entropies", "95.0, 62.6, 58.6, 26.5, 95.0299295525918, 64.9, 64.9", + Patterns::List(Patterns::Double(0)), + "List of entropies at the reference temperature and reference " + "pressure for each different endmember component." + "Units: J/K/mol."); + prm.declare_entry ("Reference specific heat capacities", "139.546209, 161.546581, 52.0016403, 73.1147154, 79.5326013, 79.5326013, 79.5326013", + Patterns::List(Patterns::Double(0)), + "List of specific heat capacities for each different endmember at the reference temperature " + "and reference pressure." + "Units: J/kg/K."); + prm.declare_entry ("Linear coefficients for specific heat polynomial", "6.36191292e-03, -3.31714290e-03, 3.36163516e-03, -6.35318887e-03, -2.41909947e-03, -2.41909947e-03, -2.41909947e-03", + Patterns::List(Patterns::Double()), + "The first of three coefficients that are used to compute the specific heat capacities for each " + "different endmember at the reference temperature and reference pressure. " + "This coefficient describes the linear part of the temperature dependence. " + "Units: J/kg/K/K."); + prm.declare_entry ("Second coefficients for specific heat polynomial", "-4.13886524e+06, -3.57533814e+06, -1.19540964e+06, -7.33679285e+05, -1.61692272e+06, -1.61692272e+06, -1.61692272e+06", + Patterns::List(Patterns::Double()), + "The second of three coefficients that are used to compute the specific heat capacities for each " + "different endmember at the reference temperature and reference pressure. This coefficient describes " + "the part of the temperature dependence that scales as the inverse of the square of the temperature. " + "Units: J K/kg."); + prm.declare_entry ("Third coefficients for specific heat polynomial", "-464.775577, -1112.54791, 25.5067110, -592.994207, -562.222634, -562.222634, -562.222634", + Patterns::List(Patterns::Double()), + "The third of three coefficients that are used to compute the specific heat capacities for each " + "different endmember at the reference temperature and reference pressure. This coefficient describes " + "the part of the temperature dependence that scales as the inverse of the square root of the temperature" + "Units: J/kg/sqrt(K)."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + MeltBoukare::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Melt boukare"); + { + eta_0 = prm.get_double ("Reference shear viscosity"); + xi_0 = prm.get_double ("Reference bulk viscosity"); + eta_f = prm.get_double ("Reference melt viscosity"); + reference_permeability = prm.get_double ("Reference permeability"); + thermal_viscosity_exponent = prm.get_double ("Thermal viscosity exponent"); + thermal_bulk_viscosity_exponent = prm.get_double ("Thermal bulk viscosity exponent"); + thermal_conductivity = prm.get_double ("Thermal conductivity"); + alpha_phi = prm.get_double ("Exponential melt weakening factor"); + include_melting_and_freezing = prm.get_bool ("Include melting and freezing"); + melting_time_scale = prm.get_double ("Melting time scale for operator splitting"); + Fe_mantle_melting_temperature = prm.get_double ("Fe mantle melting temperature"); + Mg_mantle_melting_temperature = prm.get_double ("Mg mantle melting temperature"); + Fe_number_of_moles = prm.get_double ("Fe number of moles"); + Mg_number_of_moles = prm.get_double ("Mg number of moles"); + + reference_temperature = prm.get_double ("Reference temperature"); + reference_pressure = prm.get_double ("Reference pressure"); + + if (this->convert_output_to_years() == true) + melting_time_scale *= year_in_seconds; + + AssertThrow(this->get_parameters().use_operator_splitting && + this->get_parameters().reaction_solver_type == Parameters::ReactionSolverType::fixed_step, + ExcMessage("The melt boukare material model has to be used with operator splitting, " + "and the reaction solver needs to be `fixed step'.")); + + AssertThrow(melting_time_scale >= this->get_parameters().reaction_time_step, + ExcMessage("The reaction time step " + Utilities::to_string(this->get_parameters().reaction_time_step) + + " in the operator splitting scheme is too large to compute melting rates! " + "You have to choose it in such a way that it is smaller than the 'Melting time scale for " + "operator splitting' chosen in the material model, which is currently " + + Utilities::to_string(melting_time_scale) + ".")); + AssertThrow(melting_time_scale > 0.0, + ExcMessage("The Melting time scale for operator splitting must be larger than 0!")); + + // Equation of state parameters + endmember_names = Utilities::split_string_list(prm.get("Endmember names")); + AssertThrow(Utilities::has_unique_entries(endmember_names), + ExcMessage("The list of strings for the parameter " + "'Material model/Melt boukare/Endmember names' contains entries more than once. " + "This is not allowed. Please check your parameter file.")); + + const unsigned int n_endmembers = endmember_names.size(); + AssertThrow(n_endmembers == 7 || (!this->include_melt_transport() && n_endmembers == 4), + ExcMessage("The list of strings for the parameter " + "'Material model/Melt boukare/Endmember names' does not contain the correct " + "number of entries. Please check your parameter file.")); + + std::vector endmember_states_string = Utilities::split_string_list(prm.get("Endmember states")); + endmember_states.resize(endmember_states_string.size()); + + for (unsigned int i=0; iintrospection().compositional_name_exists("molar_Fe_in_solid"), + ExcMessage("Material model melt boukare only works if there is a " + "compositional field called 'molar_Fe_in_solid'.")); + + if (this->include_melt_transport()) + { + AssertThrow(this->introspection().compositional_name_exists("porosity"), + ExcMessage("Material model melt boukare only works if there is a " + "compositional field called porosity.")); + AssertThrow(this->introspection().compositional_name_exists("molar_Fe_in_melt"), + ExcMessage("Material model melt boukare only works if there is a " + "compositional field called 'molar_Fe_in_melt'.")); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + MeltBoukare::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (this->get_parameters().use_operator_splitting + && out.template get_additional_output>() == nullptr) + { + out.additional_outputs.push_back( + std::make_unique> (out.n_evaluation_points(), this->n_compositional_fields())); + } + + if (out.template get_additional_output>() == nullptr) + { + out.additional_outputs.push_back( + std::make_unique> (out.n_evaluation_points())); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(MeltBoukare, + "melt boukare", + "A material model that implements a simplified version of the melting " + "model of Boukare et al. (https://doi.org/10.1002/2015JB011929) for the " + "lowermost mantle and uses it to compute the material parameters " + "required for the modeling of melt transport, including melting and " + "solidification and the corresponding changes in composition." + "The model parameterizes the composition (which includes the components " + "MgO, FeO and SiO2) as a mixture between two endmembers (one iron-bearing " + "and one magnesium-bearing). The equation of state considers three phases: " + "bridgmanite, ferropericlase, and melt (each with their individual " + "compositions). " + "More details can be found in Dannberg, J., Myhill, R., Gassmöller, R., " + "and Cottaar, S. (2021). The morphology, evolution and seismic visibility " + "of partial melt at the core–mantle boundary: implications for ULVZs. " + "Geophysical Journal International, 227(2), 1028-1059.") + } +} diff --git a/source/material_model/melt_global.cc.bak b/source/material_model/melt_global.cc.bak new file mode 100644 index 00000000000..b0c48491595 --- /dev/null +++ b/source/material_model/melt_global.cc.bak @@ -0,0 +1,556 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include +#include + + + +namespace aspect +{ + namespace MaterialModel + { + template + double + MeltGlobal:: + reference_darcy_coefficient () const + { + // 0.01 = 1% melt + return reference_permeability * std::pow(0.01,3.0) / eta_f; + } + + template + bool + MeltGlobal:: + is_compressible () const + { + return false; + } + + template + double + MeltGlobal:: + melt_fraction (const double temperature, + const double pressure, + const double depletion) const + { + const double T_solidus = surface_solidus + + pressure_solidus_change * pressure + + std::max(depletion_solidus_change * depletion, -200.0); + const double T_liquidus = T_solidus + 500.0; + + double melt_fraction; + if (temperature < T_solidus) + melt_fraction = 0.0; + else if (temperature > T_liquidus) + melt_fraction = 1.0; + else + melt_fraction = (temperature - T_solidus) / (T_liquidus - T_solidus); + + return melt_fraction; + } + + + template + void + MeltGlobal:: + melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const + { + double depletion = 0.0; + + for (unsigned int q=0; qinclude_melt_transport()) + { + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + const unsigned int peridotite_idx = this->introspection().compositional_index_for_name("peridotite"); + depletion = in.composition[q][peridotite_idx] - in.composition[q][porosity_idx]; + } + melt_fractions[q] = this->melt_fraction(in.temperature[q], + std::max(0.0, in.pressure[q]), + depletion); + } + } + + + template + void + MeltGlobal:: + evaluate(const typename Interface::MaterialModelInputs &in, typename Interface::MaterialModelOutputs &out) const + { + std::vector old_porosity(in.n_evaluation_points()); + + ReactionRateOutputs *reaction_rate_out = out.template get_additional_output>(); + + // we want to get the porosity field from the old solution here, + // because we need a field that is not updated in the nonlinear iterations + if (this->include_melt_transport() && in.current_cell.state() == IteratorState::valid + && this->get_timestep_number() > 0 && !this->get_parameters().use_operator_splitting) + { + // Prepare the field function + + Functions::FEFieldFunction + + fe_value(this->get_dof_handler(), this->get_old_solution(), this->get_mapping()); + + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + + fe_value.set_active_cell(in.current_cell); + fe_value.value_list(in.position, + old_porosity, + this->introspection().component_indices.compositional_fields[porosity_idx]); + } + else if (this->get_parameters().use_operator_splitting) + for (unsigned int i=0; iintrospection().compositional_index_for_name("porosity"); + old_porosity[i] = in.composition[i][porosity_idx]; + } + + for (unsigned int i=0; iinclude_adiabatic_heating ()) + temperature_dependence -= (in.temperature[i] - this->get_adiabatic_conditions().temperature(in.position[i])) + * thermal_expansivity; + else + temperature_dependence -= (in.temperature[i] - reference_T) * thermal_expansivity; + + // calculate composition dependence of density + const double delta_rho = this->introspection().compositional_name_exists("peridotite") + ? + depletion_density_change * in.composition[i][this->introspection().compositional_index_for_name("peridotite")] + : + 0.0; + out.densities[i] = (reference_rho_s + delta_rho) * temperature_dependence + * std::exp(compressibility * (in.pressure[i] - this->get_surface_pressure())); + + out.viscosities[i] = eta_0; + // By default, no melting or freezing --> set all reactions to zero + for (unsigned int c=0; cget_parameters().use_operator_splitting && reaction_rate_out != nullptr) + reaction_rate_out->reaction_rates[i][c] = 0.0; + } + + if (this->include_melt_transport()) + { + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + const double porosity = std::min(1.0, std::max(in.composition[i][porosity_idx],0.0)); + + // calculate viscosity based on local melt + out.viscosities[i] *= exp(- alpha_phi * porosity); + + if (include_melting_and_freezing && (in.requests_property(MaterialProperties::reaction_terms) || + in.requests_property(MaterialProperties::reaction_rates) || + in.requests_property(MaterialProperties::viscosity))) + { + Assert(this->get_timestep_number()<=1 || std::isfinite(in.strain_rate[i].norm()), + ExcMessage("Invalid strain_rate in the MaterialModelInputs. This is likely because it was " + "not filled by the caller.")); + const double trace_strain_rate = + (this->get_timestep_number() > 1) ? + (trace(in.strain_rate[i])) + : + numbers::signaling_nan(); + + const unsigned int peridotite_idx = this->introspection().compositional_index_for_name("peridotite"); + + // Calculate the melting rate as difference between the equilibrium melt fraction + // and the solution of the previous time step (or the current solution, in case + // operator splitting is used). + // The solidus is lowered by previous melting events (fractional melting). + const double eq_melt_fraction = melt_fraction(in.temperature[i], + this->get_adiabatic_conditions().pressure(in.position[i]), + in.composition[i][peridotite_idx] - in.composition[i][porosity_idx]); + double porosity_change = eq_melt_fraction - old_porosity[i]; + // do not allow negative porosity + if (old_porosity[i] + porosity_change < 0) + porosity_change = -old_porosity[i]; + + for (unsigned int c = 0; c < in.composition[i].size(); ++c) + { + if (c == peridotite_idx && this->get_timestep_number() > 1) + out.reaction_terms[i][c] = porosity_change - in.composition[i][peridotite_idx] * trace_strain_rate * this->get_timestep(); + else if (c == porosity_idx && this->get_timestep_number() > 1) + out.reaction_terms[i][c] = porosity_change * out.densities[i] / this->get_timestep(); + else + out.reaction_terms[i][c] = 0.0; + + // fill reaction rate outputs if the model uses operator splitting + if (this->get_parameters().use_operator_splitting) + { + if (reaction_rate_out != nullptr) + { + if (c == peridotite_idx && this->get_timestep_number() > 0) + reaction_rate_out->reaction_rates[i][c] = porosity_change / melting_time_scale - in.composition[i][peridotite_idx] * trace(in.strain_rate[i]); + else if (c == porosity_idx && this->get_timestep_number() > 0) + reaction_rate_out->reaction_rates[i][c] = porosity_change / melting_time_scale; + else + reaction_rate_out->reaction_rates[i][c] = 0.0; + } + out.reaction_terms[i][c] = 0.0; + } + } + + // find depletion = peridotite, which might affect shear viscosity: + const double depletion_visc = std::min(1.0, std::max(in.composition[i][peridotite_idx], 0.0)); + + // calculate strengthening due to depletion: + const double depletion_strengthening = std::min(exp(alpha_depletion * depletion_visc), delta_eta_depletion_max); + + // calculate viscosity change due to local melt and depletion: + out.viscosities[i] *= depletion_strengthening; + } + } + + out.entropy_derivative_pressure[i] = 0.0; + out.entropy_derivative_temperature[i] = 0.0; + out.thermal_expansion_coefficients[i] = thermal_expansivity; + out.specific_heat[i] = reference_specific_heat; + out.thermal_conductivities[i] = thermal_conductivity; + out.compressibilities[i] = 0.0; + + double visc_temperature_dependence = 1.0; + if (this->include_adiabatic_heating ()) + { + const double delta_temp = in.temperature[i]-this->get_adiabatic_conditions().temperature(in.position[i]); + visc_temperature_dependence = std::max(std::min(std::exp(-thermal_viscosity_exponent*delta_temp/this->get_adiabatic_conditions().temperature(in.position[i])),1e4),1e-4); + } + else if (thermal_viscosity_exponent != 0.0) + { + const double delta_temp = in.temperature[i]-reference_T; + visc_temperature_dependence = std::max(std::min(std::exp(-thermal_viscosity_exponent*delta_temp/reference_T),1e4),1e-4); + } + out.viscosities[i] *= visc_temperature_dependence; + } + + // fill melt outputs if they exist + MeltOutputs *melt_out = out.template get_additional_output>(); + + if (melt_out != nullptr) + { + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + + for (unsigned int i=0; ifluid_viscosities[i] = eta_f; + melt_out->permeabilities[i] = reference_permeability * std::pow(porosity,3) * std::pow(1.0-porosity,2); + melt_out->fluid_density_gradients[i] = Tensor<1,dim>(); + + // temperature dependence of density is 1 - alpha * (T - T(adiabatic)) + double temperature_dependence = 1.0; + if (this->include_adiabatic_heating ()) + temperature_dependence -= (in.temperature[i] - this->get_adiabatic_conditions().temperature(in.position[i])) + * thermal_expansivity; + else + temperature_dependence -= (in.temperature[i] - reference_T) * thermal_expansivity; + melt_out->fluid_densities[i] = reference_rho_f * temperature_dependence + * std::exp(melt_compressibility * (in.pressure[i] - this->get_surface_pressure())); + + melt_out->compaction_viscosities[i] = xi_0 * exp(- alpha_phi * porosity); + + double visc_temperature_dependence = 1.0; + if (this->include_adiabatic_heating ()) + { + const double delta_temp = in.temperature[i]-this->get_adiabatic_conditions().temperature(in.position[i]); + visc_temperature_dependence = std::max(std::min(std::exp(-thermal_bulk_viscosity_exponent*delta_temp/this->get_adiabatic_conditions().temperature(in.position[i])),1e4),1e-4); + } + else if (thermal_viscosity_exponent != 0.0) + { + const double delta_temp = in.temperature[i]-reference_T; + visc_temperature_dependence = std::max(std::min(std::exp(-thermal_bulk_viscosity_exponent*delta_temp/reference_T),1e4),1e-4); + } + melt_out->compaction_viscosities[i] *= visc_temperature_dependence; + } + } + } + + + + template + void + MeltGlobal::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Melt global"); + { + prm.declare_entry ("Reference solid density", "3000.", + Patterns::Double (0.), + "Reference density of the solid $\\rho_{s,0}$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference melt density", "2500.", + Patterns::Double (0.), + "Reference density of the melt/fluid$\\rho_{f,0}$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. The reference temperature is used " + "in both the density and viscosity formulas. Units: \\si{\\kelvin}."); + prm.declare_entry ("Reference shear viscosity", "5e20", + Patterns::Double (0.), + "The value of the constant viscosity $\\eta_0$ of the solid matrix. " + "This viscosity may be modified by both temperature and porosity " + "dependencies. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Reference bulk viscosity", "1e22", + Patterns::Double (0.), + "The value of the constant bulk viscosity $\\xi_0$ of the solid matrix. " + "This viscosity may be modified by both temperature and porosity " + "dependencies. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Reference melt viscosity", "10.", + Patterns::Double (0.), + "The value of the constant melt viscosity $\\eta_f$. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Exponential melt weakening factor", "27.", + Patterns::Double (0.), + "The porosity dependence of the viscosity. Units: dimensionless."); + prm.declare_entry ("Thermal viscosity exponent", "0.0", + Patterns::Double (0.), + "The temperature dependence of the shear viscosity. Dimensionless exponent. " + "See the general documentation " + "of this model for a formula that states the dependence of the " + "viscosity on this factor, which is called $\\beta$ there."); + prm.declare_entry ("Thermal bulk viscosity exponent", "0.0", + Patterns::Double (0.), + "The temperature dependence of the bulk viscosity. Dimensionless exponent. " + "See the general documentation " + "of this model for a formula that states the dependence of the " + "viscosity on this factor, which is called $\\beta$ there."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Reference specific heat", "1250.", + Patterns::Double (0.), + "The value of the specific heat $C_p$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Thermal expansion coefficient", "2e-5", + Patterns::Double (0.), + "The value of the thermal expansion coefficient $\\beta$. " + "Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Reference permeability", "1e-8", + Patterns::Double(), + "Reference permeability of the solid host rock." + "Units: \\si{\\meter\\squared}."); + prm.declare_entry ("Depletion density change", "0.0", + Patterns::Double (), + "The density contrast between material with a depletion of 1 and a " + "depletion of zero. Negative values indicate lower densities of " + "depleted material. Depletion is indicated by the compositional " + "field with the name peridotite. Not used if this field does not " + "exist in the model. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Surface solidus", "1300.", + Patterns::Double (0.), + "Solidus for a pressure of zero. " + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Depletion solidus change", "200.0", + Patterns::Double (), + "The solidus temperature change for a depletion of 100\\%. For positive " + "values, the solidus gets increased for a positive peridotite field " + "(depletion) and lowered for a negative peridotite field (enrichment). " + "Scaling with depletion is linear. Only active when fractional melting " + "is used. " + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Pressure solidus change", "6e-8", + Patterns::Double (), + "The linear solidus temperature change with pressure. For positive " + "values, the solidus gets increased for positive pressures. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("Solid compressibility", "0.0", + Patterns::Double (0.), + "The value of the compressibility of the solid matrix. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("Melt compressibility", "0.0", + Patterns::Double (0.), + "The value of the compressibility of the melt. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("Melt bulk modulus derivative", "0.0", + Patterns::Double (0.), + "The value of the pressure derivative of the melt bulk " + "modulus. " + "Units: None."); + prm.declare_entry ("Include melting and freezing", "true", + Patterns::Bool (), + "Whether to include melting and freezing (according to a simplified " + "linear melting approximation in the model (if true), or not (if " + "false)."); + prm.declare_entry ("Melting time scale for operator splitting", "1e3", + Patterns::Double (0.), + "In case the operator splitting scheme is used, the porosity field can not " + "be set to a new equilibrium melt fraction instantly, but the model has to " + "provide a melting time scale instead. This time scale defines how fast melting " + "happens, or more specifically, the parameter defines the time after which " + "the deviation of the porosity from the equilibrium melt fraction will be " + "reduced to a fraction of $1/e$. So if the melting time scale is small compared " + "to the time step size, the reaction will be so fast that the porosity is very " + "close to the equilibrium melt fraction after reactions are computed. Conversely, " + "if the melting time scale is large compared to the time step size, almost no " + "melting and freezing will occur." + "\n\n" + "Also note that the melting time scale has to be larger than or equal to the reaction " + "time step used in the operator splitting scheme, otherwise reactions can not be " + "computed. If the model does not use operator splitting, this parameter is not used. " + "Units: yr or s, depending on the ``Use years " + "in output instead of seconds'' parameter."); + prm.declare_entry ("Exponential depletion strengthening factor", "0.0", + Patterns::Double (0.), + "$\\alpha_F$: exponential dependency of viscosity on the depletion " + "field $F$ (called peridotite). " + "Dimensionless factor. With a value of 0.0 (the default) the " + "viscosity does not depend on the depletion. The effective viscosity increase" + "due to depletion is defined as $exp( \\alpha_F * F)$. " + "Rationale: melting dehydrates the source rock by removing most of the volatiles," + "and makes it stronger. Hirth and Kohlstedt (1996) report typical values around a " + "factor 100 to 1000 viscosity contrast between wet and dry rocks, although some " + "experimental studies report a smaller (factor 10) contrast (e.g. Fei et al., 2013)."); + prm.declare_entry ("Maximum Depletion viscosity change", "1.0e3", + Patterns::Double (0.), + "$\\Delta \\eta_{F,max}$: maximum depletion strengthening of viscosity. " + "Rationale: melting dehydrates the source rock by removing most of the volatiles," + "and makes it stronger. Hirth and Kohlstedt (1996) report typical values around a " + "factor 100 to 1000 viscosity contrast between wet and dry rocks, although some " + "experimental studies report a smaller (factor 10) contrast (e.g. Fei et al., 2013)."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + MeltGlobal::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Melt global"); + { + reference_rho_s = prm.get_double ("Reference solid density"); + reference_rho_f = prm.get_double ("Reference melt density"); + reference_T = prm.get_double ("Reference temperature"); + eta_0 = prm.get_double ("Reference shear viscosity"); + xi_0 = prm.get_double ("Reference bulk viscosity"); + eta_f = prm.get_double ("Reference melt viscosity"); + reference_permeability = prm.get_double ("Reference permeability"); + thermal_viscosity_exponent = prm.get_double ("Thermal viscosity exponent"); + thermal_bulk_viscosity_exponent = prm.get_double ("Thermal bulk viscosity exponent"); + thermal_conductivity = prm.get_double ("Thermal conductivity"); + reference_specific_heat = prm.get_double ("Reference specific heat"); + thermal_expansivity = prm.get_double ("Thermal expansion coefficient"); + alpha_phi = prm.get_double ("Exponential melt weakening factor"); + depletion_density_change = prm.get_double ("Depletion density change"); + surface_solidus = prm.get_double ("Surface solidus"); + depletion_solidus_change = prm.get_double ("Depletion solidus change"); + pressure_solidus_change = prm.get_double ("Pressure solidus change"); + compressibility = prm.get_double ("Solid compressibility"); + melt_compressibility = prm.get_double ("Melt compressibility"); + include_melting_and_freezing = prm.get_bool ("Include melting and freezing"); + melting_time_scale = prm.get_double ("Melting time scale for operator splitting"); + alpha_depletion = prm.get_double ("Exponential depletion strengthening factor"); + delta_eta_depletion_max = prm.get_double ("Maximum Depletion viscosity change"); + + if (thermal_viscosity_exponent!=0.0 && reference_T == 0.0) + AssertThrow(false, ExcMessage("Error: Material model Melt global with Thermal viscosity exponent can not have reference_T=0.")); + + if (this->convert_output_to_years() == true) + melting_time_scale *= year_in_seconds; + + if (this->get_parameters().use_operator_splitting) + { + if (this->get_parameters().reaction_solver_type == Parameters::ReactionSolverType::fixed_step) + AssertThrow(melting_time_scale >= this->get_parameters().reaction_time_step, + ExcMessage("The reaction time step " + Utilities::to_string(this->get_parameters().reaction_time_step) + + " in the operator splitting scheme is too large to compute melting rates! " + "You have to choose it in such a way that it is smaller than the 'Melting time scale for " + "operator splitting' chosen in the material model, which is currently " + + Utilities::to_string(melting_time_scale) + ".")); + AssertThrow(melting_time_scale > 0, + ExcMessage("The Melting time scale for operator splitting must be larger than 0!")); + AssertThrow(this->introspection().compositional_name_exists("porosity"), + ExcMessage("Material model Melt global with melt transport only " + "works if there is a compositional field called porosity.")); + } + + if (this->include_melt_transport()) + { + AssertThrow(this->introspection().compositional_name_exists("porosity"), + ExcMessage("Material model Melt global with melt transport only " + "works if there is a compositional field called porosity.")); + if (include_melting_and_freezing) + { + AssertThrow(this->introspection().compositional_name_exists("peridotite"), + ExcMessage("Material model Melt global only works if there is a " + "compositional field called peridotite.")); + } + } + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + MeltGlobal::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (this->get_parameters().use_operator_splitting + && out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points, this->n_compositional_fields())); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(MeltGlobal, + "melt global", + "A material model that implements a simple formulation of the " + "material parameters required for the modeling of melt transport, " + "including a source term for the porosity according to a simplified " + "linear melting model similar to \\cite{schmeling2006}:\n" + "$\\phi_{\\text{equilibrium}} = \\frac{T-T_{\\text{sol}}}{T_{\\text{liq}}-T_{\\text{sol}}}$\n" + "with " + "$T_{\\text{sol}} = T_{\\text{sol,0}} + \\Delta T_p \\, p + \\Delta T_c \\, C$ \n" + "$T_{\\text{liq}} = T_{\\text{sol}} + \\Delta T_{\\text{sol-liq}}$.") + } +} diff --git a/source/material_model/melt_simple.cc.bak b/source/material_model/melt_simple.cc.bak new file mode 100644 index 00000000000..1debe1eb863 --- /dev/null +++ b/source/material_model/melt_simple.cc.bak @@ -0,0 +1,284 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + double + MeltSimple:: + reference_darcy_coefficient () const + { + // 0.01 = 1% melt + return katz2003_model.reference_darcy_coefficient(); + } + + template + bool + MeltSimple:: + is_compressible () const + { + return model_is_compressible; + } + + template + void + MeltSimple:: + melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const + { + for (unsigned int q=0; qget_adiabatic_conditions().pressure(in.position[q])); + } + + + template + void + MeltSimple::initialize () + { + if (this->include_melt_transport()) + { + AssertThrow(this->get_parameters().use_operator_splitting, + ExcMessage("The material model ``Melt simple'' can only be used with operator splitting!")); + AssertThrow(this->introspection().compositional_name_exists("peridotite"), + ExcMessage("Material model Melt simple only works if there is a " + "compositional field called peridotite.")); + AssertThrow(this->introspection().compositional_name_exists("porosity"), + ExcMessage("Material model Melt simple with melt transport only " + "works if there is a compositional field called porosity.")); + } + } + + + template + void + MeltSimple:: + evaluate(const typename Interface::MaterialModelInputs &in, typename Interface::MaterialModelOutputs &out) const + { + for (unsigned int i=0; iinclude_adiabatic_heating ()) + { + // temperature dependence is 1 - alpha * (T - T(adiabatic)) + temperature_dependence -= (in.temperature[i] - this->get_adiabatic_conditions().temperature(in.position[i])) + * thermal_expansivity; + } + else + temperature_dependence -= (in.temperature[i] - reference_T) * thermal_expansivity; + + // calculate composition dependence of density + const double delta_rho = this->introspection().compositional_name_exists("peridotite") + ? + depletion_density_change * in.composition[i][this->introspection().compositional_index_for_name("peridotite")] + : + 0.0; + out.densities[i] = (reference_rho_solid + delta_rho) + * temperature_dependence * std::exp(compressibility * (in.pressure[i] - this->get_surface_pressure())); + + out.viscosities[i] = eta_0; + out.thermal_expansion_coefficients[i] = thermal_expansivity; + out.specific_heat[i] = reference_specific_heat; + out.thermal_conductivities[i] = thermal_conductivity; + out.compressibilities[i] = compressibility; + + double visc_temperature_dependence = 1.0; + if (this->include_adiabatic_heating ()) + { + const double delta_temp = in.temperature[i]-this->get_adiabatic_conditions().temperature(in.position[i]); + visc_temperature_dependence = std::max(std::min(std::exp(-thermal_viscosity_exponent*delta_temp/this->get_adiabatic_conditions().temperature(in.position[i])),1e4),1e-4); + } + else + { + const double delta_temp = in.temperature[i]-reference_T; + const double T_dependence = (thermal_viscosity_exponent == 0.0 + ? + 0.0 + : + thermal_viscosity_exponent*delta_temp/reference_T); + visc_temperature_dependence = std::max(std::min(std::exp(-T_dependence),1e4),1e-4); + } + out.viscosities[i] *= visc_temperature_dependence; + + } + + katz2003_model.calculate_reaction_rate_outputs(in, out); + katz2003_model.calculate_fluid_outputs(in, out, reference_T); + } + + + template + void + MeltSimple::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Melt simple"); + { + // Melt Fraction Parameters + ReactionModel::Katz2003MantleMelting::declare_parameters(prm); + + + prm.declare_entry ("Use full compressibility", "false", + Patterns::Bool (), + "If the compressibility should be used everywhere in the code " + "(if true), changing the volume of material when the density changes, " + "or only in the momentum conservation and advection equations " + "(if false)."); + prm.declare_entry ("Thermal expansion coefficient", "2e-5", + Patterns::Double (0.), + "The value of the thermal expansion coefficient $\\beta$. " + "Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Reference shear viscosity", "5e20", + Patterns::Double (0.), + "The value of the constant viscosity $\\eta_0$ of the solid matrix. " + "This viscosity may be modified by both temperature and porosity " + "dependencies. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Reference specific heat", "1250.", + Patterns::Double (0.), + "The value of the specific heat $C_p$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Solid compressibility", "0.0", + Patterns::Double (0.), + "The value of the compressibility of the solid matrix. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("Thermal viscosity exponent", "0.0", + Patterns::Double (0.), + "The temperature dependence of the shear viscosity. Dimensionless exponent. " + "See the general documentation " + "of this model for a formula that states the dependence of the " + "viscosity on this factor, which is called $\\beta$ there."); + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. The reference temperature is used " + "in both the density and viscosity formulas. Units: \\si{\\kelvin}."); + prm.declare_entry ("Depletion density change", "0.0", + Patterns::Double (), + "The density contrast between material with a depletion of 1 and a " + "depletion of zero. Negative values indicate lower densities of " + "depleted material. Depletion is indicated by the compositional " + "field with the name peridotite. Not used if this field does not " + "exist in the model. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference solid density", "3000.", + Patterns::Double (0.), + "Reference density of the solid $\\rho_{s,0}$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + MeltSimple::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Melt simple"); + { + model_is_compressible = prm.get_bool ("Use full compressibility"); + reference_specific_heat = prm.get_double ("Reference specific heat"); + eta_0 = prm.get_double ("Reference shear viscosity"); + thermal_expansivity = prm.get_double ("Thermal expansion coefficient"); + thermal_conductivity = prm.get_double ("Thermal conductivity"); + compressibility = prm.get_double ("Solid compressibility"); + thermal_viscosity_exponent = prm.get_double ("Thermal viscosity exponent"); + reference_T = prm.get_double ("Reference temperature"); + depletion_density_change = prm.get_double ("Depletion density change"); + reference_rho_solid = prm.get_double ("Reference solid density"); + + + + if (thermal_viscosity_exponent!=0.0 && reference_T == 0.0) + AssertThrow(false, ExcMessage("Error: Material model Melt simple with Thermal viscosity exponent can not have reference_T=0.")); + + // Melt model + katz2003_model.initialize_simulator (this->get_simulator()); + katz2003_model.parse_parameters(prm); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + MeltSimple::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (this->get_parameters().use_operator_splitting && out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points, this->n_compositional_fields())); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(MeltSimple, + "melt simple", + "A material model that implements a simple formulation of the " + "material parameters required for the modeling of melt transport, " + "including a source term for the porosity according to the melting " + "model for dry peridotite of \\cite{katz:etal:2003}. This also includes a " + "computation of the latent heat of melting (if the `latent heat' " + "heating model is active)." + "\n\n" + "Most of the material properties are constant, except for the shear, " + "viscosity $\\eta$, the compaction viscosity $\\xi$, and the " + "permeability $k$, which depend on the porosity; and the solid and melt " + "densities, which depend on temperature and pressure:\n " + "$\\eta(\\phi,T) = \\eta_0 e^{\\alpha(\\phi-\\phi_0)} e^{-\\beta(T-T_0)/T_0}$, " + "$\\xi(\\phi,T) = \\xi_0 \\frac{\\phi_0}{\\phi} e^{-\\beta(T-T_0)/T_0}$, " + "$k=k_0 \\phi^n (1-\\phi)^m$, " + "$\\rho=\\rho_0 (1 - \\alpha (T - T_{\\text{adi}})) e^{\\kappa p}$." + "\n\n" + "The model is compressible only if this is specified in the input file, " + "and contains compressibility for both solid and melt.") + } +} diff --git a/source/material_model/modified_tait.cc.bak b/source/material_model/modified_tait.cc.bak new file mode 100644 index 00000000000..6340609a461 --- /dev/null +++ b/source/material_model/modified_tait.cc.bak @@ -0,0 +1,271 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + void + ModifiedTait:: + evaluate(const MaterialModelInputs &in, + MaterialModelOutputs &out) const + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const double temperature = in.temperature[i]; + const double pressure = in.pressure[i]; + + AssertThrow(temperature > 100., ExcMessage("The current temperature is <100 K. " + "The modified Tait equations of state is " + "not designed for such temperatures. " + "If this exception is triggered at the " + "beginning of a run, you may need to " + "set Adiabatic surface temperature " + "to a value > 100 in the parameter file.")); + out.viscosities[i] = eta; + out.thermal_conductivities[i] = k_value; + + // Einstein equations for the heat capacity at constant volume + const double x_einstein = einstein_temperature/temperature; + const double x_einstein0 = einstein_temperature/reference_temperature; + + + AssertThrow(x_einstein < 35., ExcMessage("The current temperature is less than 1/35th " + "of the Einstein temperature. This is not " + "expected for geological materials.")); + AssertThrow(x_einstein0 < 35., ExcMessage("The reference temperature of the " + "equation of state is less than 1/35th " + "of the Einstein temperature. This is not " + "expected for geological materials.")); + + // The following Einstein energies and heat capacities are divided through by 3nR. + // This doesn't matter, as the equation of state relies only on ratios of these quantities. + const double E_th0 = einstein_temperature * (0.5 + 1. / (std::exp(x_einstein0) - 1.0)); + const double C_V0 = x_einstein0 * x_einstein0 * std::exp(x_einstein0) / std::pow(std::exp(x_einstein0) - 1.0, 2.0); + + const double E_th = einstein_temperature * (0.5 + 1. / (std::exp(x_einstein) - 1.0)); + const double C_V = x_einstein * x_einstein * std::exp(x_einstein) / std::pow(std::exp(x_einstein) - 1.0, 2.0); + + // The relative thermal pressure + const double Pth_rel = reference_thermal_expansivity * reference_isothermal_bulk_modulus * (E_th - E_th0) / C_V0; + const double psubpth = pressure - reference_pressure - Pth_rel; + + // x = rho0/rho + const double x = 1 - tait_a * (1. - std::pow((1. + tait_b * psubpth), -1.0 * tait_c)); + + // xi + const double xi = (C_V / C_V0); + + // Here we calculate the pressure effect on the heat capacity. It is a bit involved. + const double dintVdpdT = ((reference_thermal_expansivity * + reference_isothermal_bulk_modulus / reference_rho * + tait_a * xi) * + (std::pow((1. + tait_b * psubpth), - tait_c) - + std::pow((1. - tait_b * Pth_rel), - tait_c))); + + const double dSdT = (reference_isothermal_bulk_modulus / reference_rho * + std::pow((xi * reference_thermal_expansivity), 2) * + (std::pow((1. + tait_b * psubpth), -1. - tait_c) - + std::pow((1. - tait_b * Pth_rel), -1. - tait_c)) + + dintVdpdT * (( 1 - 2./x_einstein + 2./(std::exp(x_einstein) - 1.)) + * einstein_temperature/(temperature*temperature))); + + const double rho = reference_rho / x; + const double isothermal_compressibility = 1./(reference_isothermal_bulk_modulus * (1. + tait_b * psubpth) * (tait_a + (1. - tait_a) * std::pow((1. + tait_b * psubpth), tait_c))); + const double alpha = reference_thermal_expansivity * xi * 1. / ((1. + tait_b * psubpth) * (tait_a + (1. - tait_a) * std::pow((1 + tait_b * psubpth), tait_c))); + const double heat_capacity = reference_heat_capacity_function.value(Point<1>(temperature)) + temperature * dSdT; + + // The following line might be useful for some compressibility models + // double isentropic_compressibility = isothermal_compressibility - alpha*alpha*temperature/(rho*heat_capacity); + out.densities[i] = rho; + out.compressibilities[i] = isothermal_compressibility; + out.thermal_expansion_coefficients[i] = alpha; + out.specific_heat[i] = heat_capacity; + + out.entropy_derivative_pressure[i] = -alpha / rho; + out.entropy_derivative_temperature[i] = heat_capacity/temperature; + // Change in composition due to chemical reactions at the + // given positions. The term reaction_terms[i][c] is the + // change in compositional field c at point i. + for (unsigned int c=0; c + bool + ModifiedTait:: + is_compressible () const + { + return true; + } + + + + template + void + ModifiedTait::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Modified Tait model"); + { + prm.declare_entry ("Reference pressure", "1e5", + Patterns::Double (0.), + "Reference pressure $P_0$. Units: \\si{\\pascal}."); + prm.declare_entry ("Reference temperature", "298.15", + Patterns::Double (0.), + "Reference temperature $T_0$. Units: \\si{\\kelvin}."); + prm.declare_entry ("Reference density", "3300.", + Patterns::Double (0.), + "The density at the reference pressure and temperature. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference isothermal bulk modulus", "125e9", + Patterns::Double (0.), + "The isothermal bulk modulus at the reference pressure and temperature. " + "Units: \\si{\\pascal}."); + prm.declare_entry ("Reference bulk modulus derivative", "4.", + Patterns::Double (0.), + "The value of the first pressure derivative of the isothermal bulk modulus " + "at the reference pressure and temperature. " + "Units: None."); + prm.declare_entry ("Reference thermal expansivity", "2e-5", + Patterns::Double (0.), + "The thermal expansion coefficient at the reference pressure and temperature. " + "Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Einstein temperature", "600.", + Patterns::Double (0.), + "The Einstein temperature at the reference pressure and temperature. " + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Viscosity", "1e21", + Patterns::Double (0.), + "The value of the constant viscosity $\\eta_0$. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the constant thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + + prm.enter_subsection("Reference heat capacity function"); + { + Functions::ParsedFunction<1>::declare_parameters(prm,1); + prm.declare_entry("Function expression","1.25e3"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + ModifiedTait::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Modified Tait model"); + { + reference_pressure = prm.get_double ("Reference pressure"); + reference_temperature = prm.get_double ("Reference temperature"); + reference_rho = prm.get_double ("Reference density"); + reference_isothermal_bulk_modulus = prm.get_double ("Reference isothermal bulk modulus"); + reference_Kprime = prm.get_double ("Reference bulk modulus derivative"); + reference_thermal_expansivity = prm.get_double ("Reference thermal expansivity"); + einstein_temperature = prm.get_double ("Einstein temperature"); + + eta = prm.get_double ("Viscosity"); + k_value = prm.get_double ("Thermal conductivity"); + + prm.enter_subsection("Reference heat capacity function"); + { + try + { + reference_heat_capacity_function.parse_parameters(prm); + } + catch (...) + { + std::cerr << "FunctionParser failed to parse\n" + << "\t Reference heat capacity function\n" + << "with expression \n" + << "\t' " << prm.get("Function expression") << "'"; + throw; + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Calculate dependent parameters + Kdprime_0 = -reference_Kprime/reference_isothermal_bulk_modulus; + tait_a = (1. + reference_Kprime) / (1. + reference_Kprime + reference_isothermal_bulk_modulus * Kdprime_0); + tait_b = (reference_Kprime / reference_isothermal_bulk_modulus) - (Kdprime_0 / (1. + reference_Kprime )); + tait_c = (1. + reference_Kprime + reference_isothermal_bulk_modulus * Kdprime_0) / + (reference_Kprime * reference_Kprime + reference_Kprime - reference_isothermal_bulk_modulus * Kdprime_0); + + // Declare dependencies on solution variables + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + this->model_dependence.viscosity = NonlinearDependence::none; + + + this->model_dependence.density = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + this->model_dependence.specific_heat = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(ModifiedTait, + "modified tait", + "A material model that implements the thermal modified Tait " + "equation of state as written in \\cite{HP2011}. " + "Constant values are used for the thermal conductivity and " + "viscosity. The defaults for all coefficients are chosen " + "to be similar to what is believed to be correct " + "for Earth's mantle. " + "All of the values that define this model are read " + "from a section ``Material model/Modified Tait model'' " + "in the input file, see " + "Section~\\ref{parameters:Material_20model/Modified_20Tait_20model}.") + } +} diff --git a/source/material_model/multicomponent.cc.bak b/source/material_model/multicomponent.cc.bak new file mode 100644 index 00000000000..66040fe62ac --- /dev/null +++ b/source/material_model/multicomponent.cc.bak @@ -0,0 +1,179 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + void + Multicomponent:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + EquationOfStateOutputs eos_outputs (this->introspection().n_chemical_composition_fields()+1); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + // The (incompressible) Boussinesq approximation treats the + // buoyancy term as Delta rho[i] * C[i], which implies that + // compositional fields are given as volume fractions. + const std::vector volume_fractions = MaterialUtilities::compute_only_composition_fractions(in.composition[i], + this->introspection().chemical_composition_field_indices()); + + equation_of_state.evaluate(in, i, eos_outputs); + out.viscosities[i] = MaterialUtilities::average_value(volume_fractions, viscosities, viscosity_averaging); + out.specific_heat[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.specific_heat_capacities, MaterialUtilities::arithmetic); + out.thermal_expansion_coefficients[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.thermal_expansion_coefficients, MaterialUtilities::arithmetic); + out.compressibilities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.compressibilities, MaterialUtilities::arithmetic); + out.entropy_derivative_pressure[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.entropy_derivative_pressure, MaterialUtilities::arithmetic); + out.entropy_derivative_temperature[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.entropy_derivative_temperature, MaterialUtilities::arithmetic); + + // Arithmetic averaging of thermal conductivities + // This may not be strictly the most reasonable thing, but for most Earth materials we hope + // that they do not vary so much that it is a big problem. + out.thermal_conductivities[i] = MaterialUtilities::average_value (volume_fractions, thermal_conductivities, MaterialUtilities::arithmetic); + + // not strictly correct if thermal expansivities are different, since we are interpreting + // these compositions as volume fractions, but the error introduced should not be too bad. + out.densities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.densities, MaterialUtilities::arithmetic); + + for (unsigned int c=0; c + bool + Multicomponent:: + is_compressible () const + { + return equation_of_state.is_compressible(); + } + + template + void + Multicomponent::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Multicomponent"); + { + EquationOfState::MulticomponentIncompressible::declare_parameters (prm, 4.e-5); + + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. Units: \\si{\\kelvin}."); + prm.declare_entry ("Viscosities", "1.e21", + Patterns::Anything(), + "List of viscosities for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Thermal conductivities", "4.7", + Patterns::Anything(), + "List of thermal conductivities for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Viscosity averaging scheme", "harmonic", + Patterns::Selection("arithmetic|harmonic|geometric|maximum composition"), + "When more than one compositional field is present at a point " + "with different viscosities, we need to come up with an average " + "viscosity at that point. Select a weighted harmonic, arithmetic, " + "geometric, or maximum composition."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + Multicomponent::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Multicomponent"); + { + equation_of_state.initialize_simulator (this->get_simulator()); + equation_of_state.parse_parameters (prm); + + reference_T = prm.get_double ("Reference temperature"); + + viscosity_averaging = MaterialUtilities::parse_compositional_averaging_operation ("Viscosity averaging scheme", + prm); + + // Make options file for parsing maps to double arrays + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + chemical_field_names.insert(chemical_field_names.begin(),"background"); + + std::vector compositional_field_names = this->introspection().get_composition_names(); + compositional_field_names.insert(compositional_field_names.begin(),"background"); + + Utilities::MapParsing::Options options(chemical_field_names, "Viscosities"); + options.list_of_allowed_keys = compositional_field_names; + options.allow_multiple_values_per_key = true; + + // Parse multicomponent properties + viscosities = Utilities::MapParsing::parse_map_to_double_array (prm.get("Viscosities"), options); + options.property_name = "Thermal conductivities"; + thermal_conductivities = Utilities::MapParsing::parse_map_to_double_array (prm.get("Thermal conductivities"), options); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::compositional_fields; + this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::compositional_fields; + this->model_dependence.thermal_conductivity = NonlinearDependence::compositional_fields; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(Multicomponent, + "multicomponent", + "This incompressible model is for use with an arbitrary number of" + " compositional fields, where each field represents a rock type which" + " can have completely different properties from the others." + " However, each rock type itself has constant material properties. The value of the " + " compositional field is interpreted as a volume fraction. If the sum of the fields is" + " greater than one, they are renormalized. If it is less than one, material properties " + " for ``background mantle'' make up the rest. When more than one field is present, the" + " material properties are averaged arithmetically. An exception is the viscosity," + " where the averaging should make more of a difference. For this, the user selects" + " between arithmetic, harmonic, geometric, or maximum composition averaging.") + } +} diff --git a/source/material_model/multicomponent_compressible.cc.bak b/source/material_model/multicomponent_compressible.cc.bak new file mode 100644 index 00000000000..09bc2634bb3 --- /dev/null +++ b/source/material_model/multicomponent_compressible.cc.bak @@ -0,0 +1,184 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + void + MulticomponentCompressible:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + EquationOfStateOutputs eos_outputs (this->n_compositional_fields()+1); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + equation_of_state.evaluate(in, i, eos_outputs); + + // Calculate volume fractions from mass fractions + const std::vector mass_fractions = MaterialUtilities::compute_composition_fractions(in.composition[i]); + const std::vector volume_fractions = MaterialUtilities::compute_volumes_from_masses(mass_fractions, + eos_outputs.densities, + true); + + // Specific quantities are mass averaged + out.specific_heat[i] = MaterialUtilities::average_value (mass_fractions, eos_outputs.specific_heat_capacities, MaterialUtilities::arithmetic); + out.entropy_derivative_pressure[i] = MaterialUtilities::average_value (mass_fractions, eos_outputs.entropy_derivative_pressure, MaterialUtilities::arithmetic); + out.entropy_derivative_temperature[i] = MaterialUtilities::average_value (mass_fractions, eos_outputs.entropy_derivative_temperature, MaterialUtilities::arithmetic); + + // Density, thermal expansivity and compressibility are all volume averaged + out.densities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.densities, MaterialUtilities::arithmetic); + out.thermal_expansion_coefficients[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.thermal_expansion_coefficients, MaterialUtilities::arithmetic); + out.compressibilities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.compressibilities, MaterialUtilities::arithmetic); + + // Arithmetic volume fraction averaging of thermal conductivities + // This may not be the most reasonable thing, but for most Earth materials we hope + // that they do not vary so much that it is a big problem. + out.thermal_conductivities[i] = MaterialUtilities::average_value (volume_fractions, thermal_conductivities, MaterialUtilities::arithmetic); + + // User-defined volume fraction averaging of viscosities + out.viscosities[i] = MaterialUtilities::average_value (volume_fractions, viscosities, viscosity_averaging); + + for (unsigned int c=0; c + bool + MulticomponentCompressible:: + is_compressible () const + { + return equation_of_state.is_compressible(); + } + + template + void + MulticomponentCompressible::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Multicomponent compressible"); + { + EquationOfState::MulticomponentCompressible::declare_parameters (prm); + + prm.declare_entry ("Viscosities", "1.e21", + Patterns::Anything(), + "List of viscosities for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Thermal conductivities", "4.7", + Patterns::Anything(), + "List of thermal conductivities for background mantle and compositional fields," + "for a total of N+1 values, where N is the number of compositional fields." + "If only one value is given, then all use the same value. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Viscosity averaging scheme", "harmonic", + Patterns::Selection("arithmetic|harmonic|geometric|maximum composition"), + "When more than one compositional field is present at a point " + "with different viscosities, we need to come up with an average " + "viscosity at that point. Select a weighted harmonic, arithmetic, " + "geometric, or maximum composition."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + MulticomponentCompressible::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Multicomponent compressible"); + { + equation_of_state.initialize_simulator (this->get_simulator()); + equation_of_state.parse_parameters (prm); + + viscosity_averaging = MaterialUtilities::parse_compositional_averaging_operation ("Viscosity averaging scheme", + prm); + + // Establish that a background field is required here + const bool has_background_field = true; + + // Retrieve the list of composition names + const std::vector list_of_composition_names = this->introspection().get_composition_names(); + + viscosities = Utilities::parse_map_to_double_array (prm.get("Viscosities"), + list_of_composition_names, + has_background_field, + "Viscosities"); + + thermal_conductivities = Utilities::parse_map_to_double_array (prm.get("Thermal conductivities"), + list_of_composition_names, + has_background_field, + "Thermal conductivities"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.thermal_conductivity = NonlinearDependence::compositional_fields; + this->model_dependence.viscosity = NonlinearDependence::compositional_fields; + this->model_dependence.density |= NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + this->model_dependence.specific_heat = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(MulticomponentCompressible, + "multicomponent compressible", + "This model is for use with an arbitrary number of compositional fields, where each field" + " represents a rock type which can have completely different properties from the others." + " Each rock type is described by a self-consistent equation of state. The value of the " + " compositional field is interpreted as a mass fraction. If the sum of the fields is" + " greater than one, they are renormalized. If it is less than one, material properties " + " for ``background mantle'' make up the rest. When more than one field is present, the " + "material properties are averaged arithmetically by mass fraction (for specific heat), " + "or volume fraction (for density, thermal expansivity and compressibility). " + "The thermal conductivity is also arithmetically averaged by volume fraction. " + "Finally, the viscosity is averaged by volume fraction, but the user can choose " + "between arithmetic, harmonic, geometric or maximum composition averaging.") + } +} diff --git a/source/material_model/nondimensional.cc.bak b/source/material_model/nondimensional.cc.bak new file mode 100644 index 00000000000..88607a5573f --- /dev/null +++ b/source/material_model/nondimensional.cc.bak @@ -0,0 +1,216 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + void + Nondimensional::initialize () + { + Assert(this->get_parameters().formulation_temperature_equation + == Parameters::Formulation::TemperatureEquation::reference_density_profile, + ExcMessage("The Nondimensional material model can only work with a " + "temperature formulation that is based on the reference " + "profile.")); + Assert((this->get_parameters().formulation_mass_conservation + == Parameters::Formulation::MassConservation::incompressible + && !compressible) + || + (this->get_parameters().formulation_mass_conservation + == Parameters::Formulation::MassConservation::reference_density_profile + && compressible) + || + (this->get_parameters().formulation_mass_conservation + == Parameters::Formulation::MassConservation::implicit_reference_density_profile + && compressible) + , + ExcMessage("The Nondimensional material model can only work with a " + "mass formulation that is incompressible or based on " + "the reference profile and the Di has to be chosen " + "accordingly.")); + } + + + template + void + Nondimensional:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const Point position = in.position[i]; + const double temperature_deviation = in.temperature[i] - this->get_adiabatic_conditions().temperature(position); + const double pressure_deviation = in.pressure[i] - this->get_adiabatic_conditions().pressure(position); + + const double depth = this->get_geometry_model().depth(position); + + out.viscosities[i] = (compressible ? Di : 1.0) / Ra + * std::exp( -exponential_viscosity_temperature_prefactor * temperature_deviation + + exponential_viscosity_depth_prefactor * depth); + + out.specific_heat[i] = reference_specific_heat; + out.thermal_conductivities[i] = 1.0; + out.thermal_expansion_coefficients[i] = compressible ? Di : 1.0; + + out.densities[i] = reference_rho + * std::exp(depth * Di/gamma) + * (1.0 + - out.thermal_expansion_coefficients[i] * temperature_deviation + + (tala ? 0.0 : 1.0) * Di * gamma * pressure_deviation); + + out.compressibilities[i] = 0.0; + out.entropy_derivative_pressure[i] = 0.0; + out.entropy_derivative_temperature[i] = 0.0; + + for (unsigned int c=0; c + bool + Nondimensional:: + is_compressible () const + { + return compressible; + } + + + + template + void + Nondimensional::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Nondimensional model"); + { + prm.declare_entry ("Reference density", "1.0", + Patterns::Double (0.), + "Reference density $\\rho_0$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Ra", "1e4", + Patterns::Double (0.), + "Rayleigh number Ra"); + prm.declare_entry ("Di", "0.0", + Patterns::Double (0.), + "Dissipation number. Pick 0.0 for incompressible " + "computations."); + prm.declare_entry ("gamma", "1.0", + Patterns::Double (0.), + "Grueneisen parameter"); + prm.declare_entry ("Reference specific heat", "1.0", + Patterns::Double (0.), + "The value of the specific heat $C_p$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Viscosity temperature prefactor", "0.0", + Patterns::Double (0.), + "Exponential temperature prefactor for viscosity."); + prm.declare_entry ("Viscosity depth prefactor", "0.0", + Patterns::Double (0.), + "Exponential depth prefactor for viscosity."); + prm.declare_entry ("Use TALA", "false", + Patterns::Bool (), + "Whether to use the TALA instead of the ALA " + "approximation."); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + Nondimensional::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Nondimensional model"); + { + reference_rho = prm.get_double ("Reference density"); + exponential_viscosity_temperature_prefactor = prm.get_double ("Viscosity temperature prefactor"); + exponential_viscosity_depth_prefactor = prm.get_double ("Viscosity depth prefactor"); + Di = prm.get_double ("Di"); + Ra = prm.get_double ("Ra"); + gamma = prm.get_double ("gamma"); + tala = prm.get_bool ("Use TALA"); + reference_specific_heat = prm.get_double ("Reference specific heat"); + + compressible = (Di!=0.0); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::temperature; + this->model_dependence.density = NonlinearDependence::pressure | NonlinearDependence::temperature; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(Nondimensional, + "nondimensional", + "A material model for nondimensionalized " + "computations for compressible or incompressible " + "computations defined through Rayleigh number \text{Ra} " + "and Dissipation number Di. This model is made " + "to be used with the Boussinesq, ALA, or TALA " + "formulation." + "\n\n" + "The viscosity is defined as $\\eta = \\text{Di} / \\text{Ra} \\cdot \\exp(-b T^\\prime + c z)$ " + "where $T^\\prime$ is the temperature variation from the " + "adiabatic temperature, $z$ is the depth, " + "$b$ is given by ``Viscosity temperature prefactor'', " + "and $c$ by ``Viscosity depth prefactor''. If " + "$\\text{Di}$ is zero, it will be replaced by 1.0 in $\\eta$." + "\n\n" + "The density is defined as $\\rho = \\exp(\\text{Di}/\\gamma \\cdot z) " + " (1.0 - \\alpha T^\\prime + \\text{Di} \\gamma p^\\prime),$ where " + "$\\alpha=\\text{Di}$ is the thermal expansion coefficient, " + "$\\gamma$ is the Grueneisen parameter, and $p^\\prime$ is " + "the pressure variation from the adiabatic " + "pressure. The pressure dependent term is not present " + "if ``TALA'' is enabled.") + } +} diff --git a/source/material_model/perplex_lookup.cc.bak b/source/material_model/perplex_lookup.cc.bak new file mode 100644 index 00000000000..46daf562cf7 --- /dev/null +++ b/source/material_model/perplex_lookup.cc.bak @@ -0,0 +1,230 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include + +#ifdef ASPECT_WITH_PERPLEX +extern "C" { +#include +} +#include +#endif + +namespace aspect +{ + namespace MaterialModel + { + + template + void + PerpleXLookup::initialize() + { +#ifdef ASPECT_WITH_PERPLEX + AssertThrow(dealii::MultithreadInfo::is_running_single_threaded(), + ExcMessage("The PerpleXLookup MaterialModel only works in single threaded mode (do not use -j)!")); + + ini_phaseq(perplex_file_name.c_str()); // this line initializes meemum +#else + Assert (false, ExcMessage("ASPECT has not been compiled with the PerpleX libraries")); +#endif + } + + template + bool + PerpleXLookup:: + is_compressible () const + { + return true; + } + + template + void + PerpleXLookup:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + /* Instead of evaluating at every quadrature point per cell, + * we here average the P, T and X values, and evaluate once. + * This is much quicker than evaluating at all quadrature + * points, and if the grid is fine, it should be a reasonable + * approximation + */ + +#ifdef ASPECT_WITH_PERPLEX + std::vector wtphases(p_size_phases); + std::vector cphases(p_size_phases * p_size_components); + std::vector namephases(p_size_phases * p_pname_len); + std::vector sysprop(p_size_sysprops); + + int phaseq_dbg = 0; + + unsigned int n_quad = in.n_evaluation_points(); // number of quadrature points in cell + unsigned int n_comp = in.composition[0].size(); // number of components in rock + + const double average_temperature = std::min(max_temperature, + std::max(min_temperature, + (accumulate( in.temperature.begin(), in.temperature.end(), 0.0) / + n_quad))); + const double average_pressure = std::min(max_pressure, + std::max(min_pressure, + (accumulate( in.pressure.begin(), in.pressure.end(), 0.0) / + n_quad))); + + std::vector comp; + comp.resize(n_comp); + + for (unsigned int c=0; c + void + PerpleXLookup::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("PerpleX lookup model"); + { + + prm.declare_entry ("PerpleX input file name", "rock.dat", + Patterns::Anything (), + "The name of the PerpleX input file (should end with .dat)."); + prm.declare_entry ("Viscosity", "5e24", + Patterns::Double (0.), + "The value of the viscosity $\\eta$. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Minimum material temperature", "0.", + Patterns::Double (0.), + "The value of the minimum temperature used to query PerpleX. " + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Maximum material temperature", "6000.", + Patterns::Double (0.), + "The value of the maximum temperature used to query PerpleX. " + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Minimum material pressure", "1.e5", + Patterns::Double (0.), + "The value of the minimum pressure used to query PerpleX. " + "Units: \\si{\\pascal}."); + prm.declare_entry ("Maximum material pressure", "1.e12", + Patterns::Double (0.), + "The value of the maximum pressure used to query PerpleX. " + "Units: \\si{\\pascal}."); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + PerpleXLookup::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("PerpleX lookup model"); + { + perplex_file_name = prm.get ("PerpleX input file name"); + eta = prm.get_double ("Viscosity"); + k_value = prm.get_double ("Thermal conductivity"); + min_temperature = prm.get_double ("Minimum material temperature"); + max_temperature = prm.get_double ("Maximum material temperature"); + min_pressure = prm.get_double ("Minimum material pressure"); + max_pressure = prm.get_double ("Maximum material pressure"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + + this->model_dependence.density = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + this->model_dependence.specific_heat = NonlinearDependence::temperature + | NonlinearDependence::pressure + | NonlinearDependence::compositional_fields; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(PerpleXLookup, + "perplex lookup", + "A material model that has constant values " + "for viscosity and thermal conductivity, and " + "calculates other properties on-the-fly using " + "PerpleX meemum. Compositional fields correspond " + "to the individual components in the order given " + "in the PerpleX file.") + } +} diff --git a/source/material_model/prescribed_viscosity.cc.bak b/source/material_model/prescribed_viscosity.cc.bak new file mode 100644 index 00000000000..25f647ae177 --- /dev/null +++ b/source/material_model/prescribed_viscosity.cc.bak @@ -0,0 +1,210 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + template + void + PrescribedViscosity::initialize() + { + base_model->initialize(); + } + + + + template + void + PrescribedViscosity::update() + { + base_model->update(); + + // we get time passed as seconds (always) but may want + // to reinterpret it in years + const double time = this->convert_output_to_years() ? this->get_time() / year_in_seconds : this->get_time(); + prescribed_viscosity_indicator_function.set_time (time); + prescribed_viscosity_function.set_time (time); + } + + + + template + void + PrescribedViscosity::evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const + { + base_model->evaluate(in,out); + for (unsigned int i=0; i 0.5) + { + out.viscosities[i] = prescribed_viscosity_function.value(in.position[i]); + } + } + } + } + + + + template + bool + PrescribedViscosity:: + is_compressible () const + { + return base_model->is_compressible(); + } + + + + template + void + PrescribedViscosity::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection ("Prescribed viscosity"); + { + + prm.declare_entry("Base model","simple", + Patterns::Selection(MaterialModel::get_valid_model_names_pattern()), + "The name of a material model that will be modified by the prescribed " + "viscosity material model. Valid values for this parameter " + "are the names of models that are also valid for the " + "``Material models/Model name'' parameter. See the documentation for " + "that for more information."); + + prm.enter_subsection ("Indicator function"); + { + Functions::ParsedFunction::declare_parameters (prm, 3); + } + prm.leave_subsection (); + + prm.enter_subsection ("Viscosity function"); + { + Functions::ParsedFunction::declare_parameters (prm, 3); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + + template + void + PrescribedViscosity::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection ("Prescribed viscosity"); + { + AssertThrow( prm.get("Base model") != "prescribed viscosity", + ExcMessage("You may not use ``prescribed viscosity'' as the base model for " + "a prescribed viscosity model.") ); + + // create the base model and initialize its SimulatorAccess base + // class; it will get a chance to read its parameters below after we + // leave the current section + base_model = create_material_model(prm.get("Base model")); + if (SimulatorAccess *sim = dynamic_cast*>(base_model.get())) + sim->initialize_simulator (this->get_simulator()); + + prm.enter_subsection("Indicator function"); + { + try + { + prescribed_viscosity_indicator_function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Prescribed viscosity.Indicator function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'"; + throw; + } + } + prm.leave_subsection(); + + prm.enter_subsection("Viscosity function"); + { + try + { + prescribed_viscosity_function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Prescribed viscosity.Viscosity function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'"; + throw; + } + } + prm.leave_subsection(); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + /* After parsing the parameters for prescribed viscosity, it is essential to parse + parameters related to the base model. */ + base_model->parse_parameters(prm); + this->model_dependence = base_model->get_model_dependence(); + } + + + + template + void + PrescribedViscosity::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + base_model->create_additional_named_outputs(out); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(PrescribedViscosity, + "prescribed viscosity", + "A material model that applies a viscosity to a ''base model'' chosen from any of " + "the other available material models. This prescribed viscosity material model " + "allows the user to specify a function which describes where the viscosity should be " + "prescribed and a second function which describes the viscosity in that region. " + "This material model requires a base model which prescribes the viscosity and the " + "other material parameters in the rest of the model." + ) + } +} diff --git a/source/material_model/reaction_model/katz2003_mantle_melting.cc.bak b/source/material_model/reaction_model/katz2003_mantle_melting.cc.bak new file mode 100644 index 00000000000..71993bc7ea7 --- /dev/null +++ b/source/material_model/reaction_model/katz2003_mantle_melting.cc.bak @@ -0,0 +1,651 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace ReactionModel + { + + + template + Katz2003MantleMelting::Katz2003MantleMelting() + = default; + + + + template + double + Katz2003MantleMelting:: + reference_darcy_coefficient () const + { + // 0.01 = 1% melt + return reference_permeability * std::pow(0.01,3.0) / viscosity_fluid; + } + + + template + double + Katz2003MantleMelting:: + melt_fraction (const double temperature, + const double pressure) const + { + // anhydrous melting of peridotite after Katz, 2003 + const double T_solidus = A1 + 273.15 + + A2 * pressure + + A3 * pressure * pressure; + const double T_lherz_liquidus = B1 + 273.15 + + B2 * pressure + + B3 * pressure * pressure; + const double T_liquidus = C1 + 273.15 + + C2 * pressure + + C3 * pressure * pressure; + + // melt fraction for peridotite with clinopyroxene + double peridotite_melt_fraction; + if (temperature < T_solidus || pressure > 1.3e10) + peridotite_melt_fraction = 0.0; + else if (temperature > T_lherz_liquidus) + peridotite_melt_fraction = 1.0; + else + peridotite_melt_fraction = std::pow((temperature - T_solidus) / (T_lherz_liquidus - T_solidus),beta); + + // melt fraction after melting of all clinopyroxene + const double R_cpx = r1 + r2 * std::max(0.0, pressure); + const double F_max = M_cpx / R_cpx; + + if (peridotite_melt_fraction > F_max && temperature < T_liquidus) + { + const double T_max = std::pow(F_max,1/beta) * (T_lherz_liquidus - T_solidus) + T_solidus; + peridotite_melt_fraction = F_max + (1 - F_max) * pow((temperature - T_max) / (T_liquidus - T_max),beta); + } + return peridotite_melt_fraction; + } + + + + template + double + Katz2003MantleMelting:: + entropy_change (const double temperature, + const double pressure, + const double maximum_melt_fraction, + const NonlinearDependence::Dependence dependence) const + { + double entropy_gradient = 0.0; + + // calculate latent heat of melting + // we need the change of melt fraction in dependence of pressure and temperature + + // for peridotite after Katz, 2003 + const double T_solidus = A1 + 273.15 + + A2 * pressure + + A3 * pressure * pressure; + const double T_lherz_liquidus = B1 + 273.15 + + B2 * pressure + + B3 * pressure * pressure; + const double T_liquidus = C1 + 273.15 + + C2 * pressure + + C3 * pressure * pressure; + + const double dT_solidus_dp = A2 + 2 * A3 * pressure; + const double dT_lherz_liquidus_dp = B2 + 2 * B3 * pressure; + const double dT_liquidus_dp = C2 + 2 * C3 * pressure; + + if (temperature > T_solidus && temperature < T_liquidus && pressure < 1.3e10) + { + // melt fraction when clinopyroxene is still present + double melt_fraction_derivative_temperature + = beta * pow((temperature - T_solidus)/(T_lherz_liquidus - T_solidus),beta-1) + / (T_lherz_liquidus - T_solidus); + + double melt_fraction_derivative_pressure + = beta * pow((temperature - T_solidus)/(T_lherz_liquidus - T_solidus),beta-1) + * (dT_solidus_dp * (temperature - T_lherz_liquidus) + + dT_lherz_liquidus_dp * (T_solidus - temperature)) + / pow(T_lherz_liquidus - T_solidus,2); + + // melt fraction after melting of all clinopyroxene + const double R_cpx = r1 + r2 * std::max(0.0, pressure); + const double F_max = M_cpx / R_cpx; + + if (melt_fraction(temperature, pressure) > F_max) + { + const double T_max = std::pow(F_max,1.0/beta) * (T_lherz_liquidus - T_solidus) + T_solidus; + const double dF_max_dp = - M_cpx * std::pow(r1 + r2 * pressure,-2) * r2; + const double dT_max_dp = dT_solidus_dp + + 1.0/beta * std::pow(F_max,1.0/beta - 1.0) * dF_max_dp * (T_lherz_liquidus - T_solidus) + + std::pow(F_max,1.0/beta) * (dT_lherz_liquidus_dp - dT_solidus_dp); + + melt_fraction_derivative_temperature + = (1.0 - F_max) * beta * std::pow((temperature - T_max)/(T_liquidus - T_max),beta-1) + / (T_liquidus - T_max); + + melt_fraction_derivative_pressure + = dF_max_dp + - dF_max_dp * std::pow((temperature - T_max)/(T_liquidus - T_max),beta) + + (1.0 - F_max) * beta * std::pow((temperature - T_max)/(T_liquidus - T_max),beta-1) + * (dT_max_dp * (T_max - T_liquidus) - (dT_liquidus_dp - dT_max_dp) * (temperature - T_max)) / std::pow(T_liquidus - T_max, 2); + } + + double melt_fraction_derivative = 0; + if (dependence == NonlinearDependence::temperature) + melt_fraction_derivative = melt_fraction_derivative_temperature; + else if (dependence == NonlinearDependence::pressure) + melt_fraction_derivative = melt_fraction_derivative_pressure; + else + AssertThrow(false, ExcMessage("not implemented")); + + if (melt_fraction(temperature, pressure) >= maximum_melt_fraction) + entropy_gradient = melt_fraction_derivative * peridotite_melting_entropy_change; + } + return entropy_gradient; + } + + + + template + void + Katz2003MantleMelting:: + calculate_reaction_rate_outputs(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const + { + ReactionRateOutputs *reaction_rate_out = out.template get_additional_output>(); + + for (unsigned int i=0; iinclude_melt_transport()) + { + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + const unsigned int peridotite_idx = this->introspection().compositional_index_for_name("peridotite"); + const double old_porosity = in.composition[i][porosity_idx]; + const double maximum_melt_fraction = in.composition[i][peridotite_idx]; + + // calculate the melting rate as difference between the equilibrium melt fraction + // and the solution of the previous time step + double porosity_change = 0.0; + if (fractional_melting) + { + // solidus is lowered by previous melting events (fractional melting) + const double solidus_change = (maximum_melt_fraction - old_porosity) * depletion_solidus_change; + const double eq_melt_fraction = melt_fraction(in.temperature[i] - solidus_change, this->get_adiabatic_conditions().pressure(in.position[i])); + porosity_change = eq_melt_fraction - old_porosity; + } + else + { + // batch melting + porosity_change = melt_fraction(in.temperature[i], this->get_adiabatic_conditions().pressure(in.position[i])) + - std::max(maximum_melt_fraction, 0.0); + porosity_change = std::max(porosity_change, 0.0); + + // freezing of melt below the solidus + + // If the porosity is larger than the equilibrium melt fraction, melt should freeze again. + // Because we do not track the melt composition, we have to use a workaround here for freezing of melt: + // We reduce the porosity until either it reaches the equilibrium melt fraction, or the depletion + // (peridotite field), which decreases as melt freezes, reaches the same value as the equilibrium + // melt fraction, whatever happens earlier. An exception is when the melt fraction is zero; in this case + // all melt should freeze. + const double eq_melt_fraction = melt_fraction(in.temperature[i], this->get_adiabatic_conditions().pressure(in.position[i])); + + // If the porosity change is not negative, there is no freezing, and the change in porosity + // is covered by the melting relation above. + + // porosity reaches the equilibrium melt fraction: + const double porosity_change_wrt_melt_fraction = std::min(eq_melt_fraction - old_porosity - porosity_change,0.0); + + // depletion reaches the equilibrium melt fraction: + const double porosity_change_wrt_depletion = std::min((eq_melt_fraction - std::max(maximum_melt_fraction, 0.0)) + * (1.0 - old_porosity) / (1.0 - maximum_melt_fraction),0.0); + double freezing_amount = std::max(porosity_change_wrt_melt_fraction, porosity_change_wrt_depletion); + + if (eq_melt_fraction == 0.0) + freezing_amount = - old_porosity; + + porosity_change += freezing_amount; + + // Adapt time scale of freezing with respect to melting. + // We have to multiply with the melting time scale here to obtain the porosity change + // that happens in the time defined by the melting time scale (as opposed to a rate). + // This is important because we want to perform some checks on this quantity (for example, + // we want to make sure that this change does not lead to a negative porosity, see below). + // Later on, the overall porosity change is then divided again by the melting time scale + // to obtain the rate of melting or freezing, which is used in the operator splitting scheme. + if (porosity_change < 0 ) + porosity_change *= freezing_rate * melting_time_scale; + + } + + // remove melt that gets close to the surface + if (this->get_geometry_model().depth(in.position[i]) < extraction_depth) + porosity_change = -old_porosity * (in.position[i](1) - (this->get_geometry_model().maximal_depth() - extraction_depth))/extraction_depth; + + // do not allow negative porosity + porosity_change = std::max(porosity_change, -old_porosity); + + // because depletion is a volume-based, and not a mass-based property that is advected, + // additional scaling factors on the right hand side apply + for (unsigned int c=0; cget_timestep_number() > 0) + reaction_rate_out->reaction_rates[i][c] = porosity_change / melting_time_scale * (1 - maximum_melt_fraction) / (1 - old_porosity); + else if (c == porosity_idx && this->get_timestep_number() > 0) + reaction_rate_out->reaction_rates[i][c] = porosity_change / melting_time_scale; + else + reaction_rate_out->reaction_rates[i][c] = 0.0; + } + out.reaction_terms[i][c] = 0.0; + } + + out.entropy_derivative_pressure[i] = entropy_change (in.temperature[i], this->get_adiabatic_conditions().pressure(in.position[i]), maximum_melt_fraction, NonlinearDependence::pressure); + out.entropy_derivative_temperature[i] = entropy_change (in.temperature[i], this->get_adiabatic_conditions().pressure(in.position[i]), maximum_melt_fraction, NonlinearDependence::temperature); + } + else + { + out.entropy_derivative_pressure[i] = entropy_change (in.temperature[i], this->get_adiabatic_conditions().pressure(in.position[i]), 0, NonlinearDependence::pressure); + out.entropy_derivative_temperature[i] = entropy_change (in.temperature[i], this->get_adiabatic_conditions().pressure(in.position[i]), 0, NonlinearDependence::temperature); + + // no melting/freezing is used in the model --> set all reactions to zero + for (unsigned int c=0; creaction_rates[i][c] = 0.0; + } + } + } + + } + + + template + void + Katz2003MantleMelting:: + calculate_fluid_outputs(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out, + const double reference_T) const + { + MeltOutputs *melt_out = out.template get_additional_output>(); + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + + if (melt_out != nullptr) + { + + for (unsigned int i=0; ifluid_viscosities[i] = viscosity_fluid; + melt_out->permeabilities[i] = reference_permeability * std::pow(porosity,3) * std::pow(1.0-porosity,2); + + // first, calculate temperature dependence of density + double temperature_dependence = 1.0; + if (this->include_adiabatic_heating ()) + { + // temperature dependence is 1 - alpha * (T - T(adiabatic)) + temperature_dependence -= (in.temperature[i] - this->get_adiabatic_conditions().temperature(in.position[i])) + * out.thermal_expansion_coefficients[i]; + } + else + temperature_dependence -= (in.temperature[i] - reference_T) * out.thermal_expansion_coefficients[i]; + + // the fluid compressibility includes two parts, a constant compressibility, and a pressure-dependent one + // this is a simplified formulation, experimental data are often fit to the Birch-Murnaghan equation of state + const double fluid_compressibility = melt_compressibility / (1.0 + in.pressure[i] * melt_bulk_modulus_derivative * melt_compressibility); + + melt_out->fluid_densities[i] = reference_rho_fluid * std::exp(fluid_compressibility * (in.pressure[i] - this->get_surface_pressure())) + * temperature_dependence; + + melt_out->fluid_density_gradients[i] = melt_out->fluid_densities[i] * melt_out->fluid_densities[i] + * fluid_compressibility + * this->get_gravity_model().gravity_vector(in.position[i]); + + const double phi_0 = 0.05; + porosity = std::max(std::min(porosity,0.995),1e-4); + melt_out->compaction_viscosities[i] = xi_0 * phi_0 / porosity; + + double visc_temperature_dependence = 1.0; + if (this->include_adiabatic_heating ()) + { + const double delta_temp = in.temperature[i]-this->get_adiabatic_conditions().temperature(in.position[i]); + visc_temperature_dependence = std::max(std::min(std::exp(-thermal_bulk_viscosity_exponent*delta_temp/this->get_adiabatic_conditions().temperature(in.position[i])),1e4),1e-4); + } + else + { + const double delta_temp = in.temperature[i]-reference_T; + const double T_dependence = (thermal_bulk_viscosity_exponent == 0.0 + ? + 0.0 + : + thermal_bulk_viscosity_exponent*delta_temp/reference_T); + visc_temperature_dependence = std::max(std::min(std::exp(-T_dependence),1e4),1e-4); + } + melt_out->compaction_viscosities[i] *= visc_temperature_dependence; + + + } + } + + if (this->include_melt_transport() && in.requests_property(MaterialProperties::viscosity)) + { + for (unsigned int i=0; i + void + Katz2003MantleMelting::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("A1", "1085.7", + Patterns::Double (), + "Constant parameter in the quadratic " + "function that approximates the solidus " + "of peridotite. " + "Units: \\si{\\degreeCelsius}."); + prm.declare_entry ("A2", "1.329e-7", + Patterns::Double (), + "Prefactor of the linear pressure term " + "in the quadratic function that approximates " + "the solidus of peridotite. " + "Units: \\si{\\degreeCelsius\\per\\pascal}."); + prm.declare_entry ("A3", "-5.1e-18", + Patterns::Double (), + "Prefactor of the quadratic pressure term " + "in the quadratic function that approximates " + "the solidus of peridotite. " + "Units: \\si{\\degreeCelsius\\per\\pascal\\squared}."); + prm.declare_entry ("B1", "1475.0", + Patterns::Double (), + "Constant parameter in the quadratic " + "function that approximates the lherzolite " + "liquidus used for calculating the fraction " + "of peridotite-derived melt. " + "Units: \\si{\\degreeCelsius}."); + prm.declare_entry ("B2", "8.0e-8", + Patterns::Double (), + "Prefactor of the linear pressure term " + "in the quadratic function that approximates " + "the lherzolite liquidus used for " + "calculating the fraction of peridotite-" + "derived melt. " + "Units: \\si{\\degreeCelsius\\per\\pascal}."); + prm.declare_entry ("B3", "-3.2e-18", + Patterns::Double (), + "Prefactor of the quadratic pressure term " + "in the quadratic function that approximates " + "the lherzolite liquidus used for " + "calculating the fraction of peridotite-" + "derived melt. " + "Units: \\si{\\degreeCelsius\\per\\pascal\\squared}."); + prm.declare_entry ("C1", "1780.0", + Patterns::Double (), + "Constant parameter in the quadratic " + "function that approximates the liquidus " + "of peridotite. " + "Units: \\si{\\degreeCelsius}."); + prm.declare_entry ("C2", "4.50e-8", + Patterns::Double (), + "Prefactor of the linear pressure term " + "in the quadratic function that approximates " + "the liquidus of peridotite. " + "Units: \\si{\\degreeCelsius\\per\\pascal}."); + prm.declare_entry ("C3", "-2.0e-18", + Patterns::Double (), + "Prefactor of the quadratic pressure term " + "in the quadratic function that approximates " + "the liquidus of peridotite. " + "Units: \\si{\\degreeCelsius\\per\\pascal\\squared}."); + prm.declare_entry ("r1", "0.5", + Patterns::Double (), + "Constant in the linear function that " + "approximates the clinopyroxene reaction " + "coefficient. " + "Units: non-dimensional."); + prm.declare_entry ("r2", "8e-11", + Patterns::Double (), + "Prefactor of the linear pressure term " + "in the linear function that approximates " + "the clinopyroxene reaction coefficient. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("beta", "1.5", + Patterns::Double (), + "Exponent of the melting temperature in " + "the melt fraction calculation. " + "Units: non-dimensional."); + prm.declare_entry ("Mass fraction cpx", "0.15", + Patterns::Double (), + "Mass fraction of clinopyroxene in the " + "peridotite to be molten. " + "Units: non-dimensional."); + prm.declare_entry ("Peridotite melting entropy change", "-300.", + Patterns::Double (), + "The entropy change for the phase transition " + "from solid to melt of peridotite. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Reference melt density", "2500.", + Patterns::Double (0.), + "Reference density of the melt/fluid$\\rho_{f,0}$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Reference bulk viscosity", "1e22", + Patterns::Double (0.), + "The value of the constant bulk viscosity $\\xi_0$ of the solid matrix. " + "This viscosity may be modified by both temperature and porosity " + "dependencies. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Reference melt viscosity", "10.", + Patterns::Double (0.), + "The value of the constant melt viscosity $\\viscosity_fluid$. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Exponential melt weakening factor", "27.", + Patterns::Double (0.), + "The porosity dependence of the viscosity. Units: dimensionless."); + prm.declare_entry ("Thermal bulk viscosity exponent", "0.0", + Patterns::Double (0.), + "The temperature dependence of the bulk viscosity. Dimensionless exponent. " + "See the general documentation " + "of this model for a formula that states the dependence of the " + "viscosity on this factor, which is called $\\beta$ there."); + prm.declare_entry ("Melt extraction depth", "1000.0", + Patterns::Double (0.), + "Depth above that melt will be extracted from the model, " + "which is done by a negative reaction term proportional to the " + "porosity field. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Melt compressibility", "0.0", + Patterns::Double (0.), + "The value of the compressibility of the melt. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("Melt bulk modulus derivative", "0.0", + Patterns::Double (0.), + "The value of the pressure derivative of the melt bulk " + "modulus. " + "Units: None."); + prm.declare_entry ("Use fractional melting", "false", + Patterns::Bool (), + "If fractional melting should be used (if true), including a solidus " + "change based on depletion (in this case, the amount of melt that has " + "migrated away from its origin), and freezing of melt when it has moved " + "to a region with temperatures lower than the solidus; or if batch " + "melting should be used (if false), assuming that the melt fraction only " + "depends on temperature and pressure, and how much melt has already been " + "generated at a given point, but not considering movement of melt in " + "the melting parameterization." + "\n\n" + "Note that melt does not freeze unless the 'Freezing rate' parameter is set " + "to a value larger than 0."); + prm.declare_entry ("Freezing rate", "0.0", + Patterns::Double (0.), + "Freezing rate of melt when in subsolidus regions. " + "If this parameter is set to a number larger than 0.0, it specifies the " + "fraction of melt that will freeze per year (or per second, depending on the " + "``Use years in output instead of seconds'' parameter), as soon as the porosity " + "exceeds the equilibrium melt fraction, and the equilibrium melt fraction " + "falls below the depletion. In this case, melt will freeze according to the " + "given rate until one of those conditions is not fulfilled anymore. The " + "reasoning behind this is that there should not be more melt present than " + "the equilibrium melt fraction, as melt production decreases with increasing " + "depletion, but the freezing process of melt also reduces the depletion by " + "the same amount, and as soon as the depletion falls below the equilibrium " + "melt fraction, we expect that material should melt again (no matter how " + "much melt is present). This is quite a simplification and not a realistic " + "freezing parameterization, but without tracking the melt composition, there " + "is no way to compute freezing rates accurately. " + "If this parameter is set to zero, no freezing will occur. " + "Note that freezing can never be faster than determined by the " + "``Melting time scale for operator splitting''. The product of the " + "``Freezing rate'' and the ``Melting time scale for operator splitting'' " + "defines how fast freezing occurs with respect to melting (if the " + "product is 0.5, melting will occur twice as fast as freezing). " + "Units: 1/yr or 1/s, depending on the ``Use years " + "in output instead of seconds'' parameter."); + prm.declare_entry ("Melting time scale for operator splitting", "1e3", + Patterns::Double (0.), + "Because the operator splitting scheme is used, the porosity field can not " + "be set to a new equilibrium melt fraction instantly, but the model has to " + "provide a melting time scale instead. This time scale defines how fast melting " + "happens, or more specifically, the parameter defines the time after which " + "the deviation of the porosity from the equilibrium melt fraction will be " + "reduced to a fraction of $1/e$. So if the melting time scale is small compared " + "to the time step size, the reaction will be so fast that the porosity is very " + "close to the equilibrium melt fraction after reactions are computed. Conversely, " + "if the melting time scale is large compared to the time step size, almost no " + "melting and freezing will occur." + "\n\n" + "Also note that the melting time scale has to be larger than or equal to the reaction " + "time step used in the operator splitting scheme, otherwise reactions can not be " + "computed. " + "Units: yr or s, depending on the ``Use years in output instead of seconds'' parameter."); + prm.declare_entry ("Depletion solidus change", "200.0", + Patterns::Double (0.), + "The solidus temperature change for a depletion of 100\\%. For positive " + "values, the solidus gets increased for a positive peridotite field " + "(depletion) and lowered for a negative peridotite field (enrichment). " + "Scaling with depletion is linear. Only active when fractional melting " + "is used. " + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Reference permeability", "1e-8", + Patterns::Double(), + "Reference permeability of the solid host rock." + "Units: \\si{\\meter\\squared}."); + + + } + + + template + void + Katz2003MantleMelting::parse_parameters (ParameterHandler &prm) + { + A1 = prm.get_double ("A1"); + A2 = prm.get_double ("A2"); + A3 = prm.get_double ("A3"); + B1 = prm.get_double ("B1"); + B2 = prm.get_double ("B2"); + B3 = prm.get_double ("B3"); + C1 = prm.get_double ("C1"); + C2 = prm.get_double ("C2"); + C3 = prm.get_double ("C3"); + r1 = prm.get_double ("r1"); + r2 = prm.get_double ("r2"); + beta = prm.get_double ("beta"); + M_cpx = prm.get_double ("Mass fraction cpx"); + peridotite_melting_entropy_change + = prm.get_double ("Peridotite melting entropy change"); + + reference_rho_fluid = prm.get_double ("Reference melt density"); + xi_0 = prm.get_double ("Reference bulk viscosity"); + viscosity_fluid = prm.get_double ("Reference melt viscosity"); + thermal_bulk_viscosity_exponent = prm.get_double ("Thermal bulk viscosity exponent"); + alpha_phi = prm.get_double ("Exponential melt weakening factor"); + extraction_depth = prm.get_double ("Melt extraction depth"); + melt_compressibility = prm.get_double ("Melt compressibility"); + fractional_melting = prm.get_bool ("Use fractional melting"); + freezing_rate = prm.get_double ("Freezing rate"); + melting_time_scale = prm.get_double ("Melting time scale for operator splitting"); + melt_bulk_modulus_derivative = prm.get_double ("Melt bulk modulus derivative"); + depletion_solidus_change = prm.get_double ("Depletion solidus change"); + reference_permeability = prm.get_double ("Reference permeability"); + + + if (this->convert_output_to_years() == true) + { + melting_time_scale *= year_in_seconds; + freezing_rate /= year_in_seconds; + } + + AssertThrow(melting_time_scale > 0, + ExcMessage("The Melting time scale for operator splitting must be larger than 0!")); + + if (this->get_parameters().reaction_solver_type == Parameters::ReactionSolverType::fixed_step) + { + AssertThrow(melting_time_scale >= this->get_parameters().reaction_time_step, + ExcMessage("The reaction time step " + Utilities::to_string(this->get_parameters().reaction_time_step) + + " in the operator splitting scheme is too large to compute melting rates! " + "You have to choose it in such a way that it is smaller than the 'Melting time scale for " + "operator splitting' chosen in the material model, which is currently " + + Utilities::to_string(melting_time_scale) + ".")); + + AssertThrow(freezing_rate * this->get_parameters().reaction_time_step <= 1.0, + ExcMessage("The reaction time step " + Utilities::to_string(this->get_parameters().reaction_time_step) + + " in the operator splitting scheme is too large to compute freezing rates! " + "You have to choose it in such a way that it is smaller than the inverse of the " + "'Freezing rate' chosen in the material model, which is currently " + + Utilities::to_string(1.0/freezing_rate) + ".")); + } + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace ReactionModel \ + { \ + template class Katz2003MantleMelting; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/reactive_fluid_transport.cc b/source/material_model/reactive_fluid_transport.cc index 84bd54dc09f..1f2d76610bb 100644 --- a/source/material_model/reactive_fluid_transport.cc +++ b/source/material_model/reactive_fluid_transport.cc @@ -123,7 +123,7 @@ namespace aspect melt_fractions (const MaterialModel::MaterialModelInputs &in, std::vector &melt_fractions) const { - for (unsigned int q=0; qintrospection().compositional_index_for_name("porosity"); switch (fluid_solid_reaction_scheme) diff --git a/source/material_model/reactive_fluid_transport.cc.bak b/source/material_model/reactive_fluid_transport.cc.bak new file mode 100644 index 00000000000..84bd54dc09f --- /dev/null +++ b/source/material_model/reactive_fluid_transport.cc.bak @@ -0,0 +1,585 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + template + bool + ReactiveFluidTransport:: + is_compressible () const + { + return base_model->is_compressible(); + } + + + + template + double + ReactiveFluidTransport:: + reference_darcy_coefficient () const + { + if (fluid_solid_reaction_scheme == katz2003) + { + return katz2003_model.reference_darcy_coefficient(); + } + else + { + // 0.01 = 1% melt + return reference_permeability * std::pow(0.01,3.0) / eta_f; + } + } + + + + template + std::vector + ReactiveFluidTransport:: + tian_equilibrium_bound_water_content (const MaterialModel::MaterialModelInputs &in, + unsigned int q) const + { + // Create arrays that will store the values of the polynomials at the current pressure + std::vector LR_values(4); + std::vector csat_values(4); + std::vector Td_values(4); + + // Loop over the four rock types (peridotite, gabbro, MORB, sediment) and the polynomial + // coefficients to fill the vectors defined above. The polynomials for LR are defined in + // equations 13, B2, B10, and B18. csat polynomials are defined in equations 14, B1, B9, and B17. + // Td polynomials are defined in equations 15, B3, B11, and B19. + for (unsigned int i = 0; i eq_bound_water_content(4); + + // Define the maximum bound water content allowed for the four different rock compositions + std::vector max_bound_water_content = {tian_max_peridotite_water, tian_max_gabbro_water, tian_max_MORB_water, tian_max_sediment_water}; + + // Loop over all rock compositions and fill the equilibrium bound water content, divide by 100 to convert + // from percentage to fraction (equation 1) + for (unsigned int k = 0; k + void + ReactiveFluidTransport:: + melt_fractions (const MaterialModel::MaterialModelInputs &in, + std::vector &melt_fractions) const + { + for (unsigned int q=0; qintrospection().compositional_index_for_name("porosity"); + switch (fluid_solid_reaction_scheme) + { + case no_reaction: + { + // No reactions occur between the solid and fluid phases, + // and the fluid volume fraction (stored in the melt_fractions + // vector) is equal to the porosity. + melt_fractions[q] = in.composition[q][porosity_idx]; + break; + } + case zero_solubility: + { + // The fluid volume fraction in equilibrium with the solid + // at any point (stored in the melt_fractions vector) is + // equal to the sum of the bound fluid content and porosity. + const unsigned int bound_fluid_idx = this->introspection().compositional_index_for_name("bound_fluid"); + melt_fractions[q] = in.composition[q][bound_fluid_idx] + in.composition[q][porosity_idx]; + break; + } + case tian_approximation: + { + // The bound fluid content is calculated using parametrized phase + // diagrams for four different rock types: sediment, MORB, gabbro, and + // peridotite. + const unsigned int bound_fluid_idx = this->introspection().compositional_index_for_name("bound_fluid"); + const unsigned int sediment_idx = this->introspection().compositional_index_for_name("sediment"); + const unsigned int MORB_idx = this->introspection().compositional_index_for_name("MORB"); + const unsigned int gabbro_idx = this->introspection().compositional_index_for_name("gabbro"); + const unsigned int peridotite_idx = this->introspection().compositional_index_for_name("peridotite"); + + // Initialize a vector that stores the compositions (mass fractions) for + // the four different rock compositions, + std::vector tracked_rock_mass_fractions(4); + tracked_rock_mass_fractions[0] = (in.composition[q][peridotite_idx]); + tracked_rock_mass_fractions[1] = (in.composition[q][gabbro_idx]); + tracked_rock_mass_fractions[2] = (in.composition[q][MORB_idx]); + tracked_rock_mass_fractions[3] = (in.composition[q][sediment_idx]); + + // The bound water content (water within the solid phase) for the four different rock types + std::vector tian_eq_bound_water_content = tian_equilibrium_bound_water_content(in, q); + + // average the water content between the four different rock types + double average_eq_bound_water_content = MaterialUtilities::average_value (tracked_rock_mass_fractions, tian_eq_bound_water_content, MaterialUtilities::arithmetic); + + // The fluid volume fraction in equilibrium with the solid (stored in the melt_fractions vector) + // is equal to the sum of the porosity and the change in bound fluid content + // (current bound fluid - updated average bound fluid). + melt_fractions[q] = std::max(in.composition[q][bound_fluid_idx] + in.composition[q][porosity_idx] - average_eq_bound_water_content, 0.0); + break; + } + case katz2003: + { + melt_fractions[q] = katz2003_model.melt_fraction(in.temperature[q], + this->get_adiabatic_conditions().pressure(in.position[q])); + break; + } + default: + { + AssertThrow(false, ExcNotImplemented()); + break; + } + } + } + } + + + + template + void + ReactiveFluidTransport::initialize() + { + base_model->initialize(); + } + + + + template + void + ReactiveFluidTransport::update() + { + base_model->update(); + } + + + + template + void + ReactiveFluidTransport::evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const + { + base_model->evaluate(in,out); + + if (fluid_solid_reaction_scheme != katz2003) + { + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + + // Modify the viscosity from the base model based on the presence of fluid. + if (in.requests_property(MaterialProperties::viscosity)) + { + // Scale the base model viscosity value based on the porosity. + for (unsigned int q=0; q *fluid_out = out.template get_additional_output>(); + + if (fluid_out != nullptr) + { + for (unsigned int q=0; qfluid_viscosities[q] = eta_f; + fluid_out->permeabilities[q] = reference_permeability * std::pow(porosity,3) * std::pow(1.0-porosity,2); + + fluid_out->fluid_densities[q] = reference_rho_f * std::exp(fluid_compressibility * (in.pressure[q] - this->get_surface_pressure())); + + if (in.requests_property(MaterialProperties::viscosity)) + { + const double phi_0 = 0.05; + + // Limit the porosity to be no smaller than 1e-8 when + // calculating fluid effects on viscosities. + porosity = std::max(porosity,1e-8); + fluid_out->compaction_viscosities[q] = std::max(std::min(out.viscosities[q] * shear_to_bulk_viscosity_ratio * phi_0/porosity, max_compaction_visc), min_compaction_visc); + } + } + } + + ReactionRateOutputs *reaction_rate_out = out.template get_additional_output>(); + + // Fill reaction rate outputs if the model uses operator splitting. + // Specifically, change the porosity (representing the amount of free fluid) + // based on the water solubility and the fluid content. + if (this->get_parameters().use_operator_splitting && reaction_rate_out != nullptr) + { + std::vector eq_free_fluid_fractions(out.n_evaluation_points()); + melt_fractions(in, eq_free_fluid_fractions); + + for (unsigned int q=0; qintrospection().compositional_index_for_name("bound_fluid"); + if (c == bound_fluid_idx && this->get_timestep_number() > 0) + reaction_rate_out->reaction_rates[q][c] = - porosity_change / fluid_reaction_time_scale; + else if (c == porosity_idx && this->get_timestep_number() > 0) + reaction_rate_out->reaction_rates[q][c] = porosity_change / fluid_reaction_time_scale; + else + reaction_rate_out->reaction_rates[q][c] = 0.0; + } + else + { + if (c == porosity_idx && this->get_timestep_number() > 0) + reaction_rate_out->reaction_rates[q][c] = porosity_change / fluid_reaction_time_scale; + else + reaction_rate_out->reaction_rates[q][c] = 0.0; + } + + } + } + } + else + { + katz2003_model.calculate_reaction_rate_outputs(in, out); + katz2003_model.calculate_fluid_outputs(in, out, reference_T); + } + } + + template + void + ReactiveFluidTransport::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Reactive Fluid Transport Model"); + { + prm.enter_subsection("Katz 2003 model"); + { + // read in melting model parameters + ReactionModel::Katz2003MantleMelting::declare_parameters(prm); + } + prm.leave_subsection(); + + prm.declare_entry("Base model","visco plastic", + Patterns::Selection(MaterialModel::get_valid_model_names_pattern()), + "The name of a material model incorporating the " + "addition of fluids. Valid values for this parameter " + "are the names of models that are also valid for the " + "``Material models/Model name'' parameter. See the documentation for " + "that for more information."); + prm.declare_entry ("Reference fluid density", "2500", + Patterns::Double (0), + "Reference density of the melt/fluid$\\rho_{f,0}$. Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Shear to bulk viscosity ratio", "0.1", + Patterns::Double (0), + "Ratio between shear and bulk viscosity at the reference " + "permeability $\\phi_0=0.05$. The bulk viscosity additionally " + "scales with $\\phi_0/\\phi$. The shear viscosity is read in " + "from the base model. Units: dimensionless."); + prm.declare_entry ("Minimum compaction viscosity", "0", + Patterns::Double (0), + "Lower cutoff for the compaction viscosity. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Maximum compaction viscosity", + boost::lexical_cast(std::numeric_limits::max()), + Patterns::Double (0), + "Upper cutoff for the compaction viscosity. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Reference fluid viscosity", "10", + Patterns::Double (0), + "The value of the constant melt/fluid viscosity $\\eta_f$. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Exponential fluid weakening factor", "27", + Patterns::Double (0), + "The porosity dependence of the viscosity. Units: dimensionless."); + prm.declare_entry ("Reference permeability", "1e-8", + Patterns::Double(), + "Reference permeability of the solid host rock." + "Units: \\si{\\meter\\squared}."); + prm.declare_entry ("Fluid compressibility", "0.0", + Patterns::Double (0), + "The value of the compressibility of the fluid. " + "Units: \\si{\\per\\pascal}."); + prm.declare_entry ("Fluid reaction time scale for operator splitting", "1e3", + Patterns::Double (0), + "In case the operator splitting scheme is used, the porosity field can not " + "be set to a new equilibrium fluid fraction instantly, but the model has to " + "provide a reaction time scale instead. This time scale defines how fast fluid " + "release and absorption happen, or more specifically, the parameter defines the " + "time after which the deviation of the porosity from the free fluid fraction " + "that would be in equilibrium with the solid will be reduced to a fraction of " + "$1/e$. So if the fluid reaction time scale is small compared " + "to the time step size, the reaction will be so fast that the porosity is very " + "close to this equilibrium value after reactions are computed. Conversely, " + "if the fluid reaction time scale is large compared to the time step size, almost no " + "fluid release and absorption will occur." + "\n\n" + "Also note that the fluid reaction time scale has to be larger than or equal to the reaction " + "time step used in the operator splitting scheme, otherwise reactions can not be " + "computed. If the model does not use operator splitting, this parameter is not used. " + "Units: yr or s, depending on the ``Use years " + "in output instead of seconds'' parameter."); + prm.declare_entry ("Maximum weight percent water in sediment", "3", + Patterns::Double (0), + "The maximum allowed weight percent that the sediment composition can hold."); + prm.declare_entry ("Maximum weight percent water in MORB", "2", + Patterns::Double (0), + "The maximum allowed weight percent that the sediment composition can hold."); + prm.declare_entry ("Maximum weight percent water in gabbro", "1", + Patterns::Double (0), + "The maximum allowed weight percent that the sediment composition can hold."); + prm.declare_entry ("Maximum weight percent water in peridotite", "8", + Patterns::Double (0), + "The maximum allowed weight percent that the sediment composition can hold."); + prm.declare_entry ("Fluid-solid reaction scheme", "no reaction", + Patterns::Selection("no reaction|zero solubility|tian approximation|katz2003"), + "Select what type of scheme to use for reactions between fluid and solid phases. " + "The current available options are models where no reactions occur between " + "the two phases, or the solid phase is insoluble (zero solubility) and all " + "of the bound fluid is released into the fluid phase, tian approximation " + "use polynomials to describe hydration and dehydration reactions for four different " + "rock compositions as defined in Tian et al., 2019, or the Katz et. al. 2003 mantle " + "melting model. If the Katz 2003 melting model is used, its parameters are declared " + "in its own subsection."); + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$ for the katz2003 reaction model. " + "The reference temperature is used in both the density and " + "viscosity formulas of this model. Units: \\si{\\kelvin}."); + } + prm.leave_subsection(); + + } + prm.leave_subsection(); + } + + template + void + ReactiveFluidTransport::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Reactive Fluid Transport Model"); + { + AssertThrow( prm.get("Base model") != "reactive fluid transport", + ExcMessage("You may not use ``reactive fluid transport'' " + "as the base model for the reactive fluid transport " + "model itself.") ); + + reference_rho_f = prm.get_double ("Reference fluid density"); + shear_to_bulk_viscosity_ratio = prm.get_double ("Shear to bulk viscosity ratio"); + max_compaction_visc = prm.get_double ("Maximum compaction viscosity"); + min_compaction_visc = prm.get_double ("Minimum compaction viscosity"); + eta_f = prm.get_double ("Reference fluid viscosity"); + reference_permeability = prm.get_double ("Reference permeability"); + alpha_phi = prm.get_double ("Exponential fluid weakening factor"); + fluid_compressibility = prm.get_double ("Fluid compressibility"); + fluid_reaction_time_scale = prm.get_double ("Fluid reaction time scale for operator splitting"); + reference_T = prm.get_double ("Reference temperature"); + + tian_max_peridotite_water = prm.get_double ("Maximum weight percent water in peridotite"); + tian_max_gabbro_water = prm.get_double ("Maximum weight percent water in gabbro"); + tian_max_MORB_water = prm.get_double ("Maximum weight percent water in MORB"); + tian_max_sediment_water = prm.get_double ("Maximum weight percent water in sediment"); + + // Create the base model and initialize its SimulatorAccess base + // class; it will get a chance to read its parameters below after we + // leave the current section. + base_model = create_material_model(prm.get("Base model")); + if (SimulatorAccess *sim = dynamic_cast*>(base_model.get())) + sim->initialize_simulator (this->get_simulator()); + + if (this->convert_output_to_years() == true) + fluid_reaction_time_scale *= year_in_seconds; + + // Reaction scheme parameter + if (prm.get ("Fluid-solid reaction scheme") == "zero solubility") + { + fluid_solid_reaction_scheme = zero_solubility; + } + else if (prm.get ("Fluid-solid reaction scheme") == "no reaction") + { + fluid_solid_reaction_scheme = no_reaction; + } + else if (prm.get ("Fluid-solid reaction scheme") == "tian approximation") + { + AssertThrow(this->introspection().compositional_name_exists("sediment"), + ExcMessage("The Tian approximation only works " + "if there is a compositional field called sediment.")); + AssertThrow(this->introspection().compositional_name_exists("MORB"), + ExcMessage("The Tian approximation only works " + "if there is a compositional field called MORB.")); + AssertThrow(this->introspection().compositional_name_exists("gabbro"), + ExcMessage("The Tian approximation only works " + "if there is a compositional field called gabbro.")); + AssertThrow(this->introspection().compositional_name_exists("peridotite"), + ExcMessage("The Tian approximation only works " + "if there is a compositional field called peridotite.")); + fluid_solid_reaction_scheme = tian_approximation; + } + else if (prm.get ("Fluid-solid reaction scheme") == "katz2003") + { + fluid_solid_reaction_scheme = katz2003; + prm.enter_subsection("Katz 2003 model"); + { + katz2003_model.initialize_simulator (this->get_simulator()); + katz2003_model.parse_parameters(prm); + } + prm.leave_subsection(); + } + else + AssertThrow(false, ExcMessage("Not a valid fluid-solid reaction scheme")); + + if (fluid_solid_reaction_scheme == no_reaction) + { + AssertThrow(this->get_parameters().use_operator_splitting == false, + ExcMessage("The Fluid-reaction scheme no reaction should not be used with operator splitting.")); + } + + if (fluid_solid_reaction_scheme == zero_solubility) + { + AssertThrow(this->get_parameters().use_operator_splitting, + ExcMessage("The Fluid-reaction scheme zero solubility must be used with operator splitting.")); + } + + if (fluid_solid_reaction_scheme == tian_approximation) + { + AssertThrow(this->get_parameters().use_operator_splitting, + ExcMessage("The Fluid-reaction scheme tian approximation must be used with operator splitting.")); + } + + if (this->get_parameters().use_operator_splitting) + { + if (this->get_parameters().reaction_solver_type == Parameters::ReactionSolverType::fixed_step) + AssertThrow(fluid_reaction_time_scale >= this->get_parameters().reaction_time_step, + ExcMessage("The reaction time step " + Utilities::to_string(this->get_parameters().reaction_time_step) + + " in the operator splitting scheme is too large to compute fluid release rates! " + "You have to choose it in such a way that it is smaller than the 'Fluid reaction time scale for " + "operator splitting' chosen in the material model, which is currently " + + Utilities::to_string(fluid_reaction_time_scale) + ".")); + AssertThrow(fluid_reaction_time_scale > 0, + ExcMessage("The Fluid reaction time scale for operator splitting must be larger than 0!")); + } + + AssertThrow(this->introspection().compositional_name_exists("porosity"), + ExcMessage("Material model Reactive Fluid Transport only " + "works if there is a compositional field called porosity.")); + + if (fluid_solid_reaction_scheme != katz2003) + { + AssertThrow(this->introspection().compositional_name_exists("bound_fluid"), + ExcMessage("Material model Reactive Fluid Transport only " + "works if there is a compositional field called bound_fluid.")); + } + else + { + AssertThrow(this->introspection().compositional_name_exists("peridotite"), + ExcMessage("Material model Katz 2003 Mantle Melting only " + "works if there is a compositional field called peridotite.")); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // After parsing the parameters for this model, parse parameters related to the base model. + base_model->parse_parameters(prm); + this->model_dependence = base_model->get_model_dependence(); + if (fluid_solid_reaction_scheme == zero_solubility) + { + AssertThrow(this->get_material_model().is_compressible() == false, + ExcMessage("The Fluid-reaction scheme zero solubility must be used with an incompressible base model.")); + } + } + + + + template + void + ReactiveFluidTransport::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (this->get_parameters().use_operator_splitting + && out.template get_additional_output>() == nullptr) + { + out.additional_outputs.push_back( + std::make_unique> (out.n_evaluation_points(), this->n_compositional_fields())); + } + base_model->create_additional_named_outputs(out); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(ReactiveFluidTransport, + "reactive fluid transport", + "Material model that is designed to advect fluids and compute " + "fluid release and absorption based on different models for " + "fluid-rock interaction. At present, models where no fluid-rock " + "interactions occur or the solid has zero solubility are available. " + "The properties of the solid can be taken from another material model " + "that is used as a base model.") + } +} diff --git a/source/material_model/replace_lithosphere_viscosity.cc.bak b/source/material_model/replace_lithosphere_viscosity.cc.bak new file mode 100644 index 00000000000..1107255f18d --- /dev/null +++ b/source/material_model/replace_lithosphere_viscosity.cc.bak @@ -0,0 +1,172 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include + +#include + +#include +#include + + + +namespace aspect +{ + namespace MaterialModel + { + template + void + ReplaceLithosphereViscosity::initialize() + { + base_model->initialize(); + + lab_depth_lookup.initialize(); + } + + + template + void + ReplaceLithosphereViscosity::evaluate(const typename Interface::MaterialModelInputs &in, + typename Interface::MaterialModelOutputs &out) const + { + base_model->evaluate(in,out); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const double depth = this->SimulatorAccess::get_geometry_model().depth(in.position[i]); + const double lab_depth = lab_depth_lookup.get_lab_depth(in.position[i]); + + if (depth <= lab_depth) + out.viscosities[i] = lithosphere_viscosity; + } + + } + + + template + void + ReplaceLithosphereViscosity::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Replace lithosphere viscosity"); + { + prm.declare_entry("Base model","simple", + Patterns::Selection(MaterialModel::get_valid_model_names_pattern()), + "The name of a material model that will be modified by a replacing" + "the viscosity in the lithosphere by a constant value. Valid values for this parameter " + "are the names of models that are also valid for the " + "``Material models/Model name'' parameter. See the documentation for " + "more information."); + prm.declare_entry ("Lithosphere viscosity", "1e23", + Patterns::Double (0.), + "The viscosity within lithosphere, applied above" + "the maximum lithosphere depth."); + + InitialTemperature::LABDepth::LABDepthLookup::declare_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + ReplaceLithosphereViscosity::parse_parameters (ParameterHandler &prm) + { + AssertThrow (dim == 3, + ExcMessage ("The 'Replace lithosphere viscosity' material model " + "is only available for 3d computations.")); + + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Replace lithosphere viscosity"); + { + AssertThrow( prm.get("Base model") != "replace lithosphere viscosity", + ExcMessage("You may not use ``replace lithosphere viscosity'' as the base model for " + "a replace lithosphere viscosity model.") ); + + // create the base model and initialize its SimulatorAccess base + // class; it will get a chance to read its parameters below after we + // leave the current section + base_model = create_material_model(prm.get("Base model")); + if (SimulatorAccess *sim = dynamic_cast*>(base_model.get())) + sim->initialize_simulator (this->get_simulator()); + + lab_depth_lookup.initialize_simulator(this->get_simulator()); + lab_depth_lookup.parse_parameters(prm); + lithosphere_viscosity = prm.get_double ("Lithosphere viscosity"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + /* After parsing the parameters for replace lithosphere viscosity, it is essential to parse + parameters related to the base model. */ + base_model->parse_parameters(prm); + this->model_dependence = base_model->get_model_dependence(); + } + + template + bool + ReplaceLithosphereViscosity:: + is_compressible () const + { + return base_model->is_compressible(); + } + + template + void + ReplaceLithosphereViscosity::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + base_model->create_additional_named_outputs(out); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(ReplaceLithosphereViscosity, + "replace lithosphere viscosity", + "The ``replace lithosphere viscosity'' Material model sets viscosity to a " + "prescribed constant above the lithosphere-asthenosphere boundary (specified by " + "an ascii file or maximum lithosphere depth). Below the lithosphere-asthenosphere" + "boundary the viscosity is taken from any of the other available material model. " + "In other words, it is a ``compositing material model''." + "\n" + "Parameters related to the replace lithosphere viscosity model are read from a subsection " + "``Material model/Replace lithosphere viscosity''. " + "The user must specify a ``Base model'' from which other material properties are " + "derived. " + "\n" + "Note the required format of the input data file: The first lines may " + "contain any number of comments if they begin with ‘#’, but one of these lines " + "needs to contain the number of grid points in each dimension as for example " + "‘# POINTS: 3 3’. For a spherical model, the order of the data columns has to be" + "'phi', 'theta','depth (m)', where phi is the azimuth angle and theta is the " + "polar angle measured positive from the north pole.") + } +} diff --git a/source/material_model/rheology/ascii_depth_profile.cc.bak b/source/material_model/rheology/ascii_depth_profile.cc.bak new file mode 100644 index 00000000000..7b2a90bb529 --- /dev/null +++ b/source/material_model/rheology/ascii_depth_profile.cc.bak @@ -0,0 +1,99 @@ +/* + Copyright (C) 2020 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + + template + AsciiDepthProfile::AsciiDepthProfile () + = default; + + + + template + void + AsciiDepthProfile::initialize () + { + this->initialize(this->get_mpi_communicator()); + viscosity_index = this->get_column_index_from_name("viscosity"); + } + + + + template + double + AsciiDepthProfile::compute_viscosity (const double depth) const + { + return this->get_data_component (Point<1>(depth), viscosity_index); + } + + + + template + void + AsciiDepthProfile::declare_parameters (ParameterHandler &prm, + const std::string &subsection_name) + { + Utilities::AsciiDataBase::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/material-model/rheology/", + "ascii_depth_profile.txt", + subsection_name); + } + + + + template + void + AsciiDepthProfile::parse_parameters (ParameterHandler &prm, + const std::string &subsection_name) + { + Utilities::AsciiDataBase::parse_parameters(prm, + subsection_name); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace Rheology \ + { \ + template class AsciiDepthProfile; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/composite_visco_plastic.cc.bak b/source/material_model/rheology/composite_visco_plastic.cc.bak new file mode 100644 index 00000000000..39ea0204c7b --- /dev/null +++ b/source/material_model/rheology/composite_visco_plastic.cc.bak @@ -0,0 +1,458 @@ +/* + Copyright (C) 2020 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + // The following function is not yet used by ASPECT, so + // it is commented out to avoid tester issues. + // + // It will provide useful output when a material model which + // uses the CompositeViscoPlastic rheology has been implemented. + // + // The composite visco plastic rheology calculates the decomposed strain + // rates for each of the following deformation mechanisms: + // diffusion creep, dislocation creep, Peierls creep, + // Drucker-Prager plasticity and a constant (high) viscosity limiter. + // The values are provided in this order as a vector of additional + // outputs. If the user declares one or more mechanisms inactive + // (by assigning use_mechanism = False) then the corresponding + // strain rate output will be equal to zero. + //namespace + //{ + // std::vector make_strain_rate_additional_outputs_names() + // { + // std::vector names; + // names.emplace_back("edot_diffusion"); + // names.emplace_back("edot_dislocation"); + // names.emplace_back("edot_peierls"); + // names.emplace_back("edot_drucker_prager"); + // names.emplace_back("edot_limiter"); + // return names; + // } + //} + + + template + CompositeViscoPlastic::CompositeViscoPlastic () + = default; + + + + template + double + CompositeViscoPlastic::compute_viscosity (const double pressure, + const double temperature, + const std::vector &volume_fractions, + const SymmetricTensor<2,dim> &strain_rate, + std::vector &partial_strain_rates, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + double viscosity = 0.; + partial_strain_rates.resize(5, 0.); + + // Isostrain averaging + double total_volume_fraction = 1.; + for (unsigned int composition=0; composition < number_of_compositions; ++composition) + { + // Only include the contribution to the viscosity + // from a given composition if the volume fraction exceeds + // a certain (small) fraction. + if (volume_fractions[composition] > 2.*std::numeric_limits::epsilon()) + { + std::vector partial_strain_rates_composition(5, 0.); + viscosity += (volume_fractions[composition] + * compute_composition_viscosity (pressure, + temperature, + composition, + strain_rate, + partial_strain_rates_composition, + phase_function_values, + n_phase_transitions_per_composition)); + for (unsigned int j=0; j < 5; ++j) + partial_strain_rates[j] += volume_fractions[composition] * partial_strain_rates_composition[j]; + } + else + { + total_volume_fraction -= volume_fractions[composition]; + } + + viscosity /= total_volume_fraction; + for (unsigned int j=0; j < 5; ++j) + partial_strain_rates[j] /= total_volume_fraction; + } + return viscosity; + } + + + + template + double + CompositeViscoPlastic::compute_composition_viscosity (const double pressure, + const double temperature, + const unsigned int composition, + const SymmetricTensor<2,dim> &strain_rate, + std::vector &partial_strain_rates, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + // If strain rate is zero (like during the first time step) set it to some very small number + // to prevent a division-by-zero, and a floating point exception. + // Otherwise, calculate the square-root of the norm of the second invariant of the deviatoric- + // strain rate (often simplified as epsilondot_ii) + const double edot_ii = std::max(std::sqrt(std::max(-second_invariant(deviator(strain_rate)), 0.)), + min_strain_rate); + + Rheology::DiffusionCreepParameters diffusion_creep_parameters; + Rheology::DislocationCreepParameters dislocation_creep_parameters; + Rheology::PeierlsCreepParameters peierls_creep_parameters; + Rheology::DruckerPragerParameters drucker_prager_parameters; + + double eta_diff = maximum_viscosity; + double eta_disl = maximum_viscosity; + double eta_prls = maximum_viscosity; + + if (use_diffusion_creep) + { + diffusion_creep_parameters = diffusion_creep->compute_creep_parameters(composition, phase_function_values, n_phase_transitions_per_composition); + eta_diff = diffusion_creep->compute_viscosity(pressure, temperature, composition, phase_function_values, n_phase_transitions_per_composition); + } + + if (use_dislocation_creep) + { + dislocation_creep_parameters = dislocation_creep->compute_creep_parameters(composition, phase_function_values, n_phase_transitions_per_composition); + eta_disl = dislocation_creep->compute_viscosity(edot_ii, pressure, temperature, composition, phase_function_values, n_phase_transitions_per_composition); + } + + if (use_peierls_creep) + { + peierls_creep_parameters = peierls_creep->compute_creep_parameters(composition); + eta_prls = peierls_creep->compute_approximate_viscosity(edot_ii, pressure, temperature, composition); + } + // First guess at a stress using diffusion, dislocation, and Peierls creep viscosities calculated with the total second strain rate invariant. + const double eta_guess = std::min(std::max(minimum_viscosity, eta_diff*eta_disl*eta_prls/(eta_diff*eta_disl + eta_diff*eta_prls + eta_disl*eta_prls)), maximum_viscosity); + + double creep_stress = 2.*eta_guess*edot_ii; + + // Crude modification of the creep stress to be no higher than the + // Drucker-Prager yield stress. Probably fine for a first guess. + if (use_drucker_prager) + { + drucker_prager_parameters = drucker_prager->compute_drucker_prager_parameters(composition, phase_function_values, n_phase_transitions_per_composition); + const double yield_stress = drucker_prager->compute_yield_stress(drucker_prager_parameters.cohesion, + drucker_prager_parameters.angle_internal_friction, + pressure, + drucker_prager_parameters.max_yield_stress); + + creep_stress = std::min(creep_stress, yield_stress); + } + + // In this rheology model, the total strain rate is partitioned between + // different flow laws. We do not know how the strain is partitioned + // between these flow laws, nor do we know the creep stress, which is + // required to calculate the partitioning. + + // The following while loop conducts a Newton iteration to obtain the + // creep stress, which we need in order to calculate the viscosity. + double strain_rate_residual = 2*strain_rate_residual_threshold; + double strain_rate_deriv = 0; + unsigned int stress_iteration = 0; + while (std::abs(strain_rate_residual) > strain_rate_residual_threshold + && stress_iteration < stress_max_iteration_number) + { + + const std::pair creep_edot_and_deriv = compute_strain_rate_and_derivative (creep_stress, + pressure, + temperature, + diffusion_creep_parameters, + dislocation_creep_parameters, + peierls_creep_parameters, + drucker_prager_parameters); + + const double strain_rate = creep_stress/(2.*maximum_viscosity) + (maximum_viscosity/(maximum_viscosity - minimum_viscosity))*creep_edot_and_deriv.first; + strain_rate_deriv = 1./(2.*maximum_viscosity) + (maximum_viscosity/(maximum_viscosity - minimum_viscosity))*creep_edot_and_deriv.second; + + strain_rate_residual = strain_rate - edot_ii; + + // If the strain rate derivative is zero, we catch it below. + if (strain_rate_deriv>std::numeric_limits::min()) + creep_stress -= strain_rate_residual/strain_rate_deriv; + stress_iteration += 1; + + // If anything that would be used in the next iteration is not finite, the + // Newton iteration would trigger an exception and we want to abort the + // iteration instead. + // Currently, we still throw an exception, but if this exception is thrown, + // another more robust iterative scheme should be implemented + // (similar to that seen in the diffusion-dislocation material model). + const bool abort_newton_iteration = !numbers::is_finite(creep_stress) + || !numbers::is_finite(strain_rate_residual) + || !numbers::is_finite(strain_rate_deriv) + || strain_rate_deriv < std::numeric_limits::min() + || stress_iteration == stress_max_iteration_number; + AssertThrow(!abort_newton_iteration, + ExcMessage("No convergence has been reached in the loop that determines " + "the composite viscous creep stress. Aborting! " + "Residual is " + Utilities::to_string(strain_rate_residual) + + " after " + Utilities::to_string(stress_iteration) + " iterations. " + "You can increase the number of iterations by adapting the " + "parameter 'Maximum creep strain rate iterations'.")); + } + + // The creep stress is not the total stress, so we still need to do a little work to obtain the effective viscosity. + // First, we compute the stress running through the strain rate limiter, and then add that to the creep stress + // NOTE: The viscosity of the strain rate limiter is equal to (minimum_viscosity*maximum_viscosity)/(maximum_viscosity - minimum_viscosity) + const double lim_stress = 2.*minimum_viscosity*(edot_ii - creep_stress/(2.*maximum_viscosity)); + const double total_stress = creep_stress + lim_stress; + + // Compute the strain rate experienced by the different mechanisms + // These should sum to the total strain rate + + // The components of partial_strain_rates must be provided in the order + // dictated by make_strain_rate_additional_outputs_names + if (use_diffusion_creep) + { + const std::pair diff_edot_and_deriv = diffusion_creep->compute_strain_rate_and_derivative(creep_stress, pressure, temperature, diffusion_creep_parameters); + partial_strain_rates[0] = diff_edot_and_deriv.first; + } + + if (use_dislocation_creep) + { + const std::pair disl_edot_and_deriv = dislocation_creep->compute_strain_rate_and_derivative(creep_stress, pressure, temperature, dislocation_creep_parameters); + partial_strain_rates[1] = disl_edot_and_deriv.first; + } + + if (use_peierls_creep) + { + const std::pair prls_edot_and_deriv = peierls_creep->compute_strain_rate_and_derivative(creep_stress, pressure, temperature, peierls_creep_parameters); + partial_strain_rates[2] = prls_edot_and_deriv.first; + } + + if (use_drucker_prager) + { + const std::pair drpr_edot_and_deriv = drucker_prager->compute_strain_rate_and_derivative(creep_stress, pressure, drucker_prager_parameters); + partial_strain_rates[3] = drpr_edot_and_deriv.first; + } + + partial_strain_rates[4] = total_stress/(2.*maximum_viscosity); + + // Now we return the viscosity using the total stress + return total_stress/(2.*edot_ii); + } + + + + // Overload the + operator to act on two pairs of doubles. + std::pair operator+(const std::pair &x, const std::pair &y) + { + return std::make_pair(x.first+y.first, x.second+y.second); + } + + + + template + std::pair + CompositeViscoPlastic::compute_strain_rate_and_derivative (const double creep_stress, + const double pressure, + const double temperature, + const DiffusionCreepParameters diffusion_creep_parameters, + const DislocationCreepParameters dislocation_creep_parameters, + const PeierlsCreepParameters peierls_creep_parameters, + const DruckerPragerParameters drucker_prager_parameters) const + { + std::pair creep_edot_and_deriv = std::make_pair(0., 0.); + + if (use_diffusion_creep) + creep_edot_and_deriv = creep_edot_and_deriv + diffusion_creep->compute_strain_rate_and_derivative(creep_stress, pressure, temperature, diffusion_creep_parameters); + + if (use_dislocation_creep) + creep_edot_and_deriv = creep_edot_and_deriv + dislocation_creep->compute_strain_rate_and_derivative(creep_stress, pressure, temperature, dislocation_creep_parameters); + + if (use_peierls_creep) + creep_edot_and_deriv = creep_edot_and_deriv + peierls_creep->compute_strain_rate_and_derivative(creep_stress, pressure, temperature, peierls_creep_parameters); + + if (use_drucker_prager) + creep_edot_and_deriv = creep_edot_and_deriv + drucker_prager->compute_strain_rate_and_derivative(creep_stress, pressure, drucker_prager_parameters); + + return creep_edot_and_deriv; + } + + + + template + void + CompositeViscoPlastic::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Include diffusion creep in composite rheology", "true", + Patterns::Bool (), + "Whether to include diffusion creep in the composite rheology formulation."); + + prm.declare_entry ("Include dislocation creep in composite rheology", "true", + Patterns::Bool (), + "Whether to include dislocation creep in the composite rheology formulation."); + + prm.declare_entry ("Include Peierls creep in composite rheology", "true", + Patterns::Bool (), + "Whether to include Peierls creep in the composite rheology formulation."); + + prm.declare_entry ("Include Drucker Prager plasticity in composite rheology", "true", + Patterns::Bool (), + "Whether to include Drucker-Prager plasticity in the composite rheology formulation."); + + // Diffusion creep parameters + Rheology::DiffusionCreep::declare_parameters(prm); + + // Dislocation creep parameters + Rheology::DislocationCreep::declare_parameters(prm); + + // Dislocation creep parameters + Rheology::PeierlsCreep::declare_parameters(prm); + + // Drucker Prager parameters + Rheology::DruckerPrager::declare_parameters(prm); + + // Some of the parameters below are shared with the subordinate + // rheology models (diffusion, dislocation, ...), + // and will already have been declared. This is fine, the deal.II + // parameter handler allows repeated declarations. The default values + // below will override any defaults given in the subordinate + // rheology models. The new defaults will apply both to + // this rheology model and to the subordinate rheology modules. + prm.declare_entry ("Minimum strain rate", "1.4e-20", Patterns::Double(0.), + "Stabilizes strain dependent viscosity. Units: \\si{\\per\\second}."); + + // Viscosity iteration parameters + prm.declare_entry ("Strain rate residual tolerance", "1e-22", Patterns::Double(0.), + "Tolerance for correct diffusion/dislocation strain rate ratio."); + prm.declare_entry ("Maximum creep strain rate iterations", "40", Patterns::Integer(0), + "Maximum number of iterations to find the correct " + "creep strain rate."); + + // Strain rate and stress limiting parameters + prm.declare_entry ("Minimum viscosity", "1.e17", + Patterns::Double(0.), + "Minimum effective viscosity. Units: \\si{\\pascal\\second}."); + + prm.declare_entry ("Maximum viscosity", "1.e28", + Patterns::Double(0.), + "Maximum effective viscosity. Units: \\si{\\pascal\\second}."); + } + + + + template + void + CompositeViscoPlastic::parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition) + { + // Retrieve the list of composition names + const std::vector list_of_composition_names = this->introspection().get_composition_names(); + + // A background field is required by the subordinate material models + number_of_compositions = list_of_composition_names.size() + 1; + + min_strain_rate = prm.get_double("Minimum strain rate"); + + // Iteration parameters + strain_rate_residual_threshold = prm.get_double ("Strain rate residual tolerance"); + stress_max_iteration_number = prm.get_integer ("Maximum creep strain rate iterations"); + + // Read min and max viscosity parameters + minimum_viscosity = prm.get_double ("Minimum viscosity"); + maximum_viscosity = prm.get_double ("Maximum viscosity"); + + // Rheological parameters + + // Diffusion creep parameters + use_diffusion_creep = prm.get_bool ("Include diffusion creep in composite rheology"); + if (use_diffusion_creep) + { + diffusion_creep = std::make_unique>(); + diffusion_creep->initialize_simulator (this->get_simulator()); + diffusion_creep->parse_parameters(prm, expected_n_phases_per_composition); + } + + // Dislocation creep parameters + use_dislocation_creep = prm.get_bool ("Include dislocation creep in composite rheology"); + if (use_dislocation_creep) + { + dislocation_creep = std::make_unique>(); + dislocation_creep->initialize_simulator (this->get_simulator()); + dislocation_creep->parse_parameters(prm, expected_n_phases_per_composition); + } + + // Peierls creep parameters + use_peierls_creep = prm.get_bool ("Include Peierls creep in composite rheology"); + if (use_peierls_creep) + { + peierls_creep = std::make_unique>(); + peierls_creep->initialize_simulator (this->get_simulator()); + peierls_creep->parse_parameters(prm, expected_n_phases_per_composition); + } + + // Drucker Prager parameters + use_drucker_prager = prm.get_bool ("Include Drucker Prager plasticity in composite rheology"); + if (use_drucker_prager) + { + drucker_prager = std::make_unique>(); + drucker_prager->initialize_simulator (this->get_simulator()); + drucker_prager->parse_parameters(prm, expected_n_phases_per_composition); + + AssertThrow(prm.get_bool("Use plastic damper") && prm.get_double("Plastic damper viscosity") > 0., + ExcMessage("If Drucker-Prager plasticity is included in the rheological formulation, you must use a viscous damper with a positive viscosity.")); + } + + AssertThrow(use_diffusion_creep == true || use_dislocation_creep == true || use_peierls_creep == true || use_drucker_prager == true, + ExcMessage("You need to include at least one deformation mechanism.")); + + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace Rheology \ + { \ + template class CompositeViscoPlastic; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/compositional_viscosity_prefactors.cc.bak b/source/material_model/rheology/compositional_viscosity_prefactors.cc.bak new file mode 100644 index 00000000000..45dae88661a --- /dev/null +++ b/source/material_model/rheology/compositional_viscosity_prefactors.cc.bak @@ -0,0 +1,178 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + template + CompositionalViscosityPrefactors::CompositionalViscosityPrefactors () + = default; + + template + double + CompositionalViscosityPrefactors::compute_viscosity (const MaterialModel::MaterialModelInputs &in, + const double base_viscosity, + const unsigned int composition_index, + const unsigned int q, + const ModifiedFlowLaws &modified_flow_laws) const + { + double factored_viscosities = base_viscosity; + switch (viscosity_prefactor_scheme) + { + case none: + { + factored_viscosities = base_viscosity; + break; + } + case hk04_olivine_hydration: + { + // We calculate the atomic H/Si ppm (C_OH) at each point to compute the water fugacity of + // olivine assuming a composition of 90 mol% Forsterite and 10 mol% Fayalite from Hirth + // and Kohlstaedt 2004 10.1029/138GM06. + const unsigned int bound_fluid_idx = this->introspection().compositional_index_for_name("bound_fluid"); + const double mass_fraction_H2O = std::max(minimum_mass_fraction_water_for_dry_creep[composition_index], in.composition[q][bound_fluid_idx]); // mass fraction of bound water + const double mass_fraction_olivine = 1 - mass_fraction_H2O; // mass fraction of olivine + const double COH = (mass_fraction_H2O/molar_mass_H2O) / (mass_fraction_olivine/molar_mass_olivine) * 1e6; // COH in H / Si ppm + const double point_water_fugacity = COH / A_H2O * + std::exp((activation_energy_H2O + in.pressure[q]*activation_volume_H2O)/ + (constants::gas_constant * in.temperature[q])); + const double r = modified_flow_laws == diffusion + ? + -diffusion_water_fugacity_exponents[composition_index] + : + -dislocation_water_fugacity_exponents[composition_index]; + factored_viscosities = base_viscosity*std::pow(point_water_fugacity, r); + break; + } + } + return factored_viscosities; + } + + + template + void + CompositionalViscosityPrefactors::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Minimum mass fraction bound water content for fugacity", "6.15e-6", + Patterns::List(Patterns::Double(0)), + "The minimum water content for the HK04 olivine hydration viscosity " + "prefactor scheme. This acts as the cutoff between 'dry' creep and 'wet' creep " + "for olivine, and the default value is chosen based on the value reported by " + "Hirth & Kohlstaedt 2004. For a mass fraction of bound water beneath this value, " + "this value is used instead to compute the water fugacity. Units: \\si{\\kg} / \\si{\\kg} %."); + + prm.declare_entry ("Water fugacity exponents for diffusion creep", "0.0", + Patterns::List(Patterns::Double(0)), + "List of water fugacity exponents for diffusion creep for " + "background material and compositional fields, for a total of N+1 " + "where N is the number of all compositional fields or only those " + "corresponding to chemical compositions. This is only applied when using the " + "Viscosity prefactor scheme 'HK04 olivine hydration'. Note, the water fugacity exponent " + "required by ASPECT for diffusion creep is r/n, where n is the stress exponent " + "for diffusion creep, which typically is 1. Units: none."); + + prm.declare_entry ("Water fugacity exponents for dislocation creep", "0.0", + Patterns::List(Patterns::Double(0)), + "List of water fugacity exponents for dislocation creep for " + "background material and compositional fields, for a total of N+1 " + "where N is the number of all compositional fields or only those " + "corresponding to chemical compositions. This is only applied when using the " + "Viscosity prefactor scheme 'HK04 olivine hydration'. Note, the water fugacity exponent " + "required by ASPECT for dislocation creep is r/n, where n is the stress exponent " + "for dislocation creep, which typically is 3.5. Units: none."); + + prm.declare_entry ("Viscosity prefactor scheme", "none", + Patterns::Selection("none|HK04 olivine hydration"), + "Select what type of viscosity multiplicative prefactor scheme to apply. " + "Allowed entries are 'none', and 'HK04 olivine hydration'. HK04 olivine " + "hydration calculates the viscosity change due to hydrogen incorporation " + "into olivine following Hirth & Kohlstaedt 2004 (10.1029/138GM06). none " + "does not modify the viscosity. Units: none."); + } + + + + template + void + CompositionalViscosityPrefactors::parse_parameters (ParameterHandler &prm) + { + if (prm.get ("Viscosity prefactor scheme") == "none") + viscosity_prefactor_scheme = none; + if (prm.get ("Viscosity prefactor scheme") == "HK04 olivine hydration") + { + // Retrieve the list of compositional names + std::vector compositional_field_names = this->introspection().get_composition_names(); + AssertThrow(this->introspection().compositional_name_exists("bound_fluid"), + ExcMessage("The HK04 olivine hydration pre-exponential factor only works if " + "there is a compositional field called bound_fluid.")); + viscosity_prefactor_scheme = hk04_olivine_hydration; + + // Retrieve the list of chemical names + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + + // Establish that a background field is required here + compositional_field_names.insert(compositional_field_names.begin(), "background"); + chemical_field_names.insert(chemical_field_names.begin(),"background"); + + Utilities::MapParsing::Options options(chemical_field_names, "Water fugacity exponents for diffusion creep"); + + options.list_of_allowed_keys = compositional_field_names; + diffusion_water_fugacity_exponents = Utilities::MapParsing::parse_map_to_double_array (prm.get("Water fugacity exponents for diffusion creep"), + options); + dislocation_water_fugacity_exponents = Utilities::MapParsing::parse_map_to_double_array (prm.get("Water fugacity exponents for dislocation creep"), + options); + minimum_mass_fraction_water_for_dry_creep = Utilities::MapParsing::parse_map_to_double_array (prm.get("Minimum mass fraction bound water content for fugacity"), + options); + } + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace Rheology \ + { \ + template class CompositionalViscosityPrefactors; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/constant_viscosity.cc.bak b/source/material_model/rheology/constant_viscosity.cc.bak new file mode 100644 index 00000000000..06da2a5b933 --- /dev/null +++ b/source/material_model/rheology/constant_viscosity.cc.bak @@ -0,0 +1,67 @@ +/* + Copyright (C) 2019 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + ConstantViscosity::ConstantViscosity () + : + viscosity(numbers::signaling_nan()) + {} + + + + double + ConstantViscosity::compute_viscosity () const + { + return viscosity; + } + + + + void + ConstantViscosity::declare_parameters (ParameterHandler &prm, + const double default_viscosity) + { + prm.declare_entry ("Viscosity", std::to_string(default_viscosity), + Patterns::Double (0.), + "The value of the viscosity $\\eta$. Units: \\si{\\pascal\\second}."); + } + + + + void + ConstantViscosity::parse_parameters (ParameterHandler &prm) + { + viscosity = prm.get_double ("Viscosity"); + } + } + } +} diff --git a/source/material_model/rheology/constant_viscosity_prefactors.cc.bak b/source/material_model/rheology/constant_viscosity_prefactors.cc.bak new file mode 100644 index 00000000000..4b3b91d6cfc --- /dev/null +++ b/source/material_model/rheology/constant_viscosity_prefactors.cc.bak @@ -0,0 +1,105 @@ +/* + Copyright (C) 2020 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + template + ConstantViscosityPrefactors::ConstantViscosityPrefactors () + = default; + + + + template + double + ConstantViscosityPrefactors::compute_viscosity (const double base_viscosity, + const unsigned int composition_index) const + { + return base_viscosity * constant_viscosity_prefactors[composition_index]; + } + + + + template + void + ConstantViscosityPrefactors::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Constant viscosity prefactors", "1.0", + Patterns::List(Patterns::Double(0)), + "List of constant viscosity prefactors (i.e., multiplicative factors) " + "for background material and compositional fields, for a total of N+1 " + "where N is the number of all compositional fields or only those " + "corresponding to chemical compositions. Units: none."); + } + + + + template + void + ConstantViscosityPrefactors::parse_parameters (ParameterHandler &prm) + { + // Retrieve the list of composition names + std::vector compositional_field_names = this->introspection().get_composition_names(); + + // Retrieve the list of names of fields that represent chemical compositions, and not, e.g., + // plastic strain + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + + // Establish that a background field is required here + compositional_field_names.insert(compositional_field_names.begin(), "background"); + chemical_field_names.insert(chemical_field_names.begin(),"background"); + + Utilities::MapParsing::Options options(chemical_field_names, "Constant viscosity prefactors"); + options.list_of_allowed_keys = compositional_field_names; + + constant_viscosity_prefactors = Utilities::MapParsing::parse_map_to_double_array (prm.get("Constant viscosity prefactors"), + options); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace Rheology \ + { \ + template class ConstantViscosityPrefactors; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/diffusion_creep.cc.bak b/source/material_model/rheology/diffusion_creep.cc.bak new file mode 100644 index 00000000000..b2b3f0d087d --- /dev/null +++ b/source/material_model/rheology/diffusion_creep.cc.bak @@ -0,0 +1,303 @@ +/* + Copyright (C) 2019 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + DiffusionCreepParameters::DiffusionCreepParameters() + : prefactor (numbers::signaling_nan()), + activation_energy (numbers::signaling_nan()), + activation_volume (numbers::signaling_nan()), + stress_exponent (numbers::signaling_nan()), + grain_size_exponent (numbers::signaling_nan()) + {} + + + + template + DiffusionCreep::DiffusionCreep () + = default; + + + + template + const DiffusionCreepParameters + DiffusionCreep::compute_creep_parameters (const unsigned int composition, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + DiffusionCreepParameters creep_parameters; + if (phase_function_values == std::vector()) + { + // no phases + creep_parameters.prefactor = prefactors_diffusion[composition]; + creep_parameters.activation_energy = activation_energies_diffusion[composition]; + creep_parameters.activation_volume = activation_volumes_diffusion[composition]; + creep_parameters.stress_exponent = stress_exponents_diffusion[composition]; + creep_parameters.grain_size_exponent = grain_size_exponents_diffusion[composition]; + } + else + { + // Average among phases + creep_parameters.prefactor = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + prefactors_diffusion, composition, MaterialModel::MaterialUtilities::PhaseUtilities::logarithmic); + creep_parameters.activation_energy = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + activation_energies_diffusion, composition); + creep_parameters.activation_volume = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + activation_volumes_diffusion, composition); + creep_parameters.stress_exponent = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + stress_exponents_diffusion, composition); + creep_parameters.grain_size_exponent = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + grain_size_exponents_diffusion, composition); + } + return creep_parameters; + } + + + + template + double + DiffusionCreep::compute_viscosity (const double pressure, + const double temperature, + const unsigned int composition, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + const DiffusionCreepParameters p = compute_creep_parameters(composition, + phase_function_values, + n_phase_transitions_per_composition); + + // Power law creep equation + // viscosity = 0.5 * A^(-1) * d^(m) * exp((E + P*V)/(RT)) + // A: prefactor, + // d: grain size, m: grain size exponent, E: activation energy, P: pressure, + // V; activation volume, R: gas constant, T: temperature. + double viscosity_diffusion = 0.5 / p.prefactor * + std::exp((p.activation_energy + + pressure*p.activation_volume)/ + (constants::gas_constant*temperature)) * + std::pow(grain_size, p.grain_size_exponent); + + Assert (viscosity_diffusion > 0.0, + ExcMessage ("Negative diffusion viscosity detected. This is unphysical and should not happen. " + "Check for negative parameters. Temperature and pressure are " + + Utilities::to_string(temperature) + " K, " + Utilities::to_string(pressure) + " Pa. ")); + + // Creep viscosities become extremely large at low + // temperatures and can therefore provoke floating-point overflow errors. In + // real rocks, other deformation mechanisms become dominant at low temperatures, + // so these high viscosities are never achieved. It is therefore both reasonable + // and desirable to require the single-mechanism viscosity to be smaller than + // std::sqrt(max_double). + viscosity_diffusion = std::min(viscosity_diffusion, std::sqrt(std::numeric_limits::max())); + + return viscosity_diffusion; + } + + + template + std::pair + DiffusionCreep::compute_strain_rate_and_derivative (const double stress, + const double pressure, + const double temperature, + const DiffusionCreepParameters creep_parameters) const + { + // Power law creep equation + // edot_ii_partial = A * stress^n * d^-m * exp(-(E + P*V)/(RT)) + // d(edot_ii_partial)/d(stress) = A * n * stress^(n-1) * d^-m * exp(-(E + P*V)/(RT)) + // A: prefactor, edot_ii_partial: square root of second invariant of deviatoric strain rate tensor attributable to the creep mechanism, + // d: grain size, m: grain size exponent, E: activation energy, P: pressure, + // V; activation volume, R: gas constant, T: temperature. + // For diffusion creep, n = 1 (strain rate is linearly dependent on stress). + const double dstrain_rate_dstress_diffusion = creep_parameters.prefactor * + std::pow(grain_size, -creep_parameters.grain_size_exponent) * + std::exp(-(creep_parameters.activation_energy + pressure*creep_parameters.activation_volume)/ + (constants::gas_constant*temperature)); + + const double strain_rate_diffusion = stress * dstrain_rate_dstress_diffusion; + + return std::make_pair(strain_rate_diffusion, dstrain_rate_dstress_diffusion); + } + + + template + std::pair + DiffusionCreep::compute_log_strain_rate_and_derivative (const double log_stress, + const double pressure, + const double temperature, + const DiffusionCreepParameters creep_parameters) const + { + // Power law creep equation + // log(edot_ii_partial) = std::log(A) + n*std::log(stress) - m*std::log(d) - (E + P*V)/(RT) + // d(log_edot_ii_partial)/d(log_stress) = n + // A: prefactor, edot_ii_partial: square root of second invariant of deviatoric strain rate tensor attributable to the creep mechanism, + // d: grain size, m: grain size exponent, E: activation energy, P: pressure, + // V; activation volume, R: gas constant, T: temperature. + // For diffusion creep, n = 1 (strain rate is linearly dependent on stress). + const double log_strain_rate_diffusion = std::log(creep_parameters.prefactor) + + log_stress - + creep_parameters.grain_size_exponent * std::log(grain_size) - + (creep_parameters.activation_energy + pressure*creep_parameters.activation_volume)/ + (constants::gas_constant*temperature); + + const double dlog_strain_rate_dlog_stress_diffusion = 1.0; + + return std::make_pair(log_strain_rate_diffusion, dlog_strain_rate_dlog_stress_diffusion); + } + + + + + template + void + DiffusionCreep::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Prefactors for diffusion creep", "1.5e-15", + Patterns::Anything(), + "List of viscosity prefactors, $A$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\per\\pascal\\meter}$^{m_{\\text{diffusion}}}$\\si{\\per\\second}."); + prm.declare_entry ("Stress exponents for diffusion creep", "1.", + Patterns::List(Patterns::Double(0.)), + "List of stress exponents, $n_{\\text{diffusion}}$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "The stress exponent for diffusion creep is almost always equal to one. " + "If only one value is given, then all use the same value. Units: None."); + prm.declare_entry ("Grain size exponents for diffusion creep", "3.", + Patterns::Anything(), + "List of grain size exponents, $m_{\\text{diffusion}}$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + prm.declare_entry ("Activation energies for diffusion creep", "375e3", + Patterns::Anything(), + "List of activation energies, $E_a$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\joule\\per\\mole}."); + prm.declare_entry ("Activation volumes for diffusion creep", "6e-6", + Patterns::Anything(), + "List of activation volumes, $V_a$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\meter\\cubed\\per\\mole}."); + prm.declare_entry ("Grain size", "1e-3", Patterns::Double (0.), + "Units: \\si{\\meter}."); + } + + + + template + void + DiffusionCreep::parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition) + { + // Retrieve the list of composition names + std::vector compositional_field_names = this->introspection().get_composition_names(); + + // Retrieve the list of names of fields that represent chemical compositions, and not, e.g., + // plastic strain + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + + // Establish that a background field is required here + compositional_field_names.insert(compositional_field_names.begin(), "background"); + chemical_field_names.insert(chemical_field_names.begin(), "background"); + + // Make options file for parsing maps to double arrays + Utilities::MapParsing::Options options(chemical_field_names, "Prefactors for diffusion creep"); + options.list_of_allowed_keys = compositional_field_names; + options.allow_multiple_values_per_key = true; + if (expected_n_phases_per_composition) + { + options.n_values_per_key = *expected_n_phases_per_composition; + + // check_values_per_key is required to be true to duplicate single values + // if they are to be used for all phases associated with a given key. + options.check_values_per_key = true; + } + + // Read parameters, each of size of number of composition + number of phases + 1 + prefactors_diffusion = Utilities::MapParsing::parse_map_to_double_array(prm.get("Prefactors for diffusion creep"), + options); + + options.property_name = "Stress exponents for diffusion creep"; + stress_exponents_diffusion = Utilities::MapParsing::parse_map_to_double_array(prm.get("Stress exponents for diffusion creep"), + options); + + options.property_name = "Grain size exponents for diffusion creep"; + grain_size_exponents_diffusion = Utilities::MapParsing::parse_map_to_double_array(prm.get("Grain size exponents for diffusion creep"), + options); + + options.property_name = "Activation energies for diffusion creep"; + activation_energies_diffusion = Utilities::MapParsing::parse_map_to_double_array(prm.get("Activation energies for diffusion creep"), + options); + + options.property_name = "Activation volumes for diffusion creep"; + activation_volumes_diffusion = Utilities::MapParsing::parse_map_to_double_array(prm.get("Activation volumes for diffusion creep"), + options); + + grain_size = prm.get_double("Grain size"); + + // Check that there are no entries set to zero, + // for example because the entry is for a field + // that is masked anyway, like strain. Despite + // these compositions being masked, their viscosities + // are computed anyway and this will lead to division by zero. + for (const double prefactor : prefactors_diffusion) + AssertThrow(prefactor > 0., + ExcMessage("The diffusion prefactor should be larger than zero.")); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace Rheology \ + { \ + template class DiffusionCreep; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/diffusion_dislocation.cc.bak b/source/material_model/rheology/diffusion_dislocation.cc.bak new file mode 100644 index 00000000000..d86b36f491c --- /dev/null +++ b/source/material_model/rheology/diffusion_dislocation.cc.bak @@ -0,0 +1,386 @@ +/* + Copyright (C) 2020 - 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + template + DiffusionDislocation::DiffusionDislocation () + = default; + + template + std::vector + DiffusionDislocation:: + calculate_isostrain_viscosities ( const double pressure, + const double temperature, + const SymmetricTensor<2,dim> &strain_rate) const + { + // This function calculates viscosities assuming that all the compositional fields + // experience the same strain rate (isostrain). + + // If strain rate is zero (like during the first time step) set it to some very small number + // to prevent a division-by-zero, and a floating point exception. + // Otherwise, calculate the square-root of the norm of the second invariant of the deviatoric- + // strain rate (often simplified as epsilondot_ii) + const double edot_ii = std::max(std::sqrt(std::max(-second_invariant(deviator(strain_rate)), 0.)), + min_strain_rate); + const double log_edot_ii = std::log(edot_ii); + + + // Find effective viscosities for each of the individual phases + // Viscosities should have same number of entries as compositional fields + std::vector composition_viscosities(n_chemical_composition_fields); + for (unsigned int j=0; j < n_chemical_composition_fields; ++j) + { + // Power law creep equation + // edot_ii_i = A_i * stress_ii_i^{n_i} * d^{-m} \exp\left(-\frac{E_i^\ast + PV_i^\ast}{n_iRT}\right) + // where ii indicates the square root of the second invariant and + // i corresponds to diffusion or dislocation creep + + // For diffusion creep, viscosity is grain size dependent + const Rheology::DiffusionCreepParameters diffusion_creep_parameters = diffusion_creep.compute_creep_parameters(j); + + // For dislocation creep, viscosity is grain size independent (m=0) + const Rheology::DislocationCreepParameters dislocation_creep_parameters = dislocation_creep.compute_creep_parameters(j); + + // For diffusion creep, viscosity is grain size dependent + const double prefactor_stress_diffusion = diffusion_creep_parameters.prefactor * + std::pow(grain_size, -diffusion_creep_parameters.grain_size_exponent) * + std::exp(-(std::max(diffusion_creep_parameters.activation_energy + pressure*diffusion_creep_parameters.activation_volume,0.0))/ + (constants::gas_constant*temperature)); + + // Because the ratios of the diffusion and dislocation strain rates are not known, stress is also unknown + // We use Newton's method to find the second invariant of the stress tensor. + // Start with the assumption that all strain is accommodated by diffusion creep: + // If the diffusion creep prefactor is very small, that means that the diffusion viscosity is very large. + // In this case, use the maximum viscosity instead to compute the starting guess. + double stress_ii = (prefactor_stress_diffusion > (0.5 / maximum_viscosity) + ? + edot_ii/prefactor_stress_diffusion + : + 0.5 / maximum_viscosity); + double log_stress_ii = std::log(stress_ii); + double log_strain_rate_residual = 2 * log_strain_rate_residual_threshold; + double log_strain_rate_deriv = 0; + unsigned int stress_iteration = 0; + while (std::abs(log_strain_rate_residual) > log_strain_rate_residual_threshold + && stress_iteration < stress_max_iteration_number) + { + const std::pair log_diff_edot_and_deriv = diffusion_creep.compute_log_strain_rate_and_derivative(log_stress_ii, pressure, temperature, diffusion_creep_parameters); + const std::pair log_disl_edot_and_deriv = dislocation_creep.compute_log_strain_rate_and_derivative(log_stress_ii, pressure, temperature, dislocation_creep_parameters); + + const double strain_rate_diffusion = std::exp(log_diff_edot_and_deriv.first); + const double strain_rate_dislocation = std::exp(log_disl_edot_and_deriv.first); + log_strain_rate_residual = std::log(strain_rate_diffusion + strain_rate_dislocation) - log_edot_ii; + log_strain_rate_deriv = (strain_rate_diffusion * log_diff_edot_and_deriv.second + strain_rate_dislocation * log_disl_edot_and_deriv.second)/ + (strain_rate_diffusion + strain_rate_dislocation); + + // If the log strain rate derivative is zero, we catch it below. + if (log_strain_rate_deriv>std::numeric_limits::min()) + log_stress_ii -= log_strain_rate_residual/log_strain_rate_deriv; + stress_ii = std::exp(log_stress_ii); + stress_iteration += 1; + + // In case the Newton iteration does not succeed, we do a fixpoint iteration. + // This allows us to bound both the diffusion and dislocation viscosity + // between a minimum and maximum value, so that we can compute the correct + // viscosity values even if the parameters lead to one or both of the + // viscosities being essentially zero or infinity. + // If anything that would be used in the next iteration is not finite, the + // Newton iteration would trigger an exception and we want to do the fixpoint + // iteration instead. + const bool abort_newton_iteration = !numbers::is_finite(stress_ii) + || !numbers::is_finite(log_strain_rate_residual) + || !numbers::is_finite(log_strain_rate_deriv) + || log_strain_rate_deriv < std::numeric_limits::min() + || !numbers::is_finite(std::pow(stress_ii, diffusion_creep_parameters.stress_exponent-1)) + || !numbers::is_finite(std::pow(stress_ii, dislocation_creep_parameters.stress_exponent-1)) + || stress_iteration == stress_max_iteration_number; + if (abort_newton_iteration) + { + double diffusion_strain_rate = edot_ii; + double dislocation_strain_rate = min_strain_rate; + stress_iteration = 0; + + do + { + const double old_diffusion_strain_rate = diffusion_strain_rate; + + const double diffusion_prefactor = 0.5 * std::pow(diffusion_creep_parameters.prefactor,-1.0/diffusion_creep_parameters.stress_exponent); + const double diffusion_grain_size_dependence = std::pow(grain_size, diffusion_creep_parameters.grain_size_exponent/diffusion_creep_parameters.stress_exponent); + const double diffusion_strain_rate_dependence = std::pow(diffusion_strain_rate, (1.-diffusion_creep_parameters.stress_exponent)/diffusion_creep_parameters.stress_exponent); + const double diffusion_T_and_P_dependence = std::exp(std::max(diffusion_creep_parameters.activation_energy + pressure*diffusion_creep_parameters.activation_volume,0.0)/ + (constants::gas_constant*temperature)); + + const double diffusion_viscosity = std::min(std::max(diffusion_prefactor * diffusion_grain_size_dependence + * diffusion_strain_rate_dependence * diffusion_T_and_P_dependence, + minimum_viscosity), maximum_viscosity); + + const double dislocation_prefactor = 0.5 * std::pow(dislocation_creep_parameters.prefactor,-1.0/dislocation_creep_parameters.stress_exponent); + const double dislocation_strain_rate_dependence = std::pow(dislocation_strain_rate, (1.-dislocation_creep_parameters.stress_exponent)/dislocation_creep_parameters.stress_exponent); + const double dislocation_T_and_P_dependence = std::exp(std::max(dislocation_creep_parameters.activation_energy + pressure*dislocation_creep_parameters.activation_volume,0.0)/ + (dislocation_creep_parameters.stress_exponent*constants::gas_constant*temperature)); + + const double dislocation_viscosity = std::min(std::max(dislocation_prefactor * dislocation_strain_rate_dependence + * dislocation_T_and_P_dependence, + minimum_viscosity), maximum_viscosity); + + diffusion_strain_rate = dislocation_viscosity / (diffusion_viscosity + dislocation_viscosity) * edot_ii; + dislocation_strain_rate = diffusion_viscosity / (diffusion_viscosity + dislocation_viscosity) * edot_ii; + + ++stress_iteration; + AssertThrow(stress_iteration < stress_max_iteration_number, + ExcMessage("No convergence has been reached in the loop that determines " + "the ratio of diffusion/dislocation viscosity. Aborting! " + "Residual is " + Utilities::to_string(log_strain_rate_residual) + + " after " + Utilities::to_string(stress_iteration) + " iterations. " + "You can increase the number of iterations by adapting the " + "parameter 'Maximum strain rate ratio iterations'.")); + + log_strain_rate_residual = std::abs(std::log(diffusion_strain_rate/old_diffusion_strain_rate)); + stress_ii = 2.0 * edot_ii * 1./(1./diffusion_viscosity + 1./dislocation_viscosity); + } + while (log_strain_rate_residual > log_strain_rate_residual_threshold); + + break; + } + } + + // The effective viscosity, with minimum and maximum bounds + composition_viscosities[j] = std::min(std::max(stress_ii/edot_ii/2, minimum_viscosity), maximum_viscosity); + } + return composition_viscosities; + } + + template + double + DiffusionDislocation::compute_viscosity (const double pressure, + const double temperature, + const std::vector &volume_fractions, + const SymmetricTensor<2,dim> &strain_rate) const + { + // Currently, the viscosities for each of the compositional fields are calculated assuming + // isostrain amongst all compositions, allowing calculation of the viscosity ratio. + // TODO: This is only consistent with viscosity averaging if the arithmetic averaging + // scheme is chosen. It would be useful to have a function to calculate isostress viscosities. + const std::vector composition_viscosities = + calculate_isostrain_viscosities(pressure, temperature, strain_rate); + + // The isostrain condition implies that the viscosity averaging should be arithmetic (see above). + // We have given the user freedom to apply alternative bounds, because in diffusion-dominated + // creep (where n_diff=1) viscosities are stress and strain-rate independent, so the calculation + // of compositional field viscosities is consistent with any averaging scheme. + return MaterialUtilities::average_value(volume_fractions, composition_viscosities, viscosity_averaging); + } + + + template + void + DiffusionDislocation::declare_parameters (ParameterHandler &prm) + { + // Reference and minimum/maximum values + prm.declare_entry ("Reference temperature", "293.", Patterns::Double(0.), + "For calculating density by thermal expansivity. Units: \\si{\\kelvin}."); + prm.declare_entry ("Minimum strain rate", "1.4e-20", Patterns::Double(0.), + "Stabilizes strain dependent viscosity. Units: \\si{\\per\\second}."); + prm.declare_entry ("Minimum viscosity", "1e17", Patterns::Double(0.), + "Lower cutoff for effective viscosity. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Maximum viscosity", "1e28", Patterns::Double(0.), + "Upper cutoff for effective viscosity. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Effective viscosity coefficient", "1.0", Patterns::Double(0.), + "Scaling coefficient for effective viscosity."); + + // Viscosity iteration parameters + prm.declare_entry ("Strain rate residual tolerance", "1e-10", Patterns::Double(0.), + "Tolerance for determining the correct stress and viscosity from the " + "strain rate by internal iteration. The tolerance is expressed as the " + "difference between the natural logarithm of the input strain rate and " + "the strain rate at the current iteration. This determines that strain " + "rate is correctly partitioned between diffusion and dislocation creep " + "assuming that both mechanisms experience the same stress."); + prm.declare_entry ("Maximum strain rate ratio iterations", "40", Patterns::Integer(0), + "Maximum number of iterations to find the correct " + "diffusion/dislocation strain rate ratio."); + + // Equation of state parameters + prm.declare_entry ("Thermal diffusivity", "0.8e-6", Patterns::Double(0.), + "Units: \\si{\\meter\\squared\\per\\second}."); + prm.declare_entry ("Heat capacity", "1.25e3", + Patterns::Double(0.), + "The value of the specific heat $C_p$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Densities", "3300.", + Patterns::List(Patterns::Double(0.)), + "List of densities, $\\rho$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Thermal expansivities", "3.5e-5", + Patterns::List(Patterns::Double(0.)), + "List of thermal expansivities for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: \\si{\\per\\kelvin}."); + + // Rheological parameters + prm.declare_entry ("Viscosity averaging scheme", "harmonic", + Patterns::Selection("arithmetic|harmonic|geometric|maximum composition"), + "When more than one compositional field is present at a point " + "with different viscosities, we need to come up with an average " + "viscosity at that point. Select a weighted harmonic, arithmetic, " + "geometric, or maximum composition."); + // Diffusion creep parameters + prm.declare_entry ("Prefactors for diffusion creep", "1.5e-15", + Patterns::List(Patterns::Double(0.)), + "List of viscosity prefactors, $A$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\per\\pascal} \\si{\\meter}$^{m_{\\text{diffusion}}}$ \\si{\\per\\second}."); + prm.declare_entry ("Stress exponents for diffusion creep", "1.", + Patterns::List(Patterns::Double(0.)), + "List of stress exponents, $n_{\\text{diffusion}}$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + prm.declare_entry ("Grain size exponents for diffusion creep", "3.", + Patterns::List(Patterns::Double(0.)), + "List of grain size exponents, $m_{\\text{diffusion}}$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + prm.declare_entry ("Activation energies for diffusion creep", "375e3", + Patterns::List(Patterns::Double(0.)), + "List of activation energies, $E_a$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\joule\\per\\mole}."); + prm.declare_entry ("Activation volumes for diffusion creep", "6e-6", + Patterns::List(Patterns::Double(0.)), + "List of activation volumes, $V_a$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\meter\\cubed\\per\\mole}."); + + // Dislocation creep parameters + prm.declare_entry ("Prefactors for dislocation creep", "1.1e-16", + Patterns::List(Patterns::Double(0.)), + "List of viscosity prefactors, $A$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\pascal}$^{-n_{\\text{dislocation}}}$\\si{\\per\\second}."); + prm.declare_entry ("Stress exponents for dislocation creep", "3.5", + Patterns::List(Patterns::Double(0.)), + "List of stress exponents, $n_{\\text{dislocation}}$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + prm.declare_entry ("Activation energies for dislocation creep", "530e3", + Patterns::List(Patterns::Double(0.)), + "List of activation energies, $E_a$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\joule\\per\\mole}."); + prm.declare_entry ("Activation volumes for dislocation creep", "1.4e-5", + Patterns::List(Patterns::Double(0.)), + "List of activation volumes, $V_a$, for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\meter\\cubed\\per\\mole}."); + + // Diffusion creep parameters + Rheology::DiffusionCreep::declare_parameters(prm); + + // Dislocation creep parameters + Rheology::DislocationCreep::declare_parameters(prm); + } + + + + template + void + DiffusionDislocation::parse_parameters (ParameterHandler &prm) + { + // Reference and minimum/maximum values + min_strain_rate = prm.get_double("Minimum strain rate"); + minimum_viscosity = prm.get_double ("Minimum viscosity"); + maximum_viscosity = prm.get_double ("Maximum viscosity"); + + // Iteration parameters + log_strain_rate_residual_threshold = prm.get_double ("Strain rate residual tolerance"); + stress_max_iteration_number = prm.get_integer ("Maximum strain rate ratio iterations"); + + // ---- Compositional parameters + grain_size = prm.get_double("Grain size"); + + viscosity_averaging = MaterialUtilities::parse_compositional_averaging_operation ("Viscosity averaging scheme", + prm); + + // Rheological parameters for chemical compositions + // increment by one for background: + n_chemical_composition_fields = this->introspection().n_chemical_composition_fields() + 1; + + // Diffusion creep parameters + diffusion_creep.initialize_simulator (this->get_simulator()); + diffusion_creep.parse_parameters(prm, std::make_unique>(n_chemical_composition_fields)); + + // Dislocation creep parameters + dislocation_creep.initialize_simulator (this->get_simulator()); + dislocation_creep.parse_parameters(prm, std::make_unique>(n_chemical_composition_fields)); + + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace Rheology \ + { \ + template class DiffusionDislocation; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/dislocation_creep.cc.bak b/source/material_model/rheology/dislocation_creep.cc.bak new file mode 100644 index 00000000000..511444fb281 --- /dev/null +++ b/source/material_model/rheology/dislocation_creep.cc.bak @@ -0,0 +1,285 @@ +/* + Copyright (C) 2019 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + DislocationCreepParameters::DislocationCreepParameters() + : prefactor (numbers::signaling_nan()), + activation_energy (numbers::signaling_nan()), + activation_volume (numbers::signaling_nan()), + stress_exponent (numbers::signaling_nan()) + {} + + + + template + DislocationCreep::DislocationCreep () + = default; + + + + template + const DislocationCreepParameters + DislocationCreep::compute_creep_parameters (const unsigned int composition, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + DislocationCreepParameters creep_parameters; + if (phase_function_values == std::vector()) + { + // no phases + creep_parameters.prefactor = prefactors_dislocation[composition]; + creep_parameters.activation_energy = activation_energies_dislocation[composition]; + creep_parameters.activation_volume = activation_volumes_dislocation[composition]; + creep_parameters.stress_exponent = stress_exponents_dislocation[composition]; + } + else + { + // Average among phases + creep_parameters.prefactor = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + prefactors_dislocation, composition, + MaterialModel::MaterialUtilities::PhaseUtilities::logarithmic); + creep_parameters.activation_energy = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + activation_energies_dislocation, composition); + creep_parameters.activation_volume = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + activation_volumes_dislocation , composition); + creep_parameters.stress_exponent = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + stress_exponents_dislocation, composition); + } + + return creep_parameters; + } + + + + template + double + DislocationCreep::compute_viscosity (const double strain_rate, + const double pressure, + const double temperature, + const unsigned int composition, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + const DislocationCreepParameters p = compute_creep_parameters(composition, + phase_function_values, + n_phase_transitions_per_composition); + + // Power law creep equation: + // viscosity = 0.5 * A^(-1/n) * edot_ii^((1-n)/n) * exp((E + P*V)/(nRT)) + // A: prefactor, edot_ii: square root of second invariant of deviatoric strain rate tensor, + // E: activation energy, P: pressure, + // V; activation volume, n: stress exponent, R: gas constant, T: temperature. + double viscosity_dislocation = 0.5 * std::pow(p.prefactor,-1/p.stress_exponent) * + std::exp((p.activation_energy + pressure*p.activation_volume)/ + (constants::gas_constant*temperature*p.stress_exponent)) * + std::pow(strain_rate,((1. - p.stress_exponent)/p.stress_exponent)); + + Assert (viscosity_dislocation > 0.0, + ExcMessage ("Negative dislocation viscosity detected. This is unphysical and should not happen. " + "Check for negative parameters. Temperature and pressure are " + + Utilities::to_string(temperature) + " K, " + Utilities::to_string(pressure) + " Pa. ")); + + // Creep viscosities become extremely large at low + // temperatures and can therefore provoke floating-point overflow errors. In + // real rocks, other deformation mechanisms become dominant at low temperatures, + // so these high viscosities are never achieved. It is therefore both reasonable + // and desirable to require the single-mechanism viscosity to be smaller than + // std::sqrt(max_double). + viscosity_dislocation = std::min(viscosity_dislocation, std::sqrt(std::numeric_limits::max())); + + return viscosity_dislocation; + } + + + + template + std::pair + DislocationCreep::compute_strain_rate_and_derivative (const double stress, + const double pressure, + const double temperature, + const DislocationCreepParameters creep_parameters) const + { + // Power law creep equation: + // edot_ii_partial = A * stress^n * exp(-(E + P*V)/(RT)) + // d(edot_ii_partial)/d(stress) = A * n * stress^(n-1) * exp(-(E + P*V)/(RT)) + // A: prefactor, edot_ii_partial: square root of second invariant of deviatoric strain rate tensor attributable to the creep mechanism, + // stress: deviatoric stress, E: activation energy, P: pressure, + // V; activation volume, n: stress exponent, R: gas constant, T: temperature. + const double strain_rate_dislocation = creep_parameters.prefactor * + std::pow(stress,creep_parameters.stress_exponent) * + std::exp(-(creep_parameters.activation_energy + pressure*creep_parameters.activation_volume)/ + (constants::gas_constant*temperature)); + + const double dstrain_rate_dstress_dislocation = creep_parameters.prefactor * + creep_parameters.stress_exponent * + std::pow(stress,creep_parameters.stress_exponent-1.) * + std::exp(-(creep_parameters.activation_energy + pressure*creep_parameters.activation_volume)/ + (constants::gas_constant*temperature)); + + return std::make_pair(strain_rate_dislocation, dstrain_rate_dstress_dislocation); + } + + + template + std::pair + DislocationCreep::compute_log_strain_rate_and_derivative (const double log_stress, + const double pressure, + const double temperature, + const DislocationCreepParameters creep_parameters) const + { + // Power law creep equation + // log(edot_ii_partial) = std::log(A) + n*std::log(stress) - m*std::log(d) - (E + P*V)/(RT) + // d(log_edot_ii_partial)/d(log_stress) = n + // A: prefactor, edot_ii_partial: square root of second invariant of deviatoric strain rate tensor attributable to the creep mechanism, + // stress: deviatoric stress, E: activation energy, P: pressure, + // V; activation volume, n: stress exponent, R: gas constant, T: temperature. + const double log_strain_rate_dislocation = std::log(creep_parameters.prefactor) + + creep_parameters.stress_exponent * log_stress - + (creep_parameters.activation_energy + pressure*creep_parameters.activation_volume)/ + (constants::gas_constant*temperature); + + const double dlog_strain_rate_dlog_stress_dislocation = creep_parameters.stress_exponent; + + return std::make_pair(log_strain_rate_dislocation, dlog_strain_rate_dlog_stress_dislocation); + } + + + + template + void + DislocationCreep::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Prefactors for dislocation creep", "1.1e-16", + Patterns::Anything(), + "List of viscosity prefactors, $A$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\pascal}$^{-n_{\\text{dislocation}}}$ \\si{\\per\\second}."); + prm.declare_entry ("Stress exponents for dislocation creep", "3.5", + Patterns::Anything(), + "List of stress exponents, $n_{\\text{dislocation}}$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + prm.declare_entry ("Activation energies for dislocation creep", "530e3", + Patterns::Anything(), + "List of activation energies, $E_a$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\joule\\per\\mole}."); + prm.declare_entry ("Activation volumes for dislocation creep", "1.4e-5", + Patterns::Anything(), + "List of activation volumes, $V_a$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\meter\\cubed\\per\\mole}."); + } + + + + template + void + DislocationCreep::parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition) + { + // Retrieve the list of composition names + std::vector compositional_field_names = this->introspection().get_composition_names(); + + // Retrieve the list of names of fields that represent chemical compositions, and not, e.g., + // plastic strain + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + + // Establish that a background field is required here + compositional_field_names.insert(compositional_field_names.begin(), "background"); + chemical_field_names.insert(chemical_field_names.begin(), "background"); + + // Make options file for parsing maps to double arrays + Utilities::MapParsing::Options options(chemical_field_names, "Prefactors for dislocation creep"); + options.list_of_allowed_keys = compositional_field_names; + options.allow_multiple_values_per_key = true; + if (expected_n_phases_per_composition) + { + options.n_values_per_key = *expected_n_phases_per_composition; + + // check_values_per_key is required to be true to duplicate single values + // if they are to be used for all phases associated with a given key. + options.check_values_per_key = true; + } + + // Read parameters, each of size of number of composition + number of phases + 1 + prefactors_dislocation = Utilities::MapParsing::parse_map_to_double_array(prm.get("Prefactors for dislocation creep"), + options); + + options.property_name = "Stress exponents for dislocation creep"; + stress_exponents_dislocation = Utilities::MapParsing::parse_map_to_double_array(prm.get("Stress exponents for dislocation creep"), + options); + + options.property_name = "Activation energies for dislocation creep"; + activation_energies_dislocation = Utilities::MapParsing::parse_map_to_double_array(prm.get("Activation energies for dislocation creep"), + options); + + options.property_name = "Activation volumes for dislocation creep"; + activation_volumes_dislocation = Utilities::MapParsing::parse_map_to_double_array(prm.get("Activation volumes for dislocation creep"), + options); + + // Check that there are no prefactor entries set to zero, + // for example because the entry is for a field + // that is masked anyway, like strain. Despite + // these compositions being masked, their viscosities + // are computed anyway and this will lead to division by zero. + for (const double prefactor : prefactors_dislocation) + AssertThrow(prefactor > 0., ExcMessage("The dislocation prefactor should be larger than zero.")); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace Rheology \ + { \ + template class DislocationCreep; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/drucker_prager.cc.bak b/source/material_model/rheology/drucker_prager.cc.bak new file mode 100644 index 00000000000..aa5856a7a5e --- /dev/null +++ b/source/material_model/rheology/drucker_prager.cc.bak @@ -0,0 +1,294 @@ +/* + Copyright (C) 2019 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + DruckerPragerParameters::DruckerPragerParameters() + : angle_internal_friction (numbers::signaling_nan()), + cohesion (numbers::signaling_nan()), + max_yield_stress (numbers::signaling_nan()) + {} + + + + template + DruckerPrager::DruckerPrager () + = default; + + + + template + const DruckerPragerParameters + DruckerPrager::compute_drucker_prager_parameters (const unsigned int composition, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + DruckerPragerParameters drucker_prager_parameters; + + drucker_prager_parameters.max_yield_stress = max_yield_stress; + + if (phase_function_values == std::vector()) + { + // no phases + drucker_prager_parameters.angle_internal_friction = angles_internal_friction[composition]; + drucker_prager_parameters.cohesion = cohesions[composition]; + } + else + { + // Average among phases + drucker_prager_parameters.angle_internal_friction = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + angles_internal_friction, composition); + drucker_prager_parameters.cohesion = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + cohesions, composition); + } + return drucker_prager_parameters; + } + + template + double + DruckerPrager::compute_yield_stress (const double cohesion, + const double angle_internal_friction, + const double pressure, + const double max_yield_stress) const + { + const double sin_phi = std::sin(angle_internal_friction); + const double cos_phi = std::cos(angle_internal_friction); + + // The expression below differs from Eq. 9 of Glerum et al, 2018. + // There are actually three different ways of choosing this parameter, which + // correspond to the Drucker-Prager yield surface either + // circumscribing (Glerum et al 2018), middle circumscribing or + // inscribing the Mohr-Coulomb yield surface. + // See for instance Owen & Hinton, Finite Elements in Plasticity, 1980. + // Here the middle circumscribing approach is taken. + const double stress_inv_part = 1. / (std::sqrt(3.0) * (3.0 + sin_phi)); + + // Initial yield stress (no stabilization terms) + const double yield_stress = ( (dim==3) + ? + ( 6.0 * cohesion * cos_phi + 6.0 * pressure * sin_phi) * stress_inv_part + : + cohesion * cos_phi + pressure * sin_phi); + + return std::min(yield_stress, max_yield_stress); + } + + + + template + double + DruckerPrager::compute_viscosity (const double cohesion, + const double angle_internal_friction, + const double pressure, + const double effective_strain_rate, + const double max_yield_stress, + const double non_yielding_viscosity) const + { + const double yield_stress = compute_yield_stress(cohesion, angle_internal_friction, pressure, max_yield_stress); + + // If there is no damper, the yielding plastic element accommodates all the strain + double apparent_viscosity = yield_stress / (2. * effective_strain_rate); + + // If the plastic damper is used, the effective strain rate is partitioned between the + // viscoelastic and damped plastic (Bingham) elements. Assuming that the viscoelastic + // elements have viscosities that are not strain rate dependent, we have: + // edot_eff = tau_T / (2 * eta_ve) + (tau_T - tau_yield) / (2 * eta_d) + // The apparent viscosity is defined such that: + // tau_T = 2 * eta_app * edot_eff. + // Substituting one equation into the other and rearranging yields the expression + // eta_app = ((1 + tau_yield / (2 * eta_d * edot_eff)) / (1 / eta_d + 1 / eta_ve)). + if (use_plastic_damper) + { + apparent_viscosity = ((damper_viscosity + apparent_viscosity) / + (1. + damper_viscosity / non_yielding_viscosity)); + } + + return apparent_viscosity; + } + + + + template + std::pair + DruckerPrager::compute_strain_rate_and_derivative (const double stress, + const double pressure, + const DruckerPragerParameters p) const + { + + const double yield_stress = compute_yield_stress(p.cohesion, p.angle_internal_friction, pressure, p.max_yield_stress); + + if (stress > yield_stress) + { + return std::make_pair((stress - yield_stress)/(2.*damper_viscosity), 1./(2.*damper_viscosity)); + } + else + { + return std::make_pair(0., 0.); + } + } + + + + template + double + DruckerPrager::compute_derivative (const double angle_internal_friction, + const double effective_strain_rate) const + { + const double sin_phi = std::sin(angle_internal_friction); + + const double stress_inv_part = 1. / (std::sqrt(3.0) * (3.0 + sin_phi)); + + const double strain_rate_effective_inv = 1./(2.*effective_strain_rate); + + const double viscosity_pressure_derivative = sin_phi * strain_rate_effective_inv * + (dim == 3 + ? + (6.0 * stress_inv_part) + : + 1); + + return viscosity_pressure_derivative; + } + + + + template + void + DruckerPrager::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Angles of internal friction", "0.", + Patterns::Anything(), + "List of angles of internal friction, $\\phi$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "For a value of zero, in 2d the von Mises criterion is retrieved. " + "Angles higher than 30 degrees are harder to solve numerically. Units: degrees."); + prm.declare_entry ("Cohesions", "1e20", + Patterns::Anything(), + "List of cohesions, $C$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "The extremely large default cohesion value (1e20 Pa) prevents the viscous stress from " + "exceeding the yield stress. Units: \\si{\\pascal}."); + prm.declare_entry ("Maximum yield stress", "1e12", Patterns::Double (0.), + "Limits the maximum value of the yield stress determined by the " + "Drucker-Prager plasticity parameters. Default value is chosen so this " + "is not automatically used. Values of 100e6--1000e6 $Pa$ have been used " + "in previous models. Units: \\si{\\pascal}."); + prm.declare_entry ("Use plastic damper","false", + Patterns::Bool (), + "Whether to use a plastic damper when computing the Drucker-Prager " + "plastic viscosity. The damper acts to stabilize the plastic shear " + "band width and remove associated mesh-dependent behavior at " + "sufficient resolutions."); + prm.declare_entry ("Plastic damper viscosity", "0.0", Patterns::Double(0), + "Viscosity of the damper that acts in parallel with the plastic viscosity " + "to produce mesh-independent behavior at sufficient resolutions. Units: \\si{\\pascal\\second}"); + } + + + + template + void + DruckerPrager::parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition) + { + // Retrieve the list of composition names + std::vector compositional_field_names = this->introspection().get_composition_names(); + + // Retrieve the list of names of fields that represent chemical compositions, and not, e.g., + // plastic strain + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + + // Establish that a background field is required here + compositional_field_names.insert(compositional_field_names.begin(), "background"); + chemical_field_names.insert(chemical_field_names.begin(), "background"); + + Utilities::MapParsing::Options options(chemical_field_names, "Angles of internal friction"); + options.list_of_allowed_keys = compositional_field_names; + + if (expected_n_phases_per_composition) + { + options.allow_multiple_values_per_key = true; + options.n_values_per_key = *expected_n_phases_per_composition; + + // check_values_per_key is required to be true to duplicate single values + // if they are to be used for all phases associated with a given key. + options.check_values_per_key = true; + } + + angles_internal_friction = Utilities::MapParsing::parse_map_to_double_array(prm.get("Angles of internal friction"), + options); + + // Convert angles from degrees to radians + for (double &angle : angles_internal_friction) + angle *= constants::degree_to_radians; + + options.property_name = "Cohesions"; + cohesions = Utilities::MapParsing::parse_map_to_double_array(prm.get("Cohesions"), + options); + + // Limit maximum value of the Drucker-Prager yield stress + max_yield_stress = prm.get_double("Maximum yield stress"); + + // Whether to include a plastic damper when computing the Drucker-Prager plastic viscosity + use_plastic_damper = prm.get_bool("Use plastic damper"); + + // Stabilize plasticity through a viscous damper. + // The viscosity of the damper is implicitly zero if it is not used + if (use_plastic_damper) + damper_viscosity = prm.get_double("Plastic damper viscosity"); + else + damper_viscosity = 0.; + + } + + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace Rheology \ + { \ + template class DruckerPrager; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/elasticity.cc.bak b/source/material_model/rheology/elasticity.cc.bak new file mode 100644 index 00000000000..dd4022c4650 --- /dev/null +++ b/source/material_model/rheology/elasticity.cc.bak @@ -0,0 +1,529 @@ +/* + Copyright (C) 2019 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include +#include + +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace + { + std::vector make_elastic_additional_outputs_names() + { + std::vector names; + names.emplace_back("elastic_shear_modulus"); + return names; + } + } + + template + ElasticAdditionalOutputs::ElasticAdditionalOutputs (const unsigned int n_points) + : + NamedAdditionalMaterialOutputs(make_elastic_additional_outputs_names()), + elastic_shear_moduli(n_points, numbers::signaling_nan()) + {} + + + + template + std::vector + ElasticAdditionalOutputs::get_nth_output(const unsigned int idx) const + { + (void)idx; // suppress warning in release mode + AssertIndexRange (idx, 1); + return elastic_shear_moduli; + } + + + + namespace Rheology + { + template + void + Elasticity::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Elastic shear moduli", "75.0e9", + Patterns::List(Patterns::Double(0.)), + "List of elastic shear moduli, $G$, " + "for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "The default value of 75 GPa is representative of mantle rocks. Units: Pa."); + prm.declare_entry ("Use fixed elastic time step", "unspecified", + Patterns::Selection("true|false|unspecified"), + "Select whether the material time scale in the viscoelastic constitutive " + "relationship uses the regular numerical time step or a separate fixed " + "elastic time step throughout the model run. The fixed elastic time step " + "is always used during the initial time step. If a fixed elastic time " + "step is used throughout the model run, a stress averaging scheme is " + "applied to account for differences with the numerical time step. An " + "alternative approach is to limit the maximum time step size so that it " + "is equal to the elastic time step. The default value of this parameter is " + "'unspecified', which throws an exception during runtime. In order for " + "the model to run the user must select 'true' or 'false'."); + prm.declare_entry ("Fixed elastic time step", "1.e3", + Patterns::Double (0.), + "The fixed elastic time step $dte$. Units: years if the " + "'Use years in output instead of seconds' parameter is set; " + "seconds otherwise."); + prm.declare_entry ("Stabilization time scale factor", "1.", + Patterns::Double (1.), + "A stabilization factor for the elastic stresses that influences how fast " + "elastic stresses adjust to deformation. 1.0 is equivalent to no stabilization " + "and may lead to oscillatory motion. Setting the factor to 2 " + "avoids oscillations, but still enables an immediate elastic response. " + "However, in complex models this can lead to problems of convergence, in which " + "case the factor needs to be increased slightly. Setting the factor to " + "infinity is equivalent to not applying elastic stresses at all. The " + "factor is multiplied with the computational time step to create a time scale. "); + prm.declare_entry ("Elastic damper viscosity", "0.0", + Patterns::Double (0.), + "Viscosity of a viscous damper that acts in parallel with the elastic " + "element to stabilize behavior. Units: \\si{\\pascal\\second}"); + } + + + + template + void + Elasticity::parse_parameters (ParameterHandler &prm) + { + // Retrieve the list of composition names + std::vector compositional_field_names = this->introspection().get_composition_names(); + + // Retrieve the list of names of fields that represent chemical compositions, and not, e.g., + // plastic strain + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + + // Establish that a background field is required here + compositional_field_names.insert(compositional_field_names.begin(), "background"); + chemical_field_names.insert(chemical_field_names.begin(),"background"); + + Utilities::MapParsing::Options options(chemical_field_names, "Elastic shear moduli"); + options.list_of_allowed_keys = compositional_field_names; + + elastic_shear_moduli = Utilities::MapParsing::parse_map_to_double_array (prm.get("Elastic shear moduli"), + options); + + // Stabilize elasticity through a viscous damper + elastic_damper_viscosity = prm.get_double("Elastic damper viscosity"); + + if (prm.get ("Use fixed elastic time step") == "true") + use_fixed_elastic_time_step = true; + else if (prm.get ("Use fixed elastic time step") == "false") + use_fixed_elastic_time_step = false; + else + AssertThrow(false, ExcMessage("'Use fixed elastic time step' must be set to 'true' or 'false'")); + + stabilization_time_scale_factor = prm.get_double ("Stabilization time scale factor"); + + fixed_elastic_time_step = prm.get_double ("Fixed elastic time step"); + AssertThrow(fixed_elastic_time_step > 0, + ExcMessage("The fixed elastic time step must be greater than zero")); + + if (this->convert_output_to_years()) + fixed_elastic_time_step *= year_in_seconds; + + AssertThrow(this->get_parameters().enable_elasticity == true, + ExcMessage ("Material model Viscoelastic only works if 'Enable elasticity' is set to true")); + + // Check whether the compositional fields representing the viscoelastic + // stress tensor are both named correctly and listed in the right order. + AssertThrow(this->introspection().compositional_index_for_name("ve_stress_xx") == 0, + ExcMessage("Rheology model Elasticity only works if the first " + "compositional field is called ve_stress_xx.")); + AssertThrow(this->introspection().compositional_index_for_name("ve_stress_yy") == 1, + ExcMessage("Rheology model Elasticity only works if the second " + "compositional field is called ve_stress_yy.")); + if (dim == 2) + { + AssertThrow(this->introspection().compositional_index_for_name("ve_stress_xy") == 2, + ExcMessage("Rheology model Elasticity only works if the third " + "compositional field is called ve_stress_xy.")); + } + else if (dim == 3) + { + AssertThrow(this->introspection().compositional_index_for_name("ve_stress_zz") == 2, + ExcMessage("Rheology model Elasticity only works if the third " + "compositional field is called ve_stress_zz.")); + AssertThrow(this->introspection().compositional_index_for_name("ve_stress_xy") == 3, + ExcMessage("Rheology model Elasticity only works if the fourth " + "compositional field is called ve_stress_xy.")); + AssertThrow(this->introspection().compositional_index_for_name("ve_stress_xz") == 4, + ExcMessage("Rheology model Elasticity only works if the fifth " + "compositional field is called ve_stress_xz.")); + AssertThrow(this->introspection().compositional_index_for_name("ve_stress_yz") == 5, + ExcMessage("Rheology model Elasticity only works if the sixth " + "compositional field is called ve_stress_yz.")); + } + else + AssertThrow(false, ExcNotImplemented()); + + // Currently, it only makes sense to use this material model when the nonlinear solver + // scheme does a single Advection iteration and at minimum one Stokes iteration. More + // than one nonlinear Advection iteration will produce an unrealistic build-up of + // viscoelastic stress, which are tracked through compositional fields. + AssertThrow((this->get_parameters().nonlinear_solver == + Parameters::NonlinearSolver::single_Advection_single_Stokes + || + this->get_parameters().nonlinear_solver == + Parameters::NonlinearSolver::single_Advection_iterated_Stokes + || + this->get_parameters().nonlinear_solver == + Parameters::NonlinearSolver::single_Advection_iterated_Newton_Stokes + || + this->get_parameters().nonlinear_solver == + Parameters::NonlinearSolver::single_Advection_iterated_defect_correction_Stokes), + ExcMessage("The material model will only work with the nonlinear " + "solver schemes 'single Advection, single Stokes', " + "'single Advection, iterated Stokes', " + "'single Advection, iterated Newton Stokes', and " + "'single Advection, iterated defect correction Stokes' ")); + + // Functionality to average the additional RHS terms over the cell is not implemented. + // Also, there is no option implemented in this rheology module to project to Q1 the viscosity + // in the elastic force term for the RHS. + // Consequently, it is only possible to use elasticity with the Material averaging schemes + // 'none', 'harmonic average only viscosity', and 'geometric average only viscosity'. + // TODO: Find a way to include 'project to Q1 only viscosity'. + AssertThrow((this->get_parameters().material_averaging == MaterialModel::MaterialAveraging::none + || + this->get_parameters().material_averaging == MaterialModel::MaterialAveraging::harmonic_average_only_viscosity + || + this->get_parameters().material_averaging == MaterialModel::MaterialAveraging::geometric_average_only_viscosity + || + this->get_parameters().material_averaging == MaterialModel::MaterialAveraging::default_averaging), + ExcMessage("Material models with elasticity can only be used with the material " + "averaging schemes 'none', 'harmonic average only viscosity' and " + "'geometric average only viscosity'. This parameter ('Material averaging') " + "is located within the 'Material model' subsection.")); + } + + + + template + void + Elasticity::create_elastic_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + } + + + namespace + { + MaterialAveraging::AveragingOperation + get_averaging_operation_for_viscosity(const MaterialAveraging::AveragingOperation operation) + { + MaterialAveraging::AveragingOperation operation_for_viscosity = operation; + switch (operation) + { + case MaterialAveraging::harmonic_average: + operation_for_viscosity = MaterialAveraging::harmonic_average_only_viscosity; + break; + + case MaterialAveraging::geometric_average: + operation_for_viscosity = MaterialAveraging::geometric_average_only_viscosity; + break; + + case MaterialAveraging::project_to_Q1: + operation_for_viscosity = MaterialAveraging::project_to_Q1_only_viscosity; + break; + + default: + operation_for_viscosity = operation; + } + + return operation_for_viscosity; + } + } + + + + template + void + Elasticity::fill_elastic_outputs (const MaterialModel::MaterialModelInputs &in, + const std::vector &average_elastic_shear_moduli, + MaterialModel::MaterialModelOutputs &out) const + { + // Create a reference to the structure for the elastic outputs + MaterialModel::ElasticOutputs + *elastic_out = out.template get_additional_output>(); + + if (elastic_out == nullptr) + return; + + if (in.requests_property(MaterialProperties::additional_outputs)) + { + // The viscosity should be averaged if material averaging is applied. + std::vector effective_creep_viscosities; + if (this->get_parameters().material_averaging != MaterialAveraging::none) + { + MaterialModelOutputs out_copy(out.n_evaluation_points(), + this->introspection().n_compositional_fields); + out_copy.viscosities = out.viscosities; + + const MaterialAveraging::AveragingOperation averaging_operation_for_viscosity = + get_averaging_operation_for_viscosity(this->get_parameters().material_averaging); + MaterialAveraging::average(averaging_operation_for_viscosity, + in.current_cell, + this->introspection().quadratures.velocities, + this->get_mapping(), + in.requested_properties, + out_copy); + + effective_creep_viscosities = out_copy.viscosities; + } + else + effective_creep_viscosities = out.viscosities; + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + // Get old stresses from compositional fields + const SymmetricTensor<2,dim> stress_old (Utilities::Tensors::to_symmetric_tensor(&in.composition[i][0], + &in.composition[i][0]+SymmetricTensor<2,dim>::n_independent_components)); + + elastic_out->elastic_force[i] = -effective_creep_viscosities[i] / calculate_elastic_viscosity(average_elastic_shear_moduli[i]) * stress_old; + // The viscoelastic strain rate is needed only when the Newton method is selected. + const typename Parameters::NonlinearSolver::Kind nonlinear_solver = this->get_parameters().nonlinear_solver; + if ((nonlinear_solver == Parameters::NonlinearSolver::iterated_Advection_and_Newton_Stokes) || + (nonlinear_solver == Parameters::NonlinearSolver::single_Advection_iterated_Newton_Stokes)) + elastic_out->viscoelastic_strain_rate[i] = calculate_viscoelastic_strain_rate(in.strain_rate[i], stress_old, average_elastic_shear_moduli[i]); + } + } + } + + + + template + void + Elasticity::fill_reaction_outputs (const MaterialModel::MaterialModelInputs &in, + const std::vector &average_elastic_shear_moduli, + MaterialModel::MaterialModelOutputs &out) const + { + if (in.current_cell.state() == IteratorState::valid && this->get_timestep_number() > 0 && in.requests_property(MaterialProperties::reaction_terms)) + { + // Get old (previous time step) velocity gradients + std::vector> quadrature_positions(in.n_evaluation_points()); + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + quadrature_positions[i] = this->get_mapping().transform_real_to_unit_cell(in.current_cell, in.position[i]); + + std::vector solution_values(this->get_fe().dofs_per_cell); + in.current_cell->get_dof_values(this->get_old_solution(), + solution_values.begin(), + solution_values.end()); + + // Only create the evaluator the first time we get here + if (!evaluator) + evaluator = std::make_unique>(this->get_mapping(), + this->get_fe(), + update_gradients, + this->introspection().component_indices.velocities[0]); + + // Initialize the evaluator for the old velocity gradients + evaluator->reinit(in.current_cell, quadrature_positions); + evaluator->evaluate(solution_values, + EvaluationFlags::gradients); + + const double dte = elastic_timestep(); + const double dt = this->get_timestep(); + + // The viscosity should be averaged if material averaging is applied. + // Here the averaging scheme "project to Q1 (only viscosity)" is + // excluded, because there is no way to know the quadrature formula + // used for evaluation. + // TODO: find a way to include "project to Q1 (only viscosity)" as well. + std::vector effective_creep_viscosities; + if (this->get_parameters().material_averaging != MaterialAveraging::none && + this->get_parameters().material_averaging != MaterialAveraging::project_to_Q1 && + this->get_parameters().material_averaging != MaterialAveraging::project_to_Q1_only_viscosity) + { + MaterialModelOutputs out_copy(out.n_evaluation_points(), + this->introspection().n_compositional_fields); + out_copy.viscosities = out.viscosities; + + const MaterialAveraging::AveragingOperation averaging_operation_for_viscosity = + get_averaging_operation_for_viscosity(this->get_parameters().material_averaging); + MaterialAveraging::average(averaging_operation_for_viscosity, + in.current_cell, + this->introspection().quadratures.compositional_fields, + this->get_mapping(), + in.requested_properties, + out_copy); + + effective_creep_viscosities = out_copy.viscosities; + } + else + effective_creep_viscosities = out.viscosities; + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + // Get old stresses from compositional fields + const SymmetricTensor<2,dim> stress_old(Utilities::Tensors::to_symmetric_tensor(&in.composition[i][0], + &in.composition[i][0]+SymmetricTensor<2,dim>::n_independent_components)); + + // Calculate the rotated stresses + // Rotation (vorticity) tensor (equation 25 in Moresi et al., 2003, J. Comp. Phys.) + const Tensor<2,dim> rotation = 0.5 * (evaluator->get_gradient(i) - transpose(evaluator->get_gradient(i))); + + // Calculate the current (new) stored elastic stress, which is a function of the material + // properties (viscoelastic viscosity, shear modulus), elastic time step size, strain rate, + // vorticity, prior (inherited) viscoelastic stresses and viscosity of the elastic damper. + // In the absence of the elastic damper, the expression for "stress_new" is identical + // to the one found in Moresi et al. (2003, J. Comp. Phys., equation 29). + const double damped_elastic_viscosity = calculate_elastic_viscosity(average_elastic_shear_moduli[i]); + + // stress_0 is the combination of the elastic stress tensor stored at the end of the last time step and the change in that stress generated by local rotation + const SymmetricTensor<2,dim> stress_0 = (stress_old + dte * ( symmetrize(rotation * Tensor<2,dim>(stress_old) ) - symmetrize(Tensor<2,dim>(stress_old) * rotation) ) ); + + // stress_creep is the stress experienced by the viscous and elastic components. + Assert(std::isfinite(in.strain_rate[i].norm()), + ExcMessage("Invalid strain_rate in the MaterialModelInputs. This is likely because it was " + "not filled by the caller.")); + const SymmetricTensor<2,dim> stress_creep = 2. * effective_creep_viscosities[i] * ( deviator(in.strain_rate[i]) + stress_0 / (2. * damped_elastic_viscosity ) ); + + // stress_new is the (new) stored elastic stress + SymmetricTensor<2,dim> stress_new = stress_creep * (1. - (elastic_damper_viscosity / damped_elastic_viscosity)) + elastic_damper_viscosity * stress_0 / damped_elastic_viscosity; + + // Stress averaging scheme to account for difference between the elastic time step + // and the numerical time step (see equation 32 in Moresi et al., 2003, J. Comp. Phys.) + // Note that if there is no difference between the elastic timestep and the numerical + // timestep, then no averaging occurs as dt/dte = 1. + stress_new = ( ( 1. - ( dt / dte ) ) * stress_old ) + ( ( dt / dte ) * stress_new ) ; + + const SymmetricTensor<2,dim> stress_update = stress_new - stress_old; + + // Fill reaction terms + Utilities::Tensors::unroll_symmetric_tensor_into_array(stress_update, + &out.reaction_terms[i][0], + &out.reaction_terms[i][0]+SymmetricTensor<2,dim>::n_independent_components); + } + } + } + + + + template + double + Elasticity::elastic_timestep () const + { + // The elastic time step (dte) is equal to the numerical time step if the time step number + // is greater than 0 and the parameter 'use_fixed_elastic_time_step' is set to false. + // On the first (0) time step the elastic time step is always equal to the value + // specified in 'fixed_elastic_time_step', which is also used in all subsequent time + // steps if 'use_fixed_elastic_time_step' is set to true. + // + // We also use this parameter when we are still *before* the first time step, + // i.e., if the time step number is numbers::invalid_unsigned_int. + const double dte = ( ( this->get_timestep_number() > 0 && + this->simulator_is_past_initialization() && + use_fixed_elastic_time_step == false ) + ? + this->get_timestep() * stabilization_time_scale_factor + : + fixed_elastic_time_step); + return dte; + } + + + + template + const std::vector & + Elasticity::get_elastic_shear_moduli () const + { + return elastic_shear_moduli; + } + + + + template + double + Elasticity:: + calculate_elastic_viscosity (const double shear_modulus) const + { + return shear_modulus*elastic_timestep() + elastic_damper_viscosity; + } + + + + template + double + Elasticity:: + calculate_viscoelastic_viscosity (const double viscosity, + const double shear_modulus) const + { + const double elastic_viscosity = calculate_elastic_viscosity(shear_modulus); + return 1. / (1./elastic_viscosity + 1./viscosity); + } + + + + template + SymmetricTensor<2,dim> + Elasticity:: + calculate_viscoelastic_strain_rate(const SymmetricTensor<2,dim> &strain_rate, + const SymmetricTensor<2,dim> &stored_stress, + const double shear_modulus) const + { + // The first term in the following expression is the deviator of the true strain rate + // of one or more isostress rheological elements (in series). + // One of these elements must be an elastic component (potentially damped). + // The second term corresponds to a fictional strain rate arising from + // elastic stresses stored from the last time step. + // Note the parallels with the viscous part of the strain rate deviator, + // which is equal to 0.5 * stress / viscosity. + return deviator(strain_rate) + 0.5 * deviator(stored_stress) / + calculate_elastic_viscosity(shear_modulus); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + template class ElasticAdditionalOutputs; \ + \ + namespace Rheology \ + { \ + template class Elasticity; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/frank_kamenetskii.cc.bak b/source/material_model/rheology/frank_kamenetskii.cc.bak new file mode 100644 index 00000000000..fc61a80485e --- /dev/null +++ b/source/material_model/rheology/frank_kamenetskii.cc.bak @@ -0,0 +1,156 @@ +/* + Copyright (C) 2020 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + template + FrankKamenetskii::FrankKamenetskii () + = default; + + + + template + double + FrankKamenetskii::compute_viscosity (const double temperature, + const unsigned int composition, + const double pressure, + const double density, + const double gravity) const + { + const double reference_temperature = this->get_adiabatic_surface_temperature(); + const double reference_pressure = this->get_surface_pressure(); + const double max_depth = this->get_geometry_model().maximal_depth(); + + //Frank-Kamenetskii equation with added pressure dependence terms + const double viscosity_frank_kamenetskii = prefactors_frank_kamenetskii[composition] * std::exp(viscosity_ratios_frank_kamenetskii[composition] * 0.5 * (1.0-temperature/reference_temperature) + + pressure_prefactors_frank_kamenetskii[composition] * (pressure-reference_pressure)/(density*gravity*max_depth)); + + + return viscosity_frank_kamenetskii; + } + + + + + + template + void + FrankKamenetskii::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Viscosity ratios for Frank Kamenetskii", "15.", + Patterns::List(Patterns::Double (0.)), + "An adjusted viscosity ratio, $E$, for the viscosity approximation, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: None"); + prm.declare_entry ("Prefactors for Frank Kamenetskii", "1.e21", + Patterns::List(Patterns::Double (0.)), + "A viscosity prefactor for the viscosity approximation, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None"); + + prm.declare_entry ("Pressure prefactors for Frank Kamenetskii", "0.0", + Patterns::List(Patterns::Double (0.)), + "A prefactor for the pressure term in the viscosity approximation, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: None"); + } + + + + template + void + FrankKamenetskii::parse_parameters (ParameterHandler &prm) + { + + AssertThrow (this->include_adiabatic_heating() == false, + ExcMessage("The Frank-Kamenetskii rheology is currently only implemented for " + "models without adiabatic heating. Please implement the necessary " + "temperature adjustment if you need this feature.")); + + AssertThrow (this->get_adiabatic_surface_temperature() > 0.0, + ExcMessage("The Frank-Kamenetskii rheology can only be used when the adiabatic " + "surface temperature (reference_temperature in equation for viscosity) " + "is non-zero.")); + + // Retrieve the list of composition names + std::vector compositional_field_names = this->introspection().get_composition_names(); + + // Retrieve the list of names of fields that represent chemical compositions, and not, e.g., + // plastic strain + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + + // Establish that a background field is required here + compositional_field_names.insert(compositional_field_names.begin(), "background"); + chemical_field_names.insert(chemical_field_names.begin(),"background"); + + // Make options file for parsing maps to double arrays + Utilities::MapParsing::Options options(chemical_field_names, "Viscosity ratios for Frank Kamenetskii"); + options.list_of_allowed_keys = compositional_field_names; + + viscosity_ratios_frank_kamenetskii = Utilities::MapParsing::parse_map_to_double_array (prm.get("Viscosity ratios for Frank Kamenetskii"), + options); + + options.property_name = "Prefactors for Frank Kamenetskii"; + prefactors_frank_kamenetskii = Utilities::MapParsing::parse_map_to_double_array(prm.get("Prefactors for Frank Kamenetskii"), + options); + + options.property_name = "Pressure prefactors for Frank Kamenetskii"; + pressure_prefactors_frank_kamenetskii = Utilities::MapParsing::parse_map_to_double_array(prm.get("Pressure prefactors for Frank Kamenetskii"), + options); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace Rheology \ + { \ + template class FrankKamenetskii; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/friction_models.cc.bak b/source/material_model/rheology/friction_models.cc.bak new file mode 100644 index 00000000000..bb2d49361bb --- /dev/null +++ b/source/material_model/rheology/friction_models.cc.bak @@ -0,0 +1,312 @@ +/* + Copyright (C) 2019 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include + +#include +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + template + double + FrictionModels:: + compute_friction_angle(const double current_edot_ii, + const unsigned int volume_fraction_index, + const double static_friction_angle, + const Point &position) const + { + + switch (friction_mechanism) + { + case static_friction: + { + return static_friction_angle; + } + case dynamic_friction: + { + // Calculate effective steady-state friction coefficient. + // This is based on the former material model dynamic friction. + // The formula below is equivalent to the equation 13 in \cite{van_dinther_seismic_2013}. + // Although here the dynamic friction coefficient is directly specified. In addition, + // we also use a reference strain rate in place of a characteristic + // velocity divided by local element size. This reference strain rate is called + // the dynamic characteristic strain rate and is used to compute what value between + // dynamic and static angle of internal friction should be used. + // Furthermore a smoothness exponent X is added, which determines whether the + // friction vs strain rate curve is rather step-like or more gradual. + // mu = mu_d + (mu_s - mu_d) / ( (1 + strain_rate_dev_inv2/dynamic_characteristic_strain_rate)^X ); + // Angles of friction are used in radians within ASPECT. The coefficient + // of friction (mu) is the tangent of the internal angle of friction, hence convergence is needed. + // The incoming variable static_friction_angle holds the static friction angle. It's value is + // then updated with the strain rate dependent friction angle which is returned by the function. + const double mu = (std::tan(dynamic_angles_of_internal_friction[volume_fraction_index]) + + (std::tan(static_friction_angle) - std::tan(dynamic_angles_of_internal_friction[volume_fraction_index])) + / (1. + std::pow((current_edot_ii / dynamic_characteristic_strain_rate), + dynamic_friction_smoothness_exponent))); + const double dynamic_friction_angle = std::atan (mu); + Assert((mu < 1) && (0 < dynamic_friction_angle) && (dynamic_friction_angle <= 1.6), ExcMessage( + "The friction coefficient should be larger than zero and smaller than 1. " + "The friction angle should be smaller than 1.6 rad.")); + return dynamic_friction_angle; + } + case function: + { + // Use a given function input per composition to get the friction angle + Utilities::NaturalCoordinate point = + this->get_geometry_model().cartesian_to_other_coordinates(position, coordinate_system_friction_function); + + // we get time passed as seconds (always) but may want + // to reinterpret it in years + if (this->convert_output_to_years()) + friction_function->set_time (this->get_time() / year_in_seconds); + else + friction_function->set_time (this->get_time()); + + // determine the friction angle based on position and composition + // The volume_fraction_index is based on the number of chemical compositional fields. + // However, this plugin reads a function for every compositional field, regardless of + // its type. Therefore we have to get the correct index. + // If no fields or no chemical fields are present, but only background material, the index is zero. + // If chemical fields are present, volume_fractions will be of size 1+n_chemical_composition_fields. + // The size of chemical_composition_field_indices will be one less. + unsigned int index = 0; + if (this->introspection().composition_type_exists(CompositionalFieldDescription::chemical_composition)) + index = this->introspection().chemical_composition_field_indices()[volume_fraction_index-1]; + double friction_from_function = + friction_function->value(Utilities::convert_array_to_point(point.get_coordinates()),index); + + // Convert angles from degrees to radians + friction_from_function *= constants::degree_to_radians; + + return friction_from_function; + } + } + // we should never get here, return something anyway, so the compiler does not complain... + AssertThrow (false, ExcMessage("Unknown friction model.")); + return static_friction_angle; + } + + + + template + FrictionMechanism + FrictionModels:: + get_friction_mechanism() const + { + return friction_mechanism; + } + + + + template + void + FrictionModels::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Friction mechanism", "none", + Patterns::Selection("none|dynamic friction|function"), + "Whether to make the friction angle dependent on strain rate or not. This rheology " + "is intended to be used together with the visco-plastic rheology model." + "\n\n" + "\\item ``none'': No dependence of the friction angle is applied. " + "\n\n" + "\\item ``dynamic friction'': The friction angle is rate dependent." + "When 'dynamic angles of internal friction' are specified, " + "the friction angle will be weakened for high strain rates with: " + "$\\mu = \\mu_d + \\frac{\\mu_s-\\mu_d}{1+\\frac{\\dot{\\epsilon}_{ii}}{\\dot{\\epsilon}_C}}^x$ " + "where $\\mu_s$ and $\\mu_d$ are the friction angles at low and high strain rates, " + "respectively. $\\dot{\\epsilon}_{ii}$ is the second invariant of the strain rate and " + "$\\dot{\\epsilon}_C$ is the 'dynamic characteristic strain rate' where $\\mu = (\\mu_s+\\mu_d)/2$. " + "The 'dynamic friction smoothness exponent' x controls how " + "smooth or step-like the change from $\\mu_s$ to $\\mu_d$ is. " + "The equation is modified after Equation (13) in \\cite{van_dinther_seismic_2013}. " + "$\\mu_s$ and $\\mu_d$ can be specified by setting 'Angles of internal friction' and " + "'Dynamic angles of internal friction', respectively. " + "This relationship is similar to rate-and-state friction constitutive relationships, which " + "are applicable to the strength of rocks during earthquakes." + "\n\n" + "\\item ``function'': Specify the friction angle as a function of space and time " + "for each compositional field."); + + // Dynamic friction parameters + prm.declare_entry ("Dynamic characteristic strain rate", "1e-12", + Patterns::Double (0), + "The characteristic strain rate value at which the angle of friction is " + "equal to $\\mu = (\\mu_s+\\mu_d)/2$. When the effective strain rate " + "is very high, the dynamic angle of friction is taken, when it is very low, " + "the static angle of internal friction is used. Around the dynamic characteristic " + "strain rate, there is a smooth gradient from the static to the dynamic angle " + "of internal friction. " + "Units: \\si{\\per\\second}."); + + prm.declare_entry ("Dynamic angles of internal friction", "2", + Patterns::List(Patterns::Double(0)), + "List of dynamic angles of internal friction, $\\phi$, for background material and compositional " + "fields, for a total of N$+$1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "Dynamic angles of friction are used as the current friction angle when the effective " + "strain rate is well above the 'dynamic characteristic strain rate'. " + "Units: \\si{\\degree}."); + + prm.declare_entry ("Dynamic friction smoothness exponent", "1", + Patterns::Double (0), + "An exponential factor in the equation for the calculation of the friction angle when a " + "static and a dynamic angle of internal friction are specified. A factor of 1 returns the equation " + "to Equation (13) in \\cite{van_dinther_seismic_2013}. A factor between 0 and 1 makes the " + "curve of the friction angle vs. the strain rate smoother, while a factor $>$ 1 makes " + "the change between static and dynamic friction angle more steplike. " + "Units: none."); + + /** + * If friction is specified as a function input. + */ + prm.enter_subsection("Friction function"); + { + /** + * The function to specify the friction angle per composition can be declared in dependence + * of depth, cartesian coordinates or spherical coordinates. Note that the order + * of spherical coordinates is r,phi,theta and not r,theta,phi, since + * this allows for dimension independent expressions. + */ + prm.declare_entry ("Coordinate system", "cartesian", + Patterns::Selection ("cartesian|spherical|depth"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `cartesian', `spherical', and `depth'. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle. `depth' " + "will create a function, in which only the first " + "parameter is non-zero, which is interpreted to " + "be the depth of the point."); + + Functions::ParsedFunction::declare_parameters(prm,1); + } + prm.leave_subsection(); + } + + + + template + void + FrictionModels::parse_parameters (ParameterHandler &prm) + { + // Friction dependence parameters + if (prm.get ("Friction mechanism") == "none") + friction_mechanism = static_friction; + else if (prm.get ("Friction mechanism") == "dynamic friction") + friction_mechanism = dynamic_friction; + else if (prm.get ("Friction mechanism") == "function") + friction_mechanism = function; + else + AssertThrow(false, ExcMessage("Not a valid friction mechanism option!")); + + // Dynamic friction parameters + dynamic_characteristic_strain_rate = prm.get_double("Dynamic characteristic strain rate"); + + // Retrieve the list of composition names + std::vector compositional_field_names = this->introspection().get_composition_names(); + + // Retrieve the list of names of fields that represent chemical compositions, and not, e.g., + // plastic strain + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + + // Establish that a background field is required here + compositional_field_names.insert(compositional_field_names.begin(), "background"); + chemical_field_names.insert(chemical_field_names.begin(), "background"); + + Utilities::MapParsing::Options options(chemical_field_names, "Dynamic angles of internal friction"); + options.list_of_allowed_keys = compositional_field_names; + + dynamic_angles_of_internal_friction = Utilities::MapParsing::parse_map_to_double_array (prm.get("Dynamic angles of internal friction"), + options); + + // Convert angles from degrees to radians + for (double &angle : dynamic_angles_of_internal_friction) + { + AssertThrow(angle <= 90, + ExcMessage("Dynamic angles of friction must be <= 90 degrees")); + angle *= constants::degree_to_radians; + } + + dynamic_friction_smoothness_exponent = prm.get_double("Dynamic friction smoothness exponent"); + + + // Get the number of fields for composition-dependent material properties + // including the background field. + // TODO Make sure functions only have to be specified per chemical composition, + // but can still be specified for all fields for backwards compatibility. + const unsigned int n_fields = this->n_compositional_fields() + 1; + + // if friction is specified as a function + if (friction_mechanism == function) + { + prm.enter_subsection("Friction function"); + { + coordinate_system_friction_function = Utilities::Coordinates::string_to_coordinate_system(prm.get("Coordinate system")); + try + { + friction_function + = std::make_unique>(n_fields); + friction_function->parse_parameters (prm); + } + catch (...) + { + std::cerr << "FunctionParser failed to parse\n" + << "\t friction function\n" + << "with expression \n" + << "\t' " << prm.get("Function expression") << "'"; + throw; + } + } + prm.leave_subsection(); + } + + } + } + } +} + + + +// Explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace Rheology \ + { \ + template class FrictionModels; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/peierls_creep.cc.bak b/source/material_model/rheology/peierls_creep.cc.bak new file mode 100644 index 00000000000..8b46fd86b72 --- /dev/null +++ b/source/material_model/rheology/peierls_creep.cc.bak @@ -0,0 +1,679 @@ +/* + Copyright (C) 2020 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + PeierlsCreepParameters::PeierlsCreepParameters() + : prefactor (numbers::signaling_nan()), + stress_exponent (numbers::signaling_nan()), + activation_energy (numbers::signaling_nan()), + activation_volume (numbers::signaling_nan()), + peierls_stress (numbers::signaling_nan()), + glide_parameter_p (numbers::signaling_nan()), + glide_parameter_q (numbers::signaling_nan()), + fitting_parameter (numbers::signaling_nan()), + stress_cutoff (numbers::signaling_nan()) + {} + + + + template + PeierlsCreep::PeierlsCreep () + = default; + + + + /** + * Compute the creep parameters for the Peierls creep law. + */ + template + const PeierlsCreepParameters + PeierlsCreep::compute_creep_parameters (const unsigned int composition, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + PeierlsCreepParameters creep_parameters; + if (phase_function_values == std::vector()) + { + // no phases + creep_parameters.prefactor = prefactors[composition]; + creep_parameters.stress_exponent = stress_exponents[composition]; + creep_parameters.activation_energy = activation_energies[composition]; + creep_parameters.activation_volume = activation_volumes[composition]; + creep_parameters.peierls_stress = peierls_stresses[composition]; + creep_parameters.glide_parameter_p = glide_parameters_p[composition]; + creep_parameters.glide_parameter_q = glide_parameters_q[composition]; + creep_parameters.fitting_parameter = fitting_parameters[composition]; + creep_parameters.stress_cutoff = stress_cutoffs[composition]; + } + else + { + // Average among phases. This averaging is not strictly correct, but + // it will not matter much if the parameters are similar across transitions. + creep_parameters.prefactor = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + prefactors, composition, MaterialModel::MaterialUtilities::PhaseUtilities::logarithmic); + creep_parameters.stress_exponent = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + stress_exponents, composition); + creep_parameters.activation_energy = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + activation_energies, composition); + creep_parameters.activation_volume = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + activation_volumes, composition); + creep_parameters.peierls_stress = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + peierls_stresses, composition); + creep_parameters.glide_parameter_p = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + glide_parameters_p, composition); + creep_parameters.glide_parameter_q = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + glide_parameters_q, composition); + creep_parameters.fitting_parameter = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + fitting_parameters, composition); + creep_parameters.stress_cutoff = MaterialModel::MaterialUtilities::phase_average_value(phase_function_values, n_phase_transitions_per_composition, + stress_cutoffs, composition); + } + return creep_parameters; + } + + + + template + double + PeierlsCreep::compute_approximate_viscosity (const double strain_rate, + const double pressure, + const double temperature, + const unsigned int composition, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + /** + * An approximation of the Peierls creep formulation, where stress is replaced with strain rate + * (second invariant) when calculating viscosity. This substitution requires a fitting parameter (gamma), + * which describes the relationship between stress and the Peierls stress (gamma = stress/stress_peierls). + * Details of this derivation can be found in the following document: + * https://ucdavis.app.box.com/s/cl5mwhkjeabol4otrdukfcdwfvg9me4w/file/705438695737 + * The formulation for the viscosity is: + * stress_term * arrhenius_term * strain_rate_term, where + * stress_term = (0.5 * gamma * sigma_p) / (A * ((gamma * sigma_p)^n)^(1/(s+n))) + * arrhenius_term = exp(( (E + P * V) / (R * T)) * (1 - gamma^p)^q / (s + n) ) + * strain_rate_term = edot_ii^(1 / (s + n) - 1) + * Above, + * s = ((E + P * V) / (R * T)) * p * q * (1 - gamma^p)^(q-1) * (gamma^p) + * sigma_p is the Peierls stress + * gamma is the Peierls creep fitting parameter + * p is the first Peierls glide parameter + * q is the second Peierls creep glide parameter + * A is the Peierls prefactor term (1/s 1/Pa^2) + * n is the Peierls stress exponent + * E is the Peierls activation energy (J/mol) + * V is the Peierls activation volume (m^3/mol). However, to date V has always been set to 0. + * edot_ii is the second invariant of the deviatoric strain rate (1/s) + * T is temperature (K) + * R is the gas constant + */ + + const PeierlsCreepParameters p = compute_creep_parameters(composition, phase_function_values, n_phase_transitions_per_composition); + + const double s = ( (p.activation_energy + pressure * p.activation_volume) / (constants::gas_constant * temperature)) * + p.glide_parameter_p * p.glide_parameter_q * + std::pow((1. - std::pow(p.fitting_parameter, p.glide_parameter_p)),(p.glide_parameter_q - 1.)) * + std::pow(p.fitting_parameter, p.glide_parameter_p); + + const double stress_term = 0.5 * (p.fitting_parameter * p.peierls_stress) / + std::pow((p.prefactor * std::pow(p.fitting_parameter * p.peierls_stress,p.stress_exponent)),( 1. / (s + p.stress_exponent))); + + const double arrhenius_term = std::exp( ((p.activation_energy + pressure * p.activation_volume) / (constants::gas_constant * temperature)) * + (std::pow((1. - std::pow(p.fitting_parameter,p.glide_parameter_p)),p.glide_parameter_q)) / + (s + p.stress_exponent) ); + + const double strain_rate_term = std::pow(strain_rate, (1. / (s + p.stress_exponent)) - 1.); + + double viscosity_peierls = stress_term * arrhenius_term * strain_rate_term; + + Assert (viscosity_peierls > 0.0, + ExcMessage ("Negative peierls viscosity detected. This is unphysical and should not happen. " + "Check for negative parameters.")); + + // Creep viscosities become extremely large at low + // temperatures and can therefore provoke floating-point overflow errors. In + // real rocks, other deformation mechanisms become dominant at low temperatures, + // so these high viscosities are never achieved. It is therefore both reasonable + // and desirable to require the single-mechanism viscosity to be smaller than + // std::sqrt(max_double). + viscosity_peierls = std::min(viscosity_peierls, std::sqrt(std::numeric_limits::max())); + + return viscosity_peierls; + } + + + + template + double + PeierlsCreep::compute_exact_viscosity (const double strain_rate, + const double pressure, + const double temperature, + const unsigned int composition, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + /** + * A generalized Peierls creep formulation. The Peierls creep expression + * for the strain rate has multiple stress-dependent terms, and cannot be + * directly inverted to find an expression for viscosity in terms of + * strain rate. For this reason, a Newton-Raphson iteration is required, + * which can be quite expensive. + * The equation for the strain rate is given in + * compute_exact_strain_rate_and_derivative. + */ + const PeierlsCreepParameters p = compute_creep_parameters(composition, phase_function_values, n_phase_transitions_per_composition); + + // The generalized Peierls creep flow law cannot be expressed as viscosity in + // terms of strain rate, because there are two stress-dependent terms + // in the strain rate expression. + // We use Newton's method to find the second invariant of the stress tensor. + + // Apply a strict cutoff if this option is chosen by user. A strain rate cutoff + // will be first computed and then compared to the input strain rate. A cutoff + // on stress will be triggered if the input strain rate is smaller. + const double log_strain_rate = std::log(strain_rate); + + if (apply_strict_cutoff) + { + const std::pair log_edot_and_deriv = compute_exact_log_strain_rate_and_derivative(std::log(p.stress_cutoff), pressure, temperature, p); + if (log_strain_rate < log_edot_and_deriv.first) + { + double viscosity = 0.5 * p.stress_cutoff / strain_rate; + return viscosity; + } + } + + // Create a starting guess for the stress using + // the approximate form of the viscosity expression + double viscosity = compute_approximate_viscosity(strain_rate, pressure, temperature, composition); + double log_stress_ii = std::log(2.*viscosity*strain_rate); + + // Before the first iteration, compute the residual + // of the initial guess and the derivative + unsigned int stress_iteration = 0; + const std::pair log_edot_and_deriv = compute_exact_log_strain_rate_and_derivative(log_stress_ii, pressure, temperature, p); + double strain_rate_residual = log_edot_and_deriv.first - log_strain_rate; + double log_strain_rate_deriv = log_edot_and_deriv.second; + + while (std::abs(strain_rate_residual) > strain_rate_residual_threshold + && stress_iteration < stress_max_iteration_number) + { + // If the strain rate derivative is zero, we catch it below. + if (log_strain_rate_deriv>std::numeric_limits::min()) + log_stress_ii -= strain_rate_residual/log_strain_rate_deriv; + + const std::pair log_edot_and_deriv = compute_exact_log_strain_rate_and_derivative(log_stress_ii, pressure, temperature, p); + + strain_rate_residual = log_edot_and_deriv.first - log_strain_rate; + log_strain_rate_deriv = log_edot_and_deriv.second; + + stress_iteration += 1; + + // If anything that would be used in the next iteration is not finite, the + // Newton iteration would trigger an exception and we want to abort the + // iteration instead. + // Currently, we still throw an exception, but if this exception is thrown, + // another more robust iterative scheme should be implemented + // (similar to that seen in the diffusion-dislocation material model). + const bool abort_newton_iteration = !numbers::is_finite(log_stress_ii) + || !numbers::is_finite(strain_rate_residual) + || !numbers::is_finite(log_strain_rate_deriv) + || log_strain_rate_deriv < std::numeric_limits::min() + || stress_iteration == stress_max_iteration_number; + AssertThrow(!abort_newton_iteration, + ExcMessage("No convergence has been reached in the loop that determines " + "the Peierls creep viscosity. Aborting! " + "Residual is " + Utilities::to_string(strain_rate_residual) + + " after " + Utilities::to_string(stress_iteration) + " iterations. " + "You can increase the number of iterations by adapting the " + "parameter 'Maximum Peierls strain rate iterations'.")); + } + + viscosity = 0.5*std::exp(log_stress_ii)/strain_rate; + + return viscosity; + } + + + + template + double + PeierlsCreep::compute_viscosity (const double strain_rate, + const double pressure, + const double temperature, + const unsigned int composition, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + double viscosity = 0.0; + + switch (peierls_creep_flow_law) + { + case viscosity_approximation: + { + viscosity = compute_approximate_viscosity(strain_rate, pressure, temperature, composition, phase_function_values, n_phase_transitions_per_composition); + break; + } + case exact: + { + viscosity = compute_exact_viscosity(strain_rate, pressure, temperature, composition, phase_function_values, n_phase_transitions_per_composition); + break; + } + default: + { + AssertThrow(false, ExcNotImplemented()); + break; + } + } + + return viscosity; + } + + + + template + std::pair + PeierlsCreep::compute_approximate_strain_rate_and_derivative (const double stress, + const double pressure, + const double temperature, + const PeierlsCreepParameters creep_parameters) const + { + /** + * b = (E+P*V)/(R*T) + * c = std::pow(gamma, p) + * d = std::pow(1. - c, q) + * s = b*p*q*c*d/(1. - c) + * arrhenius = std::exp(-b*d) + * + * edot_ii = A * std::pow(stress, s + n) * std::pow(gamma*peierls_stress, -s) * arrhenius + * deriv = edot_ii / stress * (s + n) + */ + const PeierlsCreepParameters p = creep_parameters; + + const double b = (p.activation_energy + pressure*p.activation_volume)/(constants::gas_constant * temperature); + const double c = std::pow(p.fitting_parameter, p.glide_parameter_p); + const double d = std::pow(1. - c, p.glide_parameter_q); + const double s = b*p.glide_parameter_p*p.glide_parameter_q*c*d/(1. - c); + const double arrhenius = std::exp(-b*d); + + const double edot_ii = p.prefactor * std::pow(stress, s + p.stress_exponent) * std::pow(p.fitting_parameter*p.peierls_stress, -s) * arrhenius; + const double deriv = edot_ii / stress * (s + p.stress_exponent); + + return std::make_pair(edot_ii, deriv); + } + + + + template + std::pair + PeierlsCreep::compute_exact_strain_rate_and_derivative (const double stress, + const double pressure, + const double temperature, + const PeierlsCreepParameters creep_parameters) const + { + /** + * b = (E+P*V)/(R*T) + * c = std::pow(stress/peierls_stress, p) + * d = std::pow(1 - c, q) + * s = b*p*q*c*d/(1 - c) + * arrhenius = std::exp(-b*d) + * + * edot_ii = A * std::pow(stress, n) * arrhenius + * deriv = edot_ii / stress * (s + n) + */ + const PeierlsCreepParameters p = creep_parameters; + if (stress < p.stress_cutoff) + { + + /** + * For Peierls creep flow laws that have a stress exponent equal to zero the strain rate does not approach zero as + * stress approaches zero. To ensure convergence in the solver, the strain rate is modelled as a quadratic function + * of stress; + * edot_ii = quadratic_term*stress^2 + linear_term*stress + * Where the quadratic and linear terms are defined at a constant cutoff temperature and pressure. + * T_cutoff = (E/R), P_cutoff = 0 + * s_cutoff = p*q*c_cutoff*d_cutoff / (1 - c_cutoff) + * arrhenius_cutoff = std::exp(-d_cutoff) + */ + const double c_cutoff = std::pow(p.stress_cutoff/p.peierls_stress, p.glide_parameter_p); + const double d_cutoff = std::pow(1. - c_cutoff, p.glide_parameter_q); + const double s_cutoff = p.glide_parameter_p*p.glide_parameter_q*c_cutoff*d_cutoff/(1. - c_cutoff); + const double arrhenius_cutoff = std::exp(-d_cutoff); + const double edot_ii_cutoff = p.prefactor * std::pow(p.stress_cutoff, p.stress_exponent) * arrhenius_cutoff; + const double deriv_cutoff = edot_ii_cutoff / p.stress_cutoff * (s_cutoff + p.stress_exponent); + const double quadratic_term = (deriv_cutoff - edot_ii_cutoff / p.stress_cutoff) / p.stress_cutoff / arrhenius_cutoff; + const double linear_term = (2*(edot_ii_cutoff / p.stress_cutoff) - deriv_cutoff) / arrhenius_cutoff; + + const double b = (p.activation_energy + pressure*p.activation_volume)/(constants::gas_constant * temperature); + const double arrhenius = std::exp(-b*d_cutoff); + const double edot_ii = (quadratic_term*std::pow(stress, 2.) + linear_term*stress) * arrhenius; + const double deriv = (2*quadratic_term*stress + linear_term) * arrhenius; + + return std::make_pair(edot_ii, deriv); + } + + else + { + const double b = (p.activation_energy + pressure*p.activation_volume)/(constants::gas_constant * temperature); + const double c = std::pow(stress/p.peierls_stress, p.glide_parameter_p); + const double d = std::pow(1. - c, p.glide_parameter_q); + const double s = b*p.glide_parameter_p*p.glide_parameter_q*c*d/(1. - c); + const double arrhenius = std::exp(-b*d); + + const double edot_ii = p.prefactor * std::pow(stress, p.stress_exponent) * arrhenius; + const double deriv = edot_ii / stress * (s + p.stress_exponent); + + return std::make_pair(edot_ii, deriv); + } + } + + + + template + std::pair + PeierlsCreep::compute_exact_log_strain_rate_and_derivative (const double log_stress, + const double pressure, + const double temperature, + const PeierlsCreepParameters creep_parameters) const + { + /** + * b = (E+P*V)/(R*T) + * c = std::pow(stress/peierls_stress, p) + * d = std::pow(1 - c, q) + * + * log_edot_ii = std::log(A) + n * std::log(stress) - b*d + * deriv_log = n + p * q * b * std::(1-c, p.q - 1) + * The deriv_log is the derivative of log(edot_ii) to log(stress). + */ + const PeierlsCreepParameters p = creep_parameters; + const double stress = std::exp(log_stress); + if (stress < p.stress_cutoff) + { + + /** + * For Peierls creep flow laws that have a stress exponent equal to zero the strain rate does not approach zero as + * stress approaches zero. To ensure convergence in the solver, the strain rate is modelled as a quadratic function + * of stress; + * edot_ii = quadratic_term*stress^2 + linear_term*stress + * Where the quadratic and linear terms are defined at a constant cutoff temperature and pressure. + * T_cutoff = (E/R), P_cutoff = 0 + * s_cutoff = p*q*c_cutoff*d_cutoff / (1 - c_cutoff) + * arrhenius_cutoff = std::exp(-d_cutoff) + */ + const double c_cutoff = std::pow(p.stress_cutoff/p.peierls_stress, p.glide_parameter_p); + const double d_cutoff = std::pow(1. - c_cutoff, p.glide_parameter_q); + const double s_cutoff = p.glide_parameter_p*p.glide_parameter_q*c_cutoff*d_cutoff/(1. - c_cutoff); + const double arrhenius_cutoff = std::exp(-d_cutoff); + const double edot_ii_cutoff = p.prefactor * std::pow(p.stress_cutoff, p.stress_exponent) * arrhenius_cutoff; + const double deriv_cutoff = edot_ii_cutoff / p.stress_cutoff * (s_cutoff + p.stress_exponent); + const double quadratic_term = (deriv_cutoff - edot_ii_cutoff / p.stress_cutoff) / p.stress_cutoff / arrhenius_cutoff; + const double linear_term = (2*(edot_ii_cutoff / p.stress_cutoff) - deriv_cutoff) / arrhenius_cutoff; + + const double b = (p.activation_energy + pressure*p.activation_volume)/(constants::gas_constant * temperature); + const double arrhenius = std::exp(-b*d_cutoff); + const double edot_ii = (quadratic_term*std::pow(stress, 2.) + linear_term*stress) * arrhenius; + const double deriv_log = 2 - linear_term / (quadratic_term * stress + linear_term); + + return std::make_pair(std::log(edot_ii), deriv_log); + } + else + { + const double b = (p.activation_energy + pressure*p.activation_volume)/(constants::gas_constant * temperature); + const double c = std::pow(stress/p.peierls_stress, p.glide_parameter_p); + const double d = std::pow(1. - c, p.glide_parameter_q); + + const double log_edot_ii = std::log(p.prefactor) + p.stress_exponent * log_stress - b*d ; + const double deriv_log = p.stress_exponent + p.glide_parameter_p * p.glide_parameter_q * b * c * std::pow(1-c, p.glide_parameter_q - 1); + + return std::make_pair(log_edot_ii, deriv_log); + } + } + + + + template + std::pair + PeierlsCreep::compute_strain_rate_and_derivative (const double stress, + const double pressure, + const double temperature, + const PeierlsCreepParameters creep_parameters) const + { + std::pair strain_rate_and_deriv; + + switch (peierls_creep_flow_law) + { + case viscosity_approximation: + { + strain_rate_and_deriv = compute_approximate_strain_rate_and_derivative(stress, pressure, temperature, creep_parameters); + break; + } + case exact: + { + strain_rate_and_deriv = compute_exact_strain_rate_and_derivative(stress, pressure, temperature, creep_parameters); + break; + } + default: + { + AssertThrow(false, ExcNotImplemented()); + break; + } + } + return strain_rate_and_deriv; + } + + + + template + void + PeierlsCreep::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Peierls creep flow law", "viscosity approximation", + Patterns::Selection("viscosity approximation|exact"), + "Select what type of Peierls creep flow law to use. Currently, the " + "available options are 'exact', which uses a Newton-Raphson iterative method " + "to find the stress and then compute viscosity, and 'viscosity approximation', " + "in which viscosity is an explicit function of the strain rate invariant, " + "rather than stress. "); + + // Viscosity iteration parameters + prm.declare_entry ("Peierls strain rate residual tolerance", "1e-10", Patterns::Double(0.), + "Tolerance for the iterative solve to find the correct Peierls creep strain rate. " + "The tolerance is expressed as the difference between the natural logarithm of the " + "input strain rate and the strain rate at the current iteration."); + prm.declare_entry ("Maximum Peierls strain rate iterations", "40", Patterns::Integer(0), + "Maximum number of iterations to find the correct " + "Peierls strain rate."); + + // Rheological parameters + prm.declare_entry ("Prefactors for Peierls creep", "1.4e-19", + Patterns::Anything(), + "List of viscosity prefactors, $A$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\pascal}$^{-n_{\\text{peierls}}}$ \\si{\\per\\second}"); + prm.declare_entry ("Stress exponents for Peierls creep", "2.0", + Patterns::Anything(), + "List of stress exponents, $n_{\\text{peierls}}$, for background material and compositional " + "fields, for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + prm.declare_entry ("Activation energies for Peierls creep", "320e3", + Patterns::Anything(), + "List of activation energies, $E$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: \\si{\\joule\\per\\mole}."); + prm.declare_entry ("Activation volumes for Peierls creep", "1.4e-5", + Patterns::Anything(), + "List of activation volumes, $V$, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\meter\\cubed\\per\\mole}."); + prm.declare_entry ("Peierls stresses", "5.e9", + Patterns::Anything(), + "List of stress limits for Peierls creep $\\sigma_{\\text{peierls}}$ for background " + "material and compositional fields, for a total of N+1 values, where N is the number " + "of all compositional fields or only those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\pascal}"); + prm.declare_entry ("Peierls fitting parameters", "0.17", + Patterns::Anything(), + "List of fitting parameters $\\gamma$ between stress $\\sigma$ and the Peierls " + "stress $\\sigma_{\\text{peierls}}$ for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. If only one value is given, " + "then all use the same value. Units: none"); + prm.declare_entry ("Peierls glide parameters p", "0.5", + Patterns::Anything(), + "List of the first Peierls creep glide parameters, $p$, for background and compositional " + "fields for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: none"); + prm.declare_entry ("Peierls glide parameters q", "1.0", + Patterns::Anything(), + "List of the second Peierls creep glide parameters, $q$, for background and compositional " + "fields for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: none"); + prm.declare_entry ("Cutoff stresses for Peierls creep", "0.0", + Patterns::Anything(), + "List of the Stress thresholds below which the strain rate is solved for as a quadratic " + "function of stress to aid with convergence when stress exponent n=0. Units: \\si{\\pascal}"); + prm.declare_entry ("Apply strict stress cutoff for Peierls creep", "false", Patterns::Bool(), + "Whether the cutoff stresses for Peierls creep are used as the minimum " + "stresses in the Peierls rheology"); + + } + + + + template + void + PeierlsCreep::parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition) + { + // Retrieve the list of composition names + std::vector compositional_field_names = this->introspection().get_composition_names(); + + // Retrieve the list of names of fields that represent chemical compositions, and not, e.g., + // plastic strain + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + + // Establish that a background field is required here + compositional_field_names.insert(compositional_field_names.begin(), "background"); + chemical_field_names.insert(chemical_field_names.begin(),"background"); + + if (prm.get ("Peierls creep flow law") == "viscosity approximation") + peierls_creep_flow_law = viscosity_approximation; + else if (prm.get ("Peierls creep flow law") == "exact") + peierls_creep_flow_law = exact; + else + AssertThrow(false, ExcMessage("Not a valid Peierls creep flow law")); + + // Iteration parameters + strain_rate_residual_threshold = prm.get_double ("Peierls strain rate residual tolerance"); + stress_max_iteration_number = prm.get_integer ("Maximum Peierls strain rate iterations"); + + // Rheological parameters + // Make options file for parsing maps to double arrays + Utilities::MapParsing::Options options(chemical_field_names, "Prefactors for Peierls creep"); + options.list_of_allowed_keys = compositional_field_names; + options.allow_multiple_values_per_key = true; + if (expected_n_phases_per_composition) + { + options.n_values_per_key = *expected_n_phases_per_composition; + + // check_values_per_key is required to be true to duplicate single values + // if they are to be used for all phases associated with a given key. + options.check_values_per_key = true; + } + + prefactors = Utilities::MapParsing::parse_map_to_double_array(prm.get("Prefactors for Peierls creep"), + options); + + options.property_name = "Stress exponents for Peierls creep"; + stress_exponents = Utilities::MapParsing::parse_map_to_double_array(prm.get("Stress exponents for Peierls creep"), + options); + + options.property_name = "Activation energies for Peierls creep"; + activation_energies = Utilities::MapParsing::parse_map_to_double_array(prm.get("Activation energies for Peierls creep"), + options); + + options.property_name = "Activation volumes for Peierls creep"; + activation_volumes = Utilities::MapParsing::parse_map_to_double_array(prm.get("Activation volumes for Peierls creep"), + options); + + options.property_name = "Peierls stresses"; + peierls_stresses = Utilities::MapParsing::parse_map_to_double_array(prm.get("Peierls stresses"), + options); + + options.property_name = "Peierls fitting parameters"; + fitting_parameters = Utilities::MapParsing::parse_map_to_double_array(prm.get("Peierls fitting parameters"), + options); + + options.property_name = "Peierls glide parameters p"; + glide_parameters_p = Utilities::MapParsing::parse_map_to_double_array(prm.get("Peierls glide parameters p"), + options); + + options.property_name = "Peierls glide parameters q"; + glide_parameters_q = Utilities::MapParsing::parse_map_to_double_array(prm.get("Peierls glide parameters q"), + options); + + options.property_name = "Cutoff stresses for Peierls creep"; + stress_cutoffs = Utilities::MapParsing::parse_map_to_double_array(prm.get("Cutoff stresses for Peierls creep"), + options); + + apply_strict_cutoff = prm.get_bool("Apply strict stress cutoff for Peierls creep"); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace Rheology \ + { \ + template class PeierlsCreep; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/strain_dependent.cc.bak b/source/material_model/rheology/strain_dependent.cc.bak new file mode 100644 index 00000000000..d50c760d20c --- /dev/null +++ b/source/material_model/rheology/strain_dependent.cc.bak @@ -0,0 +1,917 @@ +/* + Copyright (C) 2019 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + namespace Rheology + { + template + void + StrainDependent::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Strain weakening mechanism", "default", + Patterns::Selection("none|finite strain tensor|total strain|plastic weakening with plastic strain only|plastic weakening with total strain only|plastic weakening with plastic strain and viscous weakening with viscous strain|viscous weakening with viscous strain only|default"), + "Whether to apply strain weakening to viscosity, cohesion and internal angle" + "of friction based on accumulated finite strain, and if yes, which method to " + "use. The following methods are available:" + "\n\n" + "\\item ``none'': No strain weakening is applied. " + "\n\n" + "\\item ``finite strain tensor'': The full finite strain tensor is tracked, " + "and its second invariant is used to weaken both the plastic yield stress " + "(specifically, the cohesion and friction angle) and the pre-yield viscosity " + "that arises from diffusion and/or dislocation creep." + "\n\n" + "\\item ``total strain'': The finite strain is approximated as the product of " + "the second invariant of the strain rate in each time step and the time step " + "size, and this quantity is integrated and tracked over time. It is used to " + "weaken both the plastic yield stress (specifically, the cohesion and friction " + "angle) and the pre-yield viscosity." + "\n\n" + "\\item ``plastic weakening with plastic strain only'': The finite strain is " + "approximated as the product of the second invariant of the strain rate" + "in each time step and the time step size in regions where material is " + "plastically yielding. This quantity is integrated and tracked over time, and " + "used to weaken the cohesion and friction angle. The pre-yield viscosity is " + "not weakened." + "\n\n" + "\\item ``plastic weakening with total strain only'': The finite strain is " + "approximated as the product of the second invariant of the strain rate in each " + "time step and the time step size, and this quantity is integrated and tracked " + "over time. It is used to weaken the plastic yield stress (specifically, the " + "cohesion and internal friction angle). The pre-yield viscosity is not weakened." + "\n\n" + "\\item ``plastic weakening with plastic strain and viscous weakening with viscous strain'': " + "Both the finite strain accumulated by plastic deformation and by viscous deformation are " + "computed separately (each approximated as the product of the second invariant of the " + "corresponding strain rate in each time step and the time step size). The plastic strain " + "is used to weaken the plastic yield stress (specifically, the cohesion and yield angle), and " + "the viscous strain is used to weaken the pre-yield viscosity." + "\n\n" + "\\item ``viscous weakening with viscous strain only'': The finite strain is " + "approximated as the product of the second invariant of the strain rate " + "in each time step and the time step size in regions where material is " + "not plastically yielding. This quantity is integrated and tracked over time, and " + "used to weaken the pre-yield viscosity. The cohesion and friction angle are " + "not weakened." + "\n\n" + "\\item ``default'': The default option has the same behavior as ``none'', " + "but is there to make sure that the original parameters for specifying the " + "strain weakening mechanism (``Use plastic/viscous strain weakening'') are still allowed, " + "but to guarantee that one uses either the old parameter names or the new ones, " + "never both." + "\n\n" + "If a compositional field named 'noninitial\\_plastic\\_strain' is " + "included in the parameter file, this field will automatically be excluded from " + "from volume fraction calculation and track the cumulative plastic strain with " + "the initial plastic strain values removed."); + + prm.declare_entry ("Start plasticity strain weakening intervals", "0.", + Patterns::List(Patterns::Double (0.)), + "List of strain weakening interval initial strains " + "for the cohesion and friction angle parameters of the " + "background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields " + "or only those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + + prm.declare_entry ("End plasticity strain weakening intervals", "1.", + Patterns::List(Patterns::Double (0.)), + "List of strain weakening interval final strains " + "for the cohesion and friction angle parameters of the " + "background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields " + "or only those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + + prm.declare_entry ("Cohesion strain weakening factors", "1.", + Patterns::List(Patterns::Double (0.)), + "List of cohesion strain weakening factors " + "for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields " + "or only those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + + prm.declare_entry ("Friction strain weakening factors", "1.", + Patterns::List(Patterns::Double (0.)), + "List of friction strain weakening factors " + "for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields " + "or only those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + + prm.declare_entry ("Start prefactor strain weakening intervals", "0.", + Patterns::List(Patterns::Double (0.)), + "List of strain weakening interval initial strains " + "for the diffusion and dislocation prefactor parameters of the " + "background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields " + "or only those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + + prm.declare_entry ("End prefactor strain weakening intervals", "1.", + Patterns::List(Patterns::Double (0.)), + "List of strain weakening interval final strains " + "for the diffusion and dislocation prefactor parameters of the " + "background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields " + "or only those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + + prm.declare_entry ("Prefactor strain weakening factors", "1.", + Patterns::List(Patterns::Double(0., 1.)), + "List of viscous strain weakening factors " + "for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields " + "or only those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: None."); + + + prm.declare_entry ("Use temperature activated strain softening", "false", + Patterns::Bool (), + "Whether viscous strain softening factor depends on temperature"); + + prm.declare_entry ("Lower temperature for onset of strain weakening", "823.", + Patterns::List(Patterns::Double (0.)), + "List of lower temperature for onset of strain weakening " + "for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields " + "or only those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: \\si{\\kelvin}."); + + prm.declare_entry ("Lower temperature for maximum strain weakening", "923.", + Patterns::List(Patterns::Double (0.)), + "List of lower temperature for maximum strain weakening " + "for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields " + "or only those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: \\si{\\kelvin}."); + + prm.declare_entry ("Upper temperature for maximum strain weakening", "1023.", + Patterns::List(Patterns::Double (0.)), + "List of upper temperatures for maximum strain weakening " + "for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields " + "or only those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: \\si{\\kelvin}."); + + prm.declare_entry ("Upper temperature for onset of strain weakening", "1123.", + Patterns::List(Patterns::Double (0.)), + "List of upper temperatures for onset of strain weakening" + "for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields " + "or only those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. Units: \\si{\\kelvin}."); + + prm.declare_entry ("Strain healing mechanism", "no healing", + Patterns::Selection("no healing|temperature dependent"), + "Whether to apply strain healing to plastic yielding and viscosity terms, " + "and if yes, which method to use. The following methods are available:" + "\n\n" + "\\item ``no healing'': No strain healing is applied. " + "\n\n" + "\\item ``temperature dependent'': Purely temperature dependent " + "strain healing applied to plastic yielding and viscosity terms, similar " + "to the temperature-dependent Frank Kamenetskii formulation, computes " + "strain healing as removing strain as a function of temperature, time, " + "and a user-defined healing rate and prefactor " + "as done in Fuchs and Becker, 2019, for mantle convection"); + + prm.declare_entry ("Strain healing temperature dependent recovery rate", "1.e-15", Patterns::Double(0), + "Recovery rate prefactor for temperature dependent " + "strain healing. Units: $1/s$"); + + prm.declare_entry ("Strain healing temperature dependent prefactor", "15.", Patterns::Double(0), + "Prefactor for temperature dependent " + "strain healing. Units: None"); + } + + template + void + StrainDependent::parse_parameters (ParameterHandler &prm) + { + // number of required compositional fields for full finite strain tensor + const unsigned int s = Tensor<2,dim>::n_independent_components; + + // Strain weakening parameters + if (prm.get ("Strain weakening mechanism") == "none") + weakening_mechanism = none; + else if (prm.get ("Strain weakening mechanism") == "finite strain tensor") + weakening_mechanism = finite_strain_tensor; + else if (prm.get ("Strain weakening mechanism") == "total strain") + weakening_mechanism = total_strain; + else if (prm.get ("Strain weakening mechanism") == "plastic weakening with plastic strain only") + weakening_mechanism = plastic_weakening_with_plastic_strain_only; + else if (prm.get ("Strain weakening mechanism") == "plastic weakening with total strain only") + weakening_mechanism = plastic_weakening_with_total_strain_only; + else if (prm.get ("Strain weakening mechanism") == "plastic weakening with plastic strain and viscous weakening with viscous strain") + weakening_mechanism = plastic_weakening_with_plastic_strain_and_viscous_weakening_with_viscous_strain; + else if (prm.get ("Strain weakening mechanism") == "viscous weakening with viscous strain only") + weakening_mechanism = viscous_weakening_with_viscous_strain_only; + else if (prm.get ("Strain weakening mechanism") == "default") + weakening_mechanism = none; + else + AssertThrow(false, ExcMessage("Not a valid Strain weakening mechanism!")); + + if (weakening_mechanism == plastic_weakening_with_plastic_strain_only + || weakening_mechanism == plastic_weakening_with_plastic_strain_and_viscous_weakening_with_viscous_strain) + { + AssertThrow(this->introspection().compositional_name_exists("plastic_strain"), + ExcMessage("Material model visco_plastic with plastic strain weakening only works if there is a " + "compositional field called plastic_strain.")); + } + + if (weakening_mechanism == viscous_weakening_with_viscous_strain_only + || weakening_mechanism == plastic_weakening_with_plastic_strain_and_viscous_weakening_with_viscous_strain) + { + AssertThrow(this->introspection().compositional_name_exists("viscous_strain"), + ExcMessage("Material model visco_plastic with viscous strain weakening only works if there is a " + "compositional field called viscous_strain.")); + } + + if (weakening_mechanism == finite_strain_tensor) + { + AssertThrow(this->n_compositional_fields() >= s, + ExcMessage("There must be enough compositional fields to track all components of the finite strain tensor (4 in 2d, 9 in 3d). ")); + // Assert that fields exist and that they are in the right order + const unsigned int n_s11 = this->introspection().compositional_index_for_name("s11"); + const unsigned int n_s12 = this->introspection().compositional_index_for_name("s12"); + const unsigned int n_s21 = this->introspection().compositional_index_for_name("s21"); + const unsigned int n_s22 = this->introspection().compositional_index_for_name("s22"); + if (dim==2) + { + AssertThrow(n_s11 < n_s12 && n_s12 < n_s21 && n_s21 < n_s22, + ExcMessage("A material model with strain weakening using the full strain tensor only works if there are " + "compositional fields called sij, with i=1,..,dim and j=1,...,dim listed in the following order: " + "s11, s12, s21, s22.")); + AssertThrow(n_s22 == n_s11+s-1, ExcMessage("The strain tensor components should be represented by consecutive fields.")); + } + if (dim==3) + { + const unsigned int n_s13 = this->introspection().compositional_index_for_name("s13"); + const unsigned int n_s23 = this->introspection().compositional_index_for_name("s23"); + const unsigned int n_s31 = this->introspection().compositional_index_for_name("s31"); + const unsigned int n_s32 = this->introspection().compositional_index_for_name("s32"); + const unsigned int n_s33 = this->introspection().compositional_index_for_name("s33"); + AssertThrow(n_s11 < n_s12 && n_s12 < n_s13 && n_s13 < n_s21 && n_s21 < n_s22 && n_s22 < n_s23 && n_s23 < n_s31 && n_s31 < n_s32 && n_s32 < n_s33, + ExcMessage("A material model with strain weakening using the full strain tensor only works if there are " + "compositional fields called sij, with i=1,..,dim and j=1,...,dim listed in the following order: " + "s11, s12, s13, s21, s22, s23, s31, s32, s33.")); + AssertThrow(n_s33 == n_s11+s-1, ExcMessage("The strain tensor components should be represented by consecutive fields.")); + } + } + + + if (weakening_mechanism == total_strain || weakening_mechanism == plastic_weakening_with_total_strain_only) + AssertThrow(this->introspection().compositional_name_exists("total_strain"), + ExcMessage("Material model visco_plastic with total strain weakening only works if there is a " + "compositional field called total_strain.")); + + // Currently, it only makes sense to use this material model with strain weakening when the + // nonlinear solver scheme does a single advection iteration. More than one nonlinear advection + // iteration will result in the incorrect value of strain being used in the material model, as + // the compositional fields representing strain are updated through the reaction terms. + if (weakening_mechanism != none) + { + AssertThrow((this->get_parameters().nonlinear_solver == + Parameters::NonlinearSolver::single_Advection_single_Stokes + || + this->get_parameters().nonlinear_solver == + Parameters::NonlinearSolver::single_Advection_iterated_Stokes + || + this->get_parameters().nonlinear_solver == + Parameters::NonlinearSolver::iterated_Advection_and_Stokes + || + this->get_parameters().nonlinear_solver == + Parameters::NonlinearSolver::single_Advection_iterated_Newton_Stokes + || + this->get_parameters().nonlinear_solver == + Parameters::NonlinearSolver::iterated_Advection_and_Newton_Stokes + || + this->get_parameters().nonlinear_solver == + Parameters::NonlinearSolver::single_Advection_iterated_defect_correction_Stokes + || + this->get_parameters().nonlinear_solver == + Parameters::NonlinearSolver::iterated_Advection_and_defect_correction_Stokes + || + this->get_parameters().nonlinear_solver == + Parameters::NonlinearSolver::no_Advection_no_Stokes), + ExcMessage("The material model will only work with the nonlinear " + "solver schemes 'single Advection, single Stokes', " + "'single Advection, iterated Stokes', " + "'iterated Advection and Stokes', " + "'single Advection, iterated Newton Stokes', " + "'iterated Advection and Newton Stokes', " + "'single Advection, iterated defect correction Stokes', " + "'iterated Advection and defect correction Stokes, and' " + "'no Advection, no Stokes' " + "when strain weakening is enabled.")); + } + + + // Retrieve the list of composition names + std::vector compositional_field_names = this->introspection().get_composition_names(); + + // Retrieve the list of names of fields that represent chemical compositions, and not, e.g., + // plastic strain + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + + // Establish that a background field is required here + compositional_field_names.insert(compositional_field_names.begin(), "background"); + chemical_field_names.insert(chemical_field_names.begin(),"background"); + + Utilities::MapParsing::Options options(chemical_field_names, "Start plasticity strain weakening intervals"); + options.list_of_allowed_keys = compositional_field_names; + + start_plastic_strain_weakening_intervals = Utilities::MapParsing::parse_map_to_double_array(prm.get("Start plasticity strain weakening intervals"), + options); + + options.property_name = "End plasticity strain weakening intervals"; + end_plastic_strain_weakening_intervals = Utilities::MapParsing::parse_map_to_double_array(prm.get("End plasticity strain weakening intervals"), + options); + + options.property_name = "Start prefactor strain weakening intervals"; + start_viscous_strain_weakening_intervals = Utilities::MapParsing::parse_map_to_double_array(prm.get("Start prefactor strain weakening intervals"), + options); + + options.property_name = "End prefactor strain weakening intervals"; + end_viscous_strain_weakening_intervals = Utilities::MapParsing::parse_map_to_double_array(prm.get("End prefactor strain weakening intervals"), + options); + + options.property_name = "Prefactor strain weakening factors"; + viscous_strain_weakening_factors = Utilities::MapParsing::parse_map_to_double_array(prm.get("Prefactor strain weakening factors"), + options); + + options.property_name = "Lower temperature for onset of strain weakening"; + viscous_strain_weakening_T0 = Utilities::MapParsing::parse_map_to_double_array(prm.get("Lower temperature for onset of strain weakening"), + options); + + options.property_name = "Lower temperature for maximum strain weakening"; + viscous_strain_weakening_T1 = Utilities::MapParsing::parse_map_to_double_array(prm.get("Lower temperature for maximum strain weakening"), + options); + + options.property_name = "Upper temperature for maximum strain weakening"; + viscous_strain_weakening_T2 = Utilities::MapParsing::parse_map_to_double_array(prm.get("Upper temperature for maximum strain weakening"), + options); + + options.property_name = "Upper temperature for onset of strain weakening"; + viscous_strain_weakening_T3 = Utilities::MapParsing::parse_map_to_double_array(prm.get("Upper temperature for onset of strain weakening"), + options); + + use_temperature_activated_strain_softening = prm.get_bool("Use temperature activated strain softening"); + + + options.property_name = "Cohesion strain weakening factors"; + cohesion_strain_weakening_factors = Utilities::MapParsing::parse_map_to_double_array(prm.get("Cohesion strain weakening factors"), + options); + + options.property_name = "Friction strain weakening factors"; + friction_strain_weakening_factors = Utilities::MapParsing::parse_map_to_double_array(prm.get("Friction strain weakening factors"), + options); + + if (prm.get ("Strain healing mechanism") == "no healing") + healing_mechanism = no_healing; + else if (prm.get ("Strain healing mechanism") == "temperature dependent") + healing_mechanism = temperature_dependent; + else + AssertThrow(false, ExcMessage("Not a valid Strain healing mechanism!")); + + // Currently this functionality only works in field composition + if (healing_mechanism != no_healing && this->n_particle_worlds() > 0) + { + const Particle::Property::Manager &particle_property_manager = this->get_particle_world(0).get_property_manager(); + AssertThrow(particle_property_manager.plugin_name_exists("viscoplastic strain invariants") == false, ExcMessage("This healing mechanism currently does not work if the strain is tracked on particles.")); + } + + // Temperature dependent strain healing requires that adiabatic surface temperature is non zero + if (healing_mechanism == temperature_dependent) + { + AssertThrow (this->get_adiabatic_surface_temperature() > 0.0, + ExcMessage("The temperature dependent strain healing can only be used when the adiabatic " + "surface temperature (reference_temperature in equation for strain healing) " + "is non-zero.")); + } + + strain_healing_temperature_dependent_recovery_rate = prm.get_double ("Strain healing temperature dependent recovery rate"); + + strain_healing_temperature_dependent_prefactor = prm.get_double ("Strain healing temperature dependent prefactor"); + } + + + + template + std::array + StrainDependent:: + compute_strain_weakening_factors(const std::vector &composition, + const unsigned int j) const + { + double viscous_weakening = 1.0; + std::pair brittle_weakening (1.0, 1.0); + + switch (weakening_mechanism) + { + case none: + { + break; + } + case finite_strain_tensor: + { + // Calculate second invariant of left stretching tensor "L" + const Tensor<2,dim> strain(make_array_view(&composition[0], + &composition[0] + Tensor<2,dim>::n_independent_components)); + const SymmetricTensor<2,dim> L = symmetrize( strain * transpose(strain) ); + + const double strain_ii = std::fabs(second_invariant(L)); + brittle_weakening = calculate_plastic_weakening(strain_ii, j); + viscous_weakening = calculate_viscous_weakening(strain_ii, j); + break; + } + case total_strain: + { + const unsigned int total_strain_index = this->introspection().compositional_index_for_name("total_strain"); + brittle_weakening = calculate_plastic_weakening(composition[total_strain_index], j); + viscous_weakening = calculate_viscous_weakening(composition[total_strain_index], j); + break; + } + case plastic_weakening_with_total_strain_only: + { + const unsigned int total_strain_index = this->introspection().compositional_index_for_name("total_strain"); + brittle_weakening = calculate_plastic_weakening(composition[total_strain_index], j); + break; + } + case plastic_weakening_with_plastic_strain_only: + { + const unsigned int plastic_strain_index = this->introspection().compositional_index_for_name("plastic_strain"); + brittle_weakening = calculate_plastic_weakening(composition[plastic_strain_index], j); + break; + } + case plastic_weakening_with_plastic_strain_and_viscous_weakening_with_viscous_strain: + { + const unsigned int plastic_strain_index = this->introspection().compositional_index_for_name("plastic_strain"); + brittle_weakening = calculate_plastic_weakening(composition[plastic_strain_index], j); + const unsigned int viscous_strain_index = this->introspection().compositional_index_for_name("viscous_strain"); + viscous_weakening = calculate_viscous_weakening(composition[viscous_strain_index], j); + break; + } + case viscous_weakening_with_viscous_strain_only: + { + const unsigned int viscous_strain_index = this->introspection().compositional_index_for_name("viscous_strain"); + viscous_weakening = calculate_viscous_weakening(composition[viscous_strain_index], j); + break; + } + default: + { + AssertThrow(false, ExcNotImplemented()); + break; + } + } + + const std::array weakening_factors = {{brittle_weakening.first,brittle_weakening.second,viscous_weakening}}; + + return weakening_factors; + + } + + + + template + std::array + StrainDependent:: + compute_strain_weakening_factors(const unsigned int j, + const std::vector &composition) const + { + return compute_strain_weakening_factors(composition,j); + } + + + + template + std::array + StrainDependent:: + apply_temperature_dependence_to_strain_weakening_factors(const std::array &weakening_factors, + const double temperature, + const unsigned int j) const + { + + double factor = 1; + const double T0 = viscous_strain_weakening_T0[j]; + const double T1 = viscous_strain_weakening_T1[j]; + const double T2 = viscous_strain_weakening_T2[j]; + const double T3 = viscous_strain_weakening_T3[j]; + std::array output = weakening_factors; + + if (temperature>T0 && temperature<=T1) + factor = (output[2]-1.) / (T1-T0)*(temperature-T0) + 1.; + else if (temperature>T1 && temperature<=T2) + factor = output[2]; + else if (temperature>T2 && temperature<=T3) + factor = (1-output[2]) / (T3-T2)*(temperature-T2) + output[2]; + output[2] = factor; + + return output; + + } + + + + template + double + StrainDependent:: + calculate_strain_healing(const MaterialModel::MaterialModelInputs &in, + const unsigned int j) const + { + const double reference_temperature = this->get_adiabatic_surface_temperature(); + double healed_strain = 0.0; + + switch (healing_mechanism) + { + case no_healing: + { + break; + } + case temperature_dependent: + { + healed_strain = strain_healing_temperature_dependent_recovery_rate * + std::exp(-strain_healing_temperature_dependent_prefactor * 0.5 * (1.0 - in.temperature[j]/reference_temperature)) + * this->get_timestep(); + break; + } + } + return healed_strain; + } + + template + std::pair + StrainDependent:: + calculate_plastic_weakening(const double strain_ii, + const unsigned int j) const + { + // Constrain the second strain invariant of the previous timestep by the strain interval + const double cut_off_strain_ii = std::max(std::min(strain_ii,end_plastic_strain_weakening_intervals[j]),start_plastic_strain_weakening_intervals[j]); + + // Linear strain weakening of cohesion and internal friction angle between specified strain values + const double strain_fraction = (cut_off_strain_ii - start_plastic_strain_weakening_intervals[j]) / + (start_plastic_strain_weakening_intervals[j] - end_plastic_strain_weakening_intervals[j]); + + const double weakening_cohesion = 1. + (1. - cohesion_strain_weakening_factors[j]) * strain_fraction; + const double weakening_friction = 1. + (1. - friction_strain_weakening_factors[j]) * strain_fraction; + + return std::make_pair (weakening_cohesion, weakening_friction); + } + + + template + double + StrainDependent:: + calculate_viscous_weakening(const double strain_ii, + const unsigned int j) const + { + // Constrain the second strain invariant of the previous timestep by the strain interval + const double cut_off_strain_ii = std::max(std::min(strain_ii,end_viscous_strain_weakening_intervals[j]),start_viscous_strain_weakening_intervals[j]); + + // Linear strain weakening of the viscous flow law prefactors between specified strain values + const double strain_fraction = (cut_off_strain_ii - start_viscous_strain_weakening_intervals[j]) / + (start_viscous_strain_weakening_intervals[j] - end_viscous_strain_weakening_intervals[j]); + return 1. + ( 1. - viscous_strain_weakening_factors[j] ) * strain_fraction; + } + + template + void + StrainDependent:: + fill_reaction_outputs (const MaterialModel::MaterialModelInputs &in, + const int i, + const double min_strain_rate, + const bool plastic_yielding, + MaterialModel::MaterialModelOutputs &out) const + { + + // If strain weakening is used, overwrite the first reaction term, + // which represents the second invariant of the (plastic) strain tensor. + // If plastic strain is tracked (so not the total strain), only overwrite + // when plastically yielding. + // If viscous strain is also tracked, overwrite the second reaction term as well. + // Calculate changes in strain and update the reaction terms + if (this->simulator_is_past_initialization() && this->get_timestep_number() > 0 && in.requests_property(MaterialProperties::reaction_terms)) + { + Assert(std::isfinite(in.strain_rate[i].norm()), + ExcMessage("Invalid strain_rate in the MaterialModelInputs. This is likely because it was " + "not filled by the caller.")); + + const double edot_ii = std::max(std::sqrt(std::max(-second_invariant(deviator(in.strain_rate[i])), 0.)), + min_strain_rate); + double delta_e_ii = edot_ii*this->get_timestep(); + + // Assign accumulated strain value according to active deformation mechanism + + // Plastic strain + double delta_e_ii_plastic = 0.; + if (plastic_yielding == true) + delta_e_ii_plastic = delta_e_ii; + + // Viscous strain + double delta_e_ii_viscous = 0.; + if (plastic_yielding == false) + delta_e_ii_viscous = delta_e_ii; + + // Now account for strain healing + if (healing_mechanism != no_healing) + { + // Temperature-dependent healing occurs independent of deformation state + const double healed_strain = calculate_strain_healing(in,i); + + delta_e_ii_plastic -= healed_strain; + delta_e_ii_viscous -= healed_strain; + delta_e_ii -= healed_strain; + } + + // We need to obtain the strain values from compositional fields at the previous time step, + // as the values from the current linearization point are an extrapolation of the solution + // from the old timesteps. + // Prepare the field function and extract the old solution values at the current cell. + std::vector> quadrature_positions(1,this->get_mapping().transform_real_to_unit_cell(in.current_cell, in.position[i])); + + // Use a boost::small_vector to avoid memory allocation if possible. + // Create 100 values by default, which should be enough for most cases. + // If there are more than 100 DoFs per cell, this will work like a normal vector. + boost::container::small_vector old_solution_values(this->get_fe().dofs_per_cell); + in.current_cell->get_dof_values(this->get_old_solution(), + old_solution_values.begin(), + old_solution_values.end()); + + // If we have not been here before, create one evaluator for each compositional field + if (composition_evaluators.size() == 0) + composition_evaluators.resize(this->n_compositional_fields()); + + // Make sure the evaluators have been initialized correctly, and have not been tampered with + Assert(composition_evaluators.size() == this->n_compositional_fields(), + ExcMessage("The number of composition evaluators should be equal to the number of compositional fields.")); + + const auto &component_indices = this->introspection().component_indices.compositional_fields; + + // Assign incremental strain values to reaction terms + if (weakening_mechanism == plastic_weakening_with_plastic_strain_only) + { + const unsigned int strain_index = this->introspection().compositional_index_for_name("plastic_strain"); + // Only create the evaluator the first time we get here + if (!composition_evaluators[strain_index]) + composition_evaluators[strain_index] + = std::make_unique>(this->get_mapping(), + this->get_fe(), + update_values, + component_indices[strain_index]); + + composition_evaluators[strain_index]->reinit(in.current_cell, quadrature_positions); + composition_evaluators[strain_index]->evaluate({old_solution_values.data(),old_solution_values.size()}, + EvaluationFlags::values); + out.reaction_terms[i][strain_index] = std::max(delta_e_ii_plastic, + -composition_evaluators[strain_index]->get_value(0)); + } + if (weakening_mechanism == viscous_weakening_with_viscous_strain_only) + { + const unsigned int strain_index = this->introspection().compositional_index_for_name("viscous_strain"); + // Only create the evaluator the first time we get here + if (!composition_evaluators[strain_index]) + composition_evaluators[strain_index] + = std::make_unique>(this->get_mapping(), + this->get_fe(), + update_values, + component_indices[strain_index]); + + composition_evaluators[strain_index]->reinit(in.current_cell, quadrature_positions); + composition_evaluators[strain_index]->evaluate({old_solution_values.data(),old_solution_values.size()}, + EvaluationFlags::values); + out.reaction_terms[i][strain_index] = std::max(delta_e_ii_viscous, + -composition_evaluators[strain_index]->get_value(0)); + } + if (weakening_mechanism == total_strain || weakening_mechanism == plastic_weakening_with_total_strain_only) + { + const unsigned int strain_index = this->introspection().compositional_index_for_name("total_strain"); + // Only create the evaluator the first time we get here + if (!composition_evaluators[strain_index]) + composition_evaluators[strain_index] + = std::make_unique>(this->get_mapping(), + this->get_fe(), + update_values, + component_indices[strain_index]); + composition_evaluators[strain_index]->reinit(in.current_cell, quadrature_positions); + composition_evaluators[strain_index]->evaluate({old_solution_values.data(),old_solution_values.size()}, + EvaluationFlags::values); + out.reaction_terms[i][strain_index] = std::max(delta_e_ii, + -composition_evaluators[strain_index]->get_value(0)); + } + if (weakening_mechanism == plastic_weakening_with_plastic_strain_and_viscous_weakening_with_viscous_strain) + { + const unsigned int plastic_strain_index = this->introspection().compositional_index_for_name("plastic_strain"); + // Only create the evaluator the first time we get here + if (!composition_evaluators[plastic_strain_index]) + composition_evaluators[plastic_strain_index] + = std::make_unique>(this->get_mapping(), + this->get_fe(), + update_values, + component_indices[plastic_strain_index]); + composition_evaluators[plastic_strain_index]->reinit(in.current_cell, quadrature_positions); + composition_evaluators[plastic_strain_index]->evaluate({old_solution_values.data(),old_solution_values.size()}, + EvaluationFlags::values); + out.reaction_terms[i][plastic_strain_index] = std::max(delta_e_ii_plastic, + -composition_evaluators[plastic_strain_index]->get_value(0)); + + const unsigned viscous_strain_index = this->introspection().compositional_index_for_name("viscous_strain"); + // Only create the evaluator the first time we get here + if (!composition_evaluators[viscous_strain_index]) + composition_evaluators[viscous_strain_index] + = std::make_unique>(this->get_mapping(), + this->get_fe(), + update_values, + component_indices[viscous_strain_index]); + composition_evaluators[viscous_strain_index]->reinit(in.current_cell, quadrature_positions); + composition_evaluators[viscous_strain_index]->evaluate({old_solution_values.data(),old_solution_values.size()}, + EvaluationFlags::values); + out.reaction_terms[i][viscous_strain_index] = std::max(delta_e_ii_viscous, + -composition_evaluators[viscous_strain_index]->get_value(0)); + } + if (this->introspection().compositional_name_exists("noninitial_plastic_strain")) + { + const unsigned int strain_index = this->introspection().compositional_index_for_name("noninitial_plastic_strain"); + // Only create the evaluator the first time we get here + if (!composition_evaluators[strain_index]) + composition_evaluators[strain_index] + = std::make_unique>(this->get_mapping(), + this->get_fe(), + update_values, + component_indices[strain_index]); + + composition_evaluators[strain_index]->reinit(in.current_cell, quadrature_positions); + composition_evaluators[strain_index]->evaluate({old_solution_values.data(),old_solution_values.size()}, + EvaluationFlags::values); + out.reaction_terms[i][strain_index] = std::max(delta_e_ii_plastic, + -composition_evaluators[strain_index]->get_value(0)); + } + } + } + + + template + void + StrainDependent:: + compute_finite_strain_reaction_terms(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + + if (in.current_cell.state() == IteratorState::valid && this->get_timestep_number() > 0 && + in.requests_property(MaterialProperties::reaction_terms) && weakening_mechanism == finite_strain_tensor) + { + // We need the velocity gradient for the finite strain (they are not + // in material model inputs), so we get them from the finite element. + std::vector> quadrature_positions(in.n_evaluation_points()); + for (unsigned int i = 0; i < in.n_evaluation_points(); ++i) + quadrature_positions[i] = this->get_mapping().transform_real_to_unit_cell(in.current_cell, in.position[i]); + + std::vector solution_values(this->get_fe().dofs_per_cell); + in.current_cell->get_dof_values(this->get_solution(), + solution_values.begin(), + solution_values.end()); + + // Only create the evaluator the first time we get here + if (!evaluator) + evaluator = std::make_unique>(this->get_mapping(), + this->get_fe(), + update_gradients, + this->introspection().component_indices.velocities[0]); + + // Initialize the evaluator for the old velocity gradients + evaluator->reinit(in.current_cell, quadrature_positions); + evaluator->evaluate(solution_values, + EvaluationFlags::gradients); + + // Assign the strain components to the compositional fields reaction terms. + // If there are too many fields, we simply fill only the first fields with the + // existing strain tensor components. + + for (unsigned int q = 0; q < in.n_evaluation_points(); ++q) + { + if (in.current_cell.state() == IteratorState::valid) + + { + // Convert the compositional fields into the tensor quantity they represent. + Tensor<2, dim> strain; + const unsigned int n_first = this->introspection().compositional_index_for_name("s11"); + for (unsigned int i = n_first; i < n_first + Tensor<2, dim>::n_independent_components; ++i) + { + strain[Tensor<2, dim>::unrolled_to_component_indices(i)] = in.composition[q][i]; + } + + // Compute the strain accumulated in this timestep. + const Tensor<2, dim> strain_increment = this->get_timestep() * (evaluator->get_gradient(q) * strain); + + // Output the strain increment component-wise to its respective compositional field's reaction terms. + for (unsigned int i = n_first; i < n_first + Tensor<2, dim>::n_independent_components; ++i) + { + out.reaction_terms[q][i] = strain_increment[Tensor<2, dim>::unrolled_to_component_indices(i)]; + } + } + } + } + } + + template + ComponentMask + StrainDependent:: + get_strain_composition_mask() const + { + + // Store which components to exclude during volume fraction computation. + ComponentMask strain_mask(this->n_compositional_fields(),true); + + if (weakening_mechanism != none) + { + if (weakening_mechanism == plastic_weakening_with_plastic_strain_only || weakening_mechanism == plastic_weakening_with_plastic_strain_and_viscous_weakening_with_viscous_strain) + strain_mask.set(this->introspection().compositional_index_for_name("plastic_strain"),false); + + if (weakening_mechanism == viscous_weakening_with_viscous_strain_only || weakening_mechanism == plastic_weakening_with_plastic_strain_and_viscous_weakening_with_viscous_strain) + strain_mask.set(this->introspection().compositional_index_for_name("viscous_strain"),false); + + if (weakening_mechanism == total_strain || weakening_mechanism == plastic_weakening_with_total_strain_only) + strain_mask.set(this->introspection().compositional_index_for_name("total_strain"),false); + + if (weakening_mechanism == finite_strain_tensor) + { + const unsigned int n_start = this->introspection().compositional_index_for_name("s11"); + for (unsigned int i = n_start; i < n_start + Tensor<2,dim>::n_independent_components ; ++i) + strain_mask.set(i,false); + } + } + + if (this->introspection().compositional_name_exists("noninitial_plastic_strain")) + strain_mask.set(this->introspection().compositional_index_for_name("noninitial_plastic_strain"),false); + + return strain_mask; + } + + template + WeakeningMechanism + StrainDependent:: + get_weakening_mechanism() const + { + return weakening_mechanism; + } + + template + HealingMechanism + StrainDependent:: + get_healing_mechanism() const + { + return healing_mechanism; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + namespace Rheology \ + { \ + template class StrainDependent; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/rheology/visco_plastic.cc.bak b/source/material_model/rheology/visco_plastic.cc.bak new file mode 100644 index 00000000000..2fe6259e7d2 --- /dev/null +++ b/source/material_model/rheology/visco_plastic.cc.bak @@ -0,0 +1,855 @@ +/* + Copyright (C) 2020 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + namespace + { + std::vector make_plastic_additional_outputs_names() + { + std::vector names; + names.emplace_back("current_cohesions"); + names.emplace_back("current_friction_angles"); + names.emplace_back("current_yield_stresses"); + names.emplace_back("plastic_yielding"); + return names; + } + } + + template + PlasticAdditionalOutputs::PlasticAdditionalOutputs(const unsigned int n_points) + : NamedAdditionalMaterialOutputs(make_plastic_additional_outputs_names()), + cohesions(n_points, numbers::signaling_nan()), + friction_angles(n_points, numbers::signaling_nan()), + yield_stresses(n_points, numbers::signaling_nan()), + yielding(n_points, numbers::signaling_nan()) + {} + + + + template + std::vector + PlasticAdditionalOutputs::get_nth_output(const unsigned int idx) const + { + AssertIndexRange (idx, 4); + switch (idx) + { + case 0: + return cohesions; + + case 1: + return friction_angles; + + case 2: + return yield_stresses; + + case 3: + return yielding; + + default: + AssertThrow(false, ExcInternalError()); + } + // We will never get here, so just return something + return cohesions; + } + + + + namespace Rheology + { + + template + ViscoPlastic::ViscoPlastic () + = default; + + + + template + IsostrainViscosities + ViscoPlastic:: + calculate_isostrain_viscosities (const MaterialModel::MaterialModelInputs &in, + const unsigned int i, + const std::vector &volume_fractions, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + IsostrainViscosities output_parameters; + + // Initialize or fill variables used to calculate viscosities + output_parameters.composition_yielding.resize(volume_fractions.size(), false); + output_parameters.composition_viscosities.resize(volume_fractions.size(), numbers::signaling_nan()); + output_parameters.current_friction_angles.resize(volume_fractions.size(), numbers::signaling_nan()); + output_parameters.current_cohesions.resize(volume_fractions.size(), numbers::signaling_nan()); + + // Assemble stress tensor if elastic behavior is enabled + SymmetricTensor<2,dim> stress_old = numbers::signaling_nan>(); + if (this->get_parameters().enable_elasticity) + { + for (unsigned int j=0; j < SymmetricTensor<2,dim>::n_independent_components; ++j) + stress_old[SymmetricTensor<2,dim>::unrolled_to_component_indices(j)] = in.composition[i][j]; + } + + // Use a specified "reference" strain rate if the strain rate is not yet available, + // or close to zero. This is to avoid division by zero. + const bool use_reference_strainrate = this->simulator_is_past_initialization() == false + || + (this->get_timestep_number() == 0 && + this->get_nonlinear_iteration() == 0) + || + (in.strain_rate[i].norm() <= std::numeric_limits::min()); + + double edot_ii; + if (use_reference_strainrate) + edot_ii = ref_strain_rate; + else + // Calculate the square root of the second moment invariant for the deviatoric strain rate tensor. + edot_ii = std::max(std::sqrt(std::max(-second_invariant(deviator(in.strain_rate[i])), 0.)), + min_strain_rate); + + // Calculate viscosities for each of the individual compositional phases + for (unsigned int j=0; j < volume_fractions.size(); ++j) + { + // Step 1: viscous behavior + double non_yielding_viscosity = numbers::signaling_nan(); + + // Choice of activation volume depends on whether there is an adiabatic temperature + // gradient used when calculating the viscosity. This allows the same activation volume + // to be used in incompressible and compressible models. + const double temperature_for_viscosity = (this->simulator_is_past_initialization()) + ? + in.temperature[i] + adiabatic_temperature_gradient_for_viscosity*in.pressure[i] + : + this->get_adiabatic_conditions().temperature(in.position[i]); + + AssertThrow(temperature_for_viscosity != 0, ExcMessage( + "The temperature used in the calculation of the visco-plastic rheology is zero. " + "This is not allowed, because this value is used to divide through. It is probably " + "being caused by the temperature being zero somewhere in the model. The relevant " + "values for debugging are: temperature (" + Utilities::to_string(in.temperature[i]) + + "), adiabatic_temperature_gradient_for_viscosity (" + + Utilities::to_string(adiabatic_temperature_gradient_for_viscosity) + ") and pressure (" + + Utilities::to_string(in.pressure[i]) + ").")); + { + + // Step 1a: compute viscosity from diffusion creep law, at least if it is going to be used + + // Determine whether to use the adiabatic pressure instead of the full pressure (default) + // when calculating creep viscosity. + double pressure_for_creep = in.pressure[i]; + + if (use_adiabatic_pressure_in_creep) + pressure_for_creep = this->get_adiabatic_conditions().pressure(in.position[i]); + + const double viscosity_diffusion + = (viscous_flow_law != dislocation + ? + diffusion_creep.compute_viscosity(pressure_for_creep, temperature_for_viscosity, j, + phase_function_values, + n_phase_transitions_per_composition) + : + numbers::signaling_nan()); + + // Step 1b: compute viscosity from dislocation creep law + const double viscosity_dislocation + = (viscous_flow_law != diffusion + ? + dislocation_creep.compute_viscosity(edot_ii, pressure_for_creep, temperature_for_viscosity, j, + phase_function_values, + n_phase_transitions_per_composition) + : + numbers::signaling_nan()); + + // Step 1c: select which form of viscosity to use (diffusion, dislocation, fk, or composite), and apply + // pre-exponential weakening, if required. + switch (viscous_flow_law) + { + case diffusion: + { + non_yielding_viscosity = compositional_viscosity_prefactors.compute_viscosity(in, viscosity_diffusion, j, i, \ + CompositionalViscosityPrefactors::ModifiedFlowLaws::diffusion); + break; + } + case dislocation: + { + non_yielding_viscosity = compositional_viscosity_prefactors.compute_viscosity(in, viscosity_dislocation, j, i, \ + CompositionalViscosityPrefactors::ModifiedFlowLaws::dislocation); + break; + } + case frank_kamenetskii: + { + non_yielding_viscosity = frank_kamenetskii_rheology->compute_viscosity(in.temperature[i], j, + in.pressure[i], + this->get_adiabatic_conditions().density(this->get_geometry_model().representative_point(0)), + this->get_gravity_model().gravity_vector(in.position[0]).norm()); + break; + } + case composite: + { + const double scaled_viscosity_diffusion = compositional_viscosity_prefactors.compute_viscosity(in, viscosity_diffusion, j, i, \ + CompositionalViscosityPrefactors::ModifiedFlowLaws::diffusion); + const double scaled_viscosity_dislocation = compositional_viscosity_prefactors.compute_viscosity(in, viscosity_dislocation, j, i, \ + CompositionalViscosityPrefactors::ModifiedFlowLaws::dislocation); + non_yielding_viscosity = (scaled_viscosity_diffusion * scaled_viscosity_dislocation)/ + (scaled_viscosity_diffusion + scaled_viscosity_dislocation); + break; + } + default: + { + AssertThrow(false, ExcNotImplemented()); + break; + } + } + + // Step 1d: compute the viscosity from the Peierls creep law and harmonically average with current viscosities + if (use_peierls_creep) + { + const double viscosity_peierls = peierls_creep->compute_viscosity(edot_ii, pressure_for_creep, temperature_for_viscosity, j, + phase_function_values, + n_phase_transitions_per_composition); + non_yielding_viscosity = (non_yielding_viscosity * viscosity_peierls) / (non_yielding_viscosity + viscosity_peierls); + } + } + + + // Step 1e: multiply the viscosity by a constant (default value is 1) + non_yielding_viscosity = constant_viscosity_prefactors.compute_viscosity(non_yielding_viscosity, j); + + // Step 2: calculate strain weakening factors for the cohesion, friction, and pre-yield viscosity + // If no strain weakening is applied, the factors are 1. + std::array weakening_factors = strain_rheology.compute_strain_weakening_factors(in.composition[i], j); + + if (strain_rheology.use_temperature_activated_strain_softening) + weakening_factors = strain_rheology.apply_temperature_dependence_to_strain_weakening_factors(weakening_factors,temperature_for_viscosity,j); + + // Apply strain weakening to the viscous viscosity. + non_yielding_viscosity *= weakening_factors[2]; + + + // Step 3: calculate the viscous stress magnitude + // and strain rate. If requested compute visco-elastic contributions. + double effective_edot_ii = edot_ii; + + if (this->get_parameters().enable_elasticity) + { + const std::vector &elastic_shear_moduli = elastic_rheology.get_elastic_shear_moduli(); + + if (use_reference_strainrate == true) + effective_edot_ii = ref_strain_rate; + else + { + // Overwrite effective_edot_ii with a value that includes a term that accounts for + // elastic stress arising from a previous time step. + // If used, this variable is no longer the "true" strain rate, but is instead + // an effective value that enables the use of a standard isotropic viscosity + // formulation (i.e. where stress and strain are related by a scalar viscosity). + // The additional strain rate component is supported by a corresponding fictional body force. + Assert(std::isfinite(in.strain_rate[i].norm()), + ExcMessage("Invalid strain_rate in the MaterialModelInputs. This is likely because it was " + "not filled by the caller.")); + const SymmetricTensor<2,dim> effective_strain_rate = + elastic_rheology.calculate_viscoelastic_strain_rate(in.strain_rate[i], + stress_old, + elastic_shear_moduli[j]); + + effective_edot_ii = std::max(std::sqrt(std::max(-second_invariant(effective_strain_rate), 0.)), + min_strain_rate); + } + + // Step 3a: calculate the viscoelastic (effective) viscosity + non_yielding_viscosity = elastic_rheology.calculate_viscoelastic_viscosity(non_yielding_viscosity, + elastic_shear_moduli[j]); + } + + // Step 3b: calculate non yielding (viscous or viscous + elastic) stress magnitude + double non_yielding_stress = 2. * non_yielding_viscosity * effective_edot_ii; + + // Step 4a: calculate the strain-weakened friction and cohesion + const DruckerPragerParameters drucker_prager_parameters = drucker_prager_plasticity.compute_drucker_prager_parameters(j, + phase_function_values, + n_phase_transitions_per_composition); + const double current_cohesion = drucker_prager_parameters.cohesion * weakening_factors[0]; + double current_friction = drucker_prager_parameters.angle_internal_friction * weakening_factors[1]; + + // Step 4b: calculate the friction angle dependent on strain rate if specified + // apply the strain rate dependence to the friction angle (including strain weakening if present) + // Note: Maybe this should also be turned around to first apply strain rate dependence and then + // the strain weakening to the dynamic friction angle. Didn't come up with a clear argument for + // one order or the other. + current_friction = friction_models.compute_friction_angle(effective_edot_ii, + j, + current_friction, + in.position[i]); + output_parameters.current_friction_angles[j] = current_friction; + output_parameters.current_cohesions[j] = current_cohesion; + + // Step 5: plastic yielding + + // Determine if the pressure used in Drucker Prager plasticity will be capped at 0 (default). + // This may be necessary in models without gravity and when the dynamic stresses are much higher + // than the lithostatic pressure. + + double pressure_for_plasticity = in.pressure[i]; + if (allow_negative_pressures_in_plasticity == false) + pressure_for_plasticity = std::max(in.pressure[i],0.0); + + // Step 5a: calculate the Drucker-Prager yield stress + const double yield_stress = drucker_prager_plasticity.compute_yield_stress(current_cohesion, + current_friction, + pressure_for_plasticity, + drucker_prager_parameters.max_yield_stress); + + // Step 5b: select if the yield viscosity is based on Drucker Prager or a stress limiter rheology + double effective_viscosity = non_yielding_viscosity; + switch (yield_mechanism) + { + case stress_limiter: + { + //Step 5b-1: always rescale the viscosity back to the yield surface + const double viscosity_limiter = yield_stress / (2.0 * ref_strain_rate) + * std::pow((edot_ii/ref_strain_rate), + 1./exponents_stress_limiter[j] - 1.0); + effective_viscosity = 1. / ( 1./viscosity_limiter + 1./non_yielding_viscosity); + break; + } + case drucker_prager: + { + // Step 5b-2: if the non-yielding stress is greater than the yield stress, + // rescale the viscosity back to yield surface + if (non_yielding_stress >= yield_stress) + { + // The following uses the effective_edot_ii + // (which has been modified for elastic effects, above), + // and calculates the effective viscosity over all active rheological elements + // assuming that the non-yielding viscosity is not strain rate dependent + effective_viscosity = drucker_prager_plasticity.compute_viscosity(current_cohesion, + current_friction, + pressure_for_plasticity, + effective_edot_ii, + drucker_prager_parameters.max_yield_stress, + non_yielding_viscosity); + output_parameters.composition_yielding[j] = true; + } + break; + } + default: + { + AssertThrow(false, ExcNotImplemented()); + break; + } + } + + // Step 6: limit the viscosity with specified minimum and maximum bounds + const double maximum_viscosity_for_composition = MaterialModel::MaterialUtilities::phase_average_value( + phase_function_values, + n_phase_transitions_per_composition, + maximum_viscosity, + j, + MaterialModel::MaterialUtilities::PhaseUtilities::logarithmic + ); + const double minimum_viscosity_for_composition = MaterialModel::MaterialUtilities::phase_average_value( + phase_function_values, + n_phase_transitions_per_composition, + minimum_viscosity, + j, + MaterialModel::MaterialUtilities::PhaseUtilities::logarithmic + ); + output_parameters.composition_viscosities[j] = std::min(std::max(effective_viscosity, minimum_viscosity_for_composition), maximum_viscosity_for_composition); + } + return output_parameters; + } + + + + template + void + ViscoPlastic:: + compute_viscosity_derivatives(const unsigned int i, + const std::vector &volume_fractions, + const std::vector &composition_viscosities, + const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out, + const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition) const + { + MaterialModel::MaterialModelDerivatives *derivatives = + out.template get_additional_output>(); + + if (derivatives != nullptr) + { + // compute derivatives if necessary + std::vector> composition_viscosities_derivatives(volume_fractions.size()); + std::vector composition_dviscosities_dpressure(volume_fractions.size()); + + const double finite_difference_accuracy = 1e-7; + + // A new material model inputs variable that uses the strain rate and pressure difference. + MaterialModel::MaterialModelInputs in_derivatives = in; + + Assert(std::isfinite(in.strain_rate[i].norm()), + ExcMessage("Invalid strain_rate in the MaterialModelInputs. This is likely because it was " + "not filled by the caller.")); + + const SymmetricTensor<2,dim> deviatoric_strain_rate = deviator(in.strain_rate[i]); + + // For each independent component, compute the derivative. + for (unsigned int component = 0; component < SymmetricTensor<2,dim>::n_independent_components; ++component) + { + const TableIndices<2> strain_rate_indices = SymmetricTensor<2,dim>::unrolled_to_component_indices (component); + + const SymmetricTensor<2,dim> strain_rate_difference = deviatoric_strain_rate + + std::max(std::fabs(deviatoric_strain_rate[strain_rate_indices]), min_strain_rate) + * finite_difference_accuracy + * Utilities::nth_basis_for_symmetric_tensors(component); + + in_derivatives.strain_rate[i] = strain_rate_difference; + + std::vector eta_component = + calculate_isostrain_viscosities(in_derivatives, i, volume_fractions, + phase_function_values, n_phase_transitions_per_composition).composition_viscosities; + + // For each composition of the independent component, compute the derivative. + for (unsigned int composition_index = 0; composition_index < eta_component.size(); ++composition_index) + { + // compute the difference between the viscosity with and without the strain-rate difference. + double viscosity_derivative = eta_component[composition_index] - composition_viscosities[composition_index]; + if (viscosity_derivative != 0) + { + // when the difference is non-zero, divide by the difference. + viscosity_derivative /= std::max(std::fabs(strain_rate_difference[strain_rate_indices]), min_strain_rate) + * finite_difference_accuracy; + } + composition_viscosities_derivatives[composition_index][strain_rate_indices] = viscosity_derivative; + } + } + + // Now compute the derivative of the viscosity to the pressure + const double pressure_difference = in.pressure[i] + (std::fabs(in.pressure[i]) * finite_difference_accuracy); + + in_derivatives.pressure[i] = pressure_difference; + + // Modify the in_derivatives object again to take the original strain rate. + in_derivatives.strain_rate[i] = in.strain_rate[i]; + + const std::vector viscosity_difference = + calculate_isostrain_viscosities(in_derivatives, i, volume_fractions, + phase_function_values, n_phase_transitions_per_composition).composition_viscosities; + + for (unsigned int composition_index = 0; composition_index < viscosity_difference.size(); ++composition_index) + { + double viscosity_derivative = viscosity_difference[composition_index] - composition_viscosities[composition_index]; + if (viscosity_difference[composition_index] != 0) + { + if (in.pressure[i] != 0) + { + viscosity_derivative /= std::fabs(in.pressure[i]) * finite_difference_accuracy; + } + else + { + viscosity_derivative = 0; + } + } + composition_dviscosities_dpressure[composition_index] = viscosity_derivative; + } + + double viscosity_averaging_p = 0; // Geometric + if (viscosity_averaging == MaterialUtilities::harmonic) + viscosity_averaging_p = -1; + if (viscosity_averaging == MaterialUtilities::arithmetic) + viscosity_averaging_p = 1; + if (viscosity_averaging == MaterialUtilities::maximum_composition) + viscosity_averaging_p = 1000; + + derivatives->viscosity_derivative_wrt_strain_rate[i] = + Utilities::derivative_of_weighted_p_norm_average(out.viscosities[i], + volume_fractions, + composition_viscosities, + composition_viscosities_derivatives, + viscosity_averaging_p); + derivatives->viscosity_derivative_wrt_pressure[i] = + Utilities::derivative_of_weighted_p_norm_average(out.viscosities[i], + volume_fractions, + composition_viscosities, + composition_dviscosities_dpressure, + viscosity_averaging_p); + } + } + + + + template + ComponentMask + ViscoPlastic:: + get_volumetric_composition_mask() const + { + // Store which components to exclude during the volume fraction computation. + ComponentMask composition_mask = strain_rheology.get_strain_composition_mask(); + + if (this->get_parameters().enable_elasticity) + { + for (unsigned int i = 0; i < SymmetricTensor<2,dim>::n_independent_components ; ++i) + composition_mask.set(i,false); + } + + return composition_mask; + } + + + + template + void + ViscoPlastic::declare_parameters (ParameterHandler &prm) + { + Rheology::StrainDependent::declare_parameters (prm); + + Rheology::FrictionModels::declare_parameters (prm); + + Rheology::Elasticity::declare_parameters (prm); + + // Reference and minimum/maximum values + prm.declare_entry ("Minimum strain rate", "1.0e-20", Patterns::Double (0.), + "Stabilizes strain dependent viscosity. Units: \\si{\\per\\second}."); + prm.declare_entry ("Reference strain rate","1.0e-15",Patterns::Double (0.), + "Reference strain rate for first time step. Units: \\si{\\per\\second}."); + prm.declare_entry ("Minimum viscosity", "1e17", Patterns::Anything(), + "Lower cutoff for effective viscosity. Units: \\si{\\pascal\\second}. " + "List with as many components as active " + "compositional fields (material data is assumed to " + "be in order with the ordering of the fields). "); + prm.declare_entry ("Maximum viscosity", "1e28", Patterns::Anything(), + "Upper cutoff for effective viscosity. Units: \\si{\\pascal\\second}. " + "List with as many components as active " + "compositional fields (material data is assumed to " + "be in order with the ordering of the fields). "); + + // Rheological parameters + prm.declare_entry ("Viscosity averaging scheme", "harmonic", + Patterns::Selection("arithmetic|harmonic|geometric|maximum composition"), + "When more than one compositional field is present at a point " + "with different viscosities, we need to come up with an average " + "viscosity at that point. Select a weighted harmonic, arithmetic, " + "geometric, or maximum composition."); + prm.declare_entry ("Viscous flow law", "composite", + Patterns::Selection("diffusion|dislocation|frank kamenetskii|composite"), + "Select what type of viscosity law to use between diffusion, " + "dislocation, frank kamenetskii, and composite options. Soon there will be an option " + "to select a specific flow law for each assigned composition "); + prm.declare_entry ("Yield mechanism", "drucker", + Patterns::Selection("drucker|limiter"), + "Select what type of yield mechanism to use between Drucker Prager " + "and stress limiter options."); + prm.declare_entry ("Allow negative pressures in plasticity", "false", + Patterns::Bool (), + "Whether to allow negative pressures to be used in the computation " + "of plastic yield stresses and viscosities. Setting this parameter " + "to true may be advantageous in models without gravity where the " + "dynamic stresses are much higher than the lithostatic pressure. " + "If false, the minimum pressure in the plasticity formulation will " + "be set to zero."); + prm.declare_entry ("Use adiabatic pressure in creep viscosity", "false", + Patterns::Bool (), + "Whether to use the adiabatic pressure instead of the full " + "pressure (default) when calculating creep (diffusion, dislocation, " + "and peierls) viscosity. This may be helpful in models where the " + "full pressure has an unusually large negative value arising from " + "large negative dynamic pressure, resulting in solver convergence " + "issue and in some cases a viscosity of zero."); + + // Diffusion creep parameters + Rheology::DiffusionCreep::declare_parameters(prm); + + // Dislocation creep parameters + Rheology::DislocationCreep::declare_parameters(prm); + + // Frank-Kamenetskii viscosity parameters + Rheology::FrankKamenetskii::declare_parameters(prm); + + // Peierls creep parameters + Rheology::PeierlsCreep::declare_parameters(prm); + + prm.declare_entry ("Include Peierls creep", "false", + Patterns::Bool (), + "Whether to include Peierls creep in the rheological formulation."); + + // Constant viscosity prefactor parameters + Rheology::ConstantViscosityPrefactors::declare_parameters(prm); + + // Variable viscosity prefactor parameters + Rheology::CompositionalViscosityPrefactors::declare_parameters(prm); + + // Drucker Prager plasticity parameters + Rheology::DruckerPrager::declare_parameters(prm); + + // Stress limiter parameters + prm.declare_entry ("Stress limiter exponents", "1.0", + Patterns::List(Patterns::Double (0.)), + "List of stress limiter exponents, $n_{\\text{lim}}$, " + "for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. Units: none."); + + // Temperature gradient in viscosity laws to include an adiabat (note units of K/Pa) + prm.declare_entry ("Adiabat temperature gradient for viscosity", "0.0", Patterns::Double (0.), + "Add an adiabatic temperature gradient to the temperature used in the flow law " + "so that the activation volume is consistent with what one would use in a " + "earth-like (compressible) model. Default is set so this is off. " + "Note that this is a linear approximation of the real adiabatic gradient, which " + "is okay for the upper mantle, but is not really accurate for the lower mantle. " + "Using a pressure gradient of 32436 Pa/m, then a value of " + "0.3 K/km = 0.0003 K/m = 9.24e-09 K/Pa gives an earth-like adiabat." + "Units: \\si{\\kelvin\\per\\pascal}."); + } + + + + template + void + ViscoPlastic::parse_parameters (ParameterHandler &prm, + const std::unique_ptr> &expected_n_phases_per_composition) + { + strain_rheology.initialize_simulator (this->get_simulator()); + strain_rheology.parse_parameters(prm); + + friction_models.initialize_simulator (this->get_simulator()); + friction_models.parse_parameters(prm); + + if (this->get_parameters().enable_elasticity) + { + elastic_rheology.initialize_simulator (this->get_simulator()); + elastic_rheology.parse_parameters(prm); + } + + // Reference and minimum/maximum values + min_strain_rate = prm.get_double("Minimum strain rate"); + ref_strain_rate = prm.get_double("Reference strain rate"); + + // Retrieve the list of composition names + std::vector compositional_field_names = this->introspection().get_composition_names(); + + // Retrieve the list of names of fields that represent chemical compositions, and not, e.g., + // plastic strain + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + + // Establish that a background field is required here + compositional_field_names.insert(compositional_field_names.begin(), "background"); + chemical_field_names.insert(chemical_field_names.begin(), "background"); + + Utilities::MapParsing::Options options(chemical_field_names, "Minimum viscosity"); + options.list_of_allowed_keys = compositional_field_names; + options.allow_multiple_values_per_key = true; + if (expected_n_phases_per_composition) + { + options.n_values_per_key = *expected_n_phases_per_composition; + + // check_values_per_key is required to be true to duplicate single values + // if they are to be used for all phases associated with a given key. + options.check_values_per_key = true; + } + + minimum_viscosity = Utilities::MapParsing::parse_map_to_double_array (prm.get("Minimum viscosity"), + options); + + options.property_name = "Maximum viscosity"; + maximum_viscosity = Utilities::MapParsing::parse_map_to_double_array (prm.get("Maximum viscosity"), + options); + + Assert(maximum_viscosity.size() == minimum_viscosity.size(), + ExcMessage("The input parameters 'Maximum viscosity' and 'Minimum viscosity' should have the same number of entries.")); + for (auto p1 = maximum_viscosity.begin(), p2 = minimum_viscosity.begin(); + p1 != maximum_viscosity.end(); ++p1, ++p2) + AssertThrow(*p1 >= *p2, ExcMessage("Maximum viscosity should be larger or equal to the minimum viscosity.")); + + viscosity_averaging = MaterialUtilities::parse_compositional_averaging_operation ("Viscosity averaging scheme", + prm); + + // Rheological parameters + if (prm.get ("Viscous flow law") == "composite") + viscous_flow_law = composite; + else if (prm.get ("Viscous flow law") == "diffusion") + viscous_flow_law = diffusion; + else if (prm.get ("Viscous flow law") == "dislocation") + viscous_flow_law = dislocation; + else if (prm.get ("Viscous flow law") == "frank kamenetskii") + viscous_flow_law = frank_kamenetskii; + else + AssertThrow(false, ExcMessage("Not a valid viscous flow law")); + + if (prm.get ("Yield mechanism") == "drucker") + yield_mechanism = drucker_prager; + else if (prm.get ("Yield mechanism") == "limiter") + yield_mechanism = stress_limiter; + else + AssertThrow(false, ExcMessage("Not a valid yield mechanism.")); + + AssertThrow(this->get_parameters().enable_elasticity == false || yield_mechanism == drucker_prager, + ExcMessage("Elastic behavior is only tested with the " + "'drucker prager' plasticity option.")); + + allow_negative_pressures_in_plasticity = prm.get_bool ("Allow negative pressures in plasticity"); + use_adiabatic_pressure_in_creep = prm.get_bool("Use adiabatic pressure in creep viscosity"); + + // Diffusion creep parameters + diffusion_creep.initialize_simulator (this->get_simulator()); + diffusion_creep.parse_parameters(prm, expected_n_phases_per_composition); + + // Dislocation creep parameters + dislocation_creep.initialize_simulator (this->get_simulator()); + dislocation_creep.parse_parameters(prm, expected_n_phases_per_composition); + + // Frank Kamenetskii viscosity parameters + if (viscous_flow_law == frank_kamenetskii) + { + frank_kamenetskii_rheology = std::make_unique>(); + frank_kamenetskii_rheology->initialize_simulator (this->get_simulator()); + frank_kamenetskii_rheology->parse_parameters(prm); + } + + // Peierls creep parameters + use_peierls_creep = prm.get_bool ("Include Peierls creep"); + if (use_peierls_creep) + { + peierls_creep = std::make_unique>(); + peierls_creep->initialize_simulator (this->get_simulator()); + peierls_creep->parse_parameters(prm, expected_n_phases_per_composition); + } + + // Constant viscosity prefactor parameters + constant_viscosity_prefactors.initialize_simulator (this->get_simulator()); + constant_viscosity_prefactors.parse_parameters(prm); + + compositional_viscosity_prefactors.initialize_simulator (this->get_simulator()); + compositional_viscosity_prefactors.parse_parameters(prm); + + // Plasticity parameters + drucker_prager_plasticity.initialize_simulator (this->get_simulator()); + drucker_prager_plasticity.parse_parameters(prm, expected_n_phases_per_composition); + + // Stress limiter parameter (does not allow for phases per composition) + options.property_name = "Stress limiter exponents"; + options.allow_multiple_values_per_key = false; + options.check_values_per_key = false; + + exponents_stress_limiter = Utilities::MapParsing::parse_map_to_double_array (prm.get("Stress limiter exponents"), + options); + + // Include an adiabat temperature gradient in flow laws + adiabatic_temperature_gradient_for_viscosity = prm.get_double("Adiabat temperature gradient for viscosity"); + if (this->get_heating_model_manager().adiabatic_heating_enabled()) + AssertThrow (adiabatic_temperature_gradient_for_viscosity == 0.0, + ExcMessage("If adiabatic heating is enabled you should not add another adiabatic gradient" + "to the temperature for computing the viscosity, because the ambient" + "temperature profile already includes the adiabatic gradient.")); + + } + + + + template + void + ViscoPlastic::create_plastic_outputs (MaterialModel::MaterialModelOutputs &out) const + { + if (out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points)); + } + } + + template + void + ViscoPlastic:: + fill_plastic_outputs(const unsigned int i, + const std::vector &volume_fractions, + const bool plastic_yielding, + const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out, + const IsostrainViscosities &isostrain_viscosities) const + { + PlasticAdditionalOutputs *plastic_out = out.template get_additional_output>(); + + if (plastic_out != nullptr) + { + AssertThrow(in.requests_property(MaterialProperties::viscosity), + ExcMessage("The PlasticAdditionalOutputs cannot be filled when the viscosity has not been computed.")); + + plastic_out->cohesions[i] = 0; + plastic_out->friction_angles[i] = 0; + plastic_out->yield_stresses[i] = 0; + plastic_out->yielding[i] = plastic_yielding ? 1 : 0; + + const std::vector friction_angles_RAD = isostrain_viscosities.current_friction_angles; + const std::vector cohesions = isostrain_viscosities.current_cohesions; + + // The max yield stress is the same for each composition, so we give the 0th field value. + const double max_yield_stress = drucker_prager_plasticity.compute_drucker_prager_parameters(0).max_yield_stress; + + double pressure_for_plasticity = in.pressure[i]; + if (allow_negative_pressures_in_plasticity == false) + pressure_for_plasticity = std::max(in.pressure[i], 0.0); + + // average over the volume volume fractions + for (unsigned int j = 0; j < volume_fractions.size(); ++j) + { + plastic_out->cohesions[i] += volume_fractions[j] * cohesions[j]; + // Also convert radians to degrees + plastic_out->friction_angles[i] += constants::radians_to_degree * volume_fractions[j] * friction_angles_RAD[j]; + plastic_out->yield_stresses[i] += volume_fractions[j] * drucker_prager_plasticity.compute_yield_stress(cohesions[j], + friction_angles_RAD[j], + pressure_for_plasticity, + max_yield_stress); + + } + } + } + + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { +#define INSTANTIATE(dim) \ + template class PlasticAdditionalOutputs; \ + \ + namespace Rheology \ + { \ + template class ViscoPlastic; \ + } + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/material_model/simple.cc.bak b/source/material_model/simple.cc.bak new file mode 100644 index 00000000000..ac2003a3744 --- /dev/null +++ b/source/material_model/simple.cc.bak @@ -0,0 +1,265 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + void + Simple:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + // The Simple model has up to one compositional field (plus one background field) + // that can influence the density + const unsigned int n_compositions_for_eos = std::min(this->n_compositional_fields()+1, 2u); + EquationOfStateOutputs eos_outputs (n_compositions_for_eos); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const double delta_temp = in.temperature[i]-reference_T; + const double temperature_dependence + = (reference_T > 0 + ? + std::max(std::min(std::exp(-thermal_viscosity_exponent * + delta_temp/reference_T), + maximum_thermal_prefactor), + minimum_thermal_prefactor) + : + 1.0); + + out.viscosities[i] = ((composition_viscosity_prefactor != 1.0) && (in.composition[i].size()>0)) + ? + // Geometric interpolation + std::pow(10.0, ((1-in.composition[i][0]) * std::log10(eta * + temperature_dependence) + + in.composition[i][0] * std::log10(eta * + composition_viscosity_prefactor * + temperature_dependence))) + : + temperature_dependence * eta; + + equation_of_state.evaluate(in, i, eos_outputs); + + // except for the density, all material properties are constant across compositions + out.thermal_expansion_coefficients[i] = eos_outputs.thermal_expansion_coefficients[0]; + out.specific_heat[i] = eos_outputs.specific_heat_capacities[0]; + out.thermal_conductivities[i] = k_value; + out.compressibilities[i] = eos_outputs.compressibilities[0]; + out.entropy_derivative_pressure[i] = eos_outputs.entropy_derivative_pressure[0]; + out.entropy_derivative_temperature[i] = eos_outputs.entropy_derivative_temperature[0]; + + // Change in composition due to chemical reactions at the + // given positions. The term reaction_terms[i][c] is the + // change in compositional field c at point i. + for (unsigned int c=0; c volume_fractions (n_compositions_for_eos, 1.0); + if (in.composition[i].size()>0) + { + volume_fractions[1] = std::max(0.0, in.composition[i][0]); + volume_fractions[0] = 1.0 - volume_fractions[1]; + } + + out.densities[i] = MaterialUtilities::average_value(volume_fractions, eos_outputs.densities, MaterialUtilities::arithmetic); + } + } + + + + template + bool + Simple:: + is_compressible () const + { + return equation_of_state.is_compressible (); + } + + + + template + void + Simple::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Simple model"); + { + EquationOfState::LinearizedIncompressible::declare_parameters (prm, 1); + + prm.declare_entry ("Reference temperature", "293.", + Patterns::Double (0.), + "The reference temperature $T_0$. The reference temperature is used " + "in both the density and viscosity formulas. Units: \\si{\\kelvin}."); + prm.declare_entry ("Viscosity", "5e24", + Patterns::Double (0.), + "The value of the constant viscosity $\\eta_0$. This viscosity may be " + "modified by both temperature and compositional dependencies. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Composition viscosity prefactor", "1.0", + Patterns::Double (0.), + "A linear dependency of viscosity on the first compositional field. " + "Dimensionless prefactor. With a value of 1.0 (the default) the " + "viscosity does not depend on the composition. See the general documentation " + "of this model for a formula that states the dependence of the " + "viscosity on this factor, which is called $\\xi$ there."); + prm.declare_entry ("Thermal viscosity exponent", "0.0", + Patterns::Double (0.), + "The temperature dependence of viscosity. Dimensionless exponent. " + "See the general documentation " + "of this model for a formula that states the dependence of the " + "viscosity on this factor, which is called $\\beta$ there."); + prm.declare_entry("Maximum thermal prefactor","1.0e2", + Patterns::Double (0.), + "The maximum value of the viscosity prefactor associated with temperature " + "dependence."); + prm.declare_entry("Minimum thermal prefactor","1.0e-2", + Patterns::Double (0.), + "The minimum value of the viscosity prefactor associated with temperature " + "dependence."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + Simple::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Simple model"); + { + equation_of_state.parse_parameters (prm, 1); + + reference_T = prm.get_double ("Reference temperature"); + eta = prm.get_double ("Viscosity"); + composition_viscosity_prefactor = prm.get_double ("Composition viscosity prefactor"); + thermal_viscosity_exponent = prm.get_double ("Thermal viscosity exponent"); + maximum_thermal_prefactor = prm.get_double ("Maximum thermal prefactor"); + minimum_thermal_prefactor = prm.get_double ("Minimum thermal prefactor"); + if ( maximum_thermal_prefactor == 0.0 ) maximum_thermal_prefactor = std::numeric_limits::max(); + if ( minimum_thermal_prefactor == 0.0 ) minimum_thermal_prefactor = std::numeric_limits::min(); + + k_value = prm.get_double ("Thermal conductivity"); + + if (thermal_viscosity_exponent!=0.0 && reference_T == 0.0) + AssertThrow(false, ExcMessage("Error: Material model simple with Thermal viscosity exponent can not have reference_T=0.")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + this->model_dependence.viscosity = NonlinearDependence::none; + this->model_dependence.density = NonlinearDependence::temperature|NonlinearDependence::compositional_fields; + + if (thermal_viscosity_exponent != 0) + this->model_dependence.viscosity |= NonlinearDependence::temperature; + if (composition_viscosity_prefactor != 1.0) + this->model_dependence.viscosity |= NonlinearDependence::compositional_fields; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(Simple, + "simple", + "A material model that has constant values " + "for all coefficients but the density and viscosity. The defaults for all " + "coefficients are chosen to be similar to what is believed to be correct " + "for Earth's mantle. All of the values that define this model are read " + "from a section ``Material model/Simple model'' in the input file, see " + "Section~\\ref{parameters:Material_20model/Simple_20model}." + "\n\n" + "This model uses the following set of equations for the two coefficients that " + "are non-constant: " + "\\begin{align}" + " \\eta(p,T,\\mathfrak c) &= \\tau(T) \\zeta(\\mathfrak c) \\eta_0, \\\\" + " \\rho(p,T,\\mathfrak c) &= \\left(1-\\alpha (T-T_0)\\right)\\rho_0 + \\Delta\\rho \\; c_0," + "\\end{align}" + "where $c_0$ is the first component of the compositional vector " + "$\\mathfrak c$ if the model uses compositional fields, or zero otherwise. " + "\n\n" + "The temperature pre-factor for the viscosity formula above is " + "defined as " + "\\begin{align}" + " \\tau(T) &= H\\left(e^{-\\beta (T-T_0)/T_0}\\right)," + "\\intertext{with} " + " \\qquad\\qquad H(x) &= \\begin{cases}" + " \\tau_{\\text{min}} & \\text{if}\\; x<\\tau_{\\text{min}}, \\\\" + " x & \\text{if}\\; 10^{-2}\\le x \\le 10^2, \\\\" + " \\tau_{\\text{max}} & \\text{if}\\; x>\\tau_{\\text{max}}, \\\\" + " \\end{cases}" + "\\end{align} " + "where $x=e^{-\\beta (T-T_0)/T_0}$, " + "$\\beta$ corresponds to the input parameter ``Thermal viscosity exponent'', " + "and $T_0$ to the parameter ``Reference temperature''. If you set $T_0=0$ " + "in the input file, the thermal pre-factor $\\tau(T)=1$. The parameters $\\tau_{\\text{min}}$ " + "and $\\tau_{\\text{max}}$ set the minimum and maximum values of the temperature pre-factor " + "and are set using ``Maximum thermal prefactor'' and ``Minimum thermal prefactor''. " + "Specifying a value of 0.0 for the minimum or maximum values will disable pre-factor limiting." + "\n\n" + "The compositional pre-factor for the viscosity is defined as " + "$ \\zeta(\\mathfrak c) = \\xi^{c_0}$ " + "if the model has compositional fields and equals one otherwise. $\\xi$ " + "corresponds to the parameter ``Composition viscosity prefactor'' in the " + "input file." + "\n\n" + "Finally, in the formula for the density, $\\alpha$ corresponds to the " + "``Thermal expansion coefficient'' and " + "$\\Delta\\rho$ " + "corresponds to the parameter ``Density differential for compositional field 1''." + "\n\n" + "Note that this model uses the formulation that assumes an incompressible " + "medium despite the fact that the density follows the law " + "$\\rho(T)=\\rho_0(1-\\alpha(T-T_{\\text{ref}}))$. " + "\n\n" + ":::{note}\n" + "Despite its name, this material model is not exactly ``simple'', " + "as indicated by the formulas above. While it was originally intended " + "to be simple, it has over time acquired all sorts of temperature " + "and compositional dependencies that weren't initially intended. " + "Consequently, there is now a ``simpler'' material model that now fills " + "the role the current model was originally intended to fill.\n" + ":::") + } +} diff --git a/source/material_model/simple_compressible.cc.bak b/source/material_model/simple_compressible.cc.bak new file mode 100644 index 00000000000..fae99bbc633 --- /dev/null +++ b/source/material_model/simple_compressible.cc.bak @@ -0,0 +1,170 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + void + SimpleCompressible:: + evaluate(const MaterialModelInputs &in, + MaterialModelOutputs &out) const + { + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const Point position = in.position[i]; + const double temperature = in.temperature[i]; + const double pressure = in.pressure[i]; + + out.viscosities[i] = constant_rheology.compute_viscosity(); + out.specific_heat[i] = reference_specific_heat; + out.thermal_conductivities[i] = k_value; + out.thermal_expansion_coefficients[i] = thermal_alpha; + + double rho = reference_rho * std::exp(reference_compressibility * (pressure - this->get_surface_pressure())); + rho *= (1 - thermal_alpha * (temperature - this->get_adiabatic_conditions().temperature(position))); + + out.densities[i] = rho; + out.compressibilities[i] = reference_compressibility; // 1/rho drho/dp + out.entropy_derivative_pressure[i] = 0.0; + out.entropy_derivative_temperature[i] = 0.0; + // Change in composition due to chemical reactions at the + // given positions. The term reaction_terms[i][c] is the + // change in compositional field c at point i. + for (unsigned int c=0; c + bool + SimpleCompressible:: + is_compressible () const + { + return (reference_compressibility != 0); + } + + + + template + void + SimpleCompressible::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Simple compressible model"); + { + prm.declare_entry ("Reference density", "3300.", + Patterns::Double (0.), + "Reference density $\\rho_0$. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Reference specific heat", "1250.", + Patterns::Double (0.), + "The value of the specific heat $C_p$. " + "Units: \\si{\\joule\\per\\kelvin\\per\\kilogram}."); + prm.declare_entry ("Thermal expansion coefficient", "2e-5", + Patterns::Double (0.), + "The value of the thermal expansion coefficient $\\alpha$. " + "Units: \\si{\\per\\kelvin}."); + prm.declare_entry ("Reference compressibility", "4e-12", + Patterns::Double (0.), + "The value of the reference compressibility. " + "Units: \\si{\\per\\pascal}."); + + Rheology::ConstantViscosity::declare_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + SimpleCompressible::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Simple compressible model"); + { + reference_rho = prm.get_double ("Reference density"); + k_value = prm.get_double ("Thermal conductivity"); + reference_specific_heat = prm.get_double ("Reference specific heat"); + thermal_alpha = prm.get_double ("Thermal expansion coefficient"); + reference_compressibility = prm.get_double ("Reference compressibility"); + + constant_rheology.parse_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::none; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + this->model_dependence.density = NonlinearDependence::none; + + if (thermal_alpha != 0) + this->model_dependence.density |= NonlinearDependence::temperature; + if (reference_compressibility != 0) + this->model_dependence.density |= NonlinearDependence::pressure; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(SimpleCompressible, + "simple compressible", + "A material model that has constant values " + "for all coefficients but the density. The defaults for all " + "coefficients are chosen to be similar to what is believed to be correct " + "for Earth's mantle. All of the values that define this model are read " + "from a section ``Material model/Simple compressible model'' in the input file, see " + "Section~\\ref{parameters:Material_20model/Simple_20compressible_20model}." + "\n\n" + "This model uses the following equations for the density: " + "$ \\rho(p,T) = \\rho_0 \\left(1-\\alpha (T-T_a)\\right) \\exp{\\beta (P-P_0))}$ " + "This formulation for the density assumes that the compressibility " + "provided by the user is the adiabatic compressibility ($\\beta_S$). " + "The thermal expansivity and isentropic compressibility implied by " + "the pressure and temperature dependence are equal to the " + "user-defined constant values only along the reference isentrope, and " + "there is also an implicit pressure dependence to the heat capacity " + "$C_p$ via Maxwell's relations.") + } +} diff --git a/source/material_model/simpler.cc.bak b/source/material_model/simpler.cc.bak new file mode 100644 index 00000000000..684666df8fc --- /dev/null +++ b/source/material_model/simpler.cc.bak @@ -0,0 +1,131 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + template + bool + Simpler:: + is_compressible () const + { + return equation_of_state.is_compressible (); + } + + template + void + Simpler:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + // The Simpler model does not depend on composition + EquationOfStateOutputs eos_outputs (1); + + for (unsigned int i=0; i + void + Simpler::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Simpler model"); + { + EquationOfState::LinearizedIncompressible::declare_parameters (prm); + + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + Rheology::ConstantViscosity::declare_parameters(prm,5e24); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + Simpler::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Simpler model"); + { + equation_of_state.parse_parameters (prm); + + k_value = prm.get_double ("Thermal conductivity"); + + constant_rheology.parse_parameters(prm); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::none; + this->model_dependence.density = NonlinearDependence::temperature; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(Simpler, + "simpler", + "A material model that has constant values " + "except for density, which depends linearly on temperature: " + "$ \\rho(p,T) = \\left(1-\\alpha (T-T_0)\\right)\\rho_0.$ " + "\n\n" + "Note that this material model fills the role the ``simple'' material " + "model was originally intended to fill, before the latter acquired " + "all sorts of complicated temperature and compositional dependencies. ") + } +} diff --git a/source/material_model/steinberger.cc.bak b/source/material_model/steinberger.cc.bak new file mode 100644 index 00000000000..061f7c649e3 --- /dev/null +++ b/source/material_model/steinberger.cc.bak @@ -0,0 +1,631 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace internal + { + LateralViscosityLookup::LateralViscosityLookup(const std::string &filename, + const MPI_Comm comm) + { + std::string temp; + // Read data from disk and distribute among processes + std::istringstream in(Utilities::read_and_distribute_file_content(filename, comm)); + + std::getline(in, temp); // eat first line + + min_depth=1e20; + max_depth=-1; + + while (!in.eof()) + { + double visc, depth; + in >> visc; + if (in.eof()) + break; + in >> depth; + depth *=1000.0; + std::getline(in, temp); + + min_depth = std::min(depth, min_depth); + max_depth = std::max(depth, max_depth); + + values.push_back(visc); + } + delta_depth = (max_depth-min_depth)/(values.size()-1); + } + + double LateralViscosityLookup::lateral_viscosity(double depth) const + { + depth=std::max(min_depth, depth); + depth=std::min(depth, max_depth); + + Assert(depth>=min_depth, ExcMessage("ASPECT found a depth less than min_depth.")); + Assert(depth<=max_depth, ExcMessage("ASPECT found a depth greater than max_depth.")); + const unsigned int idx = static_cast((depth-min_depth)/delta_depth); + Assert(idx> visc; + if (in.eof()) + break; + in >> depth; + depth *=1000.0; + std::getline(in, temp); + + min_depth = std::min(depth, min_depth); + max_depth = std::max(depth, max_depth); + + values.push_back(visc); + } + delta_depth = (max_depth-min_depth)/(values.size()-1); + } + + double RadialViscosityLookup::radial_viscosity(double depth) const + { + depth=std::max(min_depth, depth); + depth=std::min(depth, max_depth); + + Assert(depth>=min_depth, ExcMessage("ASPECT found a depth less than min_depth.")); + Assert(depth<=max_depth, ExcMessage("ASPECT found a depth greater than max_depth.")); + const unsigned int idx = static_cast((depth-min_depth)/delta_depth); + Assert(idx + void + Steinberger::initialize() + { + equation_of_state.initialize(); + + lateral_viscosity_lookup + = std::make_unique(data_directory+lateral_viscosity_file_name, + this->get_mpi_communicator()); + radial_viscosity_lookup + = std::make_unique(data_directory+radial_viscosity_file_name, + this->get_mpi_communicator()); + average_temperature.resize(n_lateral_slices); + } + + + + template + void + Steinberger:: + update() + { + if (use_lateral_average_temperature) + { + this->get_lateral_averaging().get_temperature_averages(average_temperature); + for (double temperature : average_temperature) + AssertThrow(numbers::is_finite(temperature), + ExcMessage("In computing depth averages, there is at" + " least one depth band that does not have" + " any quadrature points in it." + " Consider reducing number of depth layers" + " for averaging specified in the parameter" + " file.(Number lateral average bands)")); + } + } + + + + template + double + Steinberger:: + viscosity (const double temperature, + const double /*pressure*/, + const std::vector &volume_fractions, + const SymmetricTensor<2,dim> &, + const Point &position) const + { + const double depth = this->get_geometry_model().depth(position); + const double adiabatic_temperature = this->get_adiabatic_conditions().temperature(position); + + double delta_temperature; + if (use_lateral_average_temperature) + { + const unsigned int idx = static_cast((average_temperature.size()-1) * depth / this->get_geometry_model().maximal_depth()); + delta_temperature = temperature-average_temperature[idx]; + } + else + delta_temperature = temperature-adiabatic_temperature; + + // For an explanation on this formula see the Steinberger & Calderwood 2006 paper + // We here compute the lateral variation of viscosity due to temperature (thermal_prefactor) as + // V_lT = exp [-(H/nR)*dT/(T_adiabatic*(T_adiabatic + dT))] as in Eq. 6 of the paper. + // We get H/nR from the lateral_viscosity_lookup->lateral_viscosity function. + const double log_thermal_prefactor = -1.0 * lateral_viscosity_lookup->lateral_viscosity(depth) * delta_temperature / (temperature * adiabatic_temperature); + + // Limit the lateral viscosity variation to a reasonable interval + const double thermal_prefactor = std::max(std::min(std::exp(log_thermal_prefactor), max_lateral_eta_variation), 1/max_lateral_eta_variation); + + const double compositional_prefactor = MaterialUtilities::average_value (volume_fractions, viscosity_prefactors, viscosity_averaging_scheme); + + // Visc_rT = exp[(H/nR)/T_adiabatic], Eq. 7 of the paper + const double eta_ref = radial_viscosity_lookup->radial_viscosity(depth); + + // Radial viscosity profile is multiplied by thermal and compositional prefactors + return std::max(std::min(thermal_prefactor * compositional_prefactor * eta_ref, max_eta), min_eta); + } + + + + template + bool + Steinberger:: + is_compressible () const + { + return equation_of_state.is_compressible(); + } + + + + template + double + Steinberger:: + thermal_conductivity (const double temperature, + const double pressure, + const Point &position) const + { + if (conductivity_formulation == constant) + return thermal_conductivity_value; + + else if (conductivity_formulation == p_T_dependent) + { + // Find the conductivity layer that corresponds to the depth of the evaluation point. + const double depth = this->get_geometry_model().depth(position); + unsigned int layer_index = std::distance(conductivity_transition_depths.begin(), + std::lower_bound(conductivity_transition_depths.begin(),conductivity_transition_depths.end(), depth)); + + const double p_dependence = reference_thermal_conductivities[layer_index] + conductivity_pressure_dependencies[layer_index] * pressure; + + // Make reasonably sure we will not compute any invalid values due to the temperature-dependence. + // Since both the temperature-dependence and the saturation term scale with (Tref/T), we have to + // make sure we can compute the square of this number. If the temperature is small enough to + // be close to yielding NaN values, the conductivity will be set to the maximum value anyway. + const double T = std::max(temperature, std::sqrt(std::numeric_limits::min()) * conductivity_reference_temperatures[layer_index]); + const double T_dependence = std::pow(conductivity_reference_temperatures[layer_index] / T, conductivity_exponents[layer_index]); + + // Function based on the theory of Roufosse and Klemens (1974) that accounts for saturation. + // For the Tosi formulation, the scaling should be zero so that this term is 1. + double saturation_function = 1.0; + if (1./T_dependence > 1.) + saturation_function = (1. - saturation_scaling[layer_index]) + + saturation_scaling[layer_index] * (2./3. * std::sqrt(T_dependence) + 1./3. * 1./T_dependence); + + return std::min(p_dependence * saturation_function * T_dependence, maximum_conductivity); + } + else + { + AssertThrow(false, ExcNotImplemented()); + return numbers::signaling_nan(); + } + } + + + + template + void + Steinberger::evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + std::vector> eos_outputs (in.n_evaluation_points(), equation_of_state.number_of_lookups()); + std::vector> volume_fractions (in.n_evaluation_points(), std::vector (equation_of_state.number_of_lookups())); + + // We need to make a copy of the material model inputs because we want to use the adiabatic pressure + // rather than the real pressure for the equations of state (to avoid numerical instabilities). + MaterialModel::MaterialModelInputs eos_in(in); + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + eos_in.pressure[i] = this->get_adiabatic_conditions().pressure(in.position[i]); + + // Evaluate the equation of state properties over all evaluation points + equation_of_state.evaluate(eos_in, eos_outputs); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + out.thermal_conductivities[i] = thermal_conductivity(in.temperature[i], in.pressure[i], in.position[i]); + for (unsigned int c=0; c mass_fractions; + if (equation_of_state.number_of_lookups() == 1) + mass_fractions.push_back(1.0); + else + { + // We only want to compute mass/volume fractions for fields that are chemical compositions. + mass_fractions = MaterialUtilities::compute_only_composition_fractions(in.composition[i], + this->introspection().chemical_composition_field_indices()); + + // The function compute_volumes_from_masses expects as many mass_fractions as densities. + // But the function compute_composition_fractions always adds another element at the start + // of the vector that represents the background field. If there is no lookup table for + // the background field, the mass_fractions vector is too long and we remove this element. + if (!has_background_field) + mass_fractions.erase(mass_fractions.begin()); + } + + volume_fractions[i] = MaterialUtilities::compute_volumes_from_masses(mass_fractions, + eos_outputs[i].densities, + true); + + if (in.requests_property(MaterialProperties::viscosity)) + out.viscosities[i] = viscosity(in.temperature[i], in.pressure[i], volume_fractions[i], in.strain_rate[i], in.position[i]); + + MaterialUtilities::fill_averaged_equation_of_state_outputs(eos_outputs[i], mass_fractions, volume_fractions[i], i, out); + fill_prescribed_outputs(i, volume_fractions[i], in, out); + } + + // fill additional outputs if they exist + equation_of_state.fill_additional_outputs(in, volume_fractions, out); + } + + + + template + void + Steinberger:: + fill_prescribed_outputs(const unsigned int q, + const std::vector &, + const MaterialModel::MaterialModelInputs &, + MaterialModel::MaterialModelOutputs &out) const + { + // set up variable to interpolate prescribed field outputs onto compositional field + PrescribedFieldOutputs *prescribed_field_out = out.template get_additional_output>(); + + if (this->introspection().composition_type_exists(CompositionalFieldDescription::density) + && prescribed_field_out != nullptr) + { + const unsigned int projected_density_index = this->introspection().find_composition_type(CompositionalFieldDescription::density); + prescribed_field_out->prescribed_field_outputs[q][projected_density_index] = out.densities[q]; + } + } + + + + template + void + Steinberger::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Steinberger model"); + { + prm.declare_entry ("Data directory", "$ASPECT_SOURCE_DIR/data/material-model/steinberger/", + Patterns::DirectoryName (), + "The path to the model data. The path may also include the special " + "text '$ASPECT_SOURCE_DIR' which will be interpreted as the path " + "in which the ASPECT source files were located when ASPECT was " + "compiled. This interpretation allows, for example, to reference " + "files located in the `data/' subdirectory of ASPECT. "); + prm.declare_entry ("Radial viscosity file name", "radial-visc.txt", + Patterns::Anything (), + "The file name of the radial viscosity data. "); + prm.declare_entry ("Lateral viscosity file name", "temp-viscosity-prefactor.txt", + Patterns::Anything (), + "The file name of the lateral viscosity data. "); + prm.declare_entry ("Use lateral average temperature for viscosity", "true", + Patterns::Bool (), + "Whether to use the laterally averaged temperature " + "instead of the adiabatic temperature as reference for the " + "viscosity calculation. This ensures that the laterally averaged " + "viscosities remain more or less constant over the model " + "runtime. This behavior might or might not be desired."); + prm.declare_entry ("Number lateral average bands", "10", + Patterns::Integer (1), + "Number of bands to compute laterally averaged temperature within."); + prm.declare_entry ("Minimum viscosity", "1e19", + Patterns::Double (0.), + "The minimum viscosity that is allowed in the viscosity " + "calculation. Smaller values will be cut off."); + prm.declare_entry ("Maximum viscosity", "1e23", + Patterns::Double (0.), + "The maximum viscosity that is allowed in the viscosity " + "calculation. Larger values will be cut off."); + prm.declare_entry ("Maximum lateral viscosity variation", "1e2", + Patterns::Double (0.), + "The relative cutoff value for lateral viscosity variations " + "caused by temperature deviations. The viscosity may vary " + "laterally by this factor squared."); + prm.declare_entry ("Composition viscosity prefactors", "1", + Patterns::Anything (), + "List of N prefactors that are used to modify the reference viscosity, " + "where N is either equal to one or the number of chemical components " + "in the simulation. If only one value is given, then all components " + "use the same value. Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Viscosity averaging scheme", "harmonic", + Patterns::Selection("arithmetic|harmonic|geometric|maximum composition"), + "Method to average viscosities over multiple compositional fields. " + "One of arithmetic, harmonic, geometric or maximum composition."); + prm.declare_entry ("Thermal conductivity", "4.7", + Patterns::Double (0.), + "The value of the thermal conductivity $k$. Only used in case " + "the 'constant' Thermal conductivity formulation is selected. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Thermal conductivity formulation", "constant", + Patterns::Selection("constant|p-T-dependent"), + "Which law should be used to compute the thermal conductivity. " + "The 'constant' law uses a constant value for the thermal " + "conductivity. The 'p-T-dependent' formulation uses equations " + "from Stackhouse et al. (2015): First-principles calculations " + "of the lattice thermal conductivity of the lower mantle " + "(https://doi.org/10.1016/j.epsl.2015.06.050), and Tosi et al. " + "(2013): Mantle dynamics with pressure- and temperature-dependent " + "thermal expansivity and conductivity " + "(https://doi.org/10.1016/j.pepi.2013.02.004) to compute the " + "thermal conductivity in dependence of temperature and pressure. " + "The thermal conductivity parameter sets can be chosen in such a " + "way that either the Stackhouse or the Tosi relations are used. " + "The conductivity description can consist of several layers with " + "different sets of parameters. Note that the Stackhouse " + "parametrization is only valid for the lower mantle (bridgmanite)."); + prm.declare_entry ("Thermal conductivity transition depths", "410000, 520000, 660000", + Patterns::List(Patterns::Double (0.)), + "A list of depth values that indicate where the transitions between " + "the different conductivity parameter sets should occur in the " + "'p-T-dependent' Thermal conductivity formulation (in most cases, " + "this will be the depths of major mantle phase transitions). " + "Units: \\si{\\meter}."); + prm.declare_entry ("Reference thermal conductivities", "2.47, 3.81, 3.52, 4.9", + Patterns::List(Patterns::Double (0.)), + "A list of base values of the thermal conductivity for each of the " + "horizontal layers in the 'p-T-dependent' Thermal conductivity " + "formulation. Pressure- and temperature-dependence will be applied" + "on top of this base value, according to the parameters 'Pressure " + "dependencies of thermal conductivity' and 'Reference temperatures " + "for thermal conductivity'. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}"); + prm.declare_entry ("Pressure dependencies of thermal conductivity", "3.3e-10, 3.4e-10, 3.6e-10, 1.05e-10", + Patterns::List(Patterns::Double ()), + "A list of values that determine the linear scaling of the " + "thermal conductivity with the pressure in the 'p-T-dependent' " + "Thermal conductivity formulation. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin\\per\\pascal}."); + prm.declare_entry ("Reference temperatures for thermal conductivity", "300, 300, 300, 1200", + Patterns::List(Patterns::Double (0.)), + "A list of values of reference temperatures used to determine " + "the temperature-dependence of the thermal conductivity in the " + "'p-T-dependent' Thermal conductivity formulation. " + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Thermal conductivity exponents", "0.48, 0.56, 0.61, 1.0", + Patterns::List(Patterns::Double (0.)), + "A list of exponents in the temperature-dependent term of the " + "'p-T-dependent' Thermal conductivity formulation. Note that this " + "exponent is not used (and should have a value of 1) in the " + "formulation of Stackhouse et al. (2015). " + "Units: none."); + prm.declare_entry ("Saturation prefactors", "0, 0, 0, 1", + Patterns::List(Patterns::Double (0., 1.)), + "A list of values that indicate how a given layer in the " + "conductivity formulation should take into account the effects " + "of saturation on the temperature-dependence of the thermal " + "conducitivity. This factor is multiplied with a saturation function " + "based on the theory of Roufosse and Klemens, 1974. A value of 1 " + "reproduces the formulation of Stackhouse et al. (2015), a value of " + "0 reproduces the formulation of Tosi et al., (2013). " + "Units: none."); + prm.declare_entry ("Maximum thermal conductivity", "1000", + Patterns::Double (0.), + "The maximum thermal conductivity that is allowed in the " + "model. Larger values will be cut off."); + + // Table lookup parameters + EquationOfState::ThermodynamicTableLookup::declare_parameters(prm); + + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + + + + template + void + Steinberger::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Steinberger model"); + { + data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get ("Data directory")); + radial_viscosity_file_name = prm.get ("Radial viscosity file name"); + lateral_viscosity_file_name = prm.get ("Lateral viscosity file name"); + use_lateral_average_temperature = prm.get_bool ("Use lateral average temperature for viscosity"); + n_lateral_slices = prm.get_integer("Number lateral average bands"); + min_eta = prm.get_double ("Minimum viscosity"); + max_eta = prm.get_double ("Maximum viscosity"); + max_lateral_eta_variation = prm.get_double ("Maximum lateral viscosity variation"); + viscosity_averaging_scheme = MaterialUtilities::parse_compositional_averaging_operation ("Viscosity averaging scheme", + prm); + thermal_conductivity_value = prm.get_double ("Thermal conductivity"); + + // Rheological parameters + if (prm.get ("Thermal conductivity formulation") == "constant") + conductivity_formulation = constant; + else if (prm.get ("Thermal conductivity formulation") == "p-T-dependent") + conductivity_formulation = p_T_dependent; + else + AssertThrow(false, ExcMessage("Not a valid thermal conductivity formulation")); + + conductivity_transition_depths = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Thermal conductivity transition depths"))); + const unsigned int n_conductivity_layers = conductivity_transition_depths.size() + 1; + + AssertThrow (std::is_sorted(conductivity_transition_depths.begin(), conductivity_transition_depths.end()), + ExcMessage("The list of 'Thermal conductivity transition depths' must " + "be sorted such that the values increase monotonically.")); + + reference_thermal_conductivities = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Reference thermal conductivities"))), + n_conductivity_layers, + "Reference thermal conductivities"); + conductivity_pressure_dependencies = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Pressure dependencies of thermal conductivity"))), + n_conductivity_layers, + "Pressure dependencies of thermal conductivity"); + conductivity_reference_temperatures = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Reference temperatures for thermal conductivity"))), + n_conductivity_layers, + "Reference temperatures for thermal conductivity"); + conductivity_exponents = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Thermal conductivity exponents"))), + n_conductivity_layers, + "Thermal conductivity exponents"); + saturation_scaling = Utilities::possibly_extend_from_1_to_N (Utilities::string_to_double(Utilities::split_string_list(prm.get("Saturation prefactors"))), + n_conductivity_layers, + "Saturation prefactors"); + maximum_conductivity = prm.get_double ("Maximum thermal conductivity"); + + // Parse the table lookup parameters + equation_of_state.initialize_simulator (this->get_simulator()); + equation_of_state.parse_parameters(prm); + + // Assign background field and do some error checking + const unsigned int n_chemical_composition_fields = this->introspection().get_number_of_fields_of_type(CompositionalFieldDescription::chemical_composition); + has_background_field = ((equation_of_state.number_of_lookups() == 1) || + (equation_of_state.number_of_lookups() == n_chemical_composition_fields + 1)); + AssertThrow ((equation_of_state.number_of_lookups() == 1) || + (equation_of_state.number_of_lookups() == n_chemical_composition_fields) || + (equation_of_state.number_of_lookups() == n_chemical_composition_fields + 1), + ExcMessage("The Steinberger material model assumes that either there is a single material " + "in the simulation, or that all compositional fields of the type " + "chemical composition correspond to mass fractions of different materials. " + "There must either be one material lookup file, the same number of " + "material lookup files as compositional fields of type chemical composition, " + "or one additional file (if a background field is used). You have " + + Utilities::int_to_string(equation_of_state.number_of_lookups()) + + " material data files, but there are " + + Utilities::int_to_string(n_chemical_composition_fields) + + " fields of type chemical composition.")); + + // Parse the Composition viscosity prefactors parameter + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + std::vector compositional_field_names = this->introspection().get_composition_names(); + + // If there is only one lookup, the list of Viscosity prefactors should have length one. + // The following if statement applies when defined fields of type chemical composition + // are not intended to be used as volume fractions of distinct materials. + if (equation_of_state.number_of_lookups() == 1) + { + chemical_field_names.clear(); + compositional_field_names.clear(); + } + + if (has_background_field) + { + chemical_field_names.insert(chemical_field_names.begin(),"background"); + compositional_field_names.insert(compositional_field_names.begin(),"background"); + } + + Utilities::MapParsing::Options options(chemical_field_names, "Composition viscosity prefactors"); + options.list_of_allowed_keys = compositional_field_names; + viscosity_prefactors = Utilities::MapParsing::parse_map_to_double_array(prm.get("Composition viscosity prefactors"), options); + + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::temperature; + this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + this->model_dependence.specific_heat = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + this->model_dependence.thermal_conductivity = NonlinearDependence::none; + } + } + + + + template + void + Steinberger::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + equation_of_state.create_additional_named_outputs(out); + + if (this->introspection().composition_type_exists(CompositionalFieldDescription::density) + && out.template get_additional_output>() == nullptr) + { + const unsigned int n_points = out.n_evaluation_points(); + out.additional_outputs.push_back( + std::make_unique> (n_points, this->n_compositional_fields())); + } + } + + } +} + + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(Steinberger, + "Steinberger", + "This material model looks up the viscosity from the tables that " + "correspond to the paper of Steinberger and Calderwood " + "2006 (``Models of large-scale viscous flow in the Earth's " + "mantle with constraints from mineral physics and surface observations'', " + "Geophys. J. Int., 167, 1461-1481, " + ") and material " + "data from a database generated by the thermodynamics code \\texttt{Perplex}, " + "see . " + "The default example data builds upon the thermodynamic " + "database by Stixrude 2011 and assumes a pyrolitic composition by " + "Ringwood 1988 but is easily replaceable by other data files. ") + } +} diff --git a/source/material_model/utilities.cc.bak b/source/material_model/utilities.cc.bak new file mode 100644 index 00000000000..2c426e215c6 --- /dev/null +++ b/source/material_model/utilities.cc.bak @@ -0,0 +1,1546 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + + +namespace aspect +{ + namespace MaterialModel + { + namespace MaterialUtilities + { + namespace Lookup + { + double + MaterialLookup::specific_heat(const double temperature, + const double pressure) const + { + return value(temperature,pressure,specific_heat_values,interpolation); + } + + double + MaterialLookup::density(const double temperature, + const double pressure) const + { + return value(temperature,pressure,density_values,interpolation); + } + + double + MaterialLookup::thermal_expansivity(const double temperature, + const double pressure) const + { + return value(temperature,pressure,thermal_expansivity_values,interpolation); + } + + double + MaterialLookup::seismic_Vp(const double temperature, + const double pressure) const + { + return value(temperature,pressure,vp_values,false); + } + + double + MaterialLookup::seismic_Vs(const double temperature, + const double pressure) const + { + return value(temperature,pressure,vs_values,false); + } + + double + MaterialLookup::enthalpy(const double temperature, + const double pressure) const + { + return value(temperature,pressure,enthalpy_values,true); + } + + double + MaterialLookup::dHdT (const double temperature, + const double pressure) const + { + const double h = value(temperature,pressure,enthalpy_values,interpolation); + const double dh = value(temperature+delta_temp,pressure,enthalpy_values,interpolation); + return (dh - h) / delta_temp; + } + + double + MaterialLookup::dHdp (const double temperature, + const double pressure) const + { + const double h = value(temperature,pressure,enthalpy_values,interpolation); + const double dh = value(temperature,pressure+delta_press,enthalpy_values,interpolation); + return (dh - h) / delta_press; + } + + std::array,2> + MaterialLookup::enthalpy_derivatives(const std::vector &temperatures, + const std::vector &pressures, + const unsigned int n_substeps) const + { + Assert(temperatures.size() == pressures.size(),ExcInternalError()); + const unsigned int n_q_points = temperatures.size(); + unsigned int n_T(0), n_p(0); + double dHdT(0.0), dHdp(0.0); + + for (unsigned int q=0; q 100.0 * std::numeric_limits::epsilon() * std::fabs(temperatures[q] + std::numeric_limits::epsilon())) + { + for (unsigned int substep = 0; substep < n_substeps; ++substep) + { + const double step_ratio = static_cast(substep)/static_cast(n_substeps); + const double step_ratio_next = static_cast(substep+1)/static_cast(n_substeps); + + const double current_pressure = pressures[q] + + step_ratio + * (pressures[p]-pressures[q]); + const double T1_substep = temperatures[q] + + step_ratio + * (temperatures[p]-temperatures[q]); + const double T2_substep = temperatures[q] + + step_ratio_next + * (temperatures[p]-temperatures[q]); + const double enthalpy2 = enthalpy(T2_substep,current_pressure); + const double enthalpy1 = enthalpy(T1_substep,current_pressure); + dHdT += (enthalpy2-enthalpy1)/(T2_substep-T1_substep); + ++n_T; + } + } + if (std::fabs(pressures[q] - pressures[p]) > 100.0 * std::numeric_limits::epsilon() * std::fabs(pressures[q] + std::numeric_limits::epsilon())) + { + for (unsigned int substep = 0; substep < n_substeps; ++substep) + { + const double step_ratio = static_cast(substep)/static_cast(n_substeps); + const double step_ratio_next = static_cast(substep+1)/static_cast(n_substeps); + const double current_temperature = temperatures[q] + + step_ratio + * (temperatures[p]-temperatures[q]); + const double p1_substep = pressures[q] + + step_ratio + * (pressures[p]-pressures[q]); + const double p2_substep = pressures[q] + + step_ratio_next + * (pressures[p]-pressures[q]); + const double enthalpy2 = enthalpy(current_temperature,p2_substep); + const double enthalpy1 = enthalpy(current_temperature,p1_substep); + dHdp += (enthalpy2-enthalpy1)/(p2_substep-p1_substep); + ++n_p; + } + } + } + } + + if ((n_T > 0) + && (n_p > 0)) + { + dHdT /= n_T; + dHdp /= n_p; + } + + std::array,2> derivatives; + derivatives[0] = std::make_pair(dHdT,n_T); + derivatives[1] = std::make_pair(dHdp,n_p); + return derivatives; + } + + double + MaterialLookup::dRhodp (const double temperature, + const double pressure) const + { + const double rho = value(temperature,pressure,density_values,interpolation); + const double drho = value(temperature,pressure+delta_press,density_values,interpolation); + return (drho - rho) / delta_press; + } + + unsigned int + MaterialLookup::dominant_phase (const double temperature, + const double pressure) const + { + if (!has_dominant_phase_column) + AssertThrow(false, ExcMessage("You can not ask for the column with the dominant phase if it does not exist in the data file.")); + return value(temperature, pressure, dominant_phase_indices); + } + + bool + MaterialLookup::has_dominant_phase() const + { + return has_dominant_phase_column; + } + + std::vector + MaterialLookup::phase_volume_column_names() const + { + return phase_column_names; + } + + double + MaterialLookup::phase_volume_fraction(const int phase_id, + const double temperature, + const double pressure) const + { + return value(temperature,pressure,phase_volume_fractions[phase_id],interpolation); + } + + + const std::vector & + MaterialLookup::get_dominant_phase_names() const + { + return dominant_phase_names; + } + + double + MaterialLookup::value (const double temperature, + const double pressure, + const Table<2, double> &values, + const bool interpol) const + { + const double nT = get_nT(temperature); + const unsigned int inT = static_cast(nT); + + const double np = get_np(pressure); + const unsigned int inp = static_cast(np); + + Assert(inT &values) const + { + const double nT = get_nT(temperature); + const unsigned int inT = static_cast(nT); + + const double np = get_np(pressure); + const unsigned int inp = static_cast(np); + + Assert(inT + MaterialLookup::get_pT_steps() const + { + std::array pt_steps; + pt_steps[0] = delta_press; + pt_steps[1] = delta_temp; + return pt_steps; + } + + double + MaterialLookup::get_nT(const double temperature) const + { + double bounded_temperature=std::max(min_temp, temperature); + bounded_temperature=std::min(bounded_temperature, max_temp-delta_temp); + + return (bounded_temperature-min_temp)/delta_temp; + } + + double + MaterialLookup::get_np(const double pressure) const + { + double bounded_pressure=std::max(min_press, pressure); + bounded_pressure=std::min(bounded_pressure, max_press-delta_press); + + return (bounded_pressure-min_press)/delta_press; + } + + HeFESToReader::HeFESToReader(const std::string &material_filename, + const std::string &derivatives_filename, + const bool interpol, + const MPI_Comm comm) + { + /* Initializing variables */ + interpolation = interpol; + delta_press=numbers::signaling_nan(); + min_press=std::numeric_limits::max(); + max_press=std::numeric_limits::lowest(); + delta_temp=numbers::signaling_nan(); + min_temp=std::numeric_limits::max(); + max_temp=std::numeric_limits::lowest(); + n_temperature=0; + n_pressure=0; + + std::string temp; + + // Read material data + { + // Read data from disk and distribute among processes + std::istringstream in(Utilities::read_and_distribute_file_content(material_filename, comm)); + + bool parsed_first_column = false; + unsigned int i = 0; + double current_pressure = 0.0; + double old_pressure = -1.0; + while (!in.eof()) + { + in >> current_pressure; + if (in.fail()) + { + in.clear(); + } + + if (!parsed_first_column) + { + if (current_pressure > old_pressure) + old_pressure = current_pressure; + else if (current_pressure <= old_pressure) + { + n_pressure = i; + parsed_first_column = true; + } + } + + std::getline(in, temp); + if (in.eof()) + break; + ++i; + } + + in.clear(); + in.seekg (0, in.beg); + + n_temperature = i / n_pressure; + + Assert(i == n_temperature * n_pressure, + ExcMessage("Material table size not consistent.")); + + density_values.reinit(n_temperature,n_pressure); + thermal_expansivity_values.reinit(n_temperature,n_pressure); + specific_heat_values.reinit(n_temperature,n_pressure); + vp_values.reinit(n_temperature,n_pressure); + vs_values.reinit(n_temperature,n_pressure); + enthalpy_values.reinit(n_temperature,n_pressure); + + i = 0; + while (!in.eof()) + { + double P = 0.0; + double depth,T; + double rho,vb,vs,vp,vsq,vpq,h; + std::string code; + double alpha = 0.0; + double cp = 0.0; + + in >> P >> depth >> T; + if (in.fail()) + in.clear(); + // conversion from [GPa] to [Pa] + P *= 1e9; + + min_press=std::min(P,min_press); + min_temp=std::min(T,min_temp); + max_temp = std::max(T,max_temp); + max_press = std::max(P,max_press); + + in >> rho; + if (in.fail()) + { + in.clear(); + rho = density_values[(i-1)%n_temperature][(i-1)/n_temperature]; + } + else + rho *= 1e3; // conversion from [g/cm^3] to [kg/m^3] + + in >> vb; + if (in.fail()) + in.clear(); + + in >> vs; + if (in.fail()) + { + in.clear(); + vs = vs_values[(i-1)%n_temperature][(i-1)/n_temperature]; + } + in >> vp; + if (in.fail()) + { + in.clear(); + vp = vp_values[(i-1)%n_temperature][(i-1)/n_temperature]; + } + in >> vsq >> vpq; + + in >> h; + if (in.fail()) + { + in.clear(); + h = enthalpy_values[(i-1)%n_temperature][(i-1)/n_temperature]; + } + else + h *= 1e6; // conversion from [kJ/g] to [J/kg] + + std::getline(in, temp); + if (in.eof()) + break; + + density_values[i/n_pressure][i%n_pressure]=rho; + thermal_expansivity_values[i/n_pressure][i%n_pressure]=alpha; + specific_heat_values[i/n_pressure][i%n_pressure]=cp; + vp_values[i/n_pressure][i%n_pressure]=vp; + vs_values[i/n_pressure][i%n_pressure]=vs; + enthalpy_values[i/n_pressure][i%n_pressure]=h; + + ++i; + } + + delta_temp = (max_temp - min_temp) / (n_temperature - 1); + delta_press = (max_press - min_press) / (n_pressure - 1); + + AssertThrow(max_temp >= 0.0, ExcMessage("Read in of Material header failed (max_temp).")); + AssertThrow(delta_temp > 0, ExcMessage("Read in of Material header failed (delta_temp).")); + AssertThrow(n_temperature > 0, ExcMessage("Read in of Material header failed (numtemp).")); + AssertThrow(max_press >= 0, ExcMessage("Read in of Material header failed (max_press).")); + AssertThrow(delta_press > 0, ExcMessage("Read in of Material header failed (delta_press).")); + AssertThrow(n_pressure > 0, ExcMessage("Read in of Material header failed (numpress).")); + } + + // If requested read derivative data + if (derivatives_filename != "") + { + std::string temp; + // Read data from disk and distribute among processes + std::istringstream in(Utilities::read_and_distribute_file_content(derivatives_filename, comm)); + + int i = 0; + while (!in.eof()) + { + double P = 0.0; + double depth,T; + double cp,alpha,alpha_eff; + double temp1,temp2; + + in >> P >> depth >> T; + if (in.fail()) + in.clear(); + + + in >> cp; + if (in.fail() || (cp <= std::numeric_limits::min())) + { + in.clear(); + cp = specific_heat_values[(i-1)%n_temperature][(i-1)/n_temperature]; + } + else + cp *= 1e3; // conversion from [J/g/K] to [J/kg/K] + + in >> alpha >> alpha_eff; + if (in.fail() || (alpha_eff <= std::numeric_limits::min())) + { + in.clear(); + alpha_eff = thermal_expansivity_values[(i-1)%n_temperature][(i-1)/n_temperature]; + } + else + { + alpha *= 1e-5; + alpha_eff *= 1e-5; + } + + in >> temp1 >> temp2; + if (in.fail()) + in.clear(); + + + std::getline(in, temp); + if (in.eof()) + break; + + specific_heat_values[i/n_pressure][i%n_pressure]=cp; + thermal_expansivity_values[i/n_pressure][i%n_pressure]=alpha_eff; + + ++i; + } + } + } + + PerplexReader::PerplexReader(const std::string &filename, + const bool interpol, + const MPI_Comm comm) + { + /* Initializing variables */ + interpolation = interpol; + delta_press=numbers::signaling_nan(); + min_press=std::numeric_limits::max(); + max_press=std::numeric_limits::lowest(); + delta_temp=numbers::signaling_nan(); + min_temp=std::numeric_limits::max(); + max_temp=std::numeric_limits::lowest(); + n_temperature=0; + n_pressure=0; + has_dominant_phase_column = false; + + std::string temp; + // Read data from disk and distribute among processes + std::istringstream in(Utilities::read_and_distribute_file_content(filename, comm)); + + // The following lines read in a PerpleX tab file in standard format + // The first 13 lines are a header in the format: + // | + // + // + // (usually T(K) or P(bar)) + // + // + // + // (usually T(K) or P(bar)) + // + // + // + // Number of property columns in the table + // Column names + + // First line is the Perplex version number + std::getline(in, temp); // get next line, table file name + + std::getline(in, temp); // get next line, dimension of table + unsigned int n_variables; + in >> n_variables; + AssertThrow (n_variables==2, ExcMessage("The PerpleX file " + filename + " must be two dimensional (P(bar)-T(K)).")); + + std::getline(in, temp); // get next line, either T(K) or P(bar) + + for (unsigned int i=0; i<2; ++i) + { + std::string natural_variable; + in >> natural_variable; + + if (natural_variable == "T(K)") + { + std::getline(in, temp); + in >> min_temp; + std::getline(in, temp); + in >> delta_temp; + std::getline(in, temp); + in >> n_temperature; + std::getline(in, temp); // get next line, either T(K), P(bar) or number of columns + } + else if (natural_variable == "P(bar)") + { + std::getline(in, temp); + in >> min_press; + min_press *= 1e5; // conversion from [bar] to [Pa] + std::getline(in, temp); + in >> delta_press; + delta_press *= 1e5; // conversion from [bar] to [Pa] + std::getline(in, temp); + in >> n_pressure; + std::getline(in, temp); // get next line, either T(K), P(bar) or number of columns + } + else + { + AssertThrow (false, ExcMessage("The start of the PerpleX file " + filename + " does not have the expected format.")); + } + } + + in >> n_columns; + std::getline(in, temp); // get next line, column labels + + // here we string match to assign properties to columns + // column i in text file -> column j in properties + // Properties are stored in the order rho, alpha, cp, vp, vs, h + std::vector prp_indices(6, -1); + std::vector phase_column_indices; + unsigned int dominant_phase_column_index = numbers::invalid_unsigned_int; + + // First two columns should be P(bar) and T(K). + // Here we find the order. + std::string column_name; + in >> column_name; + + std::string first_natural_variable; + if (column_name == "P(bar)") + { + first_natural_variable = column_name; + in >> column_name; + AssertThrow(column_name == "T(K)", ExcMessage("The second column name in PerpleX lookup file " + filename + " should be T(K).")); + } + else if (column_name == "T(K)") + { + first_natural_variable = column_name; + in >> column_name; + AssertThrow(column_name == "P(bar)", ExcMessage("The second column name in PerpleX lookup file " + filename + " should be P(bar).")); + } + else + { + AssertThrow(false, ExcMessage("The first column name in the PerpleX lookup file " + filename + " should be P(bar) or T(K).")); + } + + for (unsigned int n=2; n> column_name; + if (column_name == "rho,kg/m3") + prp_indices[0] = n; + else if (column_name == "alpha,1/K") + prp_indices[1] = n; + else if (column_name == "cp,J/K/kg") + prp_indices[2] = n; + else if (column_name == "vp,km/s") + prp_indices[3] = n; + else if (column_name == "vs,km/s") + prp_indices[4] = n; + else if (column_name == "h,J/kg") + prp_indices[5] = n; + else if (column_name == "phase") + { + has_dominant_phase_column = true; + dominant_phase_column_index = n; + } + else if (column_name.length() > 3) + { + if (column_name.substr(0,13).compare("vol_fraction_") == 0) + { + if (std::find(phase_column_names.begin(), + phase_column_names.end(), + column_name) != phase_column_names.end()) + { + AssertThrow(false, + ExcMessage("The PerpleX lookup file " + filename + " must have unique column names. " + "Sometimes, the same phase is stable with >1 composition at the same " + "pressure and temperature, so you may see several columns with the same name. " + "Either combine columns with the same name, or change the names.")); + } + // Populate phase_column_names with the column name + // and phase_column_indices with the column index in the current lookup file. + phase_column_indices.push_back(n); + phase_column_names.push_back(column_name); + } + } + } + AssertThrow(std::all_of(prp_indices.begin(), prp_indices.end(), [](int i) + { + return i>=0; + }), + ExcMessage("The PerpleX lookup file " + filename + " must contain columns with names " + "rho,kg/m3, alpha,1/K, cp,J/K/kg, vp,km/s, vs,km/s and h,J/kg.")); + + std::getline(in, temp); // first data line + + AssertThrow(min_temp >= 0.0, ExcMessage("Read in of Material header failed (mintemp).")); + AssertThrow(delta_temp > 0, ExcMessage("Read in of Material header failed (delta_temp).")); + AssertThrow(n_temperature > 0, ExcMessage("Read in of Material header failed (numtemp).")); + AssertThrow(min_press >= 0, ExcMessage("Read in of Material header failed (min_press).")); + AssertThrow(delta_press > 0, ExcMessage("Read in of Material header failed (delta_press).")); + AssertThrow(n_pressure > 0, ExcMessage("Read in of Material header failed (numpress).")); + + + max_temp = min_temp + (n_temperature-1) * delta_temp; + max_press = min_press + (n_pressure-1) * delta_press; + + density_values.reinit(n_temperature,n_pressure); + thermal_expansivity_values.reinit(n_temperature,n_pressure); + specific_heat_values.reinit(n_temperature,n_pressure); + vp_values.reinit(n_temperature,n_pressure); + vs_values.reinit(n_temperature,n_pressure); + enthalpy_values.reinit(n_temperature,n_pressure); + + if (has_dominant_phase_column) + dominant_phase_indices.reinit(n_temperature,n_pressure); + + phase_volume_fractions.resize(phase_column_names.size()); + for (auto &phase_volume_fraction : phase_volume_fractions) + phase_volume_fraction.reinit(n_temperature,n_pressure); + + unsigned int i = 0; + std::vector previous_row_values(n_columns, 0.); + + while (!in.eof()) + { + std::vector row_values(n_columns); + std::string phase; + + for (unsigned int n=0; n> phase; + else + in >> row_values[n]; // assigned as 0 if in.fail() == True + + // P-T grids created with PerpleX-werami sometimes contain rows + // filled with NaNs at extreme P-T conditions where the thermodynamic + // models break down. These P-T regions are typically not relevant to + // geodynamic modeling (they most commonly appear above + // mantle liquidus temperatures at low pressures). + // More frustratingly, PerpleX-vertex occasionally fails to find a + // valid mineral assemblage in small, isolated regions within the domain, + // and so PerpleX-werami also returns NaNs for pixels within these regions. + // It is recommended that the user preprocesses their input + // files to replace these NaNs before plugging them into ASPECT. + // If this lookup encounters invalid doubles it replaces them + // with the most recent valid double. + if (in.fail()) + { + in.clear(); + row_values[n] = previous_row_values[n]; + } + } + previous_row_values = row_values; + + std::getline(in, temp); // read next line + if (in.eof()) + break; + + if (std::find(dominant_phase_names.begin(), dominant_phase_names.end(), phase) == dominant_phase_names.end()) + dominant_phase_names.push_back(phase); + + // The ordering of the first two columns in the PerpleX table files + // dictates whether the inner loop is over temperature or pressure. + // The first column is always the inner loop. + // The following lines populate the material property tables + // according to that implicit loop structure. + if (first_natural_variable == "T(K)") + { + density_values[i%n_temperature][i/n_temperature]=row_values[prp_indices[0]]; + thermal_expansivity_values[i%n_temperature][i/n_temperature]=row_values[prp_indices[1]]; + specific_heat_values[i%n_temperature][i/n_temperature]=row_values[prp_indices[2]]; + vp_values[i%n_temperature][i/n_temperature]=row_values[prp_indices[3]]; + vs_values[i%n_temperature][i/n_temperature]=row_values[prp_indices[4]]; + enthalpy_values[i%n_temperature][i/n_temperature]=row_values[prp_indices[5]]; + + if (has_dominant_phase_column) + { + std::vector::iterator it = std::find(dominant_phase_names.begin(), dominant_phase_names.end(), phase); + dominant_phase_indices[i%n_temperature][i/n_temperature] = std::distance(dominant_phase_names.begin(), it); + } + + for (unsigned int n=0; n::iterator it = std::find(dominant_phase_names.begin(), dominant_phase_names.end(), phase); + dominant_phase_indices[i/n_pressure][i%n_pressure] = std::distance(dominant_phase_names.begin(), it); + } + + for (unsigned int n=0; n>(7,1.0); + material_lookup->load_file(data_directory+material_file_name, + comm); + } + + + + double + EntropyReader::specific_heat(const double entropy, + const double pressure) const + { + const double specific_heat = material_lookup->get_data({entropy,pressure}, 3); + return specific_heat; + } + + + + double + EntropyReader::density(const double entropy, + const double pressure) const + { + const double density = material_lookup->get_data({entropy,pressure}, 1); + return density; + } + + + + double + EntropyReader::thermal_expansivity(const double entropy, + const double pressure) const + { + const double thermal_expansivity = material_lookup->get_data({entropy,pressure}, 2); + return thermal_expansivity; + } + + + + double + EntropyReader::temperature(const double entropy, + const double pressure) const + { + const double temperature = material_lookup->get_data({entropy,pressure}, 0); + return temperature; + } + + + + double + EntropyReader::seismic_vp(const double entropy, + const double pressure) const + { + const double seismic_vp = material_lookup->get_data({entropy,pressure}, 4); + return seismic_vp; + } + + + + double + EntropyReader::seismic_vs(const double entropy, + const double pressure) const + { + const double seismic_vs = material_lookup->get_data({entropy,pressure}, 5); + return seismic_vs; + } + + + + Tensor<1, 2> + EntropyReader::density_gradient(const double entropy, + const double pressure) const + { + const Tensor<1, 2> density_gradient= material_lookup->get_gradients({entropy,pressure}, 1); + return density_gradient; + } + + + } + + + + std::vector + compute_only_composition_fractions(const std::vector &compositional_fields, + const std::vector &indices_to_use) + { + std::vector composition_fractions(indices_to_use.size()+1); + + // Clip the compositional fields so they are between zero and one, + // and sum the compositional fields for normalization purposes. + double sum_composition = 0.0; + std::vector x_comp (indices_to_use.size()); + + for (unsigned int i=0; i < x_comp.size(); ++i) + { + x_comp[i] = std::min(std::max(compositional_fields[indices_to_use[i]], 0.0), 1.0); + sum_composition += x_comp[i]; + } + + // Compute background field fraction + if (sum_composition >= 1.0) + composition_fractions[0] = 0.0; + else + composition_fractions[0] = 1.0 - sum_composition; + + // Compute and possibly normalize field fractions + for (unsigned int i=0; i < x_comp.size(); ++i) + { + if (sum_composition >= 1.0) + composition_fractions[i+1] = x_comp[i]/sum_composition; + else + composition_fractions[i+1] = x_comp[i]; + } + + return composition_fractions; + } + + + + std::vector + compute_composition_fractions(const std::vector &compositional_fields, + const ComponentMask &field_mask) + { + std::vector composition_fractions(compositional_fields.size()+1); + + // Clip the compositional fields so they are between zero and one, + // and sum the compositional fields for normalization purposes. + double sum_composition = 0.0; + std::vector x_comp = compositional_fields; + for (unsigned int i=0; i < x_comp.size(); ++i) + if (field_mask[i] == true) + { + x_comp[i] = std::min(std::max(x_comp[i], 0.0), 1.0); + sum_composition += x_comp[i]; + } + + // Compute background field fraction + if (sum_composition >= 1.0) + composition_fractions[0] = 0.0; + else + composition_fractions[0] = 1.0 - sum_composition; + + // Compute and possibly normalize field fractions + for (unsigned int i=0; i < x_comp.size(); ++i) + if (field_mask[i] == true) + { + if (sum_composition >= 1.0) + composition_fractions[i+1] = x_comp[i]/sum_composition; + else + composition_fractions[i+1] = x_comp[i]; + } + + return composition_fractions; + } + + + + std::vector + compute_volume_fractions(const std::vector &compositional_fields, + const ComponentMask &field_mask) + { + return compute_composition_fractions(compositional_fields, field_mask); + } + + + + std::vector + compute_volumes_from_masses(const std::vector &masses, + const std::vector &densities, + const bool return_as_fraction) + { + Assert(masses.size() == densities.size(), + ExcMessage ("The mass fractions and densities vectors used for computing " + "volumes from masses have to have the same length! " + "You have provided " + + Utilities::int_to_string(masses.size()) + + " mass fractions and " + + Utilities::int_to_string(densities.size()) + + " densities.")); + + const unsigned int n_fields = masses.size(); + std::vector volumes(n_fields); + + if (n_fields == 1 && return_as_fraction) + { + volumes[0] = 1.0; + return volumes; + } + + double sum_volumes = 0.0; + for (unsigned int j=0; j < n_fields; ++j) + { + volumes[j] = masses[j] / densities[j]; + sum_volumes += volumes[j]; + } + + if (return_as_fraction) + { + for (unsigned int j=0; j < n_fields; ++j) + volumes[j] /= sum_volumes; + } + return volumes; + } + + + + CompositionalAveragingOperation + parse_compositional_averaging_operation (const std::string ¶meter_name, + const ParameterHandler &prm) + { + CompositionalAveragingOperation averaging_operation; + if (prm.get (parameter_name) == "harmonic") + averaging_operation = MaterialUtilities::harmonic; + else if (prm.get (parameter_name) == "arithmetic") + averaging_operation = MaterialUtilities::arithmetic; + else if (prm.get (parameter_name) == "geometric") + averaging_operation = MaterialUtilities::geometric; + else if (prm.get (parameter_name) == "maximum composition") + averaging_operation = MaterialUtilities::maximum_composition; + else + { + AssertThrow(false, ExcMessage("Not a valid viscosity averaging scheme")); + + //We will never get here, but we have to return something so the compiler does not complain + return MaterialUtilities::harmonic; + } + + return averaging_operation; + } + + + + double + average_value (const std::vector &volume_fractions, + const std::vector ¶meter_values, + const enum CompositionalAveragingOperation &average_type) + { + Assert(volume_fractions.size() == parameter_values.size(), + ExcMessage ("The volume fractions and parameter values vectors used for averaging " + "have to have the same length! You have provided " + + Utilities::int_to_string(volume_fractions.size()) + + " volume fractions and " + + Utilities::int_to_string(parameter_values.size()) + + " parameter values.")); + + double averaged_parameter = 0.0; + + switch (average_type) + { + case arithmetic: + { + for (unsigned int i=0; i 0, + ExcMessage ("All parameter values must be greater than 0 for harmonic averaging!")); + averaged_parameter += volume_fractions[i]/(parameter_values[i]); + } + averaged_parameter = 1.0/averaged_parameter; + break; + } + case geometric: + { + for (unsigned int i=0; i 0, + ExcMessage ("All parameter values must be greater than 0 for geometric averaging!")); + averaged_parameter += volume_fractions[i] * std::log(parameter_values[i]); + } + averaged_parameter = std::exp(averaged_parameter); + break; + } + case maximum_composition: + { + const unsigned int idx = static_cast(std::max_element( volume_fractions.begin(), + volume_fractions.end() ) + - volume_fractions.begin()); + averaged_parameter = parameter_values[idx]; + break; + } + default: + { + AssertThrow(false, ExcNotImplemented()); + break; + } + } + return averaged_parameter; + } + + + + template + void + fill_averaged_equation_of_state_outputs(const EquationOfStateOutputs &eos_outputs, + const std::vector &mass_fractions, + const std::vector &volume_fractions, + const unsigned int i, + MaterialModelOutputs &out) + { + // The density, isothermal compressibility and thermal expansivity are volume-averaged + // The specific entropy derivatives and heat capacity are mass-averaged + out.densities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.densities, MaterialUtilities::arithmetic); + out.compressibilities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.compressibilities, MaterialUtilities::arithmetic); + out.thermal_expansion_coefficients[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.thermal_expansion_coefficients, MaterialUtilities::arithmetic); + out.entropy_derivative_pressure[i] = MaterialUtilities::average_value (mass_fractions, eos_outputs.entropy_derivative_pressure, MaterialUtilities::arithmetic); + out.entropy_derivative_temperature[i] = MaterialUtilities::average_value (mass_fractions, eos_outputs.entropy_derivative_temperature, MaterialUtilities::arithmetic); + out.specific_heat[i] = MaterialUtilities::average_value (mass_fractions, eos_outputs.specific_heat_capacities, MaterialUtilities::arithmetic); + } + + + + double phase_average_value (const std::vector &phase_function_values, + const std::vector &n_phase_transitions_per_composition, + const std::vector ¶meter_values, + const unsigned int composition_index, + const PhaseUtilities::PhaseAveragingOperation operation) + { + // Calculate base index and assign base value + unsigned int start_phase_index = 0; + for (unsigned int i=0; i 0) + { + // Do averaging when there are multiple phases + if (operation == PhaseUtilities::logarithmic) + averaged_parameter = log(averaged_parameter); + + for (unsigned int i=0; i + PhaseFunctionInputs::PhaseFunctionInputs(const double temperature_, + const double pressure_, + const double depth_, + const double pressure_depth_derivative_, + const unsigned int phase_index_) + + : + temperature(temperature_), + pressure(pressure_), + depth(depth_), + pressure_depth_derivative(pressure_depth_derivative_), + phase_index(phase_index_) + {} + + + + template + double + PhaseFunction::compute_value (const PhaseFunctionInputs &in) const + { + AssertIndexRange (in.phase_index, transition_temperature_lower_limits.size()); + AssertIndexRange (in.phase_index, transition_temperature_upper_limits.size()); + + // the percentage of material that has undergone the transition + double function_value; + if (in.temperature < transition_temperature_lower_limits[in.phase_index] || + in.temperature >= transition_temperature_upper_limits[in.phase_index]) + { + // assign 0.0 if temperature is out of range + function_value = 0.0; + } + else + { + if (use_depth_instead_of_pressure) + { + AssertIndexRange (in.phase_index, transition_depths.size()); + + // calculate the deviation from the transition point (convert temperature to depth) + double depth_deviation = in.depth - transition_depths[in.phase_index]; + + if (in.pressure_depth_derivative != 0.0) + { + AssertIndexRange (in.phase_index, transition_slopes.size()); + AssertIndexRange (in.phase_index, transition_temperatures.size()); + + depth_deviation -= transition_slopes[in.phase_index] / in.pressure_depth_derivative + * (in.temperature - transition_temperatures[in.phase_index]); + } + + // use delta function for width = 0 + AssertIndexRange (in.phase_index, transition_widths.size()); + if (transition_widths[in.phase_index] == 0) + function_value = (depth_deviation > 0) ? 1. : 0.; + else + function_value = 0.5*(1.0 + std::tanh(depth_deviation / transition_widths[in.phase_index])); + } + else + { + // calculate the deviation from the transition point (convert temperature to pressure) + AssertIndexRange (in.phase_index, transition_pressures.size()); + const double pressure_deviation = in.pressure - transition_pressures[in.phase_index] + - transition_slopes[in.phase_index] * (in.temperature - transition_temperatures[in.phase_index]); + + // use delta function for width = 0 + AssertIndexRange (in.phase_index, transition_pressure_widths.size()); + if (transition_pressure_widths[in.phase_index] == 0) + function_value = (pressure_deviation > 0) ? 1. : 0.; + else + function_value = 0.5*(1.0 + std::tanh(pressure_deviation / transition_pressure_widths[in.phase_index])); + } + } + + return function_value; + } + + + + template + double + PhaseFunction::compute_derivative (const PhaseFunctionInputs &in) const + { + double transition_pressure; + double pressure_width; + double width_temp; + + // we already should have the adiabatic conditions here + Assert (this->get_adiabatic_conditions().is_initialized(), + ExcMessage("The adiabatic conditions need to be already initialized " + "to calculate the derivative of phase functions. Either call this " + "function after the reference conditions have been computed, or implement " + "a workaround for the case without reference profile.")); + + // phase transition based on depth + if (use_depth_instead_of_pressure) + { + const Point transition_point = this->get_geometry_model().representative_point(transition_depths[in.phase_index]); + const Point transition_plus_width = this->get_geometry_model().representative_point(transition_depths[in.phase_index] + transition_widths[in.phase_index]); + const Point transition_minus_width = this->get_geometry_model().representative_point(transition_depths[in.phase_index] - transition_widths[in.phase_index]); + transition_pressure = this->get_adiabatic_conditions().pressure(transition_point); + pressure_width = 0.5 * (this->get_adiabatic_conditions().pressure(transition_plus_width) + - this->get_adiabatic_conditions().pressure(transition_minus_width)); + width_temp = transition_widths[in.phase_index]; + } + // using pressure instead of depth to define the phase transition + else + { + transition_pressure = transition_pressures[in.phase_index]; + pressure_width = transition_pressure_widths[in.phase_index]; + width_temp = transition_pressure_widths[in.phase_index]; + } + + // calculate the deviation from the transition point + const double pressure_deviation = in.pressure - transition_pressure + - transition_slopes[in.phase_index] * (in.temperature - transition_temperatures[in.phase_index]); + + // calculate the analytical derivative of the phase function + if ( + (in.temperature < transition_temperature_lower_limits[in.phase_index]) || + (in.temperature >= transition_temperature_upper_limits[in.phase_index]) + ) + { + // return 0 if temperature is out of range + return 0; + } + else if (width_temp == 0) + return 0; + else + return 0.5 / pressure_width * (1.0 - std::tanh(pressure_deviation / pressure_width) + * std::tanh(pressure_deviation / pressure_width)); + } + + + + template + unsigned int + PhaseFunction:: + n_phase_transitions () const + { + if (use_depth_instead_of_pressure) + return transition_depths.size(); + else + return transition_pressures.size(); + } + + template + unsigned int + PhaseFunction:: + n_phases () const + { + return n_phases_total; + } + + template + const std::vector & + PhaseFunction::n_phase_transitions_for_each_composition () const + { + return *n_phase_transitions_per_composition; + } + + template + const std::vector & + PhaseFunction::n_phases_for_each_composition () const + { + return n_phases_per_composition; + } + + + + template + double + PhaseFunction:: + get_transition_slope (const unsigned int phase_index) const + { + return transition_slopes[phase_index]; + } + + + + template + double + PhaseFunction:: + get_transition_depth (const unsigned int phase_index) const + { + return transition_depths[phase_index]; + } + + + + template + void + PhaseFunction::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Phase transition depths", "", + Patterns::Anything(), + "A list of depths where phase transitions occur. Values must " + "monotonically increase. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Phase transition widths", "", + Patterns::Anything(), + "A list of widths for each phase transition, in terms of depth. The phase functions " + "are scaled with these values, leading to a jump between phases " + "for a value of zero and a gradual transition for larger values. " + "List must have the same number of entries as Phase transition depths. " + "Units: \\si{\\meter}."); + prm.declare_entry ("Phase transition pressures", "", + Patterns::Anything(), + "A list of pressures where phase transitions occur. Values must " + "monotonically increase. Define transition by depth instead of " + "pressure must be set to false to use this parameter. " + "Units: \\si{\\pascal}."); + prm.declare_entry ("Phase transition pressure widths", "", + Patterns::Anything(), + "A list of widths for each phase transition, in terms of pressure. The phase functions " + "are scaled with these values, leading to a jump between phases " + "for a value of zero and a gradual transition for larger values. " + "List must have the same number of entries as Phase transition pressures. " + "Define transition by depth instead of pressure must be set to false " + "to use this parameter. " + "Units: \\si{\\pascal}."); + prm.declare_entry ("Define transition by depth instead of pressure", "true", + Patterns::Bool (), + "Whether to list phase transitions by depth or pressure. If this parameter is true, " + "then the input file will use Phase transitions depths and Phase transition widths " + "to define the phase transition. If it is false, the parameter file will read in " + "phase transition data from Phase transition pressures and " + "Phase transition pressure widths."); + prm.declare_entry ("Phase transition temperatures", "", + Patterns::Anything(), + "A list of temperatures where phase transitions occur. Higher or lower " + "temperatures lead to phase transition occurring in smaller or greater " + "depths than given in Phase transition depths, depending on the " + "Clapeyron slope given in Phase transition Clapeyron slopes. " + "List must have the same number of entries as Phase transition depths. " + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Phase transition temperature upper limits", + boost::lexical_cast(std::numeric_limits::max()), + Patterns::Anything(), + "A list of upper temperature limits for each phase transition. Above " + "this temperature the respective phase transition is deactivated. The default " + "value means there is no upper limit for any phase transitions. " + "List must have the same number of entries as Phase transition depths. " + "When the optional temperature limits are applied, the user has to be " + "careful about the consistency between adjacent phases. Phase transitions " + "should be continuous in pressure-temperature space. " + "We recommend producing a phase diagram with " + "simple model setups to check the implementation as a starting point." + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Phase transition temperature lower limits", + boost::lexical_cast(std::numeric_limits::lowest()), + Patterns::Anything(), + "A list of lower temperature limits for each phase transition. Below " + "this temperature the respective phase transition is deactivated. The default " + "value means there is no lower limit for any phase transition. " + "List must have the same number of entries as Phase transition depths. " + "When the optional temperature limits are applied, the user has to be " + "careful about the consistency between adjacent phases. Phase transitions " + "should be continuous in pressure-temperature space. " + "We recommend producing a phase diagram with " + "simple model setups to check the implementation as a starting point." + "Units: \\si{\\kelvin}."); + prm.declare_entry ("Phase transition Clapeyron slopes", "", + Patterns::Anything(), + "A list of Clapeyron slopes for each phase transition. A positive " + "Clapeyron slope indicates that the phase transition will occur in " + "a greater depth, if the temperature is higher than the one given in " + "Phase transition temperatures and in a smaller depth, if the " + "temperature is smaller than the one given in Phase transition temperatures. " + "For negative slopes the other way round. " + "List must have the same number of entries as Phase transition depths. " + "Units: \\si{\\pascal\\per\\kelvin}."); + } + + + + template + void + PhaseFunction::parse_parameters (ParameterHandler &prm) + { + // Establish that a background field is required here + const bool has_background_field = true; + + // Retrieve the list of composition names + const std::vector list_of_composition_names = this->introspection().get_composition_names(); + + n_phase_transitions_per_composition = std::make_unique>(); + + use_depth_instead_of_pressure = prm.get_bool ("Define transition by depth instead of pressure"); + + if (use_depth_instead_of_pressure) + { + transition_depths = Utilities::parse_map_to_double_array (prm.get("Phase transition depths"), + list_of_composition_names, + has_background_field, + "Phase transition depths", + true, + n_phase_transitions_per_composition, + true); + + transition_widths = Utilities::parse_map_to_double_array (prm.get("Phase transition widths"), + list_of_composition_names, + has_background_field, + "Phase transition widths", + true, + n_phase_transitions_per_composition, + true); + } + else + { + transition_pressures = Utilities::parse_map_to_double_array (prm.get("Phase transition pressures"), + list_of_composition_names, + has_background_field, + "Phase transition pressures", + true, + n_phase_transitions_per_composition, + true); + + transition_pressure_widths = Utilities::parse_map_to_double_array (prm.get("Phase transition pressure widths"), + list_of_composition_names, + has_background_field, + "Phase transition pressure widths", + true, + n_phase_transitions_per_composition, + true); + } + + transition_temperatures = Utilities::parse_map_to_double_array (prm.get("Phase transition temperatures"), + list_of_composition_names, + has_background_field, + "Phase transition temperatures", + true, + n_phase_transitions_per_composition, + true); + + transition_temperature_upper_limits = Utilities::parse_map_to_double_array (prm.get("Phase transition temperature upper limits"), + list_of_composition_names, + has_background_field, + "Phase transition temperature upper limits", + true, + n_phase_transitions_per_composition, + true); + + transition_temperature_lower_limits = Utilities::parse_map_to_double_array (prm.get("Phase transition temperature lower limits"), + list_of_composition_names, + has_background_field, + "Phase transition temperature lower limits", + true, + n_phase_transitions_per_composition, + true); + + transition_slopes = Utilities::parse_map_to_double_array (prm.get("Phase transition Clapeyron slopes"), + list_of_composition_names, + has_background_field, + "Phase transition Clapeyron slopes", + true, + n_phase_transitions_per_composition, + true); + + n_phases_total = 0; + n_phases_per_composition.clear(); + for (unsigned int n : *n_phase_transitions_per_composition) + { + n_phases_per_composition.push_back(n+1); + n_phases_total += n+1; + } + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + namespace MaterialUtilities + { +#define INSTANTIATE(dim) \ + template void fill_averaged_equation_of_state_outputs (const EquationOfStateOutputs &, \ + const std::vector &, \ + const std::vector &, \ + const unsigned int, \ + MaterialModelOutputs &); \ + template struct PhaseFunctionInputs; \ + template class PhaseFunction; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + } +} diff --git a/source/material_model/visco_plastic.cc.bak b/source/material_model/visco_plastic.cc.bak new file mode 100644 index 00000000000..cef81e360e1 --- /dev/null +++ b/source/material_model/visco_plastic.cc.bak @@ -0,0 +1,678 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + + template + bool + ViscoPlastic:: + is_yielding (const double pressure, + const double temperature, + const std::vector &composition, + const SymmetricTensor<2,dim> &strain_rate) const + { + /* The following returns whether or not the material is plastically yielding + * as documented in evaluate. + */ + bool plastic_yielding = false; + + MaterialModel::MaterialModelInputs in (/*n_evaluation_points=*/1, + this->n_compositional_fields()); + unsigned int i = 0; + + in.pressure[i] = pressure; + in.temperature[i] = temperature; + in.composition[i] = composition; + in.strain_rate[i] = strain_rate; + + const std::vector volume_fractions = MaterialUtilities::compute_only_composition_fractions(composition, + this->introspection().chemical_composition_field_indices()); + + const IsostrainViscosities isostrain_viscosities + = rheology->calculate_isostrain_viscosities(in, i, volume_fractions); + + std::vector::const_iterator max_composition + = std::max_element(volume_fractions.begin(),volume_fractions.end()); + + plastic_yielding = isostrain_viscosities.composition_yielding[std::distance(volume_fractions.begin(), + max_composition)]; + + return plastic_yielding; + } + + + + template + bool + ViscoPlastic:: + is_yielding(const MaterialModelInputs &in) const + { + Assert(in.n_evaluation_points() == 1, ExcInternalError()); + + const std::vector volume_fractions = MaterialUtilities::compute_only_composition_fractions(in.composition[0], + this->introspection().chemical_composition_field_indices()); + + /* The following handles phases in a similar way as in the 'evaluate' function. + * Results then enter the calculation of plastic yielding. + */ + std::vector phase_function_values(phase_function.n_phase_transitions(), 0.0); + + if (phase_function.n_phase_transitions() > 0) + { + const double gravity_norm = this->get_gravity_model().gravity_vector(in.position[0]).norm(); + + double reference_density; + if (this->get_adiabatic_conditions().is_initialized()) + { + reference_density = this->get_adiabatic_conditions().density(in.position[0]); + } + else + { + EquationOfStateOutputs eos_outputs_all_phases (n_phases); + equation_of_state.evaluate(in, 0, eos_outputs_all_phases); + reference_density = eos_outputs_all_phases.densities[0]; + } + + MaterialUtilities::PhaseFunctionInputs phase_inputs(in.temperature[0], + in.pressure[0], + this->get_geometry_model().depth(in.position[0]), + gravity_norm*reference_density, + numbers::invalid_unsigned_int); + + for (unsigned int j=0; j < phase_function.n_phase_transitions(); ++j) + { + phase_inputs.phase_index = j; + phase_function_values[j] = phase_function.compute_value(phase_inputs); + } + } + + /* The following returns whether or not the material is plastically yielding + * as documented in evaluate. + */ + const IsostrainViscosities isostrain_viscosities = rheology->calculate_isostrain_viscosities(in, 0, volume_fractions, phase_function_values, phase_function.n_phase_transitions_for_each_composition()); + + std::vector::const_iterator max_composition = std::max_element(volume_fractions.begin(), volume_fractions.end()); + const bool plastic_yielding = isostrain_viscosities.composition_yielding[std::distance(volume_fractions.begin(), max_composition)]; + + return plastic_yielding; + } + + + + template + void + ViscoPlastic:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + EquationOfStateOutputs eos_outputs (this->introspection().get_number_of_fields_of_type(CompositionalFieldDescription::chemical_composition)+1); + EquationOfStateOutputs eos_outputs_all_phases (n_phases); + + std::vector average_elastic_shear_moduli (in.n_evaluation_points()); + + // Store value of phase function for each phase and composition + // While the number of phases is fixed, the value of the phase function is updated for every point + std::vector phase_function_values(phase_function.n_phase_transitions(), 0.0); + + // Loop through all requested points + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + // First compute the equation of state variables and thermodynamic properties + equation_of_state.evaluate(in, i, eos_outputs_all_phases); + + const double gravity_norm = this->get_gravity_model().gravity_vector(in.position[i]).norm(); + const double reference_density = (this->get_adiabatic_conditions().is_initialized()) + ? + this->get_adiabatic_conditions().density(in.position[i]) + : + eos_outputs_all_phases.densities[0]; + + // The phase index is set to invalid_unsigned_int, because it is only used internally + // in phase_average_equation_of_state_outputs to loop over all existing phases + MaterialUtilities::PhaseFunctionInputs phase_inputs(in.temperature[i], + in.pressure[i], + this->get_geometry_model().depth(in.position[i]), + gravity_norm*reference_density, + numbers::invalid_unsigned_int); + + // Compute value of phase functions + for (unsigned int j=0; j < phase_function.n_phase_transitions(); ++j) + { + phase_inputs.phase_index = j; + phase_function_values[j] = phase_function.compute_value(phase_inputs); + } + + // Average by value of gamma function to get value of compositions + phase_average_equation_of_state_outputs(eos_outputs_all_phases, + phase_function_values, + n_phase_transitions_for_each_chemical_composition, + eos_outputs); + + const std::vector volume_fractions = MaterialUtilities::compute_only_composition_fractions(in.composition[i], + this->introspection().chemical_composition_field_indices()); + + // not strictly correct if thermal expansivities are different, since we are interpreting + // these compositions as volume fractions, but the error introduced should not be too bad. + out.densities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.densities, MaterialUtilities::arithmetic); + out.thermal_expansion_coefficients[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.thermal_expansion_coefficients, MaterialUtilities::arithmetic); + out.specific_heat[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.specific_heat_capacities, MaterialUtilities::arithmetic); + + if (define_conductivities == false) + { + double thermal_diffusivity = 0.0; + + for (unsigned int j=0; j < volume_fractions.size(); ++j) + thermal_diffusivity += volume_fractions[j] * thermal_diffusivities[j]; + + // Thermal conductivity at the given positions. If the temperature equation uses + // the reference density profile formulation, use the reference density to + // calculate thermal conductivity. Otherwise, use the real density. If the adiabatic + // conditions are not yet initialized, the real density will still be used. + if (this->get_parameters().formulation_temperature_equation == + Parameters::Formulation::TemperatureEquation::reference_density_profile && + this->get_adiabatic_conditions().is_initialized()) + out.thermal_conductivities[i] = thermal_diffusivity * out.specific_heat[i] * + this->get_adiabatic_conditions().density(in.position[i]); + else + out.thermal_conductivities[i] = thermal_diffusivity * out.specific_heat[i] * out.densities[i]; + } + else + { + // Use thermal conductivity values specified in the parameter file, if this + // option was selected. + out.thermal_conductivities[i] = MaterialUtilities::average_value (volume_fractions, thermal_conductivities, MaterialUtilities::arithmetic); + } + + out.compressibilities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.compressibilities, MaterialUtilities::arithmetic); + out.entropy_derivative_pressure[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.entropy_derivative_pressure, MaterialUtilities::arithmetic); + out.entropy_derivative_temperature[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.entropy_derivative_temperature, MaterialUtilities::arithmetic); + + // Compute the effective viscosity if requested and retrieve whether the material is plastically yielding. + // Also always compute the viscosity if additional outputs are requested, because the viscosity is needed + // to compute the elastic force term. + bool plastic_yielding = false; + IsostrainViscosities isostrain_viscosities; + if (in.requests_property(MaterialProperties::viscosity) || in.requests_property(MaterialProperties::additional_outputs)) + { + // Currently, the viscosities for each of the compositional fields are calculated assuming + // isostrain amongst all compositions, allowing calculation of the viscosity ratio. + // TODO: This is only consistent with viscosity averaging if the arithmetic averaging + // scheme is chosen. It would be useful to have a function to calculate isostress viscosities. + isostrain_viscosities = + rheology->calculate_isostrain_viscosities(in, i, volume_fractions, phase_function_values, n_phase_transitions_for_each_chemical_composition); + + // The isostrain condition implies that the viscosity averaging should be arithmetic (see above). + // We have given the user freedom to apply alternative bounds, because in diffusion-dominated + // creep (where n_diff=1) viscosities are stress and strain-rate independent, so the calculation + // of compositional field viscosities is consistent with any averaging scheme. + out.viscosities[i] = MaterialUtilities::average_value(volume_fractions, isostrain_viscosities.composition_viscosities, rheology->viscosity_averaging); + + // Decide based on the maximum composition if material is yielding. + // This avoids for example division by zero for harmonic averaging (as plastic_yielding + // holds values that are either 0 or 1), but might not be consistent with the viscosity + // averaging chosen. + std::vector::const_iterator max_composition = std::max_element(volume_fractions.begin(), volume_fractions.end()); + plastic_yielding = isostrain_viscosities.composition_yielding[std::distance(volume_fractions.begin(), max_composition)]; + + // Compute viscosity derivatives if they are requested + if (MaterialModel::MaterialModelDerivatives *derivatives = + out.template get_additional_output>()) + + rheology->compute_viscosity_derivatives(i, volume_fractions, + isostrain_viscosities.composition_viscosities, + in, out, phase_function_values, + n_phase_transitions_for_each_chemical_composition); + } + else + { + // The viscosity was not requested. Poison its value, along with the other + // quantities we set above and that would otherwise remain uninitialized + isostrain_viscosities.composition_yielding.clear(); + isostrain_viscosities.composition_viscosities.clear(); + isostrain_viscosities.current_friction_angles.clear(); + isostrain_viscosities.current_cohesions.clear(); + + out.viscosities[i] = numbers::signaling_nan(); + + if (MaterialModel::MaterialModelDerivatives *derivatives = + out.template get_additional_output>()) + { + derivatives->viscosity_derivative_wrt_strain_rate[i] = numbers::signaling_nan>(); + derivatives->viscosity_derivative_wrt_pressure[i] = numbers::signaling_nan(); + } + } + + // Now compute changes in the compositional fields (i.e. the accumulated strain). + for (unsigned int c=0; cstrain_rheology.fill_reaction_outputs(in, i, rheology->min_strain_rate, plastic_yielding, out); + + // Fill plastic outputs if they exist. + // The values in isostrain_viscosities only make sense when the calculate_isostrain_viscosities function + // has been called. + // TODO do we even need a separate function? We could compute the PlasticAdditionalOutputs here like + // the ElasticAdditionalOutputs. + rheology->fill_plastic_outputs(i, volume_fractions, plastic_yielding, in, out, isostrain_viscosities); + + if (this->get_parameters().enable_elasticity) + { + // Compute average elastic shear modulus + average_elastic_shear_moduli[i] = MaterialUtilities::average_value(volume_fractions, + rheology->elastic_rheology.get_elastic_shear_moduli(), + rheology->viscosity_averaging); + + // Fill the material properties that are part of the elastic additional outputs + if (ElasticAdditionalOutputs *elastic_out = out.template get_additional_output>()) + { + elastic_out->elastic_shear_moduli[i] = average_elastic_shear_moduli[i]; + } + } + } + + // If we use the full strain tensor, compute the change in the individual tensor components. + rheology->strain_rheology.compute_finite_strain_reaction_terms(in, out); + + if (this->get_parameters().enable_elasticity) + { + rheology->elastic_rheology.fill_elastic_outputs(in, average_elastic_shear_moduli, out); + rheology->elastic_rheology.fill_reaction_outputs(in, average_elastic_shear_moduli, out); + } + } + + + + template + bool + ViscoPlastic:: + is_compressible () const + { + return equation_of_state.is_compressible(); + } + + + + template + double ViscoPlastic:: + get_min_strain_rate () const + { + return rheology->min_strain_rate; + } + + + + template + void + ViscoPlastic::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection ("Visco Plastic"); + { + MaterialUtilities::PhaseFunction::declare_parameters(prm); + + EquationOfState::MulticomponentIncompressible::declare_parameters (prm); + + Rheology::ViscoPlastic::declare_parameters(prm); + + // Equation of state parameters + prm.declare_entry ("Thermal diffusivities", "0.8e-6", + Patterns::List(Patterns::Double (0.)), + "List of thermal diffusivities, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\meter\\squared\\per\\second}."); + prm.declare_entry ("Define thermal conductivities","false", + Patterns::Bool (), + "Whether to directly define thermal conductivities for each compositional field " + "instead of calculating the values through the specified thermal diffusivities, " + "densities, and heat capacities. "); + prm.declare_entry ("Thermal conductivities", "3.0", + Patterns::List(Patterns::Double(0)), + "List of thermal conductivities, for background material and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + ViscoPlastic::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection ("Visco Plastic"); + { + // Phase transition parameters + phase_function.initialize_simulator (this->get_simulator()); + phase_function.parse_parameters (prm); + + std::vector n_phases_for_each_composition = phase_function.n_phases_for_each_composition(); + + // Currently, phase_function.n_phases_for_each_composition() returns a list of length + // equal to the total number of compositions, whether or not they are chemical compositions. + // The equation_of_state (multicomponent incompressible) requires a list only for + // chemical compositions. + std::vector n_phases_for_each_chemical_composition = {n_phases_for_each_composition[0]}; + n_phase_transitions_for_each_chemical_composition = {n_phases_for_each_composition[0] - 1}; + n_phases = n_phases_for_each_composition[0]; + for (auto i : this->introspection().chemical_composition_field_indices()) + { + n_phases_for_each_chemical_composition.push_back(n_phases_for_each_composition[i+1]); + n_phase_transitions_for_each_chemical_composition.push_back(n_phases_for_each_composition[i+1] - 1); + n_phases += n_phases_for_each_composition[i+1]; + } + + // Equation of state parameters + equation_of_state.initialize_simulator (this->get_simulator()); + equation_of_state.parse_parameters (prm, + std::make_unique>(n_phases_for_each_chemical_composition)); + + // Make options file for parsing maps to double arrays + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + chemical_field_names.insert(chemical_field_names.begin(),"background"); + + std::vector compositional_field_names = this->introspection().get_composition_names(); + compositional_field_names.insert(compositional_field_names.begin(),"background"); + + Utilities::MapParsing::Options options(chemical_field_names, "Thermal diffusivities"); + options.list_of_allowed_keys = compositional_field_names; + options.allow_multiple_values_per_key = true; + options.n_values_per_key = n_phases_for_each_chemical_composition; + options.check_values_per_key = (options.n_values_per_key.size() != 0); + options.store_values_per_key = (options.n_values_per_key.size() == 0); + + thermal_diffusivities = Utilities::MapParsing::parse_map_to_double_array(prm.get("Thermal diffusivities"), options); + define_conductivities = prm.get_bool ("Define thermal conductivities"); + + options.property_name = "Thermal conductivities"; + thermal_conductivities = Utilities::MapParsing::parse_map_to_double_array (prm.get("Thermal conductivities"), options); + + rheology = std::make_unique>(); + rheology->initialize_simulator (this->get_simulator()); + rheology->parse_parameters(prm, std::make_unique>(n_phases_for_each_chemical_composition)); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::strain_rate | NonlinearDependence::compositional_fields; + this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::none; + this->model_dependence.thermal_conductivity = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; + } + + + + template + void + ViscoPlastic::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + rheology->create_plastic_outputs(out); + + if (this->get_parameters().enable_elasticity) + rheology->elastic_rheology.create_elastic_outputs(out); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(ViscoPlastic, + "visco plastic", + "An implementation of an incompressible visco(elastic)-plastic rheology " + "with options for selecting dislocation creep, diffusion creep or " + "composite viscous flow laws. Prior to yielding, one may select to " + "modify the viscosity to account for viscoelastic effects by setting the " + "parameter 'Enable elasticity' in subsection Formulation to true. Plasticity " + "limits viscous stresses through a Drucker Prager yield criterion. " + "The implementation of this material model is based heavily on the " + "`DiffusionDislocation' (Bob Myhill), `DruckerPrager' " + "(Anne Glerum), and `Viscoelastic' (John Naliboff) material models. " + "\n\n " + "The viscosity for dislocation or diffusion creep is defined as " + "$ \\eta = \\frac 12 A^{-\\frac{1}{n}} d^{\\frac{m}{n}} " + "\\dot{\\varepsilon}_{ii}^{\\frac{1-n}{n}} " + "\\exp\\left(\\frac{E + PV}{nRT}\\right)$ " + "where $A$ is the prefactor, $n$ is the stress exponent, " + "$\\dot{\\varepsilon}_{ii}$ is the square root of the deviatoric " + "strain rate tensor second invariant, $d$ is grain size, " + "$m$ is the grain size exponent, $E$ is activation energy, " + "$V$ is activation volume, $P$ is pressure, $R$ is the gas " + "exponent and $T$ is temperature. " + "This form of the viscosity equation is commonly used in " + "geodynamic simulations. See, for example, Billen and Hirth " + "(2007), G3, 8, Q08012. Significantly, other studies may use " + "slightly different forms of the viscosity equation leading to " + "variations in how specific terms are defined or combined. For " + "example, the grain size exponent should always be positive in " + "the diffusion viscosity equation used here, while other studies " + "place the grain size term in the denominator and invert the sign " + "of the grain size exponent. When examining previous work, one " + "should carefully check how the viscous prefactor and grain size " + "terms are defined. " + "\n\n " + "One may select to use the diffusion ($\\eta_{\\text{diff}}$; $n=1$, $m\\neq 0$), " + "dislocation ($\\eta_{\\text{disl}}$, $n>1$, $m=0$) or composite " + "$\\frac{\\eta_{\\text{diff}} \\eta_{\\text{disl}}}{\\eta_{\\text{diff}}+\\eta_{\\text{disl}}}$ equation form. " + "\n\n " + "The diffusion and dislocation prefactors can be weakened with a factor " + "between 0 and 1 according to the total or the viscous strain only. " + "\n\n " + "Viscosity is limited through one of two different `yielding' mechanisms. " + "\n\n" + "The first plasticity mechanism limits viscous stress through a " + "Drucker Prager yield criterion, where the yield stress in 3d is " + "$\\sigma_y = \\frac{6C\\cos(\\phi) + 2P\\sin(\\phi)} " + "{\\sqrt{3}(3+\\sin(\\phi))}$ " + "and " + "$\\sigma_y = C\\cos(\\phi) + P\\sin(\\phi)$ " + "in 2d. Above, $C$ is cohesion and $\\phi$ is the angle of " + "internal friction. Note that the 2d form is equivalent to the " + "Mohr Coulomb yield surface. If $\\phi$ is 0, the yield stress " + "is fixed and equal to the cohesion (Von Mises yield criterion). " + "When the viscous stress ($2\\eta {\\varepsilon}_{ii}$) exceeds " + "the yield stress, the viscosity is rescaled back to the yield " + "surface: $\\eta_{y}=\\sigma_{y}/(2{\\varepsilon}_{ii})$. " + "This form of plasticity is commonly used in geodynamic models. " + "See, for example, Thieulot, C. (2011), PEPI 188, pp. 47-68. " + "\n\n" + "The user has the option to linearly reduce the cohesion and " + "internal friction angle as a function of the finite strain magnitude. " + "The finite strain invariant or full strain tensor is calculated through " + "compositional fields within the material model. This implementation is " + "identical to the compositional field finite strain plugin and cookbook " + "described in the manual (author: Gassmoeller, Dannberg). If the user selects to track " + "the finite strain invariant ($e_{ii}$), a single compositional field tracks " + "the value derived from $e_{ii}^t = (e_{ii})^{(t-1)} + \\dot{e}_{ii}\\; dt$, where $t$ and $t-1$ " + "are the current and prior time steps, $\\dot{e}_{ii}$ is the second invariant of the " + "strain rate tensor and $dt$ is the time step size. In the case of the " + "full strain tensor $F$, the finite strain magnitude is derived from the " + "second invariant of the symmetric stretching tensor $L$, where " + "$L = F [F]^T$. The user must specify a single compositional " + "field for the finite strain invariant or multiple fields (4 in 2d, 9 in 3d) " + "for the finite strain tensor. These field(s) must be the first listed " + "compositional fields in the parameter file. Note that one or more of the finite strain " + "tensor components must be assigned a non-zero value initially. This value can be " + "be quite small (e.g., 1.e-8), but still non-zero. While the option to track and use " + "the full finite strain tensor exists, tracking the associated compositional fields " + "is computationally expensive in 3d. Similarly, the finite strain magnitudes " + "may in fact decrease if the orientation of the deformation field switches " + "through time. Consequently, the ideal solution is track the finite strain " + "invariant (single compositional) field within the material and track " + "the full finite strain tensor through particles." + "When only the second invariant of the strain is tracked, one has the option to " + "track the full strain or only the plastic strain. In the latter case, strain is only tracked " + "in case the material is plastically yielding, i.e. the viscous stress > yield stress. " + "\n\n" + "Viscous stress may also be limited by a non-linear stress limiter " + "that has a form similar to the Peierls creep mechanism. " + "This stress limiter assigns an effective viscosity " + "$\\sigma_{\\text{eff}} = \\frac{\\tau_y}{2\\varepsilon_y} " + "{\\frac{\\varepsilon_{ii}}{\\varepsilon_y}}^{\\frac{1}{n_y}-1}$ " + "Above $\\tau_y$ is a yield stress, $\\varepsilon_y$ is the " + "reference strain rate, $\\varepsilon_{ii}$ is the strain rate " + "and $n_y$ is the stress limiter exponent. The yield stress, " + "$\\tau_y$, is defined through the Drucker Prager yield criterion " + "formulation. This method of limiting viscous stress has been used " + "in various forms within the geodynamic literature \\cite{chri92,vavv02,cibi13,cibi15}." + "When $n_y$ is 1, it essentially becomes a linear viscosity model, " + "and in the limit $n_y\\rightarrow \\infty$ it converges to the " + "standard viscosity rescaling method (concretely, values $n_y>20$ " + "are large enough)." + "\n\n " + "The visco-plastic rheology described above may also be modified to include " + "viscoelastic deformation, thus producing a viscoelastic plastic constitutive " + "relationship. " + "\n\n " + "The viscoelastic rheology behavior takes into account the elastic shear " + "strength (e.g., shear modulus), while the tensile and volumetric " + "strength (e.g., Young's and bulk modulus) are not considered. The " + "model is incompressible and allows specifying an arbitrary number " + "of compositional fields, where each field represents a different " + "rock type or component of the viscoelastic stress tensor. The stress " + "tensor in 2d and 3d, respectively, contains 3 or 6 components. The " + "compositional fields representing these components must be named " + "and listed in a very specific format, which is designed to minimize " + "mislabeling stress tensor components as distinct 'compositional " + "rock types' (or vice versa). For 2d models, the first three " + "compositional fields must be labeled 'stress\\_xx', 'stress\\_yy' and 'stress\\_xy'. " + "In 3d, the first six compositional fields must be labeled 'stress\\_xx', " + "'stress\\_yy', 'stress\\_zz', 'stress\\_xy', 'stress\\_xz', 'stress\\_yz'. " + "\n\n " + "Combining this viscoelasticity implementation with non-linear viscous flow " + "and plasticity produces a constitutive relationship commonly referred to " + "as partial elastoviscoplastic (e.g., pEVP) in the geodynamics community. " + "While extensively discussed and applied within the geodynamics " + "literature, notable references include: " + "Moresi et al. (2003), J. Comp. Phys., v. 184, p. 476-497. " + "Gerya and Yuen (2007), Phys. Earth. Planet. Inter., v. 163, p. 83-105. " + "Gerya (2010), Introduction to Numerical Geodynamic Modeling. " + "Kaus (2010), Tectonophysics, v. 484, p. 36-47. " + "Choi et al. (2013), J. Geophys. Res., v. 118, p. 2429-2444. " + "Keller et al. (2013), Geophys. J. Int., v. 195, p. 1406-1442. " + "\n\n " + "The overview below directly follows Moresi et al. (2003) eqns. 23-38. " + "However, an important distinction between this material model and " + "the studies above is the use of compositional fields, rather than " + "particles, to track individual components of the viscoelastic stress " + "tensor. The material model will be updated when an option to track " + "and calculate viscoelastic stresses with particles is implemented. " + "\n\n " + "Moresi et al. (2003) begins (eqn. 23) by writing the deviatoric " + "rate of deformation ($\\hat{D}$) as the sum of elastic " + "($\\hat{D_{e}}$) and viscous ($\\hat{D_{v}}$) components: " + "$\\hat{D} = \\hat{D_{e}} + \\hat{D_{v}}$. " + "These terms further decompose into " + "$\\hat{D_{v}} = \\frac{\\tau}{2\\eta}$ and " + "$\\hat{D_{e}} = \\frac{\\overset{\\nabla}{\\tau}}{2\\mu}$, where " + "$\\tau$ is the viscous deviatoric stress, $\\eta$ is the shear viscosity, " + "$\\mu$ is the shear modulus and $\\overset{\\nabla}{\\tau}$ is the " + "Jaumann corotational stress rate. This later term (eqn. 24) contains the " + "time derivative of the deviatoric stress ($\\dot{\\tau}$) and terms that " + "account for material spin (e.g., rotation) due to advection: " + "$\\overset{\\nabla}{\\tau} = \\dot{\\tau} + {\\tau}W -W\\tau$. " + "Above, $W$ is the material spin tensor (eqn. 25): " + "$W_{ij} = \\frac{1}{2} \\left (\\frac{\\partial V_{i}}{\\partial x_{j}} - " + "\\frac{\\partial V_{j}}{\\partial x_{i}} \\right )$. " + "\n\n " + "If plasticity is included, the deviatoric rate of deformation may be written as: " + "$\\hat{D} = \\hat{D_{e}} + \\hat{D_{v}} + \\hat{D_{p}}$, where $\\hat{D_{p}}$ " + "is the plastic component. $\\hat{D_{p}}$ decomposes to $\\frac{\\tau_{y}}{2\\eta_{y}}$, " + "where $\\tau_{y}$ is the yield stress and $\\eta_{y}$ is the viscosity rescaled " + "to the yield surface. " + "The Jaumann stress-rate can also be approximated using terms from the " + "previous time step ($t$) and current time step ($t + \\Delta t^{e}$): " + "$\\smash[t]{\\overset{\\nabla}{\\tau}}^{t + \\Delta t^{e}} \\approx " + "\\frac{\\tau^{t + \\Delta t^{e} - \\tau^{t}}}{\\Delta t^{e}} - " + "W^{t}\\tau^{t} + \\tau^{t}W^{t}$. " + "In this material model, the size of the time step above ($\\Delta t^{e}$) " + "can be specified as the numerical time step size or an independent fixed time " + "step. If the latter case is selected, the user has an option to apply a " + "stress averaging scheme to account for the differences between the numerical " + "and fixed elastic time step (eqn. 32). If one selects to use a fixed elastic time " + "step throughout the model run, this can still be achieved by using CFL and " + "maximum time step values that restrict the numerical time step to a specific time." + "\n\n " + "The formulation above allows rewriting the total rate of deformation (eqn. 29) as\n " + "$\\tau^{t + \\Delta t^{e}} = \\eta_{eff} \\left ( " + "2\\hat{D}^{t + \\triangle t^{e}} + \\frac{\\tau^{t}}{\\mu \\Delta t^{e}} + " + "\\frac{W^{t}\\tau^{t} - \\tau^{t}W^{t}}{\\mu} \\right )$. " + "\n\n " + "The effective viscosity (eqn. 28) is a function of the viscosity ($\\eta$), " + "elastic time step size ($\\Delta t^{e}$) and shear relaxation time " + "($ \\alpha = \\frac{\\eta}{\\mu} $): " + "$\\eta_{eff} = \\eta \\frac{\\Delta t^{e}}{\\Delta t^{e} + \\alpha}$ " + "The magnitude of the shear modulus thus controls how much the effective " + "viscosity is reduced relative to the initial viscosity. " + "\n\n " + "Elastic effects are introduced into the governing Stokes equations through " + "an elastic force term (eqn. 30) using stresses from the previous time step: " + "$F^{e,t} = -\\frac{\\eta_{eff}}{\\mu \\Delta t^{e}} \\tau^{t}$. " + "This force term is added onto the right-hand side force vector in the " + "system of equations. " + "\n\n " + "When plastic yielding occurs, the effective viscosity in equation 29 and 30 is the " + "plastic viscosity (equation 36). If the current stress is below the plastic " + "yield stress, the effective viscosity is still as defined in equation 28. " + "During non-linear iterations, we define the current stress prior to yielding " + "(e.g., value compared to yield stress) as " + "$\\tau^{t + \\Delta t^{e}} = \\eta_{eff} \\left ( 2\\hat{D}^{t + \\triangle t^{e}} + " + "\\frac{\\tau^{t}}{\\mu \\Delta t^{e}} \\right ) $" + "\n\n " + "Compositional fields can each be assigned individual values of " + "thermal diffusivity, heat capacity, density, thermal " + "expansivity and rheological parameters. " + "\n\n " + "If more than one compositional field is present at a given " + "point, viscosities are averaged with an arithmetic, geometric " + "harmonic (default) or maximum composition scheme. " + "\n\n " + "The value for the components of this formula and additional " + "parameters are read from the parameter file in subsection " + " 'Material model/Visco Plastic'.") + } +} diff --git a/source/material_model/viscoelastic.cc.bak b/source/material_model/viscoelastic.cc.bak new file mode 100644 index 00000000000..f25c6375a4a --- /dev/null +++ b/source/material_model/viscoelastic.cc.bak @@ -0,0 +1,313 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include +#include +#include +#include + +namespace aspect +{ + namespace MaterialModel + { + template + void + Viscoelastic:: + evaluate(const MaterialModel::MaterialModelInputs &in, + MaterialModel::MaterialModelOutputs &out) const + { + EquationOfStateOutputs eos_outputs (this->introspection().get_number_of_fields_of_type(CompositionalFieldDescription::chemical_composition)+1); + + // Store which components to exclude during volume fraction computation. + ComponentMask composition_mask(this->n_compositional_fields(), true); + // assign compositional fields associated with viscoelastic stress a value of 0 + // assume these fields are listed first + for (unsigned int i=0; i < SymmetricTensor<2,dim>::n_independent_components; ++i) + composition_mask.set(i,false); + + std::vector average_elastic_shear_moduli (in.n_evaluation_points()); + std::vector elastic_shear_moduli(elastic_rheology.get_elastic_shear_moduli()); + + for (unsigned int i=0; i < in.n_evaluation_points(); ++i) + { + const std::vector composition = in.composition[i]; + + const std::vector volume_fractions = MaterialUtilities::compute_only_composition_fractions(composition, + this->introspection().chemical_composition_field_indices()); + + equation_of_state.evaluate(in, i, eos_outputs); + + // Arithmetic averaging of thermal conductivities + // This may not be strictly the most reasonable thing, but for most Earth materials we hope + // that they do not vary so much that it is a big problem. + out.thermal_conductivities[i] = MaterialUtilities::average_value(volume_fractions, thermal_conductivities, MaterialUtilities::arithmetic); + + // not strictly correct if thermal expansivities are different, since we are interpreting + // these compositions as volume fractions, but the error introduced should not be too bad. + out.densities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.densities, MaterialUtilities::arithmetic); + out.thermal_expansion_coefficients[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.thermal_expansion_coefficients, MaterialUtilities::arithmetic); + out.specific_heat[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.specific_heat_capacities, MaterialUtilities::arithmetic); + + out.compressibilities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.compressibilities, MaterialUtilities::arithmetic); + out.entropy_derivative_pressure[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.entropy_derivative_pressure, MaterialUtilities::arithmetic); + out.entropy_derivative_temperature[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.entropy_derivative_temperature, MaterialUtilities::arithmetic); + + for (unsigned int c=0; c *elastic_out = out.template get_additional_output>()) + { + elastic_out->elastic_shear_moduli[i] = average_elastic_shear_moduli[i]; + } + } + + elastic_rheology.fill_elastic_outputs(in, average_elastic_shear_moduli, out); + elastic_rheology.fill_reaction_outputs(in, average_elastic_shear_moduli, out); + + } + + template + bool + Viscoelastic:: + is_compressible () const + { + return equation_of_state.is_compressible(); + } + + template + void + Viscoelastic::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Viscoelastic"); + { + EquationOfState::MulticomponentIncompressible::declare_parameters (prm); + Rheology::Elasticity::declare_parameters (prm); + + prm.declare_entry ("Viscosities", "1.e21", + Patterns::List(Patterns::Double (0.)), + "List of viscosities for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\pascal\\second}."); + prm.declare_entry ("Thermal conductivities", "4.7", + Patterns::List(Patterns::Double (0.)), + "List of thermal conductivities for background mantle and compositional fields, " + "for a total of N+1 values, where N is the number of all compositional fields or only " + "those corresponding to chemical compositions. " + "If only one value is given, then all use the same value. " + "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); + prm.declare_entry ("Viscosity averaging scheme", "harmonic", + Patterns::Selection("arithmetic|harmonic|geometric|maximum composition "), + "When more than one compositional field is present at a point " + "with different viscosities, we need to come up with an average " + "viscosity at that point. Select a weighted harmonic, arithmetic, " + "geometric, or maximum composition."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + Viscoelastic::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Material model"); + { + prm.enter_subsection("Viscoelastic"); + { + // Equation of state parameters + equation_of_state.initialize_simulator (this->get_simulator()); + equation_of_state.parse_parameters (prm); + + elastic_rheology.initialize_simulator (this->get_simulator()); + elastic_rheology.parse_parameters(prm); + + viscosity_averaging = MaterialUtilities::parse_compositional_averaging_operation ("Viscosity averaging scheme", + prm); + + // Make options file for parsing maps to double arrays + std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + chemical_field_names.insert(chemical_field_names.begin(),"background"); + + std::vector compositional_field_names = this->introspection().get_composition_names(); + compositional_field_names.insert(compositional_field_names.begin(),"background"); + + Utilities::MapParsing::Options options(chemical_field_names, "Viscosities"); + options.list_of_allowed_keys = compositional_field_names; + + viscosities = Utilities::MapParsing::parse_map_to_double_array (prm.get("Viscosities"), options); + options.property_name = "Thermal conductivities"; + thermal_conductivities = Utilities::MapParsing::parse_map_to_double_array (prm.get("Thermal conductivities"), options); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + + + // Declare dependencies on solution variables + this->model_dependence.viscosity = NonlinearDependence::compositional_fields; + this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::compositional_fields; + this->model_dependence.compressibility = NonlinearDependence::none; + this->model_dependence.specific_heat = NonlinearDependence::compositional_fields; + this->model_dependence.thermal_conductivity = NonlinearDependence::compositional_fields; + } + + + + template + void + Viscoelastic::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const + { + elastic_rheology.create_elastic_outputs(out); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MaterialModel + { + ASPECT_REGISTER_MATERIAL_MODEL(Viscoelastic, + "viscoelastic", + "An implementation of a simple linear viscoelastic rheology that " + "only includes the deviatoric components of elasticity. Specifically, " + "the viscoelastic rheology only takes into account the elastic shear " + "strength (e.g., shear modulus), while the tensile and volumetric " + "strength (e.g., Young's and bulk modulus) are not considered. The " + "model is incompressible and allows specifying an arbitrary number " + "of compositional fields, where each field represents a different " + "rock type or component of the viscoelastic stress tensor. The stress " + "tensor in 2d and 3d, respectively, contains 3 or 6 components. The " + "compositional fields representing these components must be named " + "and listed in a very specific format, which is designed to minimize " + "mislabeling stress tensor components as distinct 'compositional " + "rock types' (or vice versa). For 2d models, the first three " + "compositional fields must be labeled 'stress\\_xx', 'stress\\_yy' and 'stress\\_xy'. " + "In 3d, the first six compositional fields must be labeled 'stress\\_xx', " + "'stress\\_yy', 'stress\\_zz', 'stress\\_xy', 'stress\\_xz', 'stress\\_yz'. " + "\n\n " + "Expanding the model to include non-linear viscous flow (e.g., " + "diffusion/dislocation creep) and plasticity would produce a " + "constitutive relationship commonly referred to as partial " + "elastoviscoplastic (e.g., pEVP) in the geodynamics community. " + "While extensively discussed and applied within the geodynamics " + "literature, notable references include: " + "Moresi et al. (2003), J. Comp. Phys., v. 184, p. 476-497. " + "Gerya and Yuen (2007), Phys. Earth. Planet. Inter., v. 163, p. 83-105. " + "Gerya (2010), Introduction to Numerical Geodynamic Modeling. " + "Kaus (2010), Tectonophysics, v. 484, p. 36-47. " + "Choi et al. (2013), J. Geophys. Res., v. 118, p. 2429-2444. " + "Keller et al. (2013), Geophys. J. Int., v. 195, p. 1406-1442. " + "\n\n " + "The overview below directly follows Moresi et al. (2003) eqns. 23-32. " + "However, an important distinction between this material model and " + "the studies above is the use of compositional fields, rather than " + "particles, to track individual components of the viscoelastic stress " + "tensor. The material model will be updated when an option to track " + "and calculate viscoelastic stresses with particles is implemented. " + "\n\n " + "Moresi et al. (2003) begins (eqn. 23) by writing the deviatoric " + "rate of deformation ($\\hat{D}$) as the sum of elastic " + "($\\hat{D_{e}}$) and viscous ($\\hat{D_{v}}$) components: " + "$\\hat{D} = \\hat{D_{e}} + \\hat{D_{v}}$. " + "These terms further decompose into " + "$\\hat{D_{v}} = \\frac{\\tau}{2\\eta}$ and " + "$\\hat{D_{e}} = \\frac{\\overset{\\nabla}{\\tau}}{2\\mu}$, where " + "$\\tau$ is the viscous deviatoric stress, $\\eta$ is the shear viscosity, " + "$\\mu$ is the shear modulus and $\\overset{\\nabla}{\\tau}$ is the " + "Jaumann corotational stress rate. This later term (eqn. 24) contains the " + "time derivative of the deviatoric stress ($\\dot{\\tau}$) and terms that " + "account for material spin (e.g., rotation) due to advection: " + "$\\overset{\\nabla}{\\tau} = \\dot{\\tau} + {\\tau}W -W\\tau$. " + "Above, $W$ is the material spin tensor (eqn. 25): " + "$W_{ij} = \\frac{1}{2} \\left (\\frac{\\partial V_{i}}{\\partial x_{j}} - " + "\\frac{\\partial V_{j}}{\\partial x_{i}} \\right )$. " + "\n\n " + "The Jaumann stress-rate can also be approximated using terms from the " + "previous time step ($t$) and current time step ($t + \\Delta t^{e}$): " + "$\\smash[t]{\\overset{\\nabla}{\\tau}}^{t + \\Delta t^{e}} \\approx " + "\\frac{\\tau^{t + \\Delta t^{e} - \\tau^{t}}}{\\Delta t^{e}} - " + "W^{t}\\tau^{t} + \\tau^{t}W^{t}$. " + "In this material model, the size of the time step above ($\\Delta t^{e}$) " + "can be specified as the numerical time step size or an independent fixed time " + "step. If the latter case is selected, the user has an option to apply a " + "stress averaging scheme to account for the differences between the numerical " + "and fixed elastic time step (eqn. 32). If one selects to use a fixed elastic time " + "step throughout the model run, this can still be achieved by using CFL and " + "maximum time step values that restrict the numerical time step to a specific time." + "\n\n " + "The formulation above allows rewriting the total deviatoric stress (eqn. 29) as\n " + "$\\tau^{t + \\Delta t^{e}} = \\eta_\\text{eff} \\left ( " + "2\\hat{D}^{t + \\triangle t^{e}} + \\frac{\\tau^{t}}{\\mu \\Delta t^{e}} + " + "\\frac{W^{t}\\tau^{t} - \\tau^{t}W^{t}}{\\mu} \\right )$. " + "\n\n " + "The effective viscosity (eqn. 28) is a function of the viscosity ($\\eta$), " + "elastic time step size ($\\Delta t^{e}$) and shear relaxation time " + "($ \\alpha = \\frac{\\eta}{\\mu} $): " + "$\\eta_\\text{eff} = \\eta \\frac{\\Delta t^{e}}{\\Delta t^{e} + \\alpha}$ " + "The magnitude of the shear modulus thus controls how much the effective " + "viscosity is reduced relative to the initial viscosity. " + "\n\n " + "Elastic effects are introduced into the governing Stokes equations through " + "an elastic force term (eqn. 30) using stresses from the previous time step: " + "$F^{e,t} = -\\frac{\\eta_\\text{eff}}{\\mu \\Delta t^{e}} \\tau^{t}$. " + "This force term is added onto the right-hand side force vector in the " + "system of equations. " + "\n\n " + "The value of each compositional field representing distinct rock types at a " + "point is interpreted to be a volume fraction of that rock type. If the sum of " + "the compositional field volume fractions is less than one, then the remainder " + "of the volume is assumed to be 'background material'." + "\n\n " + "Several model parameters (densities, elastic shear moduli, thermal expansivities, " + "thermal conductivies, specific heats) can be defined per-compositional field. " + "For each material parameter the user supplies a comma delimited list of length " + "N+1, where N is the number of compositional fields. The additional field corresponds " + "to the value for background material. They should be ordered ''background, " + "composition1, composition2...''. However, the first 3 (2d) or 6 (3d) composition " + "fields correspond to components of the elastic stress tensor and their material " + "values will not contribute to the volume fractions. If a single value is given, then " + "all the compositional fields are given that value. Other lengths of lists are not " + "allowed. For a given compositional field the material parameters are treated as " + "constant, except density, which varies linearly with temperature according to the " + "thermal expansivity. " + "\n\n " + "When more than one compositional field is present at a point, they are averaged " + "arithmetically. An exception is viscosity, which may be averaged arithmetically, " + "harmonically, geometrically, or by selecting the viscosity of the composition field " + "with the greatest volume fraction.") + } +} diff --git a/source/mesh_deformation/ascii_data.cc.bak b/source/mesh_deformation/ascii_data.cc.bak new file mode 100644 index 00000000000..4c8a6b6f3c3 --- /dev/null +++ b/source/mesh_deformation/ascii_data.cc.bak @@ -0,0 +1,151 @@ +/* + Copyright (C) 2016 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace MeshDeformation + { + template + AsciiData::AsciiData () + : + surface_boundary_id(1) + {} + + + + template + void + AsciiData::initialize () + { + surface_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + + Utilities::AsciiDataBoundary::initialize({surface_boundary_id}, + 1); + } + + + + template + Tensor<1,dim> + AsciiData::compute_initial_deformation_on_boundary(const types::boundary_id boundary_indicator, + const Point &position) const + { + const double topo = Utilities::AsciiDataBoundary::get_data_component(boundary_indicator, + position, + 0); + + const Tensor<1,dim> gravity = this->get_gravity_model().gravity_vector(position); + + Tensor<1,dim> topography_direction; + if (gravity.norm() > 0.0) + topography_direction = -gravity / gravity.norm(); + + return topo * topography_direction; + } + + + + template + bool + AsciiData:: + needs_surface_stabilization () const + { + return false; + } + + + + template + void + AsciiData::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh deformation"); + { + Utilities::AsciiDataBase::declare_parameters(prm, + "$ASPECT_SOURCE_DIR/data/geometry-model/initial-topography-model/ascii-data/test/", + "box_3d_%s.0.txt"); + } + prm.leave_subsection(); + } + + + + template + void + AsciiData::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh deformation"); + { + Utilities::AsciiDataBase::parse_parameters(prm); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace MeshDeformation + { + ASPECT_REGISTER_MESH_DEFORMATION_MODEL(AsciiData, + "ascii data", + "Implementation of a model in which the initial mesh " + "deformation (initial topography) is " + "derived from a file containing data " + "in ascii format. The following geometry models " + "are currently supported: box, chunk, spherical. " + "Note the required format of the " + "input data: The first lines may contain any number of comments " + "if they begin with `#', but one of these lines needs to " + "contain the number of grid points in each dimension as " + "for example `# POINTS: 3 3'. " + "The order of the data columns " + "has to be `x', `Topography [m]' in a 2d model and " + " `x', `y', `Topography [m]' in a 3d model, which means that " + "there has to be a single column " + "containing the topography. " + "Note that the data in the input " + "file needs to be sorted in a specific order: " + "the first coordinate needs to ascend first, " + "followed by the second in order to " + "assign the correct data to the prescribed coordinates. " + "If you use a spherical model, " + "then the assumed grid changes. " + "`x' will be replaced by the azimuth angle in radians " + " and `y' by the polar angle in radians measured " + "positive from the north pole. The grid will be assumed to be " + "a longitude-colatitude grid. Note that the order " + "of spherical coordinates is `phi', `theta' " + "and not `theta', `phi', since this allows " + "for dimension independent expressions.") + } +} diff --git a/source/mesh_deformation/diffusion.cc.bak b/source/mesh_deformation/diffusion.cc.bak new file mode 100644 index 00000000000..abe769a856c --- /dev/null +++ b/source/mesh_deformation/diffusion.cc.bak @@ -0,0 +1,582 @@ +/* + Copyright (C) 2020 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + + namespace MeshDeformation + { + template + Diffusion::Diffusion() + : + diffusivity(0.), + timesteps_between_diffusion (1), + apply_diffusion(false) + {} + + + + template + void + Diffusion::initialize () + { + AssertThrow(Plugins::plugin_type_matches>(this->get_geometry_model()) || + Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage("The surface diffusion mesh deformation plugin only works for Box geometries.")); + } + + + + template + void + Diffusion::update () + { + // Set the current timestep number + const unsigned int current_timestep_number = this->get_timestep_number(); + + // Determine whether we need to apply diffusion based + // on the timestep interval between applications. + // Because mesh deformation is computed at the beginning + // of each timestep, we do not apply diffusion in the first timestep. + if (current_timestep_number != 0) + { + if (current_timestep_number % timesteps_between_diffusion == 0) + apply_diffusion = true; + else + apply_diffusion = false; + } + } + + + + template + void Diffusion::diffuse_boundary(const DoFHandler &mesh_deformation_dof_handler, + const IndexSet &mesh_locally_owned, + const IndexSet &mesh_locally_relevant, + LinearAlgebra::Vector &output, + const std::set &boundary_ids) const + { + // Check that the current timestep does not exceed the diffusion timestep + check_diffusion_time_step(mesh_deformation_dof_handler, boundary_ids); + + // Set up constraints + AffineConstraints matrix_constraints(mesh_locally_relevant); + DoFTools::make_hanging_node_constraints(mesh_deformation_dof_handler, matrix_constraints); + + std::set periodic_boundary_indicators; + using periodic_boundary_pairs = std::set, unsigned int>>; + const periodic_boundary_pairs pbp = this->get_geometry_model().get_periodic_boundary_pairs(); + for (const auto &p : pbp) + { + DoFTools::make_periodicity_constraints(mesh_deformation_dof_handler, + p.first.first, p.first.second, p.second, matrix_constraints); + periodic_boundary_indicators.insert(p.first.first); + periodic_boundary_indicators.insert(p.first.second); + } + + // A boundary can be: + // 1) A mesh deformation boundary with its deformation computed by this plugin. + // 2) A zero mesh displacement boundary: + // a) boundaries with zero Stokes velocity that are not an Additional tangential mesh boundary or mesh deformation boundary, + // b) boundaries with prescribed Stokes velocity that are not an Additional tangential mesh boundary or mesh deformation boundary. + // 3) A tangential mesh displacement boundary (no normal flux): + // a) tangential Stokes boundaries that are not a mesh deformation boundary, + // b) additional tangential mesh boundaries other than those in a) and c), + // c) periodic boundaries that are not a mesh deformation boundary. + // We obtain the zero mesh displacement boundaries by subtracting the mesh deformation ones (1+3) from all used boundary indicators. In this + // case, when no Stokes velocity boundary conditions are set (e.g. when using the single Advection, + // no Stokes solver scheme, we do end up with mesh displacement boundary conditions. + + // All boundary indicators used by the current geometry. + const std::set all_boundaries = this->get_geometry_model().get_used_boundary_indicators(); + + // Get the tangential Stokes velocity boundary indicators. + const std::set tangential_velocity_boundary_indicators = + this->get_boundary_velocity_manager().get_tangential_boundary_velocity_indicators(); + + // The list of all tangential mesh deformation boundary indicators. + std::set tmp_tangential_boundaries, tmp2_tangential_boundaries, all_tangential_boundaries; + std::set_union(tangential_velocity_boundary_indicators.begin(),tangential_velocity_boundary_indicators.end(), + additional_tangential_mesh_boundary_indicators.begin(),additional_tangential_mesh_boundary_indicators.end(), + std::inserter(tmp_tangential_boundaries, tmp_tangential_boundaries.end())); + std::set_union(tmp_tangential_boundaries.begin(),tmp_tangential_boundaries.end(), + periodic_boundary_indicators.begin(),periodic_boundary_indicators.end(), + std::inserter(tmp2_tangential_boundaries, tmp2_tangential_boundaries.end())); + // Tangential Stokes velocity boundaries can also be mesh deformation boundaries, + // so correct for that. + std::set_difference(tmp2_tangential_boundaries.begin(),tmp2_tangential_boundaries.end(), + boundary_ids.begin(),boundary_ids.end(), + std::inserter(all_tangential_boundaries, all_tangential_boundaries.end())); + + // The list of mesh deformation boundary indicators of boundaries that are allowed to move either + // tangentially or in all directions. + std::set all_deformable_boundaries; + std::set_union(all_tangential_boundaries.begin(),all_tangential_boundaries.end(), + boundary_ids.begin(),boundary_ids.end(), + std::inserter(all_deformable_boundaries, all_deformable_boundaries.end())); + + // The list of mesh deformation boundary indicators of boundaries that are not allowed to move. + std::set all_fixed_boundaries; + std::set_difference(all_boundaries.begin(),all_boundaries.end(), + all_deformable_boundaries.begin(),all_deformable_boundaries.end(), + std::inserter(all_fixed_boundaries, all_fixed_boundaries.end())); + + // Make the no flux boundary constraints + for (const types::boundary_id &boundary_id : all_fixed_boundaries) + { + VectorTools::interpolate_boundary_values (this->get_mapping(), + mesh_deformation_dof_handler, + boundary_id, + dealii::Functions::ZeroFunction(dim), + matrix_constraints); + } + + // Make the no normal flux boundary constraints + VectorTools::compute_no_normal_flux_constraints (mesh_deformation_dof_handler, + /* first_vector_component= */ + 0, + all_tangential_boundaries, + matrix_constraints, this->get_mapping()); + + matrix_constraints.close(); + + // Set up the system to solve + LinearAlgebra::SparseMatrix matrix; + + // Sparsity of the matrix + TrilinosWrappers::SparsityPattern sp (mesh_locally_owned, + mesh_locally_owned, + mesh_locally_relevant, + this->get_mpi_communicator()); + DoFTools::make_sparsity_pattern (mesh_deformation_dof_handler, sp, matrix_constraints, false, + Utilities::MPI::this_mpi_process(this->get_mpi_communicator())); + + sp.compress(); + matrix.reinit (sp); + + LinearAlgebra::Vector system_rhs, solution; + system_rhs.reinit(mesh_locally_owned, this->get_mpi_communicator()); + solution.reinit(mesh_locally_owned, this->get_mpi_communicator()); + + // Initialize Gauss-Legendre quadrature for degree+1 quadrature points of the surface faces + const QGauss face_quadrature(mesh_deformation_dof_handler.get_fe().degree+1); + // Update shape function values and gradients, the quadrature points and the Jacobian x quadrature weights. + const UpdateFlags update_flags = UpdateFlags(update_values | update_gradients | update_quadrature_points | update_normal_vectors | update_JxW_values); + // We want to extract the displacement at the free surface faces of the mesh deformation element. + FEFaceValues fs_fe_face_values (this->get_mapping(), mesh_deformation_dof_handler.get_fe(), face_quadrature, update_flags); + // and to solve on the whole mesh deformation mesh + // The number of quadrature points on a mesh deformation surface face + const unsigned int n_fs_face_q_points = fs_fe_face_values.n_quadrature_points; + + // What we need to build our system on the mesh deformation element + + // The nr of shape functions per mesh deformation element + const unsigned int dofs_per_cell = mesh_deformation_dof_handler.get_fe().dofs_per_cell; + + // Map of local to global cell dof indices + std::vector cell_dof_indices (dofs_per_cell); + + // The local rhs vector + Vector cell_vector (dofs_per_cell); + // The local matrix + FullMatrix cell_matrix (dofs_per_cell, dofs_per_cell); + + // Vector for getting the local dim displacement values + std::vector> displacement_values(n_fs_face_q_points); + + // Vector for getting the local dim initial topography values + std::vector> initial_topography_values(n_fs_face_q_points); + + // The global displacements on the MeshDeformation FE + LinearAlgebra::Vector displacements = this->get_mesh_deformation_handler().get_mesh_displacements(); + + // The global initial topography on the MeshDeformation FE + // TODO Once the initial mesh deformation is ready, this + // can be removed. + LinearAlgebra::Vector initial_topography = this->get_mesh_deformation_handler().get_initial_topography(); + + // Do nothing at time zero + if (this->get_timestep_number() < 1) + return; + + // An extractor for the dim-valued displacement vectors + // Later on we will compute the gravity-parallel displacement + FEValuesExtractors::Vector extract_vertical_displacements(0); + + // An extractor for the dim-valued initial topography vectors + // Later on we will compute the gravity-parallel displacement + FEValuesExtractors::Vector extract_initial_topography(0); + + // Cell iterator over the MeshDeformation FE + typename DoFHandler::active_cell_iterator + fscell = mesh_deformation_dof_handler.begin_active(), + fsendc = mesh_deformation_dof_handler.end(); + + // Iterate over all cells to find those at the mesh deformation boundary + for (; fscell!=fsendc; ++fscell) + if (fscell->at_boundary() && fscell->is_locally_owned()) + for (const unsigned int face_no : fscell->face_indices()) + if (fscell->face(face_no)->at_boundary()) + { + // Boundary indicator of current cell face + const types::boundary_id boundary_indicator + = fscell->face(face_no)->boundary_id(); + + // Only apply diffusion to the requested boundaries + if (boundary_ids.find(boundary_indicator) == boundary_ids.end()) + continue; + + // Recompute values, gradients, etc on the faces + fs_fe_face_values.reinit (fscell, face_no); + + // Get the global numbers of the local DoFs of the mesh deformation cell + fscell->get_dof_indices (cell_dof_indices); + + // Extract the displacement values + fs_fe_face_values[extract_vertical_displacements].get_function_values (displacements, displacement_values); + + // Extract the initial topography values + fs_fe_face_values[extract_initial_topography].get_function_values (initial_topography, initial_topography_values); + + // Reset local rhs and matrix + cell_vector = 0; + cell_matrix = 0; + + // Loop over the quadrature points of the current face + for (unsigned int point=0; point direction = -(this->get_gravity_model().gravity_vector(fs_fe_face_values.quadrature_point(point))); + // Normalize direction vector + if (direction.norm() > 0.0) + direction *= 1./direction.norm(); + // TODO this is only correct for box geometries + else + { + AssertThrow(Plugins::plugin_type_matches>(this->get_geometry_model()) || + Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage("The surface diffusion mesh deformation plugin only works for Box geometries.")); + direction[dim-1] = 1.; + } + + // Compute the total displacement in the gravity direction, + // i.e. the initial topography + any additional mesh displacement. + const double displacement = direction * (displacement_values[point] + initial_topography_values[point]); + + // To project onto the tangent space of the surface, + // we define the projection P:= I- n x n, + // with I the unit tensor and n the unit normal to the surface. + // The surface gradient then is P times the usual gradient of the shape functions. + const Tensor<2, dim, double> projection = unit_symmetric_tensor() - + outer_product(fs_fe_face_values.normal_vector(point), fs_fe_face_values.normal_vector(point)); + + + // The shape values for the i-loop + std::vector phi(dofs_per_cell); + + // The projected gradients of the shape values for the i-loop + std::vector> projected_grad_phi(dofs_per_cell); + + // Loop over the shape functions + for (unsigned int i=0; i>(this->get_geometry_model()) || + Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage("The surface diffusion mesh deformation plugin only works for Box geometries.")); + if (mesh_deformation_dof_handler.get_fe().system_to_component_index(i).first == dim-1) + { + // Precompute shape values and projected shape value gradients + phi[i] = fs_fe_face_values.shape_value (i, point); + projected_grad_phi[i] = projection * fs_fe_face_values.shape_grad(i, point); + + // Assemble the RHS + // RHS = M*H_old + cell_vector(i) += phi[i] * displacement * fs_fe_face_values.JxW(point); + + for (unsigned int j=0; jget_timestep() * diffusivity * + projected_grad_phi[i] * + (projection * fs_fe_face_values.shape_grad(j, point)) + ) + * fs_fe_face_values.JxW(point); + } + } + } + } + } + + matrix_constraints.distribute_local_to_global (cell_matrix, cell_vector, + cell_dof_indices, matrix, system_rhs, false); + } + + system_rhs.compress (VectorOperation::add); + matrix.compress(VectorOperation::add); + + // Jacobi seems to be fine here. Other preconditioners (ILU, IC) run into trouble + // because the matrix is mostly empty, since we don't touch internal vertices. + LinearAlgebra::PreconditionJacobi preconditioner_mass; + LinearAlgebra::PreconditionJacobi::AdditionalData preconditioner_control(1,1e-16,1); + preconditioner_mass.initialize(matrix, preconditioner_control); + + this->get_pcout() << " Solving mesh surface diffusion" << std::endl; + SolverControl solver_control(5*system_rhs.size(), this->get_parameters().linear_stokes_solver_tolerance*system_rhs.l2_norm()); + SolverCG cg(solver_control); + cg.solve (matrix, solution, system_rhs, preconditioner_mass); + + // Distribute constraints on mass matrix + matrix_constraints.distribute (solution); + + // The solution contains the new displacements, but we need to return a velocity. + // Therefore, we compute v=d_displacement/d_t. + // d_displacement are the new mesh node locations + // minus the old locations, which are initial_topography + displacements. + LinearAlgebra::Vector velocity(mesh_locally_owned, mesh_locally_relevant, this->get_mpi_communicator()); + velocity = solution; + velocity -= initial_topography; + velocity -= displacements; + + // The velocity + if (this->get_timestep() > 0.) + velocity /= this->get_timestep(); + else + AssertThrow(false, ExcZero()); + + output = velocity; + } + + + + template + void Diffusion::check_diffusion_time_step (const DoFHandler &mesh_deformation_dof_handler, + const std::set &boundary_ids) const + { + double min_local_conduction_timestep = std::numeric_limits::max(); + + for (const auto &fscell : mesh_deformation_dof_handler.active_cell_iterators()) + if (fscell->at_boundary() && fscell->is_locally_owned()) + for (const unsigned int face_no : fscell->face_indices()) + if (fscell->face(face_no)->at_boundary()) + { + // Get the boundary indicator of current cell face + const types::boundary_id boundary_indicator + = fscell->face(face_no)->boundary_id(); + + // Only consider the requested boundaries + if (boundary_ids.find(boundary_indicator) == boundary_ids.end()) + continue; + + // Calculate the corresponding conduction timestep + min_local_conduction_timestep = std::min(min_local_conduction_timestep, + this->get_parameters().CFL_number*std::pow(fscell->face(face_no)->minimum_vertex_distance(),2.) + / diffusivity); + } + + // Get the global minimum timestep + const double min_conduction_timestep = Utilities::MPI::min (min_local_conduction_timestep, this->get_mpi_communicator()); + + double conduction_timestep = min_conduction_timestep; + if (this->convert_output_to_years()) + conduction_timestep /= year_in_seconds; + + AssertThrow (this->get_timestep() <= min_conduction_timestep, + ExcMessage("The numerical timestep is too large for diffusion of the surface. Although the " + "diffusion scheme is stable, note that the error increases linearly with the timestep. " + "The diffusion timestep is: " + std::to_string(conduction_timestep) + ", while " + "the advection timestep is: " + std::to_string (this->get_timestep ()))); + } + + + + template + void + Diffusion::compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, + AffineConstraints &mesh_velocity_constraints, + const std::set &boundary_id) const + { + if (!apply_diffusion) + return; + + LinearAlgebra::Vector boundary_velocity; + + const IndexSet &mesh_locally_owned = mesh_deformation_dof_handler.locally_owned_dofs(); + IndexSet mesh_locally_relevant; + DoFTools::extract_locally_relevant_dofs (mesh_deformation_dof_handler, + mesh_locally_relevant); + boundary_velocity.reinit(mesh_locally_owned, mesh_locally_relevant, + this->get_mpi_communicator()); + + // Determine the mesh velocity at the surface based on diffusion of + // the topography + diffuse_boundary(mesh_deformation_dof_handler, mesh_locally_owned, + mesh_locally_relevant, boundary_velocity, boundary_id); + + // now insert the relevant part of the solution into the mesh constraints + const IndexSet constrained_dofs = + DoFTools::extract_boundary_dofs(mesh_deformation_dof_handler, + ComponentMask(dim, true), + boundary_id); + + for (unsigned int i = 0; i < constrained_dofs.n_elements(); ++i) + { + types::global_dof_index index = constrained_dofs.nth_index_in_set(i); + if (mesh_velocity_constraints.can_store_line(index)) + if (mesh_velocity_constraints.is_constrained(index)==false) + { + mesh_velocity_constraints.add_line(index); + mesh_velocity_constraints.set_inhomogeneity(index, boundary_velocity[index]); + } + } + } + + + + template + bool + Diffusion:: + needs_surface_stabilization () const + { + return false; + } + + + + template + void Diffusion::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Mesh deformation"); + { + prm.enter_subsection("Diffusion"); + { + prm.declare_entry("Hillslope transport coefficient", "1e-6", + Patterns::Double(0), + "The hillslope transport coefficient $\\kappa$ used to " + "diffuse the free surface, either as a " + "stabilization step or to mimic erosional " + "and depositional processes. Units: $\\si{m^2/s}$. "); + prm.declare_entry("Time steps between diffusion", "1", + Patterns::Integer(0,std::numeric_limits::max()), + "The number of time steps between each application of " + "diffusion."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void Diffusion::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection ("Mesh deformation"); + { + // Create the list of tangential mesh movement boundary indicators. + try + { + const std::vector x_additional_tangential_mesh_boundary_indicators + = this->get_geometry_model().translate_symbolic_boundary_names_to_ids(Utilities::split_string_list + (prm.get ("Additional tangential mesh velocity boundary indicators"))); + + additional_tangential_mesh_boundary_indicators.insert(x_additional_tangential_mesh_boundary_indicators.begin(), + x_additional_tangential_mesh_boundary_indicators.end()); + } + catch (const std::string &error) + { + AssertThrow (false, ExcMessage ("While parsing the entry , there was an error. Specifically, " + "the conversion function complained as follows:\n\n" + + error)); + } + + prm.enter_subsection ("Diffusion"); + { + diffusivity = prm.get_double("Hillslope transport coefficient"); + timesteps_between_diffusion = prm.get_integer("Time steps between diffusion"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + + +// explicit instantiation of the functions we implement in this file +namespace aspect +{ + namespace MeshDeformation + { + ASPECT_REGISTER_MESH_DEFORMATION_MODEL(Diffusion, + "diffusion", + "A plugin that computes the deformation of surface " + "vertices according to the solution of the hillslope diffusion problem. " + "Specifically, at the end of each timestep, or after a specific number " + "of timesteps, this plugin solves the following equation: " + "\\begin{align*}" + " \\frac{\\partial h}{\\partial t} = \\kappa \\left( \\frac{\\partial^{2} h}{\\partial x^{2}} " + "+ \\frac{\\partial^{2} h}{\\partial y^{2}} \\right), " + "\\end{align*} " + "where $\\kappa$ is the hillslope diffusion coefficient (diffusivity), and $h(x,y)$ the " + "height of a point along the top boundary with respect to the surface of the unperturbed domain. " + "\n\n" + "Using this definition, the plugin then solves for one time step, i.e., " + "using as initial condition $h(t_{n-1})$ the current surface elevation, " + "and computing $h(t_n)$ from it by solving the equation above over " + "the time interval $t_n-t_{n-1}$. From this, one can then compute " + "a surface velocity $v = \\frac{h(t_n)-h(t_{n-1})}{t_n-t_{n-1}}$. " + "\n\n" + "This surface velocity is used to deform the surface and as a boundary condition " + "for solving the Laplace equation to determine the mesh velocity in the " + "domain interior. " + "Diffusion can be applied every timestep, mimicking surface processes of erosion " + "and deposition, or at a user-defined timestep interval to purely smooth the surface " + "topography to avoid too great a distortion of mesh elements when a free " + "surface is also used.") + } +} diff --git a/source/mesh_deformation/fastscape.cc.bak b/source/mesh_deformation/fastscape.cc.bak new file mode 100644 index 00000000000..e0adde32c31 --- /dev/null +++ b/source/mesh_deformation/fastscape.cc.bak @@ -0,0 +1,1997 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ +#include + +#ifdef ASPECT_WITH_FASTSCAPE + +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace MeshDeformation + { + /** + * Define FastScape functions as C functions. Must use the exact same function/variable name + * and type as used in FastScape. All function names must be made lowercase, and an + * underscore added at the end. Types must be defined as pointers, and sent to + * FastScape as a reference. Additional functions are available within FastScape, + * see https://fastscape.org/fastscapelib-fortran/ for a list of all functions and + * their input parameters. These functions must be defined at the top here before + * they are used. + */ + extern"C" + { + /** + * Function to initialize FastScape. + */ + void fastscape_init_(); + + /** + * Set the x and y extent of the FastScape model. + */ + void fastscape_set_xl_yl_(const double *xxl, + const double *yyl); + + /** + * Set number of grid points in x (nx) and y (ny) + */ + void fastscape_set_nx_ny_(const unsigned int *nnx, + const unsigned int *nny); + + /** + * Allocate memory, must be called after set nx/ny. + */ + void fastscape_setup_(); + + /** + * Set FastScape boundary conditions. + */ + void fastscape_set_bc_(const unsigned int *jbc); + + /** + * Set FastScape timestep. This will vary based on the ASPECT timestep. + */ + void fastscape_set_dt_(const double *dtt); + + /** + * Initialize FastScape topography. + */ + void fastscape_init_h_(double *hp); + + /** + * Initialize FastScape silt fraction during a restart. + */ + void fastscape_init_f_(double *sf); + + /** + * Set FastScape erosional parameters on land. These parameters will apply to the stream power law (SPL) + * and hillslope diffusion for basement and sediment. This can be set between timesteps. + */ + void fastscape_set_erosional_parameters_(double *kkf, + const double *kkfsed, + const double *mm, + const double *nnn, + double *kkd, + const double *kkdsed, + const double *gg1, + const double *gg2, + const double *pp); + + /** + * Set FastScape marine erosional parameters. This can be set between timesteps. + */ + void fastscape_set_marine_parameters_(const double *sl, + const double *p1, + const double *p2, + const double *z1, + const double *z2, + const double *r, + const double *l, + const double *kds1, + const double *kds2); + + /** + * Set advection velocities for FastScape. This can be set between timesteps. + */ + void fastscape_set_v_(double *ux, + double *uy); + + /** + * Set FastScape uplift rate. This can be set between timesteps. + */ + void fastscape_set_u_(double *up); + + /** + * Set FastScape topography. This can be set between timesteps. + */ + void fastscape_set_h_(double *hp); + + /** + * Set FastScape basement. This can be set between timesteps. Sediment within FastScape + * is considered as the difference between the topography and basement, though this may differ + * from sediment as seen in ASPECT because the FastScape basement only takes the surface + * velocities into consideration. + */ + void fastscape_set_basement_(double *b); + + /** + * Run FastScape for a single FastScape timestep. + */ + void fastscape_execute_step_(); + + /** + * Create a .VTK file for the FastScape surface within the FastScape folder of the + * ASPECT output folder. + */ + void fastscape_named_vtk_(double *fp, + const double *vexp, + unsigned int *astep, + const char *c, + const unsigned int *length); + + /** + * Copy the current FastScape topography. + */ + void fastscape_copy_h_(double *hp); + + /** + * Copy the current FastScape basement. + */ + void fastscape_copy_basement_(double *b); + + /** + * Copy the current FastScape silt fraction. + */ + void fastscape_copy_f_(double *sf); + + /** + * Copy the current FastScape slopes. + */ + void fastscape_copy_slope_(double *slopep); + + /** + * Destroy FastScape. + */ + void fastscape_destroy_(); + } + + + template + FastScape::~FastScape () + { + // It doesn't seem to matter if this is done on all processors or only on the one that runs + // FastScape as the destroy function checks if the memory is allocated. + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + fastscape_destroy_(); + } + + template + void + FastScape::initialize () + { + AssertThrow(Plugins::plugin_type_matches>(this->get_geometry_model()), + ExcMessage("FastScape can only be run with a box geometry model.")); + + const GeometryModel::Box *geometry + = dynamic_cast*> (&this->get_geometry_model()); + + // Find the id associated with the top boundary and boundaries that call mesh deformation. + const types::boundary_id top_boundary = this->get_geometry_model().translate_symbolic_boundary_name_to_id ("top"); + const std::set mesh_deformation_boundary_ids + = this->get_mesh_deformation_handler().get_active_mesh_deformation_boundary_indicators(); + + // Get the deformation type names called for each boundary. + std::map> mesh_deformation_boundary_indicators_map + = this->get_mesh_deformation_handler().get_active_mesh_deformation_names(); + + // Loop over each mesh deformation boundary, and make sure FastScape is only called on the surface. + for (const types::boundary_id id : mesh_deformation_boundary_ids) + { + const std::vector &names = mesh_deformation_boundary_indicators_map[id]; + for (const auto &name : names) + { + if (name == "fastscape") + AssertThrow(id == top_boundary, + ExcMessage("FastScape can only be called on the surface boundary.")); + } + } + + // Several compositional fields are commonly used in conjunction with the FastScape plugin, i.e. + // "sediment_age" to track the age of the sediment deposited and "deposition_depth" to track the depth + // with respect to the unperturbed surface of the model domain. Their values are controlled by setting + // boundary conditions on the top boundary that is deformed by FastScape. While it is useful to track these + // fields, they are not needed for any function in the FastScape plugin. If they exist however, we need + // to make sure that these fields do not have the type "chemical composition" and are therefore not taken + // into account when computing material properties. + const std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); + if (this->introspection().compositional_name_exists("sediment_age")) + { + const std::vector::const_iterator + it = std::find(chemical_field_names.begin(), chemical_field_names.end(), "sediment_age"); + AssertThrow (it == chemical_field_names.end(), + ExcMessage("There is a field sediment_age that is of type chemical composition. " + "Please change it to type generic so that it does not affect material properties.")); + } + if (this->introspection().compositional_name_exists("deposition_depth")) + { + const std::vector::const_iterator + it = std::find(chemical_field_names.begin(), chemical_field_names.end(), "deposition_depth"); + AssertThrow (it == chemical_field_names.end(), + ExcMessage("There is a field deposition_depth that is of type chemical composition. " + "Please change it to type generic so that it does not affect material properties.")); + } + + // Initialize parameters for restarting FastScape + restart = this->get_parameters().resume_computation; + + // Since we don't open these until we're on one process, we need to check if the + // restart files exist beforehand. + if (restart) + { + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + AssertThrow(Utilities::fexists(this->get_output_directory() + "fastscape_elevation_restart.txt"), + ExcMessage("Cannot open topography file to restart FastScape.")); + AssertThrow(Utilities::fexists(this->get_output_directory() + "fastscape_basement_restart.txt"), + ExcMessage("Cannot open basement file to restart FastScape.")); + AssertThrow(Utilities::fexists(this->get_output_directory() + "fastscape_silt_fraction_restart.txt"), + ExcMessage("Cannot open silt fraction file to restart FastScape.")); + } + } + + // The first entry represents the minimum coordinates of the model domain, the second the model extent. + for (unsigned int d=0; dget_origin()[d]; + grid_extent[d].second = geometry->get_extents()[d]; + } + + // Get the x and y repetitions used in the parameter file so + // the FastScape cell size can be properly set. + const std::array repetitions = geometry->get_repetitions(); + + // Set number of x points, which is generally 1+(FastScape refinement level)^2. + // The FastScape refinement level is a combination of the maximum ASPECT refinement level + // at the surface and any additional refinement we want in FastScape. If + // repetitions are specified we need to adjust the number of points to match what ASPECT has, + // which can be determined by multiplying the points by the repetitions before adding 1. + // Finally, if ghost nodes are used we add two additional points on each side. + const unsigned int ghost_nodes = 2*use_ghost_nodes; + const unsigned int fastscape_refinement_level = maximum_surface_refinement_level + additional_refinement_levels; + const unsigned int fastscape_nodes = std::pow(2,fastscape_refinement_level); + fastscape_nx = fastscape_nodes * repetitions[0] + ghost_nodes + 1; + + // Size of FastScape cell. + fastscape_dx = (grid_extent[0].second)/(fastscape_nodes * repetitions[0]); + + // FastScape X extent, which is generally ASPECT's extent unless the ghost nodes are used, + // in which case 2 cells are added on either side. + fastscape_x_extent = (grid_extent[0].second) + fastscape_dx * ghost_nodes; + + // Sub intervals are 3 less than points, if including the ghost nodes. Otherwise 1 less. + table_intervals[0] = fastscape_nodes * repetitions[0]; + table_intervals[dim-1] = 1; + + if (dim == 2) + { + fastscape_dy = fastscape_dx; + fastscape_y_extent = round(fastscape_y_extent_2d/fastscape_dy)*fastscape_dy + fastscape_dy * ghost_nodes; + fastscape_ny = 1+fastscape_y_extent/fastscape_dy; + } + else + { + fastscape_ny = fastscape_nodes * repetitions[1] + ghost_nodes + 1; + fastscape_dy = (grid_extent[1].second)/(fastscape_nodes * repetitions[1]); + table_intervals[1] = fastscape_nodes * repetitions[1]; + fastscape_y_extent = (grid_extent[1].second) + fastscape_dy * ghost_nodes; + } + + // Create a folder for the FastScape visualization files. + Utilities::create_directory (this->get_output_directory() + "fastscape/", + this->get_mpi_communicator(), + false); + + last_output_time = 0; + } + + + template + void + FastScape::compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, + AffineConstraints &mesh_velocity_constraints, + const std::set &boundary_ids) const + { + + // Because there is no increase in time during timestep 0, we return and only + // initialize and run FastScape from timestep 1 and on. + if (this->get_timestep_number() == 0) + return; + + TimerOutput::Scope timer_section(this->get_computing_timer(), "FastScape plugin"); + + const unsigned int current_timestep = this->get_timestep_number (); + const double aspect_timestep_in_years = this->get_timestep() / year_in_seconds; + + // Find a FastScape timestep that is below our maximum timestep. + unsigned int fastscape_iterations = fastscape_steps_per_aspect_step; + double fastscape_timestep_in_years = aspect_timestep_in_years/fastscape_iterations; + while (fastscape_timestep_in_years>maximum_fastscape_timestep) + { + fastscape_iterations *= 2; + fastscape_timestep_in_years *= 0.5; + } + + // Vector to hold the velocities that represent the change to the surface. + const unsigned int fastscape_array_size = fastscape_nx*fastscape_ny; + std::vector mesh_velocity_z(fastscape_array_size); + + // FastScape requires multiple specially defined and ordered variables sent to its functions. To make + // the transfer of these down to one process easier, we first fill out a vector of local_aspect_values, + // then when we get down to one process we use these local_aspect_values to fill the double arrays + // in the order needed for FastScape. + std::vector> local_aspect_values = get_aspect_values(); + + // Run FastScape on single process. + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + // Initialize the variables that will be sent to FastScape. + // Elevation is initialized at a very high number so that we can later check that all points + // received data from ASPECT, and if not throw an assert. + std::vector elevation(fastscape_array_size, std::numeric_limits::max()); + std::vector velocity_x(fastscape_array_size); + std::vector velocity_y(fastscape_array_size); + std::vector velocity_z(fastscape_array_size); + std::vector bedrock_river_incision_rate_array(fastscape_array_size); + std::vector bedrock_transport_coefficient_array(fastscape_array_size); + std::vector basement(fastscape_array_size); + std::vector silt_fraction(fastscape_array_size); + std::vector elevation_old(fastscape_array_size); + + fill_fastscape_arrays(elevation, + bedrock_transport_coefficient_array, + bedrock_river_incision_rate_array, + velocity_x, + velocity_y, + velocity_z, + local_aspect_values); + + if (current_timestep == 1 || restart) + { + this->get_pcout() << " Initializing FastScape... " << (1+maximum_surface_refinement_level+additional_refinement_levels) << + " levels, cell size: " << fastscape_dx << " m." << std::endl; + + // Set ghost nodes before initializing. + if (use_ghost_nodes && !restart) + set_ghost_nodes(elevation, + velocity_x, + velocity_y, + velocity_z, + fastscape_timestep_in_years, + true); + + // If we are restarting from a checkpoint, load h values for FastScape instead of using the ASPECT values. + if (restart) + { + read_restart_files(elevation, + basement, + silt_fraction); + + restart = false; + } + + initialize_fastscape(elevation, + basement, + bedrock_transport_coefficient_array, + bedrock_river_incision_rate_array, + silt_fraction); + } + else + { + // If it isn't the first timestep we ignore initialization and instead copy all height values from FastScape. + // Generally, we overwrite the topography data from ASPECT as FastScape may be at a higher resolution. However, + // if we are not using FastScape to advect then we do not want to do this and instead use the ASPECT values. + if (fastscape_advection_uplift) + fastscape_copy_h_(elevation.data()); + } + + // Find the appropriate sediment rain based off the time interval. + const double time_in_years = this->get_time() / year_in_seconds; + auto it = std::lower_bound(sediment_rain_times.begin(), sediment_rain_times.end(), time_in_years); + const unsigned int inds = std::distance(sediment_rain_times.begin(), it); + const double sediment_rain = sediment_rain_rates[inds]; + + // Keep initial h values so we can calculate velocity later. + // In the first timestep, h will be given from other processes. + // In later timesteps, we copy h directly from FastScape. + std::mt19937 random_number_generator(fastscape_seed); + std::uniform_real_distribution random_distribution(-noise_elevation,noise_elevation); + for (unsigned int i=0; i 0 && use_marine_component) + { + // Only apply sediment rain to areas below sea level. + if (elevation[i] < sea_level) + { + // If the rain would put us above sea level, set height to sea level. + if (elevation[i] + sediment_rain*aspect_timestep_in_years > sea_level) + elevation[i] = sea_level; + else + elevation[i] = std::min(sea_level,elevation[i] + sediment_rain*aspect_timestep_in_years); + } + } + } + } + + // The ghost nodes are added as a single layer of points surrounding the entire model. + // For example, if ASPECT's surface mesh is a 2D surface that is 3x3 (nx x ny) points, + // FastScape will be set as a 2D 5x5 point surface. On return to ASPECT, the outer ghost nodes + // will be ignored, and ASPECT will see only the inner 3x3 surface of FastScape. + if (use_ghost_nodes) + set_ghost_nodes(elevation, + velocity_x, + velocity_y, + velocity_z, + fastscape_timestep_in_years, + false); + + // If specified, apply the orographic controls to the FastScape model. + if (use_orographic_controls) + apply_orographic_controls(elevation, + bedrock_transport_coefficient_array, + bedrock_river_incision_rate_array); + + // Set velocity components. + if (fastscape_advection_uplift) + { + fastscape_set_u_(velocity_z.data()); + fastscape_set_v_(velocity_x.data(), + velocity_y.data()); + } + + // Set h to new values, and erosional parameters if there have been changes. + fastscape_set_h_(elevation.data()); + + fastscape_set_erosional_parameters_(bedrock_river_incision_rate_array.data(), + &sediment_river_incision_rate, + &drainage_area_exponent_m, + &slope_exponent_n, + bedrock_transport_coefficient_array.data(), + &sediment_transport_coefficient, + &bedrock_deposition_g, + &sediment_deposition_g, + &slope_exponent_p); + + // Find timestep size, run FastScape, and make visualizations. + execute_fastscape(elevation, + bedrock_transport_coefficient_array, + velocity_x, + velocity_y, + velocity_z, + fastscape_timestep_in_years, + fastscape_iterations); + + // Write a file to store h, b & step for restarting. + // TODO: It would be good to roll this into the general ASPECT checkpointing, + // and when we do this needs to be changed. + if (((this->get_parameters().checkpoint_time_secs == 0) && + (this->get_parameters().checkpoint_steps > 0) && + ((current_timestep + 1) % this->get_parameters().checkpoint_steps == 0)) || + (this->get_time() == this->get_end_time() && this->get_timestepping_manager().need_checkpoint_on_terminate())) + { + save_restart_files(elevation, + basement, + silt_fraction); + } + + // Find out our velocities from the change in height. + // Where mesh_velocity_z is a vector of array size that exists on all processes. + for (unsigned int i=0; iget_mpi_communicator(), mesh_velocity_z, 0); + } + else + { + for (unsigned int i=0; iget_mpi_communicator()); + + // Check whether the FastScape mesh was filled with data. + const bool fastscape_mesh_filled = Utilities::MPI::broadcast (this->get_mpi_communicator(), true, 0); + if (fastscape_mesh_filled != true) + throw aspect::QuietException(); + + // This is called solely so we can set the timer and will return immediately. + execute_fastscape(mesh_velocity_z, + mesh_velocity_z, + mesh_velocity_z, + mesh_velocity_z, + mesh_velocity_z, + aspect_timestep_in_years, + fastscape_steps_per_aspect_step); + + mesh_velocity_z = Utilities::MPI::broadcast(this->get_mpi_communicator(), mesh_velocity_z, 0); + } + + // Get the sizes needed for a data table of the mesh velocities. + TableIndices size_idx; + for (unsigned int d=0; d velocity_table = fill_data_table(mesh_velocity_z, size_idx, fastscape_nx, fastscape_ny); + + // As our grid_extent variable end points do not account for the change related to an origin + // not at 0, we adjust this here into an interpolation extent. + std::array,dim> interpolation_extent; + for (unsigned int d=0; d *velocities; + Functions::InterpolatedUniformGridData velocities (interpolation_extent, + table_intervals, + velocity_table); + + VectorFunctionFromScalarFunctionObject vector_function_object( + [&](const Point &p) -> double + { + return velocities.value(p); + }, + dim-1, + dim); + + VectorTools::interpolate_boundary_values (mesh_deformation_dof_handler, + *boundary_ids.begin(), + vector_function_object, + mesh_velocity_constraints); + } + + + template + std::vector> + FastScape::get_aspect_values() const + { + + const types::boundary_id relevant_boundary = this->get_geometry_model().translate_symbolic_boundary_name_to_id ("top"); + std::vector> local_aspect_values(dim+2, std::vector()); + + // Get a quadrature rule that exists only on the corners, and increase the refinement if specified. + const QIterated face_corners (QTrapezoid<1>(), + std::pow(2,additional_refinement_levels+surface_refinement_difference)); + + FEFaceValues fe_face_values (this->get_mapping(), + this->get_fe(), + face_corners, + update_values | + update_quadrature_points); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + for (unsigned int face_no = 0; face_no < GeometryInfo::faces_per_cell; ++face_no) + if (cell->face(face_no)->at_boundary()) + { + if ( cell->face(face_no)->boundary_id() != relevant_boundary) + continue; + + std::vector> vel(face_corners.size()); + fe_face_values.reinit(cell, face_no); + fe_face_values[this->introspection().extractors.velocities].get_function_values(this->get_solution(), vel); + + for (unsigned int corner = 0; corner < face_corners.size(); ++corner) + { + const Point vertex = fe_face_values.quadrature_point(corner); + + // Find what x point we're at. Add 1 or 2 depending on if ghost nodes are used. + // Subtract the origin point so that it corresponds to an origin of 0,0 in FastScape. + const double indx = 1+use_ghost_nodes+(vertex(0) - grid_extent[0].first)/fastscape_dx; + + // The quadrature rule is created so that there are enough interpolation points in the + // lowest resolved ASPECT surface cell to fill out the FastScape mesh. However, as the + // same rule is used for all cell sizes, higher resolution areas will have interpolation + // points that do not correspond to a FastScape node. In which case, indx will not be a + // whole number and we can ignore the point. + if (std::abs(indx - round(indx)) >= node_tolerance) + continue; + + + // If we're in 2D, we want to take the values and apply them to every row of X points. + if (dim == 2) + { + for (unsigned int ys=0; ys= node_tolerance) + continue; + + const double index = round((indy-1))*fastscape_nx+round(indx); + + local_aspect_values[0].push_back(vertex(dim-1) - grid_extent[dim-1].second); //z component + local_aspect_values[1].push_back(index-1); + + for (unsigned int d=0; d + void FastScape::fill_fastscape_arrays(std::vector &elevation, + std::vector &bedrock_transport_coefficient_array, + std::vector &bedrock_river_incision_rate_array, + std::vector &velocity_x, + std::vector &velocity_y, + std::vector &velocity_z, + std::vector> &local_aspect_values) const + { + for (unsigned int i=0; iget_mpi_communicator()); ++p) + { + // First, find out the size of the array a process wants to send. + MPI_Status status; + MPI_Probe(p, 42, this->get_mpi_communicator(), &status); + int incoming_size = 0; + MPI_Get_count(&status, MPI_DOUBLE, &incoming_size); + + // Resize the array so it fits whatever the process sends. + for (unsigned int i=0; iget_mpi_communicator(), &status); + + // Now, place the numbers into the correct place based off the index. + for (unsigned int i=0; i::max() && !is_ghost_node(i,false)) + fastscape_mesh_filled = false; + } + + Utilities::MPI::broadcast(this->get_mpi_communicator(), fastscape_mesh_filled, 0); + AssertThrow (fastscape_mesh_filled == true, + ExcMessage("The FastScape mesh is missing data. A likely cause for this is that the " + "maximum surface refinement or surface refinement difference are improperly set.")); + } + + + template + void FastScape::initialize_fastscape(std::vector &elevation, + std::vector &basement, + std::vector &bedrock_transport_coefficient_array, + std::vector &bedrock_river_incision_rate_array, + std::vector &silt_fraction) const + { + Assert (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0, ExcInternalError()); + + const unsigned int current_timestep = this->get_timestep_number (); + + // Initialize FastScape with grid and extent. + fastscape_init_(); + fastscape_set_nx_ny_(&fastscape_nx, + &fastscape_ny); + fastscape_setup_(); + fastscape_set_xl_yl_(&fastscape_x_extent, + &fastscape_y_extent); + + // Set boundary conditions + fastscape_set_bc_(&fastscape_boundary_conditions); + + // Initialize topography + fastscape_init_h_(elevation.data()); + + // Set erosional parameters. + fastscape_set_erosional_parameters_(bedrock_river_incision_rate_array.data(), + &sediment_river_incision_rate, + &drainage_area_exponent_m, + &slope_exponent_n, + bedrock_transport_coefficient_array.data(), + &sediment_transport_coefficient, + &bedrock_deposition_g, + &sediment_deposition_g, + &slope_exponent_p); + + if (use_marine_component) + fastscape_set_marine_parameters_(&sea_level, + &sand_surface_porosity, + &silt_surface_porosity, + &sand_efold_depth, + &silt_efold_depth, + &sand_silt_ratio, + &sand_silt_averaging_depth, + &sand_transport_coefficient, + &silt_transport_coefficient); + + // Only set the basement and silt_fraction if it's a restart + if (current_timestep != 1) + { + fastscape_set_basement_(basement.data()); + if (use_marine_component) + fastscape_init_f_(silt_fraction.data()); + } + + } + + + template + void FastScape::execute_fastscape(std::vector &elevation, + std::vector &extra_vtk_field, + std::vector &velocity_x, + std::vector &velocity_y, + std::vector &velocity_z, + const double &fastscape_timestep_in_years, + const unsigned int &fastscape_iterations) const + { + TimerOutput::Scope timer_section(this->get_computing_timer(), "Execute FastScape"); + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) != 0) + return; + + // Because on the first timestep we will create an initial VTK file before running FastScape + // and a second after, we first set the visualization step to zero. + unsigned int visualization_step = 0; + const unsigned int current_timestep = this->get_timestep_number (); + std::string dirname = (this->get_output_directory() + "fastscape/"); + const char *dirname_char=dirname.c_str(); + const unsigned int dirname_length = dirname.length(); + + // Set time step + fastscape_set_dt_(&fastscape_timestep_in_years); + this->get_pcout() << " Executing FastScape... " << (fastscape_iterations) << " timesteps of " << fastscape_timestep_in_years << " years." << std::endl; + { + // If it is the first timestep, write an initial VTK file. + if (current_timestep == 1) + { + this->get_pcout() << " Writing initial VTK..." << std::endl; + // FastScape by default visualizes a field called HHHHH, + // and the parameter this shows will be whatever is given as the first + // position. At the moment it visualizes the bedrock diffusivity. + fastscape_named_vtk_(extra_vtk_field.data(), + &vexp, + &visualization_step, + dirname_char, + &dirname_length); + } + + for (unsigned int fastscape_iteration = 0; fastscape_iteration < fastscape_iterations; ++fastscape_iteration) + { + fastscape_execute_step_(); + + // If we are using the ghost nodes we want to reset them every FastScape timestep. + if (use_ghost_nodes) + { + fastscape_copy_h_(elevation.data()); + + set_ghost_nodes(elevation, + velocity_x, + velocity_y, + velocity_z, + fastscape_timestep_in_years, + false); + + // Set velocity components. + if (fastscape_advection_uplift) + { + fastscape_set_u_(velocity_z.data()); + fastscape_set_v_(velocity_x.data(), + velocity_y.data()); + } + + // Set h to new values, and erosional parameters if there have been changes. + fastscape_set_h_(elevation.data()); + } + } + + // Copy h values. + fastscape_copy_h_(elevation.data()); + + + // Determine whether to create a VTK file this timestep. + bool write_vtk = false; + + if (this->get_time() >= last_output_time + output_interval || this->get_time() == this->get_end_time()) + { + write_vtk = true; + + if (output_interval > 0) + { + // We need to find the last time output was supposed to be written. + // this is the last_output_time plus the largest positive multiple + // of output_intervals that passed since then. We need to handle the + // edge case where last_output_time+output_interval==current_time, + // we did an output and std::floor sadly rounds to zero. This is done + // by forcing std::floor to round 1.0-eps to 1.0. + const double magic = 1.0+2.0*std::numeric_limits::epsilon(); + last_output_time = last_output_time + std::floor((this->get_time()-last_output_time)/output_interval*magic) * output_interval/magic; + } + } + + if (write_vtk) + { + this->get_pcout() << " Writing FastScape VTK..." << std::endl; + visualization_step = current_timestep; + fastscape_named_vtk_(extra_vtk_field.data(), + &vexp, + &visualization_step, + dirname_char, + &dirname_length); + } + } + } + + + template + void FastScape::apply_orographic_controls(const std::vector &elevation, + std::vector &bedrock_transport_coefficient_array, + std::vector &bedrock_river_incision_rate_array) const + { + // First for the wind barrier, we find the maximum height and index + // along each line in the x and y direction. + // If wind is east or west, we find maximum point for each ny row along x. + const unsigned int fastscape_array_size = fastscape_nx*fastscape_ny; + std::vector> max_elevation_along_x(2, std::vector(fastscape_ny, 0.0)); + if (wind_direction == 0 || wind_direction == 1) + { + for (unsigned int i=0; i max_elevation_along_x[0][i]) + { + // Maximum elevation value along the ny row. + max_elevation_along_x[0][i] = elevation[fastscape_nx*i+j]; + // Location of maximum elevation. + max_elevation_along_x[1][i] = j; + } + } + } + } + + // If wind is north or south, we find maximum point for each nx row along y. + std::vector> max_elevation_along_y(2, std::vector(fastscape_nx, 0.0)); + if (wind_direction == 2 || wind_direction == 3) + { + for (unsigned int i=0; i max_elevation_along_y[0][i]) + { + max_elevation_along_y[0][i] = elevation[fastscape_nx*j+i]; + max_elevation_along_y[1][i] = j; + } + } + } + } + + // Now we loop through all the points again and apply the factors. + std::vector control_applied(fastscape_array_size, 0); + for (unsigned int i=0; i wind_barrier_elevation) && (j < max_elevation_along_x[1][i]) ) + { + bedrock_river_incision_rate_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; + bedrock_transport_coefficient_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; + control_applied[fastscape_nx*i+j] = 1; + } + break; + } + case 1 : + { + if ( (max_elevation_along_x[0][i] > wind_barrier_elevation) && (j > max_elevation_along_x[1][i]) ) + { + bedrock_river_incision_rate_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; + bedrock_transport_coefficient_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; + control_applied[fastscape_nx*i+j] = 1; + } + break; + } + case 2 : + { + if ( (max_elevation_along_y[0][j] > wind_barrier_elevation) && (i > max_elevation_along_y[1][j]) ) + { + bedrock_river_incision_rate_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; + bedrock_transport_coefficient_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; + control_applied[fastscape_nx*i+j] = 1; + } + break; + } + case 3 : + { + if ( (max_elevation_along_y[0][j] > wind_barrier_elevation) && (i < max_elevation_along_y[1][j]) ) + { + bedrock_river_incision_rate_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; + bedrock_transport_coefficient_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; + control_applied[fastscape_nx*i+j] = 1; + } + break; + } + default : + AssertThrow(false, ExcMessage("This does not correspond with a wind direction.")); + break; + } + + // If we are above the flat elevation and stack controls, apply the flat elevation factor. If we are not + // stacking controls, apply the factor if the wind barrier was not applied to this point. + if (elevation[fastscape_nx*i+j] > flat_elevation) + { + if ( stack_controls==true || !stack_controls && (control_applied[fastscape_nx*i+j]==0) ) + { + bedrock_river_incision_rate_array[fastscape_nx*i+j] *= flat_erosional_factor; + bedrock_transport_coefficient_array[fastscape_nx*i+j] *= flat_erosional_factor; + } + // If we are not stacking controls and the wind barrier was applied to this point, only + // switch to this control if the factor is greater. + else if ( stack_controls==false && (control_applied[fastscape_nx*i+j]==1) && (flat_erosional_factor > wind_barrier_erosional_factor) ) + { + if ( wind_barrier_erosional_factor != 0) + { + bedrock_river_incision_rate_array[fastscape_nx*i+j] = (bedrock_river_incision_rate_array[fastscape_nx*i+j]/wind_barrier_erosional_factor)*flat_erosional_factor; + bedrock_transport_coefficient_array[fastscape_nx*i+j] = (bedrock_transport_coefficient_array[fastscape_nx*i+j]/wind_barrier_erosional_factor)*flat_erosional_factor; + } + // If a wind barrier factor of zero was applied for some reason, we set it back to the default + // and apply the flat_erosional_factor. + else + { + bedrock_river_incision_rate_array[fastscape_nx*i+j] = bedrock_river_incision_rate*flat_erosional_factor; + bedrock_transport_coefficient_array[fastscape_nx*i+j] = bedrock_transport_coefficient*flat_erosional_factor; + } + } + } + } + } + } + + + template + void FastScape::set_ghost_nodes(std::vector &elevation, + std::vector &velocity_x, + std::vector &velocity_y, + std::vector &velocity_z, + const double &fastscape_timestep_in_years, + const bool init) const + { + // Copy the slopes at each point, this will be used to set an H + // at the ghost nodes if a boundary mass flux is given. + const unsigned int fastscape_array_size = fastscape_nx*fastscape_ny; + std::vector slopep(fastscape_array_size); + + if (!init) + fastscape_copy_slope_(slopep.data()); + + // Here we set the ghost nodes at the left and right boundaries. In most cases, + // this involves setting the node to the same values of v and h as the inward node. + // With the inward node being above or below for the bottom and top rows of ghost nodes, + // or to the left and right for the right and left columns of ghost nodes. + for (unsigned int j=0; j 0) + { + slope = 0; + if (j == 0) + slope = left_flux / bedrock_transport_coefficient - std::tan(slopep[index_left + fastscape_nx + 1] * numbers::PI / 180.); + else if (j == (fastscape_ny - 1)) + slope = left_flux / bedrock_transport_coefficient - std::tan(slopep[index_left - fastscape_nx + 1] * numbers::PI / 180.); + else + slope = left_flux / bedrock_transport_coefficient - std::tan(slopep[index_left + 1] * numbers::PI / 180.); + + elevation[index_left] = elevation[index_left] + slope * 2 * fastscape_dx; + } + else + elevation[index_left] = elevation[index_left + 1]; + } + + if (right == 0 && !init) + { + + if (right_flux > 0) + { + slope = 0; + if (j == 0) + slope = right_flux / bedrock_transport_coefficient - std::tan(slopep[index_right + fastscape_nx - 1] * numbers::PI / 180.); + else if (j == (fastscape_ny - 1)) + slope = right_flux / bedrock_transport_coefficient - std::tan(slopep[index_right - fastscape_nx - 1] * numbers::PI / 180.); + else + slope = right_flux / bedrock_transport_coefficient - std::tan(slopep[index_right - 1] * numbers::PI / 180.); + + elevation[index_right] = elevation[index_right] + slope * 2 * fastscape_dx; + } + else + elevation[index_right] = elevation[index_right - 1]; + + + } + + // If the boundaries are periodic, then we look at the velocities on both sides of the + // model, and set the ghost node according to the direction of flow. As FastScape will + // receive all velocities it will have a direction, and we only need to look at the (non-ghost) + // nodes directly to the left and right. + if (left == 0 && right == 0 || leftright_ghost_nodes_periodic == true) + { + // First we assume that flow is going to the left. + unsigned int side = index_left; + unsigned int op_side = index_right; + + // Indexing depending on which side the ghost node is being set to. + int jj = 1; + + // If nodes on both sides are going the same direction, then set the respective + // ghost nodes to equal these sides. By doing this, the ghost nodes at the opposite + // side of flow will work as a mirror mimicking what is happening on the other side. + if (velocity_x[index_right-1] > 0 && velocity_x[index_left+1] >= 0) + { + side = index_right; + op_side = index_left; + jj = -1; + } + else if (velocity_x[index_right-1] <= 0 && velocity_x[index_left+1] < 0) + { + side = index_left; + op_side = index_right; + jj = 1; + } + else + continue; + + // Now set the nodes for periodic boundaries. As an example, assume we have 9 FastScape nodes in x: + // + // 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 + // + // Of these 9 nodes, 0 and 8 are ghost nodes and 1 and 7 are the periodic ASPECT boundaries. + // If we assume that the horizontal ASPECT direction of travel is towards node 7, then we would + // set the ghost node 8 velocities and heights to that of node 2, ghost node 0 to node 6, and + // ASPECT boundary node 1 to ASPECT boundary node 7. E.g., based on the FastScape values for + // vx, vy, vz, and elevation, the nodes could be rewritten as: + // + // 6 - 7 - 2 - 3 - 4 - 5 - 6 - 7 - 2 + // + // This makes it so that effectively both periodic ASPECT boundaries see the same + // topography on either side of them to try and make sure they experience the same + // amount of diffusion and SPL. + velocity_x[index_right] = velocity_x[index_left+2]; + velocity_y[index_right] = velocity_y[index_left+2]; + velocity_z[index_right] = velocity_z[index_left+2] + (elevation[index_left+2] - elevation[index_right])/fastscape_timestep_in_years; + + velocity_x[index_left] = velocity_x[index_right-2]; + velocity_y[index_left] = velocity_y[index_right-2]; + velocity_z[index_left] = velocity_z[index_right-2] + (elevation[index_right-2] - elevation[index_left])/fastscape_timestep_in_years; + + // Set opposing ASPECT boundary so it's periodic. + elevation[op_side-jj] = elevation[side+jj]; + velocity_x[op_side-jj] = velocity_x[side+jj]; + velocity_y[op_side-jj] = velocity_y[side+jj]; + velocity_z[op_side-jj] = velocity_z[side+jj]; + + } + } + + // Now do the same for the top and bottom ghost nodes. + for (unsigned int j=0; j 0) + { + slope = 0; + if (j == 0) + slope = top_flux / bedrock_transport_coefficient - std::tan(slopep[index_top - fastscape_nx + 1] * numbers::PI / 180.); + else if (j == (fastscape_nx - 1)) + slope = top_flux / bedrock_transport_coefficient - std::tan(slopep[index_top - fastscape_nx - 1] * numbers::PI / 180.); + else + slope = top_flux / bedrock_transport_coefficient - std::tan(slopep[index_top - fastscape_nx] * numbers::PI / 180.); + + elevation[index_top] = elevation[index_top] + slope * 2 * fastscape_dx; + } + else + elevation[index_top] = elevation[index_top - fastscape_nx]; + } + + if (bottom == 0 && !init) + { + if (left_flux > 0) + { + slope = 0; + if (j == 0) + slope = bottom_flux / bedrock_transport_coefficient - std::tan(slopep[index_bot + fastscape_nx + 1] * numbers::PI / 180.); + else if (j == (fastscape_nx - 1)) + slope = bottom_flux / bedrock_transport_coefficient - std::tan(slopep[index_bot + fastscape_nx - 1] * numbers::PI / 180.); + else + slope = bottom_flux / bedrock_transport_coefficient - std::tan(slopep[index_bot + fastscape_nx] * numbers::PI / 180.); + + elevation[index_bot] = elevation[index_bot] + slope * 2 * fastscape_dx; + } + else + elevation[index_bot] = elevation[index_bot + fastscape_nx]; + } + + if (bottom == 0 && top == 0 || topbottom_ghost_nodes_periodic == true) + { + unsigned int side = index_bot; + unsigned int op_side = index_top; + int jj = fastscape_nx; + + if (velocity_y[index_bot+fastscape_nx-1] > 0 && velocity_y[index_top-fastscape_nx-1] >= 0) + { + side = index_top; + op_side = index_bot; + jj = -fastscape_nx; + } + else if (velocity_y[index_bot+fastscape_nx-1] <= 0 && velocity_y[index_top-fastscape_nx-1] < 0) + { + side = index_bot; + op_side = index_top; + jj = fastscape_nx; + } + else + continue; + + // Set top ghost node + velocity_x[index_top] = velocity_x[index_bot + 2*fastscape_nx]; + velocity_y[index_top] = velocity_y[index_bot + 2*fastscape_nx]; + velocity_z[index_top] = velocity_z[index_bot + 2*fastscape_nx] + (elevation[index_bot + 2*fastscape_nx] - elevation[index_top])/fastscape_timestep_in_years; + + // Set bottom ghost node + velocity_x[index_bot] = velocity_x[index_top - 2*fastscape_nx]; + velocity_y[index_bot] = velocity_y[index_top - 2*fastscape_nx]; + velocity_z[index_bot] = velocity_z[index_top - 2*fastscape_nx] + (elevation[index_top - 2*fastscape_nx] - elevation[index_bot])/fastscape_timestep_in_years; + + // Set opposing ASPECT boundary so it's periodic. + elevation[op_side-jj] = elevation[side+jj]; + velocity_x[op_side-jj] = velocity_x[side+jj]; + velocity_y[op_side-jj] = velocity_y[side+jj]; + velocity_z[op_side-jj] = velocity_z[side+jj]; + } + } + } + + template + bool FastScape::is_ghost_node(const unsigned int &index, + const bool &exclude_boundaries) const + { + if (use_ghost_nodes == false && exclude_boundaries == false) + return false; + + const unsigned int row = index / fastscape_nx; // Calculate the row index + const unsigned int col = index % fastscape_nx; // Calculate the column index + + // If we are at a boundary node and ghost nodes are enabled + // or we are excluding the boundaries then return true. + if (row == 0 || row == fastscape_ny-1 || col == 0 || col == fastscape_nx-1) + return true; + else + return false; + } + + + template + Table + FastScape::fill_data_table(std::vector &values, + TableIndices &size_idx, + const unsigned int &fastscape_nx, + const unsigned int &fastscape_ny) const + { + // Create data table based off of the given size. + Table data_table; + data_table.TableBase::reinit(size_idx); + TableIndices idx; + + // Loop through the data table and fill it with the velocities from FastScape. + if (dim == 2) + { + std::vector values_2d(fastscape_nx); + + for (unsigned int x=use_ghost_nodes; x<(fastscape_nx-use_ghost_nodes); ++x) + { + // If we do not average the values, then use a slice near the center. + if (!average_out_of_plane_surface_topography) + { + const unsigned int index = x+fastscape_nx*(round((fastscape_ny-use_ghost_nodes)/2)); + + // If we are using the ghost nodes, then the x value locations need to be shifted back 1 + // e.g., given a 4x4 mesh an index of 5 would correspond to an x of 1 and y of 1 in the loop, + // but should correspond to 0,0 for ASPECT. + values_2d[x-use_ghost_nodes] = values[index]; + } + // Here we use average velocities across the y nodes, excluding the ghost nodes (top and bottom row). + // Note: If ghost nodes are turned off, boundary effects may influence this. + else + { + for (unsigned int y=use_ghost_nodes; y<(fastscape_ny-use_ghost_nodes); ++y) + { + const unsigned int index = x+fastscape_nx*y; + values_2d[x-use_ghost_nodes] += values[index]; + } + values_2d[x-use_ghost_nodes] = values_2d[x-use_ghost_nodes]/(fastscape_ny-2*use_ghost_nodes); + } + } + + for (unsigned int x=0; x + void FastScape::read_restart_files(std::vector &elevation, + std::vector &basement, + std::vector &silt_fraction) const + { + this->get_pcout() << " Loading FastScape restart file... " << std::endl; + + // Create variables for output directory and restart file + const unsigned int fastscape_array_size = fastscape_nx*fastscape_ny; + std::string dirname = this->get_output_directory(); + const std::string restart_filename_elevation = dirname + "fastscape_elevation_restart.txt"; + const std::string restart_filename_basement = dirname + "fastscape_basement_restart.txt"; + const std::string restart_filename_silt_fraction = dirname + "fastscape_silt_fraction_restart.txt"; + const std::string restart_filename_time = dirname + "fastscape_last_output_time.txt"; + + // Load in h values. + std::ifstream in_elevation(restart_filename_elevation); + AssertThrow (in_elevation, ExcIO()); + { + unsigned int line = 0; + while (line < fastscape_array_size) + { + in_elevation >> elevation[line]; + line++; + } + } + + // Load in b values. + std::ifstream in_basement(restart_filename_basement); + AssertThrow (in_basement, ExcIO()); + { + unsigned int line = 0; + while (line < fastscape_array_size) + { + in_basement >> basement[line]; + line++; + } + } + + // Load in silt_fraction values if + // marine sediment transport and deposition is active. + if (use_marine_component) + { + std::ifstream in_silt_fraction(restart_filename_silt_fraction); + AssertThrow (in_silt_fraction, ExcIO()); + + if (sand_surface_porosity > 0. || silt_surface_porosity > 0.) + this->get_pcout() << " Restarting runs with nonzero porosity can lead to a different system after restart. " << std::endl; + unsigned int line = 0; + while (line < fastscape_array_size) + { + in_silt_fraction >> silt_fraction[line]; + line++; + } + } + + // Now load the last output at time of restart. + // this allows us to correctly track when to call + // FastScape to make new VTK files. + std::ifstream in_last_output_time(restart_filename_time); + AssertThrow (in_last_output_time, ExcIO()); + { + in_last_output_time >> last_output_time; + } + } + + template + void FastScape::save_restart_files(const std::vector &elevation, + std::vector &basement, + std::vector &silt_fraction) const + { + this->get_pcout() << " Writing FastScape restart file... " << std::endl; + + // Create variables for output directory and restart file + const unsigned int fastscape_array_size = fastscape_nx*fastscape_ny; + std::string dirname = this->get_output_directory(); + const std::string restart_filename_elevation = dirname + "fastscape_elevation_restart.txt"; + const std::string restart_filename_basement = dirname + "fastscape_basement_restart.txt"; + const std::string restart_filename_silt_fraction = dirname + "fastscape_silt_fraction_restart.txt"; + const std::string restart_filename_time = dirname + "fastscape_last_output_time.txt"; + + std::ofstream out_elevation(restart_filename_elevation); + std::ofstream out_basement(restart_filename_basement); + std::ofstream out_silt_fraction(restart_filename_silt_fraction); + std::ofstream out_last_output_time(restart_filename_time); + std::stringstream buffer_basement; + std::stringstream buffer_elevation; + std::stringstream buffer_silt_fraction; + std::stringstream buffer_time; + + fastscape_copy_basement_(basement.data()); + + // If marine sediment transport and deposition is active, + // we also need to store the silt fraction. + if (use_marine_component) + fastscape_copy_f_(silt_fraction.data()); + + out_last_output_time << last_output_time << "\n"; + + for (unsigned int i = 0; i < fastscape_array_size; ++i) + { + buffer_elevation << elevation[i] << "\n"; + buffer_basement << basement[i] << "\n"; + if (use_marine_component) + buffer_silt_fraction << silt_fraction[i] << "\n"; + } + + out_elevation << buffer_elevation.str(); + out_basement << buffer_basement.str(); + if (use_marine_component) + out_silt_fraction << buffer_silt_fraction.str(); + } + + + + template + bool + FastScape:: + needs_surface_stabilization () const + { + return true; + } + + + + template + void FastScape::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection ("Mesh deformation"); + { + prm.enter_subsection ("Fastscape"); + { + prm.declare_entry("Number of fastscape timesteps per aspect timestep", "5", + Patterns::Integer(), + "Initial number of fastscape time steps per ASPECT timestep, this value will double if" + "the FastScape timestep is above the maximum FastScape timestep."); + prm.declare_entry("Maximum timestep length", "10e3", + Patterns::Double(0), + "Maximum timestep for FastScape. Units: $\\{yrs}$"); + prm.declare_entry("Vertical exaggeration", "-1", + Patterns::Double(), + "Vertical exaggeration for FastScape's VTK file. -1 outputs topography, basement, and sealevel."); + prm.declare_entry("Additional fastscape refinement", "0", + Patterns::Integer(), + "How many levels above ASPECT FastScape should be refined."); + prm.declare_entry ("Average out of plane surface topography in 2d", "true", + Patterns::Bool (), + "If this is set to false, then a 2D model will only consider the " + "center slice FastScape gives. If set to true, then ASPECT will" + "average the mesh along Y excluding the ghost nodes."); + prm.declare_entry("Fastscape seed", "1000", + Patterns::Integer(), + "Seed used for adding an initial noise to FastScape topography based on the initial noise magnitude."); + prm.declare_entry("Maximum surface refinement level", "1", + Patterns::Integer(), + "This should be set to the highest ASPECT refinement level expected at the surface."); + prm.declare_entry("Surface refinement difference", "0", + Patterns::Integer(), + "The difference between the lowest and highest refinement level at the surface. E.g., if three resolution " + "levels are expected, this would be set to 2."); + prm.declare_entry ("Use marine component", "false", + Patterns::Bool (), + "Flag to use the marine component of FastScape."); + prm.declare_entry("Y extent in 2d", "100000", + Patterns::Double(), + "FastScape Y extent when using a 2D ASPECT model. Units: $\\{m}$"); + prm.declare_entry ("Use ghost nodes", "true", + Patterns::Bool (), + "Flag to use ghost nodes"); + prm.declare_entry ("Uplift and advect with fastscape", "true", + Patterns::Bool (), + "Flag to use FastScape advection and uplift."); + prm.declare_entry("Node tolerance", "0.001", + Patterns::Double(), + "Node tolerance for how close an ASPECT node must be to the FastScape node for the value to be transferred."); + prm.declare_entry ("Sediment rain rates", "0,0", + Patterns::List (Patterns::Double(0)), + "Sediment rain rates given as a list 1 greater than the number of sediment rain time intervals. E.g, " + " If the time interval is given at 5 Myr, there will be one value for 0-5 Myr model time and a second value " + " for 5+ Myr. Units: $\\{m/yr}$"); + prm.declare_entry ("Sediment rain time intervals", "0", + Patterns::List (Patterns::Double(0)), + "A list of times to change the sediment rain rate. Units: $\\{yrs}$"); + prm.declare_entry("Initial noise magnitude", "5", + Patterns::Double(), + "Maximum topography change from the initial noise. Units: $\\{m}$"); + + prm.enter_subsection ("Boundary conditions"); + { + prm.declare_entry ("Front", "1", + Patterns::Integer (0, 1), + "Front (bottom) boundary condition, where 1 is fixed and 0 is reflective."); + prm.declare_entry ("Right", "1", + Patterns::Integer (0, 1), + "Right boundary condition, where 1 is fixed and 0 is reflective."); + prm.declare_entry ("Back", "1", + Patterns::Integer (0, 1), + "Back (top) boundary condition, where 1 is fixed and 0 is reflective."); + prm.declare_entry ("Left", "1", + Patterns::Integer (0, 1), + "Left boundary condition, where 1 is fixed and 0 is reflective."); + prm.declare_entry("Left mass flux", "0", + Patterns::Double(), + "Flux per unit length through left boundary. Units: $\\{m^2/yr}$ "); + prm.declare_entry("Right mass flux", "0", + Patterns::Double(), + "Flux per unit length through right boundary. Units: $\\{m^2/yr}$ "); + prm.declare_entry("Back mass flux", "0", + Patterns::Double(), + "Flux per unit length through back boundary. Units: $\\{m^2/yr}$ "); + prm.declare_entry("Front mass flux", "0", + Patterns::Double(), + "Flux per unit length through front boundary. Units: $\\{m^2/yr}$ "); + prm.declare_entry ("Back front ghost nodes periodic", "false", + Patterns::Bool (), + "Whether to set the ghost nodes at the FastScape back and front boundary " + "to periodic even if 'Back' and 'Front' are set to fixed boundary."); + prm.declare_entry ("Left right ghost nodes periodic", "false", + Patterns::Bool (), + "Whether to set the ghost nodes at the FastScape left and right boundary " + "to periodic even if 'Left' and 'Right' are set to fixed boundary."); + } + prm.leave_subsection(); + + prm.enter_subsection ("Erosional parameters"); + { + prm.declare_entry("Drainage area exponent", "0.4", + Patterns::Double(), + "Exponent for drainage area."); + prm.declare_entry("Slope exponent", "1", + Patterns::Double(), + "The slope exponent for SPL (n). Generally m/n should equal approximately 0.4"); + prm.declare_entry("Multi-direction slope exponent", "1", + Patterns::Double(), + "Exponent to determine the distribution from the SPL to neighbor nodes, with" + "10 being steepest decent and 1 being more varied."); + prm.declare_entry("Bedrock deposition coefficient", "1", + Patterns::Double(), + "Deposition coefficient for bedrock."); + prm.declare_entry("Sediment deposition coefficient", "-1", + Patterns::Double(), + "Deposition coefficient for sediment, -1 sets this to the same as the bedrock deposition coefficient."); + prm.declare_entry("Bedrock river incision rate", "1e-5", + Patterns::Double(), + "River incision rate for bedrock in the Stream Power Law. Units: $\\{m^(1-2*drainage_area_exponent)/yr}$"); + prm.declare_entry("Sediment river incision rate", "-1", + Patterns::Double(), + "River incision rate for sediment in the Stream Power Law. -1 sets this to the bedrock river incision rate. Units: $\\{m^(1-2*drainage_area_exponent)/yr}$ "); + prm.declare_entry("Bedrock diffusivity", "1e-2", + Patterns::Double(), + "Transport coefficient (diffusivity) for bedrock. Units: $\\{m^2/yr}$ "); + prm.declare_entry("Sediment diffusivity", "-1", + Patterns::Double(), + "Transport coefficient (diffusivity) for sediment. -1 sets this to the bedrock diffusivity. Units: $\\{m^2/yr}$"); + prm.declare_entry("Orographic elevation control", "2000", + Patterns::Integer(), + "Above this height, the elevation factor is applied. Units: $\\{m}$"); + prm.declare_entry("Orographic wind barrier height", "500", + Patterns::Integer(), + "When terrain reaches this height the wind barrier factor is applied. Units: $\\{m}$"); + prm.declare_entry("Elevation factor", "1", + Patterns::Double(), + "Amount to multiply the bedrock river incision rate nad transport coefficient by past the given orographic elevation control."); + prm.declare_entry("Wind barrier factor", "1", + Patterns::Double(), + "Amount to multiply the bedrock river incision rate nad transport coefficient by past given wind barrier height."); + prm.declare_entry ("Stack orographic controls", "true", + Patterns::Bool (), + "Whether or not to apply both controls to a point, or only a maximum of one set as the wind barrier."); + prm.declare_entry ("Flag to use orographic controls", "false", + Patterns::Bool (), + "Whether or not to apply orographic controls."); + prm.declare_entry ("Wind direction", "west", + Patterns::Selection("east|west|south|north"), + "This parameter assumes a wind direction, deciding which side is reduced from the wind barrier."); + prm.declare_entry ("Use a fixed erosional base level", "false", + Patterns::Bool (), + "Whether or not to use an erosional base level that differs from sea level. Setting this parameter to " + "true will set all ghost nodes of fixed FastScape boundaries to the height you specify in " + "'set Erosional base level'. \nThis can make " + "sense for a continental model where the model surrounding topography is assumed above sea level, " + "e.g. highlands. If the sea level would be used as an erosional base level in this case, all topography " + "erodes away with lots of 'sediment volume' lost through the sides of the model. This is mostly " + "important, when there are mountains in the middle of the model, while it is less important when there " + "is lower relief in the middle of the model. \n" + "In the FastScape visualization files, setting the extra base level may show up as a strong " + "slope at the fixed boundaries of the model. However, in the ASPECT visualization files it will not " + "show up, as the ghost nodes only exist in FastScape."); + prm.declare_entry("Erosional base level", "0", + Patterns::Double(), + "When 'Use a fixed erosional base level' is set to true, all ghost nodes of fixed " + "FastScape boundaries where no mass flux is specified by the user (FastScape boundary condition set to 1 " + "and 'Left/Right/Bottom/Top mass flux' set to 0) will be fixed to this elevation. The " + "reflecting boundaries (FastScape boundary condition set to 0) will not be affected, nor are the " + "boundaries where a mass flux is specified. \n" + "Units: m"); + } + prm.leave_subsection(); + + prm.enter_subsection ("Marine parameters"); + { + prm.declare_entry("Sea level", "0", + Patterns::Double(), + "Sea level relative to the ASPECT surface, where the maximum Z or Y extent in ASPECT is a sea level of zero. Units: $\\{m}$ "); + prm.declare_entry("Sand porosity", "0.0", + Patterns::Double(), + "Porosity of sand. "); + prm.declare_entry("Silt porosity", "0.0", + Patterns::Double(), + "Porosity of silt. "); + prm.declare_entry("Sand e-folding depth", "1e3", + Patterns::Double(), + "E-folding depth for the exponential of the sand porosity law. Units: $\\{m}$"); + prm.declare_entry("Silt e-folding depth", "1e3", + Patterns::Double(), + "E-folding depth for the exponential of the silt porosity law. Units: $\\{m}$"); + prm.declare_entry("Sand-silt ratio", "0.5", + Patterns::Double(), + "Ratio of sand to silt for material leaving continent."); + prm.declare_entry("Depth averaging thickness", "1e2", + Patterns::Double(), + "Depth averaging for the sand-silt equation. Units: $\\{m}$"); + prm.declare_entry("Sand transport coefficient", "5e2", + Patterns::Double(), + "Transport coefficient (diffusivity) for sand. Units: $\\{m^2/yr}$"); + prm.declare_entry("Silt transport coefficient", "2.5e2", + Patterns::Double(), + "Transport coefficient (diffusivity) for silt. Units: $\\{m^2/yr}$ "); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection (); + } + + + template + void FastScape::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection ("Mesh deformation"); + { + prm.enter_subsection("Fastscape"); + { + fastscape_steps_per_aspect_step = prm.get_integer("Number of fastscape timesteps per aspect timestep"); + maximum_fastscape_timestep = prm.get_double("Maximum timestep length"); + vexp = prm.get_double("Vertical exaggeration"); + additional_refinement_levels = prm.get_integer("Additional fastscape refinement"); + average_out_of_plane_surface_topography = prm.get_bool("Average out of plane surface topography in 2d"); + fastscape_seed = prm.get_integer("Fastscape seed"); + maximum_surface_refinement_level = prm.get_integer("Maximum surface refinement level"); + surface_refinement_difference = prm.get_integer("Surface refinement difference"); + use_marine_component = prm.get_bool("Use marine component"); + fastscape_y_extent_2d = prm.get_double("Y extent in 2d"); + use_ghost_nodes = prm.get_bool("Use ghost nodes"); + fastscape_advection_uplift = prm.get_bool("Uplift and advect with fastscape"); + node_tolerance = prm.get_double("Node tolerance"); + noise_elevation = prm.get_double("Initial noise magnitude"); + sediment_rain_rates = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Sediment rain rates"))); + sediment_rain_times = Utilities::string_to_double + (Utilities::split_string_list(prm.get ("Sediment rain time intervals"))); + + if (!this->convert_output_to_years()) + { + maximum_fastscape_timestep /= year_in_seconds; + for (unsigned int j=0; j sediment_rain_times[i-1], ExcMessage("Sediment rain time intervals must be an increasing array.")); + + prm.enter_subsection("Boundary conditions"); + { + bottom = prm.get_integer("Front"); + right = prm.get_integer("Right"); + top = prm.get_integer("Back"); + left = prm.get_integer("Left"); + left_flux = prm.get_double("Left mass flux"); + right_flux = prm.get_double("Right mass flux"); + top_flux = prm.get_double("Back mass flux"); + bottom_flux = prm.get_double("Front mass flux"); + + if (!this->convert_output_to_years()) + { + left_flux *= year_in_seconds; + right_flux *= year_in_seconds; + top_flux *= year_in_seconds; + bottom_flux *= year_in_seconds; + } + + // Put the boundary condition values into a four digit value to send to FastScape. + fastscape_boundary_conditions = bottom*1000+right*100+top*10+left; + + if ((left_flux != 0 && top_flux != 0) || (left_flux != 0 && bottom_flux != 0) || + (right_flux != 0 && bottom_flux != 0) || (right_flux != 0 && top_flux != 0)) + AssertThrow(false,ExcMessage("Currently the plugin does not support mass flux through adjacent boundaries.")); + + topbottom_ghost_nodes_periodic = prm.get_bool("Back front ghost nodes periodic"); + leftright_ghost_nodes_periodic = prm.get_bool("Left right ghost nodes periodic"); + } + prm.leave_subsection(); + + prm.enter_subsection("Erosional parameters"); + { + drainage_area_exponent_m = prm.get_double("Drainage area exponent"); + slope_exponent_n = prm.get_double("Slope exponent"); + sediment_river_incision_rate = prm.get_double("Sediment river incision rate"); + bedrock_river_incision_rate = prm.get_double("Bedrock river incision rate"); + sediment_transport_coefficient = prm.get_double("Sediment diffusivity"); + bedrock_transport_coefficient = prm.get_double("Bedrock diffusivity"); + bedrock_deposition_g = prm.get_double("Bedrock deposition coefficient"); + sediment_deposition_g = prm.get_double("Sediment deposition coefficient"); + slope_exponent_p = prm.get_double("Multi-direction slope exponent"); + flat_elevation = prm.get_integer("Orographic elevation control"); + wind_barrier_elevation = prm.get_integer("Orographic wind barrier height"); + flat_erosional_factor = prm.get_double("Elevation factor"); + wind_barrier_erosional_factor = prm.get_double("Wind barrier factor"); + stack_controls = prm.get_bool("Stack orographic controls"); + use_orographic_controls = prm.get_bool("Flag to use orographic controls"); + + if (!this->convert_output_to_years()) + { + bedrock_river_incision_rate *= year_in_seconds; + bedrock_transport_coefficient *= year_in_seconds; + sediment_river_incision_rate *= year_in_seconds; + bedrock_transport_coefficient *= year_in_seconds; + } + + // Wind direction + if (prm.get ("Wind direction") == "west") + wind_direction = 0; + else if (prm.get ("Wind direction") == "east") + wind_direction = 1; + else if (prm.get ("Wind direction") == "north") + wind_direction = 2; + else if (prm.get ("Wind direction") == "south") + wind_direction = 3; + else + AssertThrow(false, ExcMessage("Not a valid wind direction.")); + + // set fixed ghost nodes to a base level for erosion that differs from sea level + use_fixed_erosional_base = prm.get_bool("Use a fixed erosional base level"); + if (use_fixed_erosional_base) + AssertThrow(use_fixed_erosional_base && use_ghost_nodes, ExcMessage( + "If you want to use an erosional base level differing from sea level, " + "you need to use ghost nodes.")); + h_erosional_base = prm.get_double("Erosional base level"); + } + prm.leave_subsection(); + + prm.enter_subsection("Marine parameters"); + { + sea_level = prm.get_double("Sea level"); + sand_surface_porosity = prm.get_double("Sand porosity"); + silt_surface_porosity = prm.get_double("Silt porosity"); + sand_efold_depth = prm.get_double("Sand e-folding depth"); + silt_efold_depth = prm.get_double("Silt e-folding depth"); + sand_silt_ratio = prm.get_double("Sand-silt ratio"); + sand_silt_averaging_depth = prm.get_double("Depth averaging thickness"); + sand_transport_coefficient = prm.get_double("Sand transport coefficient"); + silt_transport_coefficient = prm.get_double("Silt transport coefficient"); + + if (!this->convert_output_to_years()) + { + sand_transport_coefficient *= year_in_seconds; + silt_transport_coefficient *= year_in_seconds; + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + prm.leave_subsection (); + + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Visualization"); + { + output_interval = prm.get_double ("Time between graphical output"); + if (this->convert_output_to_years()) + output_interval *= year_in_seconds; + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiation of the functions we implement in this file +namespace aspect +{ + namespace MeshDeformation + { + ASPECT_REGISTER_MESH_DEFORMATION_MODEL(FastScape, + "fastscape", + "A plugin that uses the program FastScape to compute the deformation of the mesh surface. " + "FastScape is a surface processes code that computes the erosion, transport and " + "deposition of sediments both on land and in the marine domain. These surface processes " + "include river incision (through the stream power law), hillslope diffusion and " + "marine diffusion, as described in Braun and Willett 2013; Yuan et al. 2019; " + "Yuan et al. 2019b. " + "\n" + "Upon initialization, FastScape requires the initial topography of the surface boundary " + "of ASPECT's model domain and several user-specified erosional and depositional parameters. " + "In each ASPECT timestep, FastScape is then fed ASPECT's material velocity at the surface " + "boundary. The z-component of this velocity is used to uplift the FastScape surface, " + "while the horizontal components are used to advect the topography in the x-y plane. " + "\n" + "After solving its governing equations (this can be done in several timesteps " + "that are smaller than the ASPECT timestep), FastScape returns a new topography of the surface. " + "The difference in topography before and after the call to FastScape divided by the ASPECT " + "timestep provides the mesh velocity at the domain's surface that is used to displace the surface " + "and internal mesh nodes. " + "\n" + "FastScape can be used in both 2D and 3D ASPECT simulations. In 2D, one can think of the coupled " + "model as a T-model.The ASPECT domain spans the x - z plane, while FastScape acts on the horizontal " + "x-y plane. This means that to communicate ASPECT's material velocities to FastScape, " + "FastScape mesh nodes with the same x-coordinate (so lying along the y-direction) get the same velocities. " + "In turn, the FastScape topography is collapsed back onto the line of the ASPECT surface boundary " + "by averaging the topography over the y-direction. In 3D no such actions are necessary. " + "\n" + "The FastScape manual (https://fastscape.org/fastscapelib-fortran/) provides more information " + "on the input parameters. ") + + } +} +#endif diff --git a/source/mesh_deformation/free_surface.cc.bak b/source/mesh_deformation/free_surface.cc.bak new file mode 100644 index 00000000000..83d083d7b07 --- /dev/null +++ b/source/mesh_deformation/free_surface.cc.bak @@ -0,0 +1,336 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace aspect +{ + namespace MeshDeformation + { + template + void + FreeSurface::initialize () + { + // Pressure normalization doesn't really make sense with a free surface, and if we do + // use it, we can run into problems with geometry_model->depth(). + AssertThrow ( this->get_parameters().pressure_normalization == "no", + ExcMessage("The free surface scheme can only be used with no pressure normalization") ); + + // Check that we do not use the free surface on a boundary that has zero slip, + // free slip or prescribed velocity boundary conditions on it. + + // Get the zero velocity boundary indicators + std::set velocity_boundary_indicators = this->get_boundary_velocity_manager().get_zero_boundary_velocity_indicators(); + + // Get the tangential velocity boundary indicators + const std::set tmp_tangential_vel_boundary_indicators = this->get_boundary_velocity_manager().get_tangential_boundary_velocity_indicators(); + velocity_boundary_indicators.insert(tmp_tangential_vel_boundary_indicators.begin(), + tmp_tangential_vel_boundary_indicators.end()); + + // Get the active velocity boundary indicators + const std::map>> + tmp_active_vel_boundary_indicators = this->get_boundary_velocity_manager().get_active_boundary_velocity_names(); + + for (const auto &p : tmp_active_vel_boundary_indicators) + velocity_boundary_indicators.insert(p.first); + + // Get the mesh deformation boundary indicators + const std::set tmp_mesh_deformation_boundary_indicators = this->get_mesh_deformation_boundary_indicators(); + for (const auto &p : tmp_mesh_deformation_boundary_indicators) + AssertThrow(velocity_boundary_indicators.find(p) == velocity_boundary_indicators.end(), + ExcMessage("The free surface mesh deformation plugin cannot be used with the current velocity boundary conditions")); + } + + + template + void FreeSurface::project_velocity_onto_boundary(const DoFHandler &mesh_deformation_dof_handler, + const IndexSet &mesh_locally_owned, + const IndexSet &mesh_locally_relevant, + LinearAlgebra::Vector &output) const + { + // TODO: should we use the extrapolated solution? + + // stuff for iterating over the mesh + const QGauss face_quadrature(mesh_deformation_dof_handler.get_fe().degree+1); + UpdateFlags update_flags = UpdateFlags(update_values | update_quadrature_points + | update_normal_vectors | update_JxW_values); + FEFaceValues fs_fe_face_values (this->get_mapping(), mesh_deformation_dof_handler.get_fe(), face_quadrature, update_flags); + FEFaceValues fe_face_values (this->get_mapping(), this->get_fe(), face_quadrature, update_flags); + const unsigned int n_face_q_points = fe_face_values.n_quadrature_points, + dofs_per_cell = fs_fe_face_values.dofs_per_cell; + + // stuff for assembling system + std::vector cell_dof_indices (dofs_per_cell); + Vector cell_vector (dofs_per_cell); + FullMatrix cell_matrix (dofs_per_cell, dofs_per_cell); + + // stuff for getting the velocity values + std::vector> velocity_values(n_face_q_points); + + // set up constraints + AffineConstraints mass_matrix_constraints( +#if DEAL_II_VERSION_GTE(9,6,0) + mesh_deformation_dof_handler.locally_owned_dofs(), +#endif + mesh_locally_relevant); + DoFTools::make_hanging_node_constraints(mesh_deformation_dof_handler, mass_matrix_constraints); + + using periodic_boundary_pairs = std::set, unsigned int>>; + periodic_boundary_pairs pbp = this->get_geometry_model().get_periodic_boundary_pairs(); + for (const auto &p : pbp) + DoFTools::make_periodicity_constraints(mesh_deformation_dof_handler, + p.first.first, p.first.second, p.second, mass_matrix_constraints); + + mass_matrix_constraints.close(); + + // set up the matrix + LinearAlgebra::SparseMatrix mass_matrix; + TrilinosWrappers::SparsityPattern sp (mesh_locally_owned, + mesh_locally_owned, + mesh_locally_relevant, + this->get_mpi_communicator()); + DoFTools::make_sparsity_pattern (mesh_deformation_dof_handler, sp, mass_matrix_constraints, false, + Utilities::MPI::this_mpi_process(this->get_mpi_communicator())); + sp.compress(); + mass_matrix.reinit (sp); + + FEValuesExtractors::Vector extract_vel(0); + + // make distributed vectors. + LinearAlgebra::Vector rhs, dist_solution; + rhs.reinit(mesh_locally_owned, this->get_mpi_communicator()); + dist_solution.reinit(mesh_locally_owned, this->get_mpi_communicator()); + + typename DoFHandler::active_cell_iterator + cell = this->get_dof_handler().begin_active(), endc= this->get_dof_handler().end(); + typename DoFHandler::active_cell_iterator + fscell = mesh_deformation_dof_handler.begin_active(); + + // Get the boundary indicators of those boundaries with + // a free surface. + const std::set tmp_free_surface_boundary_indicators = this->get_mesh_deformation_handler().get_free_surface_boundary_indicators(); + + for (; cell!=endc; ++cell, ++fscell) + if (cell->at_boundary() && cell->is_locally_owned()) + for (const unsigned int face_no : cell->face_indices()) + if (cell->face(face_no)->at_boundary()) + { + const types::boundary_id boundary_indicator + = cell->face(face_no)->boundary_id(); + + // Only project onto the free surface boundary/boundaries. + if (tmp_free_surface_boundary_indicators.find(boundary_indicator) == tmp_free_surface_boundary_indicators.end()) + continue; + + fscell->get_dof_indices (cell_dof_indices); + fs_fe_face_values.reinit (fscell, face_no); + fe_face_values.reinit (cell, face_no); + fe_face_values[this->introspection().extractors.velocities].get_function_values(this->get_solution(), velocity_values); + + cell_vector = 0; + cell_matrix = 0; + for (unsigned int point=0; point direction; + if ( advection_direction == SurfaceAdvection::normal ) // project onto normal vector + direction = fs_fe_face_values.normal_vector(point); + else if ( advection_direction == SurfaceAdvection::vertical ) // project onto local gravity + direction = this->get_gravity_model().gravity_vector(fs_fe_face_values.quadrature_point(point)); + else + AssertThrow(false, ExcInternalError()); + + direction *= ( direction.norm() > 0.0 ? 1./direction.norm() : 0.0 ); + + for (unsigned int i=0; iget_parameters().linear_stokes_solver_tolerance*rhs.l2_norm()); + SolverCG cg(solver_control); + cg.solve (mass_matrix, dist_solution, rhs, preconditioner_mass); + + mass_matrix_constraints.distribute (dist_solution); + output = dist_solution; + } + + + + /** + * A function that creates constraints for the velocity of certain mesh + * vertices (e.g. the surface vertices) for a specific boundary. + * The calling class will respect + * these constraints when computing the new vertex positions. + */ + template + void + FreeSurface::compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, + AffineConstraints &mesh_velocity_constraints, + const std::set &boundary_id) const + { + // For the free surface indicators we constrain the displacement to be v.n + LinearAlgebra::Vector boundary_velocity; + + const IndexSet &mesh_locally_owned = mesh_deformation_dof_handler.locally_owned_dofs(); + IndexSet mesh_locally_relevant; + DoFTools::extract_locally_relevant_dofs (mesh_deformation_dof_handler, + mesh_locally_relevant); + boundary_velocity.reinit(mesh_locally_owned, mesh_locally_relevant, + this->get_mpi_communicator()); + project_velocity_onto_boundary(mesh_deformation_dof_handler, mesh_locally_owned, + mesh_locally_relevant, boundary_velocity); + + // now insert the relevant part of the solution into the mesh constraints + const IndexSet constrained_dofs = + DoFTools::extract_boundary_dofs(mesh_deformation_dof_handler, + ComponentMask(dim, true), + boundary_id); + + for (unsigned int i = 0; i < constrained_dofs.n_elements(); ++i) + { + types::global_dof_index index = constrained_dofs.nth_index_in_set(i); + if (mesh_velocity_constraints.can_store_line(index)) + if (mesh_velocity_constraints.is_constrained(index)==false) + { +#if DEAL_II_VERSION_GTE(9,6,0) + mesh_velocity_constraints.add_constraint(index, + {}, + boundary_velocity[index]); +#else + mesh_velocity_constraints.add_line(index); + mesh_velocity_constraints.set_inhomogeneity(index, boundary_velocity[index]); +#endif + } + } + } + + + + template + bool + FreeSurface:: + needs_surface_stabilization () const + { + return true; + } + + + + template + void FreeSurface::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection ("Mesh deformation"); + { + prm.enter_subsection ("Free surface"); + { + prm.declare_entry("Surface velocity projection", "normal", + Patterns::Selection("normal|vertical"), + "After each time step the free surface must be " + "advected in the direction of the velocity field. " + "Mass conservation requires that the mesh velocity " + "is in the normal direction of the surface. However, " + "for steep topography or large curvature, advection " + "in the normal direction can become ill-conditioned, " + "and instabilities in the mesh can form. Projection " + "of the mesh velocity onto the local vertical direction " + "can preserve the mesh quality better, but at the " + "cost of slightly poorer mass conservation of the " + "domain."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + + + template + void FreeSurface::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection ("Mesh deformation"); + { + prm.enter_subsection ("Free surface"); + { + std::string advection_dir = prm.get("Surface velocity projection"); + + if ( advection_dir == "normal") + advection_direction = SurfaceAdvection::normal; + else if ( advection_dir == "vertical") + advection_direction = SurfaceAdvection::vertical; + else + AssertThrow(false, ExcMessage("The surface velocity projection must be ``normal'' or ``vertical''.")); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + + +// explicit instantiation of the functions we implement in this file +namespace aspect +{ + namespace MeshDeformation + { + ASPECT_REGISTER_MESH_DEFORMATION_MODEL(FreeSurface, + "free surface", + "A plugin that computes the deformation of surface " + "vertices according to the solution of the flow problem. " + "In particular this means if the surface of the domain is " + "left open to flow, this flow will carry the mesh with it. " + "The implementation was described in \\cite{rose_freesurface}, " + "with the stabilization of the free surface originally described " + "in \\cite{kaus:etal:2010}.") + } +} diff --git a/source/mesh_deformation/function.cc.bak b/source/mesh_deformation/function.cc.bak new file mode 100644 index 00000000000..32027eafd2e --- /dev/null +++ b/source/mesh_deformation/function.cc.bak @@ -0,0 +1,149 @@ +/* + Copyright (C) 2018 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include + +#include + +namespace aspect +{ + namespace MeshDeformation + { + template + BoundaryFunction::BoundaryFunction() + : + function(dim) + {} + + + + template + void + BoundaryFunction::update () + { + // we get time passed as seconds (always) but may want + // to reinterpret it in years + if (this->convert_output_to_years()) + function.set_time (this->get_time() / year_in_seconds); + else + function.set_time (this->get_time()); + } + + + + /** + * A function that creates constraints for the velocity of certain mesh + * vertices (e.g. the surface vertices) for a specific boundary. + * The calling class will respect + * these constraints when computing the new vertex positions. + */ + template + void + BoundaryFunction::compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, + AffineConstraints &mesh_velocity_constraints, + const std::set &boundary_ids) const + { + // Loop over all boundary indicators to set the velocity constraints + for (const auto boundary_id : boundary_ids) + VectorTools::interpolate_boundary_values (this->get_mapping(), + mesh_deformation_dof_handler, + boundary_id, + function, + mesh_velocity_constraints); + } + + + + template + bool + BoundaryFunction:: + needs_surface_stabilization () const + { + return false; + } + + + + template + void BoundaryFunction::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection ("Mesh deformation"); + { + prm.enter_subsection ("Boundary function"); + { + Functions::ParsedFunction::declare_parameters (prm, dim); + } + prm.leave_subsection(); + } + prm.leave_subsection (); + } + + template + void BoundaryFunction::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection ("Mesh deformation"); + { + prm.enter_subsection("Boundary function"); + { + try + { + function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Mesh deformation.BoundaryFunction'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + } + prm.leave_subsection(); + } + prm.leave_subsection (); + } + } +} + + +// explicit instantiation of the functions we implement in this file +namespace aspect +{ + namespace MeshDeformation + { + ASPECT_REGISTER_MESH_DEFORMATION_MODEL(BoundaryFunction, + "boundary function", + "A plugin, which prescribes the surface mesh to " + "deform according to an analytically prescribed " + "function. Note that the function prescribes a " + "deformation velocity, i.e. the return value of " + "this plugin is later multiplied by the time step length " + "to compute the displacement increment in this time step. " + "Although the function's time variable is interpreted as " + "years when Use years in output instead of seconds is set to true, " + "the boundary deformation velocity should still be given " + "in m/s. The format of the " + "functions follows the syntax understood by the " + "muparser library, see {ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") + } +} diff --git a/source/mesh_deformation/interface.cc.bak b/source/mesh_deformation/interface.cc.bak new file mode 100644 index 00000000000..50d4f2307e8 --- /dev/null +++ b/source/mesh_deformation/interface.cc.bak @@ -0,0 +1,1605 @@ +/* + Copyright (C) 2014 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include + +namespace aspect +{ + namespace Assemblers + { + template + ApplyStabilization::ApplyStabilization(const double stabilization_theta) + : + free_surface_theta(stabilization_theta) + {} + + template + void + ApplyStabilization:: + execute (internal::Assembly::Scratch::ScratchBase &scratch_base, + internal::Assembly::CopyData::CopyDataBase &data_base) const + { + internal::Assembly::Scratch::StokesSystem &scratch = dynamic_cast& > (scratch_base); + internal::Assembly::CopyData::StokesSystem &data = dynamic_cast& > (data_base); + + AssertThrow(!this->get_mesh_deformation_handler().get_boundary_indicators_requiring_stabilization().empty(), + ExcMessage("Applying surface stabilization, even though no boundary requires it.")); + + + if (this->get_parameters().include_melt_transport) + { + this->get_melt_handler().apply_free_surface_stabilization_with_melt (free_surface_theta, + scratch.cell, + scratch, + data); + return; + } + + const Introspection &introspection = this->introspection(); + const FiniteElement &fe = this->get_fe(); + + const typename DoFHandler::active_cell_iterator cell (&this->get_triangulation(), + scratch.finite_element_values.get_cell()->level(), + scratch.finite_element_values.get_cell()->index(), + &this->get_dof_handler()); + + const unsigned int n_face_q_points = scratch.face_finite_element_values.n_quadrature_points; + const unsigned int stokes_dofs_per_cell = data.local_dof_indices.size(); + + // Get the boundary indicators of those boundaries that require stabilization + const std::set tmp_boundary_indicators_requiring_stabilization = this->get_mesh_deformation_handler().get_boundary_indicators_requiring_stabilization(); + + // only apply on mesh deformation faces that require stabilization + if (cell->at_boundary() && cell->is_locally_owned()) + for (const unsigned int face_no : cell->face_indices()) + if (cell->face(face_no)->at_boundary()) + { + const types::boundary_id boundary_indicator + = cell->face(face_no)->boundary_id(); + + if (tmp_boundary_indicators_requiring_stabilization.find(boundary_indicator) + == tmp_boundary_indicators_requiring_stabilization.end()) + continue; + + scratch.face_finite_element_values.reinit(cell, face_no); + + scratch.face_material_model_inputs.reinit (scratch.face_finite_element_values, + cell, + this->introspection(), + this->get_solution()); + scratch.face_material_model_inputs.requested_properties = MaterialModel::MaterialProperties::density; + + this->get_material_model().evaluate(scratch.face_material_model_inputs, scratch.face_material_model_outputs); + + for (unsigned int q_point = 0; q_point < n_face_q_points; ++q_point) + { + for (unsigned int i = 0, i_stokes = 0; i_stokes < stokes_dofs_per_cell; /*increment at end of loop*/) + { + if (introspection.is_stokes_component(fe.system_to_component_index(i).first)) + { + scratch.phi_u[i_stokes] = scratch.face_finite_element_values[introspection.extractors.velocities].value(i, q_point); + ++i_stokes; + } + ++i; + } + + const Tensor<1,dim> + gravity = this->get_gravity_model().gravity_vector(scratch.face_finite_element_values.quadrature_point(q_point)); + const double g_norm = gravity.norm(); + + // construct the relevant vectors + const Tensor<1,dim> n_hat = scratch.face_finite_element_values.normal_vector(q_point); + const Tensor<1,dim> g_hat = (g_norm == 0.0 ? Tensor<1,dim>() : gravity/g_norm); + + const double pressure_perturbation = scratch.face_material_model_outputs.densities[q_point] * + this->get_timestep() * + free_surface_theta * + g_norm; + + // see Kaus et al 2010 for details of the stabilization term + for (unsigned int i=0; i< stokes_dofs_per_cell; ++i) + for (unsigned int j=0; j< stokes_dofs_per_cell; ++j) + { + // The fictive stabilization stress is (phi_u[i].g)*(phi_u[j].n) + const double stress_value = -pressure_perturbation* + (scratch.phi_u[i]*g_hat) * (scratch.phi_u[j]*n_hat) + *scratch.face_finite_element_values.JxW(q_point); + + data.local_matrix(i,j) += stress_value; + } + } + } + } + } + + + + namespace MeshDeformation + { + template + bool + Interface::needs_surface_stabilization () const + { + return false; + } + + + + template + Tensor<1,dim> + Interface:: + compute_initial_deformation_on_boundary(const types::boundary_id /*boundary_indicator*/, + const Point &/*position*/) const + { + return Tensor<1,dim>(); + } + + + + template + void + Interface:: + compute_velocity_constraints_on_boundary(const DoFHandler &/*mesh_deformation_dof_handler*/, + AffineConstraints &/*mesh_velocity_constraints*/, + const std::set &/*boundary_id*/) const + {} + + + + template + MeshDeformationHandler::MeshDeformationHandler (Simulator &simulator) + : sim(simulator), // reference to the simulator that owns the MeshDeformationHandler + mesh_deformation_fe (FE_Q(1),dim), // Q1 elements which describe the mesh geometry + mesh_deformation_dof_handler (sim.triangulation), + include_initial_topography(false) + { + // Now reset the mapping of the simulator to be something that captures mesh deformation in time. + sim.mapping = std::make_unique> (mesh_deformation_dof_handler, + mesh_displacements); + } + + + + template + MeshDeformationHandler::~MeshDeformationHandler () + { + // Free the Simulator's mapping object, otherwise + // when the MeshDeformationHandler gets destroyed, + // the mapping's reference to the mesh displacement + // vector will be invalid. + sim.mapping.reset(); + } + + + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + MeshDeformationHandler::initialize () + { + // In case we prescribed initial topography, we should take this into + // account. However, it is not included in the mesh displacements, + // so we need to fetch it separately. + if (!Plugins::plugin_type_matches>(this->get_initial_topography_model())) + include_initial_topography = true; + + // If a surface needs to be stabilized, set up the assemblers. + if (!this->get_mesh_deformation_handler().get_boundary_indicators_requiring_stabilization().empty()) + { + this->get_signals().set_assemblers.connect( + [&](const SimulatorAccess &sim_access, + aspect::Assemblers::Manager &assemblers) + { + this->set_assemblers(sim_access, assemblers); + }); + } + } + + + + template + void MeshDeformationHandler::set_assemblers(const SimulatorAccess &, + aspect::Assemblers::Manager &assemblers) const + { + assemblers.stokes_system.push_back( + std::make_unique> (surface_theta)); + + // Note that we do not want face_material_model_data, because we do not + // connect to a face assembler. We instead connect to a normal assembler, + // and compute our own material_model_inputs in apply_stabilization + // (because we want to use the solution instead of the current_linearization_point + // to compute the material properties). + assemblers.stokes_system_assembler_on_boundary_face_properties.needed_update_flags |= (update_values | + update_gradients | + update_quadrature_points | + update_normal_vectors | + update_JxW_values); + } + + + + template + void + MeshDeformationHandler::register_mesh_deformation (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + + template + void + MeshDeformationHandler::update () + { + AssertThrow(sim.parameters.mesh_deformation_enabled, ExcInternalError()); + + for (const auto &boundary_and_deformation_objects : mesh_deformation_objects) + { + for (const auto &model : boundary_and_deformation_objects.second) + model->update(); + } + } + + + + template + void MeshDeformationHandler::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection ("Mesh deformation"); + { + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + + prm.declare_entry ("Additional tangential mesh velocity boundary indicators", "", + Patterns::List (Patterns::Anything()), + "A comma separated list of names denoting those boundaries " + "where there the mesh is allowed to move tangential to the " + "boundary. All tangential mesh movements along " + "those boundaries that have tangential material velocity " + "boundary conditions are allowed by default, this parameters " + "allows to generate mesh movements along other boundaries that are " + "open, or have prescribed material velocities or tractions." + "\n\n" + "The names of the boundaries listed here can either be " + "numbers (in which case they correspond to the numerical " + "boundary indicators assigned by the geometry object), or they " + "can correspond to any of the symbolic names the geometry object " + "may have provided for each part of the boundary. You may want " + "to compare this with the documentation of the geometry model you " + "use in your model."); + prm.declare_entry ("Mesh deformation boundary indicators", "", + Patterns::List (Patterns::Anything()), + "A comma separated list of names denoting those boundaries " + "where there the mesh is allowed to move according to the " + "specified mesh deformation objects. " + "\n\n" + "The names of the boundaries listed here can either be " + "numbers (in which case they correspond to the numerical " + "boundary indicators assigned by the geometry object), or they " + "can correspond to any of the symbolic names the geometry object " + "may have provided for each part of the boundary. You may want " + "to compare this with the documentation of the geometry model you " + "use in your model. " + "\n\n" + "The format is id1: object1 \\& object2, id2: object3 \\& object2, where " + "objects are one of " + std::get(registered_plugins).get_description_string()); + + prm.enter_subsection ("Free surface"); + { + prm.declare_entry("Free surface stabilization theta", "0.5", + Patterns::Double(0., 1.), + "Theta parameter described in \\cite{kaus:etal:2010}. " + "An unstabilized free surface can overshoot its " + "equilibrium position quite easily and generate " + "unphysical results. One solution is to use a " + "quasi-implicit correction term to the forces near the " + "free surface. This parameter describes how much " + "the free surface is stabilized with this term, " + "where zero is no stabilization, and one is fully " + "implicit."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void MeshDeformationHandler::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection ("Mesh deformation"); + { + // Create the map of prescribed mesh movement boundary indicators + // Each boundary indicator can carry a number of mesh deformation plugin names. + const std::vector x_mesh_deformation_boundary_indicators + = Utilities::split_string_list(prm.get("Mesh deformation boundary indicators"),","); + + for (const auto &entry : x_mesh_deformation_boundary_indicators) + { + // each entry has the format (white space is optional): + // : + const std::vector split_parts = Utilities::split_string_list (entry, ':'); + AssertThrow (split_parts.size() == 2, + ExcMessage ("The format for mesh deformation indicators " + "requires that each entry has the form `" + " : ', but there does not " + "appear to be a colon in the entry <" + + entry + + ">.")); + + // Get the values, i.e. the mesh deformation plugin names + const std::vector object_names = Utilities::split_string_list(split_parts[1],"&"); + + // Try to translate the id into a boundary_id. + types::boundary_id boundary_id; + try + { + boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id(split_parts[0]); + } + catch (const std::string &error) + { + AssertThrow (false, ExcMessage ("While parsing the entry , there was an error. Specifically, " + "the conversion function complained as follows:\n\n" + + error)); + } + + // Store the boundary indicator. If the entry exists this does nothing. + prescribed_mesh_deformation_boundary_indicators.insert(boundary_id); + + for (const auto &object_name : object_names) + { + // Make sure there are no duplicated entries. If this boundary is not + // already in the map the first call to map[key] will create an empty entry. + AssertThrow(std::find(mesh_deformation_object_names[boundary_id].begin(), + mesh_deformation_object_names[boundary_id].end(), object_name) + == mesh_deformation_object_names[boundary_id].end(), + ExcMessage("The current mesh deformation object is listed twice for boundary indicator " + + dealii::Utilities::int_to_string(boundary_id))); + + mesh_deformation_object_names[boundary_id].push_back(object_name); + + if (object_name == "free surface") + free_surface_boundary_indicators.insert(boundary_id); + } + } + + // Create the list of tangential mesh movement boundary indicators + try + { + const std::vector x_additional_tangential_mesh_boundary_indicators + = this->get_geometry_model().translate_symbolic_boundary_names_to_ids(Utilities::split_string_list + (prm.get ("Additional tangential mesh velocity boundary indicators"))); + + tangential_mesh_deformation_boundary_indicators.insert(x_additional_tangential_mesh_boundary_indicators.begin(), + x_additional_tangential_mesh_boundary_indicators.end()); + } + catch (const std::string &error) + { + AssertThrow (false, ExcMessage ("While parsing the entry , there was an error. Specifically, " + "the conversion function complained as follows:\n\n" + + error)); + } + + // Boundaries with tangential Stokes velocity boundary conditions are implicitly + // treated as tangential mesh boundaries, but only if they do not have + // assigned mesh deformation objects. + for (const auto &boundary_id : this->get_boundary_velocity_manager().get_tangential_boundary_velocity_indicators()) + tangential_mesh_deformation_boundary_indicators.insert(boundary_id); + + // The tangential mesh boundaries can accidentally contain prescribed mesh + // boundaries if they were in the list of tangential Stokes boundaries. + // If so remove them. + for (const auto &boundary_id : prescribed_mesh_deformation_boundary_indicators) + tangential_mesh_deformation_boundary_indicators.erase(boundary_id); + + // All periodic boundaries are implicitly treated as tangential mesh deformation boundaries. + using periodic_boundary_pair = std::pair, unsigned int>; + for (const periodic_boundary_pair &p : this->get_geometry_model().get_periodic_boundary_pairs()) + { + tangential_mesh_deformation_boundary_indicators.insert(p.first.first); + tangential_mesh_deformation_boundary_indicators.insert(p.first.second); + } + + // Create the list of zero mesh movement (fixed) boundary indicators, these are + // all boundaries, which are not prescribed or tangential. + zero_mesh_deformation_boundary_indicators = this->get_geometry_model().get_used_boundary_indicators(); + + for (const auto &boundary_id : prescribed_mesh_deformation_boundary_indicators) + zero_mesh_deformation_boundary_indicators.erase(boundary_id); + + for (const auto &boundary_id : tangential_mesh_deformation_boundary_indicators) + zero_mesh_deformation_boundary_indicators.erase(boundary_id); + + prm.enter_subsection ("Free surface"); + { + surface_theta = prm.get_double("Free surface stabilization theta"); + } + prm.leave_subsection (); + + } + prm.leave_subsection (); + + // go through the list of object names, create objects and let them parse + // their own parameters + for (const auto &boundary_and_object_names : mesh_deformation_object_names) + { + for (const auto &object_name : boundary_and_object_names.second) + { + mesh_deformation_objects[boundary_and_object_names.first].push_back( + std::unique_ptr> (std::get(registered_plugins) + .create_plugin (object_name, + "Mesh deformation::Model names"))); + + if (SimulatorAccess *sim = dynamic_cast*>(mesh_deformation_objects[boundary_and_object_names.first].back().get())) + sim->initialize_simulator (this->get_simulator()); + + mesh_deformation_objects[boundary_and_object_names.first].back()->parse_parameters (prm); + mesh_deformation_objects[boundary_and_object_names.first].back()->initialize (); + } + } + + // Go through the objects, and get the indicators for boundaries that need to be stabilized. + for (const auto &boundary_and_deformation_objects : mesh_deformation_objects) + { + for (const auto &model : boundary_and_deformation_objects.second) + if (model->needs_surface_stabilization() == true) + boundary_indicators_requiring_stabilization.insert(boundary_and_deformation_objects.first); + } + } + + + + template + void MeshDeformationHandler::execute() + { + AssertThrow(sim.parameters.mesh_deformation_enabled, ExcInternalError()); + + TimerOutput::Scope timer (sim.computing_timer, "Mesh deformation"); + + old_mesh_displacements = mesh_displacements; + + // Make the constraints for the elliptic problem. + make_constraints(); + + // Assemble and solve the vector Laplace problem which determines + // the mesh displacements in the interior of the domain + if (this->is_stokes_matrix_free()) + compute_mesh_displacements_gmg(); + else + compute_mesh_displacements(); + + // Interpolate the mesh velocity into the same + // finite element space as used in the Stokes solve, which + // is needed for the ALE corrections. + interpolate_mesh_velocity(); + + // After changing the mesh we need to rebuild things + sim.rebuild_stokes_matrix = sim.rebuild_stokes_preconditioner = true; + } + + + + template + const Mapping & + MeshDeformationHandler::get_level_mapping(const unsigned int level) const + { + return *level_mappings[level].get(); + } + + + + template + void MeshDeformationHandler::make_constraints() + { + AssertThrow(sim.parameters.mesh_deformation_enabled, ExcInternalError()); + + // Now construct the mesh displacement constraints + mesh_velocity_constraints.clear(); +#if DEAL_II_VERSION_GTE(9,6,0) + mesh_velocity_constraints.reinit(mesh_deformation_dof_handler.locally_owned_dofs(), + mesh_locally_relevant); +#else + mesh_velocity_constraints.reinit(mesh_locally_relevant); +#endif + // mesh_velocity_constraints can use the same hanging node + // information that was used for mesh_vertex constraints. + mesh_velocity_constraints.merge(mesh_vertex_constraints); + + // Add the vanilla periodic boundary constraints + using periodic_boundary_pairs = std::set, unsigned int>>; + const periodic_boundary_pairs pbp = this->get_geometry_model().get_periodic_boundary_pairs(); + for (const auto &p : pbp) + DoFTools::make_periodicity_constraints(mesh_deformation_dof_handler, + p.first.first, + p.first.second, + p.second, + mesh_velocity_constraints); + + // Zero out the displacement for the zero-velocity boundaries + // if the boundary is not in the set of tangential mesh boundaries and not in the set of mesh deformation boundary indicators + for (const auto &boundary_id : zero_mesh_deformation_boundary_indicators) + { + VectorTools::interpolate_boundary_values (this->get_mapping(), + mesh_deformation_dof_handler, + boundary_id, + Functions::ZeroFunction(dim), + mesh_velocity_constraints); + } + + this->get_signals().pre_compute_no_normal_flux_constraints(sim.triangulation); + // Make the no flux boundary constraints + VectorTools::compute_no_normal_flux_constraints (mesh_deformation_dof_handler, + /* first_vector_component= */ + 0, + tangential_mesh_deformation_boundary_indicators, + mesh_velocity_constraints, + this->get_mapping()); + + this->get_signals().post_compute_no_normal_flux_constraints(sim.triangulation); + + // Ask all plugins to add their constraints. + // For the moment add constraints from all plugins into one matrix, then + // merge that matrix with the existing constraints (respecting the existing + // constraints as more important) + AffineConstraints plugin_constraints(mesh_vertex_constraints.get_local_lines()); + + for (const auto &boundary_id : mesh_deformation_objects) + { + std::set boundary_id_set; + boundary_id_set.insert(boundary_id.first); + + for (const auto &model : boundary_id.second) + { + AffineConstraints current_plugin_constraints(mesh_vertex_constraints.get_local_lines()); + + model->compute_velocity_constraints_on_boundary(mesh_deformation_dof_handler, + current_plugin_constraints, + boundary_id_set); + if ((this->is_stokes_matrix_free())) + { + mg_constrained_dofs.make_zero_boundary_constraints(mesh_deformation_dof_handler, + boundary_id_set); + } + + const IndexSet local_lines = current_plugin_constraints.get_local_lines(); + for (dealii::IndexSet::size_type local_line : local_lines) + { + if (current_plugin_constraints.is_constrained(local_line)) + { + if (plugin_constraints.is_constrained(local_line) == false) + { +#if DEAL_II_VERSION_GTE(9,6,0) + plugin_constraints.add_constraint(local_line, + {}, + current_plugin_constraints.get_inhomogeneity(local_line)); +#else + plugin_constraints.add_line(local_line); + plugin_constraints.set_inhomogeneity(local_line, + current_plugin_constraints.get_inhomogeneity(local_line)); +#endif + } + else + { + // Add the inhomogeneity of the current plugin to the existing constraints + const double inhomogeneity = plugin_constraints.get_inhomogeneity(local_line); + plugin_constraints.set_inhomogeneity(local_line, current_plugin_constraints.get_inhomogeneity(local_line) + inhomogeneity); + } + } + } + } + } + + mesh_velocity_constraints.merge(plugin_constraints,AffineConstraints::left_object_wins); + mesh_velocity_constraints.close(); + } + + + + template + void MeshDeformationHandler::make_initial_constraints() + { + AssertThrow(this->get_parameters().mesh_deformation_enabled, ExcInternalError()); + + // This might look incorrect at first glance, but it is okay to + // overwrite the velocity constraints with our displacements + // because this object is used for updating the displacement in + // compute_mesh_displacements(). + mesh_velocity_constraints.clear(); +#if DEAL_II_VERSION_GTE(9,6,0) + mesh_velocity_constraints.reinit(mesh_deformation_dof_handler.locally_owned_dofs(), + mesh_locally_relevant); +#else + mesh_velocity_constraints.reinit(mesh_locally_relevant); +#endif + // mesh_velocity_constraints can use the same hanging node + // information that was used for mesh_vertex constraints. + mesh_velocity_constraints.merge(mesh_vertex_constraints); + + // Add the vanilla periodic boundary constraints + std::set periodic_boundaries; + using periodic_boundary_pairs = std::set, unsigned int>>; + const periodic_boundary_pairs pbp = this->get_geometry_model().get_periodic_boundary_pairs(); + for (const auto &p : pbp) + { + periodic_boundaries.insert(p.first.first); + periodic_boundaries.insert(p.first.second); + + DoFTools::make_periodicity_constraints(mesh_deformation_dof_handler, + p.first.first, + p.first.second, + p.second, + mesh_velocity_constraints); + } + + // Zero out the displacement for the fixed boundaries + for (const types::boundary_id &boundary_id : zero_mesh_deformation_boundary_indicators) + { + VectorTools::interpolate_boundary_values (this->get_mapping(), + mesh_deformation_dof_handler, + boundary_id, + Functions::ZeroFunction(dim), + mesh_velocity_constraints); + } + + // Make tangential deformation constraints for tangential boundaries + this->get_signals().pre_compute_no_normal_flux_constraints(sim.triangulation); + VectorTools::compute_no_normal_flux_constraints (mesh_deformation_dof_handler, + /* first_vector_component= */ + 0, + tangential_mesh_deformation_boundary_indicators, + mesh_velocity_constraints, + this->get_mapping()); + this->get_signals().post_compute_no_normal_flux_constraints(sim.triangulation); + + // Ask all plugins to add their constraints. + // For the moment add constraints from all plugins into one matrix, then + // merge that matrix with the existing constraints (respecting the existing + // constraints as more important) + AffineConstraints plugin_constraints(mesh_vertex_constraints.get_local_lines()); + + std::set boundary_id_set; + + for (const auto &boundary_id_and_deformation_objects: mesh_deformation_objects) + { + for (const auto &deformation_object : boundary_id_and_deformation_objects.second) + { + AffineConstraints current_plugin_constraints(mesh_vertex_constraints.get_local_lines()); + + Utilities::VectorFunctionFromVelocityFunctionObject vel + (dim, + [&] (const Point &x) -> Tensor<1,dim> + { + return deformation_object->compute_initial_deformation_on_boundary(boundary_id_and_deformation_objects.first, x); + }); + + VectorTools::interpolate_boundary_values (this->get_mapping(), + mesh_deformation_dof_handler, + boundary_id_and_deformation_objects.first, + vel, + current_plugin_constraints); + + boundary_id_set.insert(boundary_id_and_deformation_objects.first); + + + const IndexSet local_lines = current_plugin_constraints.get_local_lines(); + for (dealii::IndexSet::size_type local_line : local_lines) + { + if (current_plugin_constraints.is_constrained(local_line)) + { + if (plugin_constraints.is_constrained(local_line) == false) + { +#if DEAL_II_VERSION_GTE(9,6,0) + plugin_constraints.add_constraint(local_line, + {}, + current_plugin_constraints.get_inhomogeneity(local_line)); +#else + plugin_constraints.add_line(local_line); + plugin_constraints.set_inhomogeneity(local_line, + current_plugin_constraints.get_inhomogeneity(local_line)); +#endif + } + else + { + // Add the current plugin constraints to the existing inhomogeneity + const double inhomogeneity = plugin_constraints.get_inhomogeneity(local_line); + plugin_constraints.set_inhomogeneity(local_line, current_plugin_constraints.get_inhomogeneity(local_line) + inhomogeneity); + } + } + } + } + } + if ((this->is_stokes_matrix_free())) + { + mg_constrained_dofs.make_zero_boundary_constraints(mesh_deformation_dof_handler, + boundary_id_set); + } + mesh_velocity_constraints.merge(plugin_constraints, + AffineConstraints::left_object_wins); + mesh_velocity_constraints.close(); + } + + + + template + void MeshDeformationHandler::compute_mesh_displacements() + { + // This functions updates the mesh displacement of the whole + // domain (stored in the vector mesh_displacements) based on + // information on the boundary. + // + // Each step, we get the velocity specified on the free surface + // boundary (stored in mesh_velocity_constraints) and solve for + // the velocity in the interior by solving a vector Laplace + // problem. This velocity is then used to update the + // displacement vector. + // + // This is different in timestep 0. Here, the information on the + // boundary is actually a displacement (given initial + // topography), which is used to set the initial + // displacement. The process in this function is otherwise + // identical. + + const QGauss quadrature(mesh_deformation_fe.degree + 1); + UpdateFlags update_flags = UpdateFlags(update_values | update_JxW_values | update_gradients); + FEValues fe_values (*sim.mapping, mesh_deformation_fe, quadrature, update_flags); + + const unsigned int dofs_per_cell = fe_values.dofs_per_cell, + dofs_per_face = sim.finite_element.dofs_per_face, + n_q_points = fe_values.n_quadrature_points; + + std::vector cell_dof_indices (dofs_per_cell); + std::vector face_dof_indices (dofs_per_face); + Vector cell_vector (dofs_per_cell); + FullMatrix cell_matrix (dofs_per_cell, dofs_per_cell); + + // We are just solving a Laplacian in each spatial direction, so + // the degrees of freedom for different dimensions do not couple. + Table<2,DoFTools::Coupling> coupling (dim, dim); + coupling.fill(DoFTools::none); + + for (unsigned int c=0; cis_locally_owned()) + { + cell->get_dof_indices (cell_dof_indices); + fe_values.reinit (cell); + + cell_vector = 0; + cell_matrix = 0; + for (unsigned int point=0; point> constant_modes; + DoFTools::extract_constant_modes (mesh_deformation_dof_handler, + ComponentMask(dim, true), + constant_modes); + // TODO: think about keeping object between time steps + LinearAlgebra::PreconditionAMG preconditioner_stiffness; + LinearAlgebra::PreconditionAMG::AdditionalData Amg_data; + Amg_data.constant_modes = constant_modes; + Amg_data.elliptic = true; + Amg_data.higher_order_elements = false; + Amg_data.smoother_sweeps = 2; + Amg_data.aggregation_threshold = 0.02; + preconditioner_stiffness.initialize(mesh_matrix); + + // we solve with higher accuracy in the initial timestep: + const double tolerance + = sim.parameters.linear_stokes_solver_tolerance + * ((this->simulator_is_past_initialization()) ? 1.0 : 1e-5); + + SolverControl solver_control(5*rhs.size(), tolerance * rhs.l2_norm()); + SolverCG cg(solver_control); + + cg.solve (mesh_matrix, solution, rhs, preconditioner_stiffness); + this->get_pcout() << " Solving mesh displacement system... " << solver_control.last_step() <<" iterations."<< std::endl; + + mesh_velocity_constraints.distribute (solution); + + // Update the mesh velocity vector + fs_mesh_velocity = solution; + + // Update the mesh displacement vector + if (this->simulator_is_past_initialization()) + { + // during the simulation, we add dt*solution + LinearAlgebra::Vector distributed_mesh_displacements(mesh_locally_owned, sim.mpi_communicator); + distributed_mesh_displacements = mesh_displacements; + distributed_mesh_displacements.add(this->get_timestep(), solution); + mesh_displacements = distributed_mesh_displacements; + } + else + { + // In the initial step we apply 100% of the initial displacement + mesh_displacements = solution; + } + + if (this->is_stokes_matrix_free()) + update_multilevel_deformation(); + } + + + + template + void MeshDeformationHandler::compute_mesh_displacements_gmg() + { + // Same as compute_mesh_displacements, but using matrix-free GMG + // instead of matrix-based AMG. + + // We use this gmg solver only when the gmg stokes solver is used + // for the following reasons (TODO): + // 1. this gmg solver does not support periodic boundary conditions + // 2. To use this solver even when gmg stokes solver is not used, we need to + // initialize the triangulation with Triangulation::limit_level_difference_at_vertices + // and parallel::distributed::Triangulation::construct_multigrid_hierarchy + // 3. Although this gmg solver is much faster than the amg solver, it's only tested for + // limited free surface cases. + + Assert(mesh_deformation_fe.degree == 1, ExcNotImplemented()); + // To be efficient, the operations performed in the matrix-free implementation require + // knowledge of loop lengths at compile time, which are given by the degree of the finite element. + const unsigned int mesh_deformation_fe_degree = 1; + + using SystemOperatorType = dealii::MatrixFreeOperators:: + LaplaceOperator; + + SystemOperatorType laplace_operator; + + MGLevelObject mg_matrices; + + typename MatrixFree::AdditionalData additional_data; + additional_data.tasks_parallel_scheme = + MatrixFree::AdditionalData::none; + const UpdateFlags update_flags(update_values | update_JxW_values | update_gradients); + additional_data.mapping_update_flags = update_flags; + std::shared_ptr> system_mf_storage + = std::make_shared>(); + system_mf_storage->reinit(*sim.mapping, + mesh_deformation_dof_handler, + mesh_velocity_constraints, + QGauss<1>(mesh_deformation_fe_degree + 1), + additional_data); + laplace_operator.initialize(system_mf_storage); + + // correct rhs: + // In a matrix-free method, since the LaplaceOperator class represents + // the matrix-vector product of a homogeneous operator (the left-hand + // side of the last formula). It does not matter whether the AffineConstraints + // object passed to the MatrixFree::reinit() contains inhomogeneous constraints or not, + // the MatrixFree::cell_loop() call will only resolve the homogeneous + // part of the constraints as long as it represents a linear operator. + + // What this function does is to move the inhomogeneous constraints to the + // right-hand side of the system by computing the residual of the system + // and subtracting it from the right-hand side: r = b - A*u0, + // where u0 is the initial guess and stored the degrees of freedom constrained by + // Inhomogeneous Dirichlet boundary conditions, and r is rhs. + // Then we have a new system Ax = r, and the solution is u = u0 + x. + // More details can be found in deal.II tutorial step-37 Section Possibilities for extensions. + dealii::LinearAlgebra::distributed::Vector u0, rhs, solution; + laplace_operator.initialize_dof_vector(u0); + laplace_operator.initialize_dof_vector(rhs); + laplace_operator.initialize_dof_vector(solution); + u0 = 0.; + mesh_velocity_constraints.distribute(u0); + u0.update_ghost_values(); + + rhs = 0.; + + FEEvaluation mesh_deformation(*laplace_operator.get_matrix_free()); + for (unsigned int cell = 0; + cell < laplace_operator.get_matrix_free()->n_cell_batches(); + ++cell) + { + mesh_deformation.reinit(cell); + mesh_deformation.read_dof_values_plain(u0); + mesh_deformation.evaluate(EvaluationFlags::gradients); + for (unsigned int q = 0; q < mesh_deformation.n_q_points; ++q) + { + mesh_deformation.submit_gradient(-1.0 * mesh_deformation.get_gradient(q), q); + } + mesh_deformation.integrate(EvaluationFlags::gradients); + mesh_deformation.distribute_local_to_global(rhs); + } + rhs.compress(VectorOperation::add); + + // clear the level constraints of the previous time step + mg_constrained_dofs.clear_user_constraints(); + + // setup GMG, following deal.II step-37: + const unsigned int n_levels = sim.triangulation.n_global_levels(); + + // Currently does not support periodic boundary constraints + { + using periodic_boundary_pairs = std::set, unsigned int>>; + const periodic_boundary_pairs pbp = this->get_geometry_model().get_periodic_boundary_pairs(); + AssertThrow(pbp.size() == 0, + ExcMessage("Periodic boundary constraints are not supported in computing mesh displacements using GMG.")); + } + + mg_constrained_dofs.make_zero_boundary_constraints(mesh_deformation_dof_handler, + zero_mesh_deformation_boundary_indicators); + + mg_matrices.clear_elements(); + mg_matrices.resize(0, n_levels-1); + + for (unsigned int level = 0; level < n_levels; ++level) + { + IndexSet relevant_dofs; + DoFTools::extract_locally_relevant_level_dofs(mesh_deformation_dof_handler, + level, + relevant_dofs); + AffineConstraints level_constraints; +#if DEAL_II_VERSION_GTE(9,6,0) + level_constraints.reinit(mesh_deformation_dof_handler.locally_owned_mg_dofs(level), + relevant_dofs); + for (const auto index : mg_constrained_dofs.get_boundary_indices(level)) + level_constraints.constrain_dof_to_zero(index); +#else + level_constraints.reinit(relevant_dofs); + level_constraints.add_lines(mg_constrained_dofs.get_boundary_indices(level)); +#endif + level_constraints.close(); + + const Mapping &mapping = get_level_mapping(level); + + std::set no_flux_boundary + = sim.boundary_velocity_manager.get_tangential_boundary_velocity_indicators(); + if (!no_flux_boundary.empty()) + { + AffineConstraints user_level_constraints; +#if DEAL_II_VERSION_GTE(9,6,0) + user_level_constraints.reinit(mesh_deformation_dof_handler.locally_owned_mg_dofs(level), + relevant_dofs); +#else + user_level_constraints.reinit(relevant_dofs); +#endif + const IndexSet &refinement_edge_indices = + mg_constrained_dofs.get_refinement_edge_indices(level); + dealii::VectorTools::compute_no_normal_flux_constraints_on_level( + mesh_deformation_dof_handler, + 0, + no_flux_boundary, + user_level_constraints, + mapping, + refinement_edge_indices, + level); + + user_level_constraints.close(); + mg_constrained_dofs.add_user_constraints(level, user_level_constraints); + + // let Dirichlet values win over no normal flux: + level_constraints.merge(user_level_constraints, AffineConstraints::left_object_wins); + level_constraints.close(); + } + + typename MatrixFree::AdditionalData additional_data; + additional_data.tasks_parallel_scheme = + MatrixFree::AdditionalData::none; + additional_data.mapping_update_flags = update_flags; + additional_data.mg_level = level; + std::shared_ptr> mg_mf_storage_level + = std::make_shared>(); + + mg_mf_storage_level->reinit(mapping, + mesh_deformation_dof_handler, + level_constraints, + QGauss<1>(mesh_deformation_fe_degree + 1), + additional_data); + mg_matrices[level].clear(); + mg_matrices[level].initialize(mg_mf_storage_level, + mg_constrained_dofs, + level); + } + + MGTransferMF mg_transfer(mg_constrained_dofs); + mg_transfer.build(mesh_deformation_dof_handler); + + using SmootherType = + PreconditionChebyshev>; + + mg::SmootherRelaxation> mg_smoother; + + MGLevelObject smoother_data; + smoother_data.resize(0, n_levels - 1); + + // Smoother: Chebyshev, degree 5. We use a relatively high degree here (5), + // since matrix-vector products are comparably cheap. We choose to smooth out + // a range of [1.2lambda_max/15,1.2lambda_max] in the smoother where lambda_max + // is an estimate of the largest eigenvalue (the factor 1.2 is applied inside + // PreconditionChebyshev). In order to compute that eigenvalue, + // the Chebyshev initialization performs a few steps of a CG algorithm without preconditioner. + // Since the highest eigenvalue is usually the easiest one to find + // and a rough estimate is enough, we choose 10 iterations. + for (unsigned int level = 0; level < n_levels; + ++level) + { + if (level > 0) + { + smoother_data[level].smoothing_range = 15.; + smoother_data[level].degree = 5; + smoother_data[level].eig_cg_n_iterations = 10; + } + else + { + // On level zero, we initialize the smoother differently + // because we want to use the Chebyshev iteration as a solver. + smoother_data[0].smoothing_range = 1e-3; + smoother_data[0].degree = numbers::invalid_unsigned_int; + smoother_data[0].eig_cg_n_iterations = mg_matrices[0].m(); + } + mg_matrices[level].compute_diagonal(); + smoother_data[level].preconditioner = + mg_matrices[level].get_matrix_diagonal_inverse(); + } + mg_smoother.initialize(mg_matrices, smoother_data); + MGCoarseGridApplySmoother> mg_coarse; + mg_coarse.initialize(mg_smoother); + + // set up the interface matrices + mg::Matrix> mg_matrix(mg_matrices); + MGLevelObject> mg_interface_matrices; + mg_interface_matrices.resize(0, n_levels - 1); + for (unsigned int level = 0; level < n_levels; + ++level) + mg_interface_matrices[level].initialize(mg_matrices[level]); + mg::Matrix> mg_interface(mg_interface_matrices); + Multigrid> mg(mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother); + mg.set_edge_matrices(mg_interface, mg_interface); + PreconditionMG, + MGTransferMF> + preconditioner(mesh_deformation_dof_handler, mg, mg_transfer); + + + // solve + const double tolerance + = sim.parameters.linear_stokes_solver_tolerance + * ((this->simulator_is_past_initialization()) ? 1.0 : 1e-5); + + SolverControl solver_control_mf(5 * rhs.size(), + tolerance * rhs.l2_norm()); + SolverCG> cg(solver_control_mf); + + mesh_velocity_constraints.set_zero(solution); + cg.solve(laplace_operator, solution, rhs, preconditioner); + this->get_pcout() << " Solving mesh displacement system... " << solver_control_mf.last_step() <<" iterations."<< std::endl; + + mesh_velocity_constraints.distribute(solution); + solution.update_ghost_values(); + + // copy solution: + LinearAlgebra::Vector solution_tmp; + solution_tmp.reinit(mesh_locally_owned, sim.mpi_communicator); + internal::ChangeVectorTypes::copy(solution_tmp, solution); + + // Update the mesh velocity vector + fs_mesh_velocity = solution_tmp; + + // Update the mesh displacement vector + if (this->simulator_is_past_initialization()) + { + // during the simulation, we add dt*solution + LinearAlgebra::Vector distributed_mesh_displacements(mesh_locally_owned, sim.mpi_communicator); + distributed_mesh_displacements = mesh_displacements; + distributed_mesh_displacements.add(this->get_timestep(), solution_tmp); + mesh_displacements = distributed_mesh_displacements; + } + else + { + // In the initial step we apply 100% of the initial displacement + mesh_displacements = solution_tmp; + } + + update_multilevel_deformation(); + } + + + + template + void MeshDeformationHandler::set_initial_topography() + { + LinearAlgebra::Vector distributed_initial_topography; + distributed_initial_topography.reinit(mesh_locally_owned, sim.mpi_communicator); + + if (!include_initial_topography) + distributed_initial_topography = 0.; + else + { + const std::vector> support_points + = mesh_deformation_fe.base_element(0).get_unit_support_points(); + + const Quadrature quad(support_points); + const UpdateFlags update_flags = UpdateFlags(update_quadrature_points); + FEValues fs_fe_values (*sim.mapping, mesh_deformation_fe, quad, update_flags); + + const unsigned int n_q_points = fs_fe_values.n_quadrature_points, + dofs_per_cell = fs_fe_values.dofs_per_cell; + + std::vector cell_dof_indices (dofs_per_cell); + + for (const auto &cell : mesh_deformation_dof_handler.active_cell_iterators()) + if (cell->is_locally_owned()) + { + cell->get_dof_indices (cell_dof_indices); + + fs_fe_values.reinit (cell); + for (unsigned int j=0; j surface_point; + std::array natural_coord = this->get_geometry_model().cartesian_to_natural_coordinates(fs_fe_values.quadrature_point(j)); + if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + for (unsigned int d=0; dget_initial_topography_model().value(surface_point); + + + // TODO adapt to radial topography + const unsigned int support_point_index + = mesh_deformation_fe.component_to_system_index(dim-1,/*dof index within component=*/ j); + distributed_initial_topography[cell_dof_indices[support_point_index]] = topo; + } + } + } + + distributed_initial_topography.compress(VectorOperation::insert); + initial_topography = distributed_initial_topography; + } + + + template + void MeshDeformationHandler::interpolate_mesh_velocity() + { + // Interpolate the mesh vertex velocity onto the Stokes velocity system for use in ALE corrections + LinearAlgebra::BlockVector distributed_mesh_velocity; + distributed_mesh_velocity.reinit(sim.introspection.index_sets.system_partitioning, sim.mpi_communicator); + + const std::vector> support_points + = sim.finite_element.base_element(sim.introspection.component_indices.velocities[0]).get_unit_support_points(); + + const Quadrature quad(support_points); + const UpdateFlags update_flags = UpdateFlags(update_values | update_JxW_values); + FEValues fs_fe_values (*sim.mapping, mesh_deformation_fe, quad, update_flags); + FEValues fe_values (*sim.mapping, sim.finite_element, quad, update_flags); + const unsigned int n_q_points = fe_values.n_quadrature_points, + dofs_per_cell = fe_values.dofs_per_cell; + + std::vector cell_dof_indices (dofs_per_cell); + FEValuesExtractors::Vector extract_vel(0); + std::vector> velocity_values(n_q_points); + + typename DoFHandler::active_cell_iterator + fscell = mesh_deformation_dof_handler.begin_active(); + + for (const auto &cell : sim.dof_handler.active_cell_iterators()) + { + if (cell->is_locally_owned()) + { + cell->get_dof_indices (cell_dof_indices); + + fe_values.reinit (cell); + fs_fe_values.reinit (fscell); + fs_fe_values[extract_vel].get_function_values(fs_mesh_velocity, velocity_values); + for (unsigned int j=0; j + void MeshDeformationHandler::setup_dofs() + { + AssertThrow(sim.parameters.mesh_deformation_enabled, ExcInternalError()); + + // these live in the same FE as the velocity variable: + mesh_velocity.reinit(sim.introspection.index_sets.system_partitioning, + sim.introspection.index_sets.system_relevant_partitioning, + sim.mpi_communicator); + + mesh_deformation_dof_handler.distribute_dofs(mesh_deformation_fe); + + // Renumber the DoFs hierarchical so that we get the + // same numbering if we resume the computation. This + // is because the numbering depends on the order the + // cells are created. + DoFRenumbering::hierarchical (mesh_deformation_dof_handler); + + if (this->is_stokes_matrix_free()) + { + mesh_deformation_dof_handler.distribute_mg_dofs(); + + mg_constrained_dofs.initialize(mesh_deformation_dof_handler); + + const unsigned int n_levels = this->get_triangulation().n_global_levels(); + + level_displacements.resize(0, n_levels-1); + // Important! Preallocate level vectors with all needed ghost + // entries. While interpolate_to_mg can create these vectors + // automatically, they will not contain all ghost values that we + // need to evaluate the mapping later. + for (unsigned int level = 0; level < n_levels; ++level) + { + IndexSet relevant_mg_dofs; + DoFTools::extract_locally_relevant_level_dofs(mesh_deformation_dof_handler, + level, + relevant_mg_dofs); + level_displacements[level].reinit(mesh_deformation_dof_handler.locally_owned_mg_dofs(level), + relevant_mg_dofs, + sim.mpi_communicator); + level_displacements[level].update_ghost_values(); + } + + // create the mappings on each level: + level_mappings.resize(0, n_levels-1); + level_mappings.apply([&](const unsigned int level, std::unique_ptr> &object) + { + object = std::make_unique>>( + /* degree = */ 1, + mesh_deformation_dof_handler, + level_displacements[level], + level); + }); + + mg_transfer.build(mesh_deformation_dof_handler); + + } + + { + std::locale s = this->get_pcout().get_stream().getloc(); + // Creating std::locale with an empty string previously caused problems + // on some platforms, so the functionality to catch the exception and ignore + // is kept here, even though explicitly setting a facet should always work. + try + { + // Imbue the stream with a locale that does the right thing. The + // locale is responsible for later deleting the object pointed + // to by the last argument (the "facet"), see + // https://en.cppreference.com/w/cpp/locale/locale/locale + this->get_pcout().get_stream().imbue(std::locale(std::locale(), + new aspect::Utilities::ThousandSep)); + } + catch (const std::runtime_error &e) + { + // If the locale doesn't work, just give up + } + + this->get_pcout() << "Number of mesh deformation degrees of freedom: " + << mesh_deformation_dof_handler.n_dofs() + << std::endl; + + this->get_pcout().get_stream().imbue(s); + } + + mesh_locally_owned = mesh_deformation_dof_handler.locally_owned_dofs(); + DoFTools::extract_locally_relevant_dofs (mesh_deformation_dof_handler, + mesh_locally_relevant); + + // This will initialize the mesh displacement and free surface + // mesh velocity vectors with zero-valued entries. + mesh_displacements.reinit(mesh_locally_owned, mesh_locally_relevant, sim.mpi_communicator); + old_mesh_displacements.reinit(mesh_locally_owned, mesh_locally_relevant, sim.mpi_communicator); + initial_topography.reinit(mesh_locally_owned, mesh_locally_relevant, sim.mpi_communicator); + fs_mesh_velocity.reinit(mesh_locally_owned, mesh_locally_relevant, sim.mpi_communicator); + + // if we are just starting, we need to set the initial topography. + if (this->simulator_is_past_initialization() == false || + this->get_timestep_number() == 0) + set_initial_topography(); + + // We would like to make sure that the mesh stays conforming upon + // redistribution, so we construct mesh_vertex_constraints, which + // keeps track of hanging node constraints. + // Note: this would be a more natural fit in make_constraints(), + // but we would like to be able to apply vertex constraints directly + // after setup_dofs(), as is done, for instance, during mesh + // refinement. + mesh_vertex_constraints.clear(); +#if DEAL_II_VERSION_GTE(9,6,0) + mesh_vertex_constraints.reinit(mesh_deformation_dof_handler.locally_owned_dofs(), + mesh_locally_relevant); +#else + mesh_vertex_constraints.reinit(mesh_locally_relevant); +#endif + DoFTools::make_hanging_node_constraints(mesh_deformation_dof_handler, mesh_vertex_constraints); + + // We can safely close this now + mesh_vertex_constraints.close(); + + // if we are just starting, we need to prescribe the initial deformation + if (this->simulator_is_past_initialization() == false || + this->get_timestep_number() == 0) + { + TimerOutput::Scope timer (sim.computing_timer, "Mesh deformation initialize"); + + make_initial_constraints(); + if (this->is_stokes_matrix_free()) + compute_mesh_displacements_gmg(); + else + compute_mesh_displacements(); + } + + if (this->is_stokes_matrix_free()) + update_multilevel_deformation(); + } + + + + template + void MeshDeformationHandler::update_multilevel_deformation () + { + Assert(this->is_stokes_matrix_free(), ExcInternalError()); + + // Convert the mesh_displacements to a d:Vector that we can use + // to transfer to the MG levels below. The conversion is done by + // going through a ReadWriteVector. + dealii::LinearAlgebra::distributed::Vector displacements(mesh_deformation_dof_handler.locally_owned_dofs(), + this->get_triangulation().get_communicator()); + dealii::LinearAlgebra::ReadWriteVector rwv; + rwv.reinit(mesh_displacements); + displacements.import(rwv, VectorOperation::insert); + + const unsigned int n_levels = sim.triangulation.n_global_levels(); + for (unsigned int level = 0; level < n_levels; ++level) + { + level_displacements[level].zero_out_ghost_values(); + } + + mg_transfer.interpolate_to_mg(mesh_deformation_dof_handler, + level_displacements, + displacements); + + for (unsigned int level = 0; level < n_levels; ++level) + { + level_displacements[level].update_ghost_values(); + } + + } + + + + template + const std::map> & + MeshDeformationHandler::get_active_mesh_deformation_names () const + { + return mesh_deformation_object_names; + } + + + + template + const std::map>>> & + MeshDeformationHandler::get_active_mesh_deformation_models () const + { + return mesh_deformation_objects; + } + + + + template + const std::set & + MeshDeformationHandler::get_active_mesh_deformation_boundary_indicators () const + { + return prescribed_mesh_deformation_boundary_indicators; + } + + + + template + const std::set & + MeshDeformationHandler::get_boundary_indicators_requiring_stabilization () const + { + return boundary_indicators_requiring_stabilization; + } + + + + template + const std::set & + MeshDeformationHandler::get_free_surface_boundary_indicators () const + { + return free_surface_boundary_indicators; + } + + + + template + double MeshDeformationHandler::get_free_surface_theta()const + { + return surface_theta; + } + + + + template + const LinearAlgebra::Vector & + MeshDeformationHandler::get_mesh_displacements () const + { + return mesh_displacements; + } + + + + template + const DoFHandler & + MeshDeformationHandler::get_mesh_deformation_dof_handler () const + { + return mesh_deformation_dof_handler; + } + + + + template + const LinearAlgebra::Vector & + MeshDeformationHandler::get_initial_topography () const + { + return initial_topography; + } + + + + template + std::string + get_valid_model_names_pattern () + { + return std::get(registered_plugins).get_pattern_of_names (); + } + + + + template + void + MeshDeformationHandler::write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Mesh deformation interface", + out); + } + } +} + + +// explicit instantiation of the functions we implement in this file +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace MeshDeformation + { +#define INSTANTIATE(dim) \ + template class Interface; \ + template class MeshDeformationHandler; \ + \ + template \ + std::string \ + get_valid_model_names_pattern (); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/mesh_refinement/artificial_viscosity.cc.bak b/source/mesh_refinement/artificial_viscosity.cc.bak new file mode 100644 index 00000000000..55573204606 --- /dev/null +++ b/source/mesh_refinement/artificial_viscosity.cc.bak @@ -0,0 +1,132 @@ +/* + Copyright (C) 2015 - 2020 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + ArtificialViscosity::execute(Vector &indicators) const + { + indicators = 0; + Vector this_indicator(indicators.size()); + if (temperature_scaling_factor > 0.0) + { + this->get_artificial_viscosity(indicators); + indicators *= temperature_scaling_factor; + } + + for (unsigned int c=0; cn_compositional_fields(); ++c) + { + this_indicator = 0; + this->get_artificial_viscosity_composition(this_indicator, c); + + // compute indicators += c*this_indicator: + indicators.add(composition_scaling_factors[c], this_indicator); + } + } + + template + void + ArtificialViscosity:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Artificial viscosity"); + { + prm.declare_entry("Temperature scaling factor", + "0.0", + Patterns::Double (0.), + "A scaling factor for the artificial viscosity " + " of the temperature equation. Use 0.0 to disable."); + prm.declare_entry("Compositional field scaling factors", + "", + Patterns::List (Patterns::Double (0.)), + "A list of scaling factors by which every individual compositional " + "field will be multiplied. These " + "factors are used to weigh the various indicators relative to " + "each other and to the temperature. " + "\n\n" + "If the list of scaling factors given in this parameter is empty, then this " + "indicates that they should all be chosen equal to 0. If the list " + "is not empty then it needs to have as many entries as there are " + "compositional fields."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + ArtificialViscosity::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Artificial viscosity"); + { + temperature_scaling_factor = prm.get_double("Temperature scaling factor"); + + composition_scaling_factors + = Utilities::string_to_double( + Utilities::split_string_list(prm.get("Compositional field scaling factors"))); + + AssertThrow (composition_scaling_factors.size() == this->n_compositional_fields() + || + composition_scaling_factors.size() == 0, + ExcMessage ("The number of scaling factors given here must either be " + "zero or equal to the number of chosen refinement criteria.")); + + if (composition_scaling_factors.size() == 0) + composition_scaling_factors.resize (this->n_compositional_fields(), 0.0); + + const double sum_composition_factors = + std::accumulate (composition_scaling_factors.begin(), + composition_scaling_factors.end(), 0.0); + + AssertThrow(sum_composition_factors + temperature_scaling_factor > 0.0, + ExcMessage("You need to have a positive scaling factor " + "for at least one variable.")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(ArtificialViscosity, + "artificial viscosity", + "A mesh refinement criterion that computes " + "refinement indicators from the artificial viscosity " + "of the temperature or compositional fields " + "based on user specified weights.") + } +} diff --git a/source/mesh_refinement/boundary.cc.bak b/source/mesh_refinement/boundary.cc.bak new file mode 100644 index 00000000000..e51173946f2 --- /dev/null +++ b/source/mesh_refinement/boundary.cc.bak @@ -0,0 +1,122 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + Boundary::execute(Vector &indicators) const + { + indicators = 0; + + // iterate over all of the cells and choose the ones at the indicated + // boundaries for refinement (assign the largest error to them) + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + for (const unsigned int face_no : cell->face_indices()) + if (cell->face(face_no)->at_boundary()) + { + const types::boundary_id boundary_indicator + = cell->face(face_no)->boundary_id(); + if ( boundary_refinement_indicators.find(boundary_indicator) != + boundary_refinement_indicators.end() ) + { + indicators(cell->active_cell_index()) = 1.0; + break; // no need to loop over the rest of the faces + } + } + + } + + template + void + Boundary:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Boundary"); + { + prm.declare_entry ("Boundary refinement indicators", "", + Patterns::List (Patterns::Anything()), + "A comma separated list of names denoting those boundaries " + "where there should be mesh refinement." + "\n\n" + "The names of the boundaries listed here can either be " + "numbers (in which case they correspond to the numerical " + "boundary indicators assigned by the geometry object), or they " + "can correspond to any of the symbolic names the geometry object " + "may have provided for each part of the boundary. You may want " + "to compare this with the documentation of the geometry model you " + "use in your model."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + Boundary::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Boundary"); + { + const std::vector x_boundary_refinement_indicators + = this->get_geometry_model().translate_symbolic_boundary_names_to_ids(Utilities::split_string_list + (prm.get ("Boundary refinement indicators"))); + boundary_refinement_indicators + = std::set (x_boundary_refinement_indicators.begin(), + x_boundary_refinement_indicators.end()); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Boundary, + "boundary", + "A class that implements a mesh refinement criterion which " + "always flags all cells on specified boundaries for refinement. " + "This is useful to provide high accuracy for processes at or " + "close to the edge of the model domain." + "\n\n" + "To use this refinement criterion, you may want to combine " + "it with other refinement criteria, setting the 'Normalize " + "individual refinement criteria' flag and using the `max' " + "setting for 'Refinement criteria merge operation'.") + } +} diff --git a/source/mesh_refinement/compaction_length.cc.bak b/source/mesh_refinement/compaction_length.cc.bak new file mode 100644 index 00000000000..13d0ac9f614 --- /dev/null +++ b/source/mesh_refinement/compaction_length.cc.bak @@ -0,0 +1,158 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + CompactionLength::tag_additional_cells () const + { + // tag_additional_cells is executed before the equations are solved + // for the very first time. If we do not have the finite element, we + // do not have any material properties and just do nothing in this plugin. + if (this->get_dof_handler().n_locally_owned_dofs() == 0) + return; + + // Use a quadrature in the support points of the porosity to compute the + // compaction length at: + const typename Simulator::AdvectionField porosity = Simulator::AdvectionField::composition( + this->introspection().compositional_index_for_name("porosity")); + + const unsigned int base_element_index = porosity.base_element(this->introspection()); + const Quadrature quadrature(this->get_fe().base_element(base_element_index).get_unit_support_points()); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature, + update_quadrature_points | update_values | update_gradients); + + MaterialModel::MaterialModelInputs in(quadrature.size(), this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(quadrature.size(), this->n_compositional_fields()); + MeltHandler::create_material_model_outputs(out); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + bool refine = false; + bool clear_coarsen = false; + + fe_values.reinit(cell); + in.reinit(fe_values, cell, this->introspection(), this->get_solution()); + this->get_material_model().evaluate(in, out); + + MaterialModel::MeltOutputs *melt_out = out.template get_additional_output>(); + AssertThrow(melt_out != nullptr, + ExcMessage("Need MeltOutputs from the material model for computing the melt properties.")); + + // for each composition dof, check if the compaction length exceeds the cell size + for (unsigned int i=0; icompaction_viscosities[i]) + * melt_out->permeabilities[i] / melt_out->fluid_viscosities[i]); + + // If the compaction length exceeds the cell diameter anywhere in the cell, cell is marked for refinement. + // Do not apply any refinement if the porosity is so small that melt can not migrate. + if (compaction_length < 2.0 * cells_per_compaction_length * cell->minimum_vertex_distance() + && this->get_melt_handler().is_melt_cell(cell)) + clear_coarsen = true; + + if (compaction_length < cells_per_compaction_length * cell->minimum_vertex_distance() + && this->get_melt_handler().is_melt_cell(cell)) + { + refine = true; + break; + } + } + + if (clear_coarsen) + cell->clear_coarsen_flag (); + if (refine) + cell->set_refine_flag (); + } + } + + template + void + CompactionLength:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Compaction length"); + { + prm.declare_entry("Mesh cells per compaction length", "1.0", + Patterns::Double (0.), + "The desired ratio between compaction length and size of the " + "mesh cells, or, in other words, how many cells the mesh should " + "(at least) have per compaction length. Every cell where this " + "ratio is smaller than the value specified by this parameter " + "(in places with fewer mesh cells per compaction length) is " + "marked for refinement."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + CompactionLength::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Compaction length"); + { + cells_per_compaction_length = prm.get_double ("Mesh cells per compaction length"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(CompactionLength, + "compaction length", + "A mesh refinement criterion for models with melt transport " + "that computes refinement indicators based on the compaction " + "length, defined as " + "$\\delta = \\sqrt{\\frac{(\\xi + 4 \\eta/3) k}{\\eta_f}}$. " + "$\\xi$ is the bulk viscosity, $\\eta$ is the shear viscosity, " + "$k$ is the permeability and $\\eta_f$ is the melt viscosity. " + "If the cell width or height exceeds a multiple (which is " + "specified as an input parameter) of this compaction length, " + "the cell is marked for refinement.") + } +} diff --git a/source/mesh_refinement/composition.cc.bak b/source/mesh_refinement/composition.cc.bak new file mode 100644 index 00000000000..69a9c76d6a0 --- /dev/null +++ b/source/mesh_refinement/composition.cc.bak @@ -0,0 +1,152 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + Composition::execute(Vector &indicators) const + { + AssertThrow (this->n_compositional_fields() >= 1, + ExcMessage ("This refinement criterion cannot be used when no " + "compositional fields are active!")); + indicators = 0; + Vector this_indicator (indicators.size()); + + const Quadrature &quadrature = this->introspection().face_quadratures.compositional_fields; + + for (unsigned int c=0; cn_compositional_fields(); ++c) + { + this_indicator = 0; + KellyErrorEstimator::estimate (this->get_mapping(), + this->get_dof_handler(), + quadrature, + std::map*>(), + this->get_solution(), + this_indicator, + this->introspection().component_masks.compositional_fields[c], + nullptr, + 0, + this->get_triangulation().locally_owned_subdomain()); + // compute indicators += c*this_indicator: + indicators.add(composition_scaling_factors[c], this_indicator); + } + } + + template + void + Composition:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Composition"); + { + prm.declare_entry("Compositional field scaling factors", + "", + Patterns::List (Patterns::Double (0.)), + "A list of scaling factors by which every individual compositional " + "field will be multiplied. If only a single compositional " + "field exists, then this parameter has no particular meaning. " + "On the other hand, if multiple criteria are chosen, then these " + "factors are used to weigh the various indicators relative to " + "each other. " + "\n\n" + "If the list of scaling factors given in this parameter is empty, then this " + "indicates that they should all be chosen equal to one. If the list " + "is not empty then it needs to have as many entries as there are " + "compositional fields."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + Composition::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Composition"); + { + composition_scaling_factors + = Utilities::string_to_double( + Utilities::split_string_list(prm.get("Compositional field scaling factors"))); + + AssertThrow (composition_scaling_factors.size() == this->n_compositional_fields() + || + composition_scaling_factors.size() == 0, + ExcMessage ("The number of scaling factors given here must either be " + "zero or equal to the number of chosen refinement criteria.")); + + if (composition_scaling_factors.size() == 0) + composition_scaling_factors.resize (this->n_compositional_fields(), 1.0); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Composition, + "composition", + "A mesh refinement criterion that computes " + "refinement indicators from the compositional fields. " + "If there is more than one compositional field, then " + "it simply takes the sum of the indicators computed " + "from each of the compositional field." + "\n\n" + "The way these indicators are computed is by " + "evaluating the `Kelly error indicator' on each " + "compositional field. This error indicator takes the " + "finite element approximation of the compositional " + "field and uses it to compute an approximation " + "of the second derivatives of the composition for " + "each cell. This approximation is then multiplied " + "by an appropriate power of the cell's diameter " + "to yield an indicator for how large the error " + "is likely going to be on this cell. This " + "construction rests on the observation that for " + "many partial differential equations, the error " + "on each cell is proportional to some power of " + "the cell's diameter times the second derivatives " + "of the solution on that cell." + "\n\n" + "For complex equations such as those we solve " + "here, this observation may not be strictly " + "true in the mathematical sense, but it often " + "yields meshes that are surprisingly good.") + } +} diff --git a/source/mesh_refinement/composition_approximate_gradient.cc.bak b/source/mesh_refinement/composition_approximate_gradient.cc.bak new file mode 100644 index 00000000000..0397704160a --- /dev/null +++ b/source/mesh_refinement/composition_approximate_gradient.cc.bak @@ -0,0 +1,153 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + CompositionApproximateGradient::execute(Vector &indicators) const + { + AssertThrow (this->n_compositional_fields() >= 1, + ExcMessage ("This refinement criterion can not be used when no " + "compositional fields are active!")); + indicators = 0; + // create a vector with the requisite ghost elements + // and use it for estimating the gradients of compositional field + LinearAlgebra::BlockVector vec(this->introspection().index_sets.system_partitioning, + this->introspection().index_sets.system_relevant_partitioning, + this->get_mpi_communicator()); + Vector indicators_tmp(this->get_triangulation().n_active_cells()); + for (unsigned int c=0; cn_compositional_fields(); ++c) + { + const unsigned int block_idx = this->introspection().block_indices.compositional_fields[c]; + vec.block(block_idx) = this->get_solution().block(block_idx); + vec.compress(VectorOperation::insert); + indicators_tmp = 0; + DerivativeApproximation::approximate_gradient(this->get_mapping(), + this->get_dof_handler(), + vec, + indicators_tmp, + this->introspection().component_indices.compositional_fields[c]); + + indicators_tmp *= composition_scaling_factors[c]; + + // Scale approximated gradient in each cell with the correct power of h. Otherwise, + // error indicators do not reduce when refined if there is a density + // jump. We need at least order 1 for the error not to grow when + // refining, so anything >1 should work. (note that the gradient + // itself scales like 1/h, so multiplying it with any factor h^s, s>1 + // will yield convergence of the error indicators to zero as h->0) + const double power = 1.0 + dim / 2.0; + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + indicators_tmp(cell->active_cell_index()) *= std::pow(cell->diameter(), power); + + indicators += indicators_tmp; + } + } + + + template + void + CompositionApproximateGradient:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Composition approximate gradient"); + { + prm.declare_entry("Compositional field scaling factors", + "", + Patterns::List (Patterns::Double (0.)), + "A list of scaling factors by which every individual compositional " + "field gradient will be multiplied. If only a single compositional " + "field exists, then this parameter has no particular meaning. " + "On the other hand, if multiple criteria are chosen, then these " + "factors are used to weigh the various indicators relative to " + "each other. " + "\n\n" + "If the list of scaling factors given in this parameter is empty, then this " + "indicates that they should all be chosen equal to one. If the list " + "is not empty then it needs to have as many entries as there are " + "compositional fields."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + CompositionApproximateGradient::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Composition approximate gradient"); + { + composition_scaling_factors + = Utilities::string_to_double( + Utilities::split_string_list(prm.get("Compositional field scaling factors"))); + + AssertThrow (composition_scaling_factors.size() == this->n_compositional_fields() + || + composition_scaling_factors.size() == 0, + ExcMessage ("The number of scaling factors given here must either be " + "zero or equal to the number of chosen refinement criteria.")); + + if (composition_scaling_factors.size() == 0) + composition_scaling_factors.resize (this->n_compositional_fields(), 1.0); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(CompositionApproximateGradient, + "composition approximate gradient", + "A mesh refinement criterion that computes refinement " + "indicators from the gradients of compositional fields. " + "If there is more than one compositional field, then " + "it simply takes the sum of the indicators times " + "a user-specified weight for each field." + "\n\n" + "In contrast to the `composition gradient' refinement " + "criterion, the current criterion does not " + "compute the gradient at quadrature points on each cell, " + "but by a finite difference approximation between the " + "centers of cells. Consequently, it also works if " + "the compositional fields are computed using discontinuous " + "finite elements.") + } +} diff --git a/source/mesh_refinement/composition_gradient.cc.bak b/source/mesh_refinement/composition_gradient.cc.bak new file mode 100644 index 00000000000..47eace30bb8 --- /dev/null +++ b/source/mesh_refinement/composition_gradient.cc.bak @@ -0,0 +1,185 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + CompositionGradient::execute(Vector &indicators) const + { + AssertThrow (this->n_compositional_fields() >= 1, + ExcMessage ("This refinement criterion can not be used when no " + "compositional fields are active!")); + + indicators = 0; + const double power = 1.0 + dim/2.0; + + for (const unsigned int base_element_index : this->introspection().get_composition_base_element_indices()) + { + const Quadrature quadrature (this->get_fe().base_element(base_element_index).get_unit_support_points()); + const unsigned int dofs_per_cell = quadrature.size(); + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature, + update_quadrature_points | update_gradients); + + // the values of the compositional fields are stored as block vectors for each field + // we have to extract them in this structure + std::vector> composition_gradients (quadrature.size()); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + const unsigned int idx = cell->active_cell_index(); + fe_values.reinit(cell); + + for (const unsigned int c : this->introspection().get_compositional_field_indices_with_base_element(base_element_index)) + { + const typename Simulator::AdvectionField composition = Simulator::AdvectionField::composition(c); + fe_values[composition.scalar_extractor(this->introspection())].get_function_gradients (this->get_solution(), + composition_gradients); + + // Some up the indicators for this composition on this cell. Note that quadrature points and dofs + // are enumerated in the same order. + double this_indicator = 0.0; + for (unsigned int j=0; j1 should work. (note that the gradient + // itself scales like 1/h, so multiplying it with any factor h^s, s>1 + // will yield convergence of the error indicators to zero as h->0) + this_indicator *= std::pow(cell->diameter(), power); + + indicators[idx] += composition_scaling_factors[c] * this_indicator; + } + } + } + } + + template + void + CompositionGradient:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Composition gradient"); + { + prm.declare_entry("Compositional field scaling factors", + "", + Patterns::List (Patterns::Double (0.)), + "A list of scaling factors by which every individual compositional " + "field gradient will be multiplied. If only a single compositional " + "field exists, then this parameter has no particular meaning. " + "On the other hand, if multiple criteria are chosen, then these " + "factors are used to weigh the various indicators relative to " + "each other. " + "\n\n" + "If the list of scaling factors given in this parameter is empty, then this " + "indicates that they should all be chosen equal to one. If the list " + "is not empty then it needs to have as many entries as there are " + "compositional fields."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + CompositionGradient::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Composition gradient"); + { + composition_scaling_factors + = Utilities::string_to_double( + Utilities::split_string_list(prm.get("Compositional field scaling factors"))); + + AssertThrow (composition_scaling_factors.size() == this->n_compositional_fields() + || + composition_scaling_factors.size() == 0, + ExcMessage ("The number of scaling factors given here must either be " + "zero or equal to the number of chosen refinement criteria.")); + + if (composition_scaling_factors.size() == 0) + composition_scaling_factors.resize (this->n_compositional_fields(), 1.0); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(CompositionGradient, + "composition gradient", + "A mesh refinement criterion that computes refinement " + "indicators from the gradients of compositional fields. " + "If there is more than one compositional field, then " + "it simply takes the sum of the indicators times " + "a user-specified weight for each field." + "\n\n" + "This refinement criterion computes the gradient of " + "the compositional field at quadrature points on each " + "cell, and then averages them in some way to obtain a " + "refinement indicator for each cell. This will give a " + "reasonable approximation of the true gradient of the " + "compositional field if you are using a continuous " + "finite element." + "\n\n" + "On the other hand, for discontinuous " + "finite elements (see the `Use discontinuous composition " + "discretization' parameter in the `Discretization' " + "section), the gradient at quadrature points does not " + "include the contribution of jumps in the compositional " + "field between cells, and consequently will not be an " + "accurate approximation of the true gradient. As an " + "extreme example, consider the case of using piecewise " + "constant finite elements for compositional fields; in " + "that case, the gradient of the solution at quadrature " + "points inside each cell will always be exactly zero, " + "even if the finite element solution is different " + "from each cell to the next. Consequently, the " + "current refinement criterion will likely not be " + "useful in this situation. That said, " + "the `composition approximate " + "gradient' refinement criterion exists for exactly " + "this purpose.") + } +} diff --git a/source/mesh_refinement/composition_threshold.cc.bak b/source/mesh_refinement/composition_threshold.cc.bak new file mode 100644 index 00000000000..d2ad3cbf622 --- /dev/null +++ b/source/mesh_refinement/composition_threshold.cc.bak @@ -0,0 +1,137 @@ +/* + Copyright (C) 2015 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + CompositionThreshold::tag_additional_cells () const + { + AssertThrow (this->n_compositional_fields() >= 1, + ExcMessage ("This refinement criterion can not be used when no " + "compositional fields are active!")); + + // tag_additional_cells is executed before the equations are solved + // for the very first time. If we do not have the finite element, we + // do not have the compositional fields and just do nothing in this plugin. + if (this->get_dof_handler().n_locally_owned_dofs() == 0) + return; + + const unsigned int dofs_per_cell = this->get_fe().dofs_per_cell; + std::vector local_dof_indices(dofs_per_cell); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + cell->get_dof_indices (local_dof_indices); + bool refine = false; + + for (unsigned int c=0; cn_compositional_fields(); ++c) + { + const unsigned int component_idx = this->introspection().component_indices.compositional_fields[c]; + for (unsigned int i=0; iget_fe().system_to_component_index(i).first == component_idx) + { + const double composition_value = this->get_solution()[local_dof_indices[i]]; + // if the composition exceeds the threshold, cell is marked for refinement + if (composition_value > composition_thresholds[c]) + { + refine = true; + break; + } + } + } + if (refine) + break; + } + + if (refine) + { + cell->clear_coarsen_flag (); + cell->set_refine_flag (); + } + } + } + + template + void + CompositionThreshold:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Composition threshold"); + { + prm.declare_entry("Compositional field thresholds", + "", + Patterns::List (Patterns::Double()), + "A list of thresholds that every individual compositional " + "field will be evaluated against."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + CompositionThreshold::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Composition threshold"); + { + composition_thresholds + = Utilities::string_to_double( + Utilities::split_string_list(prm.get("Compositional field thresholds"))); + + AssertThrow (composition_thresholds.size() == this->n_compositional_fields(), + ExcMessage ("The number of thresholds given here must be " + "equal to the number of chosen refinement criteria.")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(CompositionThreshold, + "composition threshold", + "A mesh refinement criterion that computes refinement " + "indicators from the compositional fields. If any field " + "exceeds the threshold given in the input file, the cell " + "is marked for refinement.") + } +} diff --git a/source/mesh_refinement/density.cc.bak b/source/mesh_refinement/density.cc.bak new file mode 100644 index 00000000000..9f97b335d85 --- /dev/null +++ b/source/mesh_refinement/density.cc.bak @@ -0,0 +1,143 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + Density::execute(Vector &indicators) const + { + indicators = 0; + +//TODO: if the density doesn't actually depend on the solution + // then we can get away with simply interpolating it spatially + + + // create a vector in which we set the temperature block to + // be a finite element interpolation of the density. + // we do so by setting up a quadrature formula with the + // temperature unit support points, then looping over these + // points, compute the output quantity at them, and writing + // the result into the output vector in the same order + // (because quadrature points and temperature dofs are, + // by design of the quadrature formula, numbered in the + // same way) + LinearAlgebra::BlockVector vec_distributed (this->introspection().index_sets.system_partitioning, + this->get_mpi_communicator()); + + const Quadrature quadrature(this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_support_points()); + std::vector local_dof_indices (this->get_fe().dofs_per_cell); + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature, + update_quadrature_points | update_values | update_gradients); + + MaterialModel::MaterialModelInputs in(quadrature.size(), + this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(quadrature.size(), + this->n_compositional_fields()); + in.requested_properties = MaterialModel::MaterialProperties::density; + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit(cell); + // Set use_strain_rates to false since we don't need viscosity + in.reinit(fe_values, cell, this->introspection(), this->get_solution()); + + this->get_material_model().evaluate(in, out); + + cell->get_dof_indices (local_dof_indices); + + // for each temperature dof, write into the output + // vector the density. note that quadrature points and + // dofs are enumerated in the same order + for (unsigned int i=0; iget_fe().base_element(this->introspection().base_elements.temperature).dofs_per_cell; ++i) + { + const unsigned int system_local_dof + = this->get_fe().component_to_system_index(this->introspection().component_indices.temperature, + /*dof index within component=*/i); + + vec_distributed(local_dof_indices[system_local_dof]) + = out.densities[i]; + } + } + + vec_distributed.compress(VectorOperation::insert); + + // now create a vector with the requisite ghost elements + // and use it for estimating the gradients + LinearAlgebra::BlockVector vec (this->introspection().index_sets.system_partitioning, + this->introspection().index_sets.system_relevant_partitioning, + this->get_mpi_communicator()); + vec = vec_distributed; + + DerivativeApproximation::approximate_gradient (this->get_mapping(), + this->get_dof_handler(), + vec, + indicators, + this->introspection().component_indices.temperature); + + // Scale gradient in each cell with the correct power of h. Otherwise, + // error indicators do not reduce when refined if there is a density + // jump. We need at least order 1 for the error not to grow when + // refining, so anything >1 should work. (note that the gradient + // itself scales like 1/h, so multiplying it with any factor h^s, s>1 + // will yield convergence of the error indicators to zero as h->0) + const double power = 1.0 + dim/2.0; + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + indicators(cell->active_cell_index()) *= std::pow(cell->diameter(), power); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Density, + "density", + "A mesh refinement criterion that computes " + "refinement indicators from a field that describes " + "the spatial variability of the density, $\\rho$. " + "Because this quantity may not be a continuous function ($\\rho$ " + "and $C_p$ may be discontinuous functions along discontinuities in the " + "medium, for example due to phase changes), we approximate the " + "gradient of this quantity to refine the mesh. The error indicator " + "defined here takes the magnitude of the approximate gradient " + "and scales it by $h_K^{1+d/2}$ where $h_K$ is the diameter of each cell " + "and $d$ is the dimension. " + "This scaling ensures that the error indicators converge to zero as " + "$h_K\\rightarrow 0$ even if the energy density is discontinuous, since " + "the gradient of a discontinuous function grows like $1/h_K$.") + } +} diff --git a/source/mesh_refinement/interface.cc.bak b/source/mesh_refinement/interface.cc.bak new file mode 100644 index 00000000000..8e16815ddd4 --- /dev/null +++ b/source/mesh_refinement/interface.cc.bak @@ -0,0 +1,519 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include + + +namespace aspect +{ + namespace MeshRefinement + { +// ------------------------------ Interface ----------------------------- + + template + void + Interface::execute (Vector &error_indicators) const + { + for (float &error_indicator : error_indicators) + error_indicator = 0; + } + + + template + void + Interface::tag_additional_cells () const + {} + + + +// ------------------------------ Manager ----------------------------- + + template + Manager::~Manager() + = default; + + + + template + void + Manager::update () + { + Assert (this->plugin_objects.size() > 0, ExcInternalError()); + + // call the update() functions of all refinement plugins. + for (const auto &p : this->plugin_objects) + { + try + { + p->update (); + } + + // plugins that throw exceptions usually do not result in + // anything good because they result in an unwinding of the stack + // and, if only one processor triggers an exception, the + // destruction of objects often causes a deadlock. thus, if + // an exception is generated, catch it, print an error message, + // and abort the program + catch (std::exception &exc) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on MPI process <" + << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) + << "> while running mesh refinement plugin <" + << typeid(*p).name() + << ">: " << std::endl + << exc.what() << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + // terminate the program! + MPI_Abort (MPI_COMM_WORLD, 1); + } + catch (...) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on MPI process <" + << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) + << "> while running mesh refinement plugin <" + << typeid(*p).name() + << ">: " << std::endl; + std::cerr << "Unknown exception!" << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + // terminate the program! + MPI_Abort (MPI_COMM_WORLD, 1); + } + } + } + + + + template + void + Manager::execute (Vector &error_indicators) const + { + Assert (this->plugin_objects.size() > 0, ExcInternalError()); + + // call the execute() functions of all plugins we have + // here in turns. then normalize the output vector and + // verify that its values are non-negative numbers + std::vector> all_error_indicators (this->plugin_objects.size(), + Vector(error_indicators.size())); + unsigned int index = 0; + for (typename std::list>>::const_iterator + p = this->plugin_objects.begin(); + p != this->plugin_objects.end(); ++p, ++index) + { + try + { + (*p)->execute (all_error_indicators[index]); + + for (unsigned int i=0; i= 0, + ExcMessage ("Error indicators must be non-negative numbers!")); + + // see if we want to normalize the criteria + if (normalize_criteria == true) + { + const double global_max = Utilities::MPI::max (all_error_indicators[index].linfty_norm(), + this->get_mpi_communicator()); + if (global_max != 0) + all_error_indicators[index] /= global_max; + } + + // then also scale them + all_error_indicators[index] *= scaling_factors[index]; + } + // plugins that throw exceptions usually do not result in + // anything good because they result in an unwinding of the stack + // and, if only one processor triggers an exception, the + // destruction of objects often causes a deadlock. thus, if + // an exception is generated, catch it, print an error message, + // and abort the program + catch (std::exception &exc) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on MPI process <" + << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) + << "> while running mesh refinement plugin <" + << typeid(**p).name() + << ">: " << std::endl + << exc.what() << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + // terminate the program! + MPI_Abort (MPI_COMM_WORLD, 1); + } + catch (...) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on MPI process <" + << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) + << "> while running mesh refinement plugin <" + << typeid(**p).name() + << ">: " << std::endl; + std::cerr << "Unknown exception!" << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + // terminate the program! + MPI_Abort (MPI_COMM_WORLD, 1); + } + } + + // now merge the results + switch (merge_operation) + { + case plus: + { + for (unsigned int i=0; iplugin_objects.size(); ++i) + error_indicators += all_error_indicators[i]; + break; + } + + case max: + { + error_indicators = all_error_indicators[0]; + for (unsigned int i=1; iplugin_objects.size(); ++i) + { + Assert (error_indicators.size() == all_error_indicators[i].size(), + ExcInternalError()); + for (unsigned int j=0; j + void + Manager::tag_additional_cells () const + { + Assert (this->plugin_objects.size() > 0, ExcInternalError()); + + // call the tag_additional_cells() functions of all + // plugins we have here in turns. + for (const auto &p : this->plugin_objects) + { + try + { + p->tag_additional_cells (); + } + + // plugins that throw exceptions usually do not result in + // anything good because they result in an unwinding of the stack + // and, if only one processor triggers an exception, the + // destruction of objects often causes a deadlock. thus, if + // an exception is generated, catch it, print an error message, + // and abort the program + catch (std::exception &exc) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on MPI process <" + << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) + << "> while running mesh refinement plugin <" + << typeid(*p).name() + << ">: " << std::endl + << exc.what() << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + // terminate the program! + MPI_Abort (MPI_COMM_WORLD, 1); + } + catch (...) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on MPI process <" + << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) + << "> while running mesh refinement plugin <" + << typeid(*p).name() + << ">: " << std::endl; + std::cerr << "Unknown exception!" << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + // terminate the program! + MPI_Abort (MPI_COMM_WORLD, 1); + } + } + } + + + + + +// -------------------------------- Deal with registering plugins and automating +// -------------------------------- their setup and selection at run time + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + Manager::declare_parameters (ParameterHandler &prm) + { + // first declare the postprocessors we know about to + // choose from + prm.enter_subsection("Mesh refinement"); + { + // construct a string for Patterns::MultipleSelection that + // contains the names of all registered plugins + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + prm.declare_entry("Strategy", + "thermal energy density", + Patterns::MultipleSelection(pattern_of_names), + "A comma separated list of mesh refinement criteria that " + "will be run whenever mesh refinement is required. The " + "results of each of these criteria, i.e., the refinement " + "indicators they produce for all the cells of the mesh " + "will then be normalized to a range between zero and one " + "and the results of different criteria will then be " + "merged through the operation selected in this section.\n\n" + "The following criteria are available:\n\n" + + + std::get(registered_plugins).get_description_string()); + + prm.declare_entry("Normalize individual refinement criteria", + "true", + Patterns::Bool(), + "If multiple refinement criteria are specified in the " + "``Strategy'' parameter, then they need to be combined " + "somehow to form the final refinement indicators. This " + "is done using the method described by the ``Refinement " + "criteria merge operation'' parameter which can either " + "operate on the raw refinement indicators returned by " + "each strategy (i.e., dimensional quantities) or using " + "normalized values where the indicators of each strategy " + "are first normalized to the interval $[0,1]$ (which also " + "makes them non-dimensional). This parameter determines " + "whether this normalization will happen."); + prm.declare_entry("Refinement criteria scaling factors", + "", + Patterns::List (Patterns::Double (0.)), + "A list of scaling factors by which every individual refinement " + "criterion will be multiplied by. If only a single refinement " + "criterion is selected (using the ``Strategy'' parameter, then " + "this parameter has no particular meaning. On the other hand, if " + "multiple criteria are chosen, then these factors are used to " + "weigh the various indicators relative to each other. " + "\n\n" + "If ``Normalize individual refinement criteria'' is set to true, " + "then the criteria will first be normalized to the interval $[0,1]$ " + "and then multiplied by the factors specified here. You will likely " + "want to choose the factors to be not too far from 1 in that case, say " + "between 1 and 10, to avoid essentially disabling those criteria " + "with small weights. On the other hand, if the criteria are not " + "normalized to $[0,1]$ using the parameter mentioned above, then " + "the factors you specify here need to take into account the relative " + "numerical size of refinement indicators (which in that case carry " + "physical units)." + "\n\n" + "You can experimentally play with these scaling factors by choosing " + "to output the refinement indicators into the graphical output of " + "a run." + "\n\n" + "If the list of indicators given in this parameter is empty, then this " + "indicates that they should all be chosen equal to one. If the list " + "is not empty then it needs to have as many entries as there are " + "indicators chosen in the ``Strategy'' parameter."); + prm.declare_entry("Refinement criteria merge operation", + "max", + Patterns::Selection("plus|max"), + "If multiple mesh refinement criteria are computed for each cell " + "(by passing a list of more than element to the \\texttt{Strategy} " + "parameter in this section of the input file) " + "then one will have to decide which criteria should win when deciding " + "which cells to refine. The operation that determines how to combine these competing " + "criteria is the one that is selected here. The options are:\n\n" + "\\begin{itemize}\n" + "\\item \\texttt{plus}: Add the various error indicators together and " + "refine those cells on which the sum of indicators is largest.\n" + "\\item \\texttt{max}: Take the maximum of the various error indicators and " + "refine those cells on which the maximal indicators is largest.\n" + "\\end{itemize}" + "The refinement indicators computed by each strategy are modified by " + "the ``Normalize individual refinement criteria'' and ``Refinement " + "criteria scale factors'' parameters."); + } + prm.leave_subsection(); + + // now declare the parameters of each of the registered + // plugins in turn + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + Manager::parse_parameters (ParameterHandler &prm) + { + Assert (std::get(registered_plugins).plugins != nullptr, + ExcMessage ("No mesh refinement plugins registered!?")); + + // find out which plugins are requested and the various other + // parameters we declare here + std::vector plugin_names; + prm.enter_subsection("Mesh refinement"); + { + plugin_names + = Utilities::split_string_list(prm.get("Strategy")); + + AssertThrow(Utilities::has_unique_entries(plugin_names), + ExcMessage("The list of strings for the parameter " + "'Mesh refinement/Strategy' contains entries more than once. " + "This is not allowed. Please check your parameter file.")); + + normalize_criteria = prm.get_bool ("Normalize individual refinement criteria"); + + scaling_factors + = Utilities::string_to_double( + Utilities::split_string_list(prm.get("Refinement criteria scaling factors"))); + AssertThrow (scaling_factors.size() == plugin_names.size() + || + scaling_factors.size() == 0, + ExcMessage ("The number of scaling factors given here must either be " + "zero or equal to the number of chosen refinement criteria.")); + if (scaling_factors.size() == 0) + scaling_factors = std::vector (plugin_names.size(), 1.0); + + if (prm.get("Refinement criteria merge operation") == "plus") + merge_operation = plus; + else if (prm.get("Refinement criteria merge operation") == "max") + merge_operation = max; + else + AssertThrow (false, ExcNotImplemented()); + } + prm.leave_subsection(); + + // go through the list, create objects and let them parse + // their own parameters + AssertThrow (plugin_names.size() >= 1, + ExcMessage ("You need to provide at least one mesh refinement criterion in the input file!")); + for (auto &plugin_name : plugin_names) + { + this->plugin_objects.push_back (std::unique_ptr> + (std::get(registered_plugins) + .create_plugin (plugin_name, + "Mesh refinement::Refinement criteria merge operation"))); + + if (SimulatorAccess *sim = dynamic_cast*>(&*this->plugin_objects.back())) + sim->initialize_simulator (this->get_simulator()); + + this->plugin_objects.back()->parse_parameters (prm); + this->plugin_objects.back()->initialize (); + } + } + + + template + void + Manager::register_mesh_refinement_criterion (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + + template + void + Manager::write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Mesh refinement criteria interface", + out); + } + + } +} + + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace MeshRefinement + { +#define INSTANTIATE(dim) \ + template class Interface; \ + template class Manager; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/mesh_refinement/isosurfaces.cc.bak b/source/mesh_refinement/isosurfaces.cc.bak new file mode 100644 index 00000000000..c834b26fc08 --- /dev/null +++ b/source/mesh_refinement/isosurfaces.cc.bak @@ -0,0 +1,404 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#include +#include +#include +#include +#include +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + namespace internal + { + bool + Isosurface::are_all_values_in_range(const std::vector &values) const + { + // This assumes that all the vectors in isosurfaces already have the + // same length. + Assert(values.size() == min_values.size(), + ExcMessage("internal error: Vector of values passed to the isosurface class " + "function are_all_values_in_range, does not have the correct size.")); + for (unsigned int index = 0; index < values.size(); ++index) + { + if (values[index] < min_values[index] || values[index] > max_values[index]) + { + // outside this isosurface, no need to search further + return false; + } + } + // If we made it this far, then we are inside the conditions, so return true. + return true; + } + + Property::Property(const std::string &property_name, + const std::vector &available_compositions) + { + bool found = false; + if (property_name == "Temperature") + { + type = PropertyType::Temperature; + index = 0; + found = true; + } + else + { + auto p = std::find(available_compositions.begin(), available_compositions.end(), property_name); + if (p != available_compositions.end()) + { + type = PropertyType::Composition; + index = std::distance(available_compositions.begin(), p); + found = true; + } + } + if (found == false) + { + // The property name has not been found. This could be because the compositional field is not present. + // Abort and warn the user. + std::string key_list = "Temperature"; + for (auto &composition : available_compositions) + key_list += ", " + composition; + + AssertThrow(false, + ExcMessage("The key given for the isosurface could not be converted. The provided key was: " + property_name + ". " + "The following keys are allowed for this model: " + key_list + ".")); + } + } + + /** + * Convert a string describing the refinement level which potentially contains the words "min" + * or "max" to an integer. The format is "min", "max", "min+X", "max-X", or "X", where X is a positive integer. + * + * For example if minimum_refinement_level is 1, and the string is 'min+1', it will return 2. + * The returned value will be capped by the provided @p minimum_refinement_level and @p maximum_refinement_level. + * The @p minimum_refinement_level and @p maximum_refinement_level are set in this input file subsection for this + * plugin, but in the Mesh refinement subsection. + * + * This function will throw an assertion when the string contains `max+` or `min-` since + * that is always incorrect. + */ + unsigned int min_max_string_to_int(const std::string &string_value, + const unsigned int minimum_refinement_level, + const unsigned int maximum_refinement_level) + { + // start with removing the spaces so that a ' min + 1 ' would become 'min+1'. + std::string string = string_value; + std::string::iterator end_pos = std::remove(string.begin(), string.end(), ' '); + string.erase(end_pos, string.end()); + + // check whether the field starts with a 'min' + if (string.compare(0,3,"min") == 0) + { + if (string.compare(0,4,"min+") == 0) + { + std::vector tmpNumber = Utilities::split_string_list(string,'+'); + AssertThrow(tmpNumber.size() == 2, + ExcMessage("Could not convert value '" + string + "' to an int because it contains more than one '+' sign.")); + return std::min(std::max(minimum_refinement_level+Utilities::string_to_int(tmpNumber[1]),minimum_refinement_level),maximum_refinement_level); + } + else + { + AssertThrow(string == "min", + ExcMessage("A value of " + string_value + " was provided, but you can't provide a smaller value than the minimum.")); + return minimum_refinement_level; + } + } + else if (string.compare(0,3,"max") == 0) + { + if (string.compare(0,4,"max-") == 0) + { + std::vector tmpNumber = Utilities::split_string_list(string,'-'); + AssertThrow(tmpNumber.size() == 2, + ExcMessage("Could not convert value '" + string + "' to an int because it contains more than one '-' sign.")); + return std::min(std::max(maximum_refinement_level-Utilities::string_to_int(tmpNumber[1]),minimum_refinement_level),maximum_refinement_level); + } + else + { + AssertThrow(string=="max", + ExcMessage("A value of " + string_value + " was provided, but you can't provide a larger value than the maximum.")); + return maximum_refinement_level; + } + } + else + { + return std::min(std::max(static_cast(Utilities::string_to_int(string)),minimum_refinement_level),maximum_refinement_level); + } + + } + } + + template + void + Isosurfaces::update () + { } + + template + void + Isosurfaces::tag_additional_cells () const + { + if (this->get_dof_handler().n_locally_owned_dofs() == 0) + return; + + const Quadrature quadrature(this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_support_points()); + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature, + update_quadrature_points | update_values | update_gradients); + + MaterialModel::MaterialModelInputs in(quadrature.size(), + this->n_compositional_fields()); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + { + if (cell->is_locally_owned()) + { + bool coarsen = false; + bool clear_refine = false; + bool refine = false; + bool clear_coarsen = false; + + fe_values.reinit(cell); + in.reinit(fe_values, cell, this->introspection(), this->get_solution()); + + for (unsigned int i_quad=0; i_quad values(isosurface.min_values.size()); + for (unsigned int index = 0; index < isosurface.properties.size(); ++index) + { + if (isosurface.properties[index].type == internal::PropertyType::Temperature) + { + values[index] = in.temperature[i_quad]; + } + else if (isosurface.properties[index].type == internal::PropertyType::Composition) + { + values[index] = in.composition[i_quad][isosurface.properties[index].index]; + } + } + + if ( isosurface.are_all_values_in_range(values)) + { + // If the current refinement level is smaller than or equal to the minimum + // refinement level, any coarsening flag should be cleared. + if (cell->level() <= isosurface.min_refinement) + { + clear_coarsen = true; + } + + // If the current refinement level is smaller than the minimum + // refinement level, a refinement flag should be placed. + if (cell->level() < isosurface.min_refinement) + { + refine = true; + break; + } + + // If the current refinement level is larger than or equal to the maximum refinement + // level, any refinement flag should be cleared. + if (cell->level() >= isosurface.max_refinement) + { + clear_refine = true; + } + + // If the current refinement level is larger than the maximum refinement level, + // a coarsening flag should be placed. + if (cell->level() > isosurface.max_refinement) + { + coarsen = true; + } + } + } + } + + // if both coarsen and refine are true, give preference to refinement + if (coarsen && refine) + coarsen = false; + if (refine) + clear_refine = false; + if (clear_coarsen) + coarsen = false; + + // Perform the actual placement of the coarsening and refinement flags. + if (clear_coarsen) + cell->clear_coarsen_flag (); + if (clear_refine) + cell->clear_refine_flag (); + if (coarsen) + cell->set_coarsen_flag (); + if (refine) + cell->set_refine_flag (); + } + } + } + + template + void + Isosurfaces:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Isosurfaces"); + { + prm.declare_entry ("Isosurfaces", "", + Patterns::Anything(), + "A list of isosurfaces separated by semi-colons (;). Each isosurface entry consists of " + "multiple entries separated by a comma. The first two entries indicate the minimum and maximum " + "refinement levels respectively. The entries after the first two describe the fields the isosurface " + "applies to, followed by a colon (:), which is again followed by the minimum and maximum property values separated by " + "bar (|). An example for an isosurface is '0, 2, Temperature: 300 | 600; 2, 2, C\\_1: 0.5 | 1'. " + "In this example the mesh refinement is kept between level 0 and level 2 if the temperature is between " + "300 and 600 and at level 2 when the compositional field C\\_1 is between 0.5 and 1. If both happen at " + "the same location and the current refinement level is 1, it means that the first isoline will not set any flag and the " + "second isoline will set a refinement flag. This means the cell will be refined. If both the coarsening and refinement flags " + "are set, preference is given to refinement. " + "\n\n" + "The first two entries for each isosurface, describing the minimum and maximum grid levels, can be " + "two numbers or contain one of the key values 'min' and 'max'. This indicates the key will be replaced with " + "the global minimum and maximum refinement levels. The 'min' and 'max' keys also accept adding " + "values to be added or subtracted from them respectively. This is done by adding a '+' or '-' and a " + "number behind them (e.g. min+2 or max-1). Note that you can't subtract a value from a minimum value or " + "add a value to the maximum value. If, for example, `max-4` drops below the minimum or `min+4` goes above the " + "maximum, it will simply use the global minimum and maximum values respectively. The same holds for any " + "mesh refinement level below the global minimum or above the global maximum."); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + Isosurfaces::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + // lookup the minimum and maximum refinement + const unsigned int minimum_refinement_level = this->get_parameters().min_grid_level; + const unsigned int maximum_refinement_level = this->get_parameters().initial_global_refinement + + this->get_parameters().initial_adaptive_refinement; + + const std::vector &compositions = this->introspection().get_composition_names(); + prm.enter_subsection("Isosurfaces"); + { + // Split the list by comma delimited components. + const std::vector isosurface_entries = dealii::Utilities::split_string_list(prm.get("Isosurfaces"), ';'); + unsigned int isosurface_entry_number = 0; + for (auto &isosurface_entry : isosurface_entries) + { + ++isosurface_entry_number; + aspect::MeshRefinement::internal::Isosurface isosurface; + std::vector properties; + std::vector min_value_inputs; + std::vector max_value_inputs; + const std::vector field_entries = dealii::Utilities::split_string_list(isosurface_entry, ','); + + AssertThrow(field_entries.size() >= 3, + ExcMessage("An isosurface needs to contain at least 3 entries, but isosurface " + std::to_string(isosurface_entry_number) + + " contains only " + std::to_string(field_entries.size()) + " entries: " + isosurface_entry + ".")); + + // convert a potential min, min+1, min + 1, min+10, max, max-1, etc. to actual integers. + isosurface.min_refinement = internal::min_max_string_to_int(field_entries[0], minimum_refinement_level, maximum_refinement_level); + isosurface.max_refinement = internal::min_max_string_to_int(field_entries[1], minimum_refinement_level, maximum_refinement_level); + AssertThrow(isosurface.min_refinement <= isosurface.max_refinement, + ExcMessage("The provided maximum refinement level has to be larger than the minimum refinement level.")); + for (auto field_entry = field_entries.begin()+2; field_entry != field_entries.end(); ++field_entry) + { + AssertThrow(Patterns::Map(Patterns::Anything(), + Patterns::List(Patterns::Double(), 0, std::numeric_limits::max(), "|") + ).match(*field_entry), + ExcMessage("The isosurface is not formatted correctly.")); + std::vector key_and_value = Utilities::split_string_list (*field_entry, ':'); + AssertThrow(key_and_value.size() == 2, + ExcMessage("The isosurface property must have a key (e.g. Temperature) and two values separated by a | (e.g. (300 | 600).")); + properties.emplace_back(key_and_value[0], compositions); // convert key to property name + const std::vector values = dealii::Utilities::split_string_list(key_and_value[1], '|'); + AssertThrow(values.size() == 2, + ExcMessage("Both a maximum and a minimum value are required for each isosurface.")); + min_value_inputs.push_back(Utilities::string_to_double(values[0])); // get min and max values of the range + max_value_inputs.push_back(Utilities::string_to_double(values[1])); + AssertThrow(min_value_inputs.back() < max_value_inputs.back(), + ExcMessage("The provided maximum property value has to be larger than the provided minimum property value.")); + } + isosurface.min_values = min_value_inputs; + isosurface.max_values = max_value_inputs; + isosurface.properties = properties; + isosurfaces.push_back(isosurface); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Isosurfaces, + "isosurfaces", + "A mesh refinement criterion that computes " + "coarsening and refinement indicators between two isosurfaces of " + "specific field entries (e.g. temperature, composition)." + "\n\n" + "The way these indicators are derived between pairs of isosurfaces is by " + "checking whether the solutions of specific " + "fields are within the ranges of the isosurface values given. If these conditions " + "hold, then coarsening and refinement indicators are set such that " + "the mesh refinement levels lies within the range of levels " + "given. Usage of this plugin allows the user to put a conditional " + "minimum and maximum refinement function onto fields that they " + "are interested in." + "\n\n" + "For now, only temperature and compositional fields are allowed as " + "field entries. The key words could be 'Temperature' or one of the names " + "of the compositional fields which are either specified by user or set up " + "as C\\_0, C\\_1, etc." + "\n\n" + "Usage: A list of isosurfaces separated by semi-colons (;). Each " + "isosurface entry consists of multiple entries separated by a comma. " + "The first two entries indicate the minimum and maximum refinement " + "levels respectively. The entries after the first two describe the " + "fields the isosurface applies to, followed by a colon (:), which again " + "is followed by the minimum and maximum field values separated by a bar (|). An " + "example for two isosurface entries is '0, 2, Temperature: 300 | 600; 2, 2, C\\_1: 0.5 | 1'. " + "If both isoterm entries are triggered at the same location and the current refinement level is 1, " + "it means that the first isoline will not set any flag and the second isoline will set a refinement flag. " + "This means the cell will be refined. If both the coarsening and refinement flags " + "are set, preference is given to refinement. " + "\n\n" + "The minimum and maximum refinement levels per isosurface can be provided in absolute values relative to " + "the global minimum and maximum refinement. This is done with the 'min' and 'max' key words. For example: " + "'set Isosurfaces = max-2, max, Temperature: 0 | 600 ; min + 1,min+2, Temperature: 1600 | 3000, C\\_2 : 0.0 | 0.5'." + ) + } +} diff --git a/source/mesh_refinement/maximum_refinement_function.cc.bak b/source/mesh_refinement/maximum_refinement_function.cc.bak new file mode 100644 index 00000000000..1d133dbb817 --- /dev/null +++ b/source/mesh_refinement/maximum_refinement_function.cc.bak @@ -0,0 +1,193 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#include +#include +#include + +#include +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + MaximumRefinementFunction::update () + { + const double time = this->get_time() / + (this->convert_output_to_years() + ? + year_in_seconds + : + 1.0); + + max_refinement_level.set_time(time); + } + + template + void + MaximumRefinementFunction::tag_additional_cells () const + { + for (const auto &cell : this->get_triangulation().active_cell_iterators()) + { + if (cell->is_locally_owned()) + { + const Point center = cell->center(); + const Utilities::NaturalCoordinate point = + this->get_geometry_model().cartesian_to_other_coordinates(center, coordinate_system); + + const double maximum_refinement_level = max_refinement_level.value(Utilities::convert_array_to_point(point.get_coordinates())); + + if (cell->level() >= static_cast(std::round(maximum_refinement_level))) + cell->clear_refine_flag (); + + if (cell->level() > static_cast(std::round(maximum_refinement_level))) + cell->set_coarsen_flag (); + } + } + } + + template + void + MaximumRefinementFunction:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + + prm.enter_subsection("Maximum refinement function"); + { + /** + * Choose the coordinates to evaluate the maximum refinement level + * function. The function can be declared in dependence of depth, + * cartesian coordinates or spherical coordinates. Note that the order + * of spherical coordinates is r,phi,theta and not r,theta,phi, since + * this allows for dimension independent expressions. + */ + prm.declare_entry ("Coordinate system", "depth", + Patterns::Selection ("depth|cartesian|spherical"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `depth', `cartesian' and `spherical'. `depth' " + "will create a function, in which only the first " + "variable is non-zero, which is interpreted to " + "be the depth of the point. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle."); + /** + * Let the function that describes the maximal level of refinement + * as a function of position declare its parameters. + * This defines the maximum refinement level each cell should have, + * and that can not be exceeded by coarsening. + */ + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + MaximumRefinementFunction::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Maximum refinement function"); + { + if (prm.get ("Coordinate system") == "depth") + coordinate_system = Utilities::Coordinates::depth; + else if (prm.get ("Coordinate system") == "cartesian") + coordinate_system = Utilities::Coordinates::cartesian; + else if (prm.get ("Coordinate system") == "spherical") + coordinate_system = Utilities::Coordinates::spherical; + else + AssertThrow (false, ExcNotImplemented()); + + try + { + max_refinement_level.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Mesh refinement.Maximum refinement function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(MaximumRefinementFunction, + "maximum refinement function", + "A mesh refinement criterion that ensures a " + "maximum refinement level described by an " + "explicit formula with the depth or position " + "as argument. Which coordinate representation " + "is used is determined by an input parameter. " + "Whatever the coordinate system chosen, the " + "function you provide in the input file will " + "by default depend on variables `x', `y' and " + "`z' (if in 3d). However, the meaning of these " + "symbols depends on the coordinate system. In " + "the Cartesian coordinate system, they simply " + "refer to their natural meaning. If you have " + "selected `depth' for the coordinate system, " + "then `x' refers to the depth variable and `y' " + "and `z' will simply always be zero. If you " + "have selected a spherical coordinate system, " + "then `x' will refer to the radial distance of " + "the point to the origin, `y' to the azimuth " + "angle and `z' to the polar angle measured " + "positive from the north pole. Note that the " + "order of spherical coordinates is r,phi,theta " + "and not r,theta,phi, since this allows for " + "dimension independent expressions. " + "Each coordinate system also includes a final `t' " + "variable which represents the model time, evaluated " + "in years if the 'Use years in output instead of seconds' " + "parameter is set, otherwise evaluated in seconds. " + "After evaluating the function, its values are " + "rounded to the nearest integer." + "\n\n" + "The format of these " + "functions follows the syntax understood by the " + "muparser library, see " + "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") + } +} diff --git a/source/mesh_refinement/minimum_refinement_function.cc.bak b/source/mesh_refinement/minimum_refinement_function.cc.bak new file mode 100644 index 00000000000..4c5b67b64d2 --- /dev/null +++ b/source/mesh_refinement/minimum_refinement_function.cc.bak @@ -0,0 +1,192 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#include +#include +#include + +#include +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + MinimumRefinementFunction::update () + { + const double time = this->get_time() / + (this->convert_output_to_years() + ? + year_in_seconds + : + 1.0); + + min_refinement_level.set_time(time); + } + + template + void + MinimumRefinementFunction::tag_additional_cells () const + { + for (const auto &cell : this->get_triangulation().active_cell_iterators()) + { + if (cell->is_locally_owned()) + { + const Point center = cell->center(); + const Utilities::NaturalCoordinate point = + this->get_geometry_model().cartesian_to_other_coordinates(center, coordinate_system); + + const double minimum_refinement_level = min_refinement_level.value(Utilities::convert_array_to_point(point.get_coordinates())); + + if (cell->level() <= static_cast(std::round(minimum_refinement_level))) + cell->clear_coarsen_flag (); + if (cell->level() < static_cast(std::round(minimum_refinement_level))) + cell->set_refine_flag (); + } + } + } + + template + void + MinimumRefinementFunction:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + + prm.enter_subsection("Minimum refinement function"); + { + /** + * Choose the coordinates to evaluate the minimum refinement level + * function. The function can be declared in dependence of depth, + * cartesian coordinates or spherical coordinates. Note that the order + * of spherical coordinates is r,phi,theta and not r,theta,phi, since + * this allows for dimension independent expressions. + */ + prm.declare_entry ("Coordinate system", "depth", + Patterns::Selection ("depth|cartesian|spherical"), + "A selection that determines the assumed coordinate " + "system for the function variables. Allowed values " + "are `depth', `cartesian' and `spherical'. `depth' " + "will create a function, in which only the first " + "variable is non-zero, which is interpreted to " + "be the depth of the point. `spherical' coordinates " + "are interpreted as r,phi or r,phi,theta in 2d/3d " + "respectively with theta being the polar angle."); + /** + * Let the function that describes the minimal level of refinement + * as a function of position declare its parameters. + * This defines the minimum refinement level each cell should have, + * and that can not be exceeded by coarsening. + */ + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + MinimumRefinementFunction::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Minimum refinement function"); + { + if (prm.get ("Coordinate system") == "depth") + coordinate_system = Utilities::Coordinates::depth; + else if (prm.get ("Coordinate system") == "cartesian") + coordinate_system = Utilities::Coordinates::cartesian; + else if (prm.get ("Coordinate system") == "spherical") + coordinate_system = Utilities::Coordinates::spherical; + else + AssertThrow (false, ExcNotImplemented()); + + try + { + min_refinement_level.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Mesh refinement.Minimum refinement function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'" + << "More information about the cause of the parse error \n" + << "is shown below.\n"; + throw; + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(MinimumRefinementFunction, + "minimum refinement function", + "A mesh refinement criterion that ensures a " + "minimum refinement level described by an " + "explicit formula with the depth or position " + "as argument. Which coordinate representation " + "is used is determined by an input parameter. " + "Whatever the coordinate system chosen, the " + "function you provide in the input file will " + "by default depend on variables `x', `y' and " + "`z' (if in 3d). However, the meaning of these " + "symbols depends on the coordinate system. In " + "the Cartesian coordinate system, they simply " + "refer to their natural meaning. If you have " + "selected `depth' for the coordinate system, " + "then `x' refers to the depth variable and `y' " + "and `z' will simply always be zero. If you " + "have selected a spherical coordinate system, " + "then `x' will refer to the radial distance of " + "the point to the origin, `y' to the azimuth " + "angle and `z' to the polar angle measured " + "positive from the north pole. Note that the " + "order of spherical coordinates is r,phi,theta " + "and not r,theta,phi, since this allows for " + "dimension independent expressions. " + "Each coordinate system also includes a final `t' " + "variable which represents the model time, evaluated " + "in years if the 'Use years in output instead of seconds' " + "parameter is set, otherwise evaluated in seconds. " + "After evaluating the function, its values are " + "rounded to the nearest integer." + "\n\n" + "The format of these " + "functions follows the syntax understood by the " + "muparser library, see " + "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") + } +} diff --git a/source/mesh_refinement/nonadiabatic_temperature.cc.bak b/source/mesh_refinement/nonadiabatic_temperature.cc.bak new file mode 100644 index 00000000000..3177c52d25b --- /dev/null +++ b/source/mesh_refinement/nonadiabatic_temperature.cc.bak @@ -0,0 +1,127 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + NonadiabaticTemperature::execute(Vector &indicators) const + { + indicators = 0; + + // create a vector in which we set the temperature block to + // be a finite element interpolation of the nonadiabatic temperature. + // we do so by setting up a quadrature formula with the + // temperature unit support points, then looping over these + // points, compute the output quantity at them, and writing + // the result into the output vector in the same order + // (because quadrature points and temperature dofs are, + // by design of the quadrature formula, numbered in the + // same way) + LinearAlgebra::BlockVector vec_distributed (this->introspection().index_sets.system_partitioning, + this->get_mpi_communicator()); + + const Quadrature quadrature(this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_support_points()); + std::vector local_dof_indices (this->get_fe().dofs_per_cell); + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature, + update_quadrature_points | update_values); + + MaterialModel::MaterialModelInputs in(quadrature.size(), + this->n_compositional_fields()); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit(cell); + fe_values[this->introspection().extractors.temperature].get_function_values (this->get_solution(), + in.temperature); + in.position = fe_values.get_quadrature_points(); + + cell->get_dof_indices (local_dof_indices); + + // for each temperature dof, write into the output + // vector the nonadiabatic temperature. note that quadrature points and + // dofs are enumerated in the same order + for (unsigned int i=0; iget_fe().base_element(this->introspection().base_elements.temperature).dofs_per_cell; ++i) + { + const unsigned int system_local_dof + = this->get_fe().component_to_system_index(this->introspection().component_indices.temperature, + /*dof index within component=*/i); + + vec_distributed(local_dof_indices[system_local_dof]) + = in.temperature[i] - this->get_adiabatic_conditions().temperature(in.position[i]); + } + } + + vec_distributed.compress(VectorOperation::insert); + + // now create a vector with the requisite ghost elements + // and use it for estimating the gradients + LinearAlgebra::BlockVector vec (this->introspection().index_sets.system_partitioning, + this->introspection().index_sets.system_relevant_partitioning, + this->get_mpi_communicator()); + vec = vec_distributed; + + DerivativeApproximation::approximate_gradient (this->get_mapping(), + this->get_dof_handler(), + vec, + indicators, + this->introspection().component_indices.temperature); + + // Scale gradient in each cell with the correct power of h. Otherwise, + // error indicators do not reduce when refined if there is a density + // jump. We need at least order 1 for the error not to grow when + // refining, so anything >1 should work. (note that the gradient + // itself scales like 1/h, so multiplying it with any factor h^s, s>1 + // will yield convergence of the error indicators to zero as h->0) + const double power = 1.0 + dim/2.0; + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + indicators(cell->active_cell_index()) *= std::pow(cell->diameter(), power); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(NonadiabaticTemperature, + "nonadiabatic temperature", + "A mesh refinement criterion that computes " + "refinement indicators from the excess temperature" + "(difference between temperature and adiabatic " + "temperature.") + } +} diff --git a/source/mesh_refinement/nonadiabatic_temperature_threshold.cc.bak b/source/mesh_refinement/nonadiabatic_temperature_threshold.cc.bak new file mode 100644 index 00000000000..eb8b2c8007d --- /dev/null +++ b/source/mesh_refinement/nonadiabatic_temperature_threshold.cc.bak @@ -0,0 +1,158 @@ +/* + Copyright (C) 2015 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + NonadiabaticTemperatureThreshold::tag_additional_cells () const + { + // tag_additional_cells is executed before the equations are solved + // for the very first time. If we do not have the finite element, we + // do not have the temperature and just do nothing in this plugin. + if (this->get_dof_handler().n_locally_owned_dofs() == 0) + return; + + const Quadrature quadrature(this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_support_points()); + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature, + update_quadrature_points | update_values); + + std::vector temperature_values (quadrature.size()); + const unsigned int n_dofs_per_cell = this->get_fe().base_element(this->introspection().base_elements.temperature).dofs_per_cell; + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + bool refine = false; + + fe_values.reinit(cell); + fe_values[this->introspection().extractors.temperature].get_function_values (this->get_solution(), + temperature_values); + + // if the nonadiabatic temperature exceeds the threshold, cell is marked for refinement + for (unsigned int j=0; jget_adiabatic_conditions().temperature(fe_values.quadrature_point(j)); + + double nonadiabatic_temperature = 0; + if (temperature_anomaly_type == absolute_value) + nonadiabatic_temperature = std::abs(temperature_values[j] - adiabatic_temperature); + else if (temperature_anomaly_type == positive_only) + nonadiabatic_temperature = temperature_values[j] - adiabatic_temperature; + else if (temperature_anomaly_type == negative_only) + nonadiabatic_temperature = adiabatic_temperature - temperature_values[j]; + else + AssertThrow (false, ExcNotImplemented()); + + if (nonadiabatic_temperature > threshold) + { + refine = true; + break; + } + } + + if (refine) + { + cell->clear_coarsen_flag (); + cell->set_refine_flag (); + } + } + } + + template + void + NonadiabaticTemperatureThreshold:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Nonadiabatic temperature threshold"); + { + prm.declare_entry ("Threshold", + "100", + Patterns::Double (0.), + "A threshold that the nonadiabatic temperature " + "will be evaluated against. " + "Units: \\si{\\kelvin}"); + prm.declare_entry ("Temperature anomaly type", + "absolute value", + Patterns::Selection ("negative only|positive only|absolute value"), + "What type of temperature anomaly should be considered when " + "evaluating against the threshold: Only negative anomalies " + "(negative only), only positive anomalies (positive only) " + "or the absolute value of the nonadiabatic temperature."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + NonadiabaticTemperatureThreshold::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Nonadiabatic temperature threshold"); + { + threshold = prm.get_double("Threshold"); + + if (prm.get ("Temperature anomaly type") == "negative only") + temperature_anomaly_type = negative_only; + else if (prm.get ("Temperature anomaly type") == "positive only") + temperature_anomaly_type = positive_only; + else if (prm.get ("Temperature anomaly type") == "absolute value") + temperature_anomaly_type = absolute_value; + else + AssertThrow (false, ExcNotImplemented()); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(NonadiabaticTemperatureThreshold, + "nonadiabatic temperature threshold", + "A mesh refinement criterion that computes refinement " + "indicators from the temperature difference between the " + "actual temperature and the adiabatic conditions (the " + "nonadiabatic temperature). If the temperature anomaly " + "exceeds the threshold given in the input file, the cell " + "is marked for refinement.") + } +} diff --git a/source/mesh_refinement/particle_density.cc.bak b/source/mesh_refinement/particle_density.cc.bak new file mode 100644 index 00000000000..9113dcd71e4 --- /dev/null +++ b/source/mesh_refinement/particle_density.cc.bak @@ -0,0 +1,75 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + ParticleDensity::execute(Vector &indicators) const + { + AssertThrow(this->n_particle_worlds() > 0, + ExcMessage("The mesh refinement plugin `particle density' requires the " + "postprocessor plugin `particles' to be selected. Please activate the " + "particles or deactivate this mesh refinement plugin.")); + + const Particle::ParticleHandler &particle_handler = this->get_particle_world(0).get_particle_handler(); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + // Note that this refinement indicator will level out the number + // of particles per cell, therefore creating fine cells in regions + // of high particle density and coarse cells in low particle + // density regions. + indicators(cell->active_cell_index()) = static_cast(particle_handler.n_particles_in_cell(cell)); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(ParticleDensity, + "particle density", + "A mesh refinement criterion that computes " + "refinement indicators based on the density " + "of particles. In practice this plugin " + "equilibrates the number of particles per cell, " + "leading to fine cells in high particle density regions " + "and coarse cells in low particle density regions. " + "This plugin is mostly useful for models with inhomogeneous " + "particle density, e.g. when tracking an initial interface " + "with a high particle density, or when the spatial particle " + "density denotes the region of interest. Additionally, this " + "plugin tends to balance the computational load between " + "processes in parallel computations, because the particle " + "and mesh density is more aligned.") + } +} diff --git a/source/mesh_refinement/slope.cc.bak b/source/mesh_refinement/slope.cc.bak new file mode 100644 index 00000000000..e0804b371d6 --- /dev/null +++ b/source/mesh_refinement/slope.cc.bak @@ -0,0 +1,103 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace MeshRefinement + { + template + void + Slope::execute(Vector &indicators) const + { + const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + + indicators = 0; + + QMidpoint quadrature; + UpdateFlags update_flags = UpdateFlags(update_normal_vectors | update_quadrature_points ); + FEFaceValues fe_face_values (this->get_mapping(), this->get_fe(), quadrature, update_flags); + + // iterate over all of the cells, get a face normal, then + // dot it with the local gravity + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + { + const unsigned int idx = cell->active_cell_index(); + for (const unsigned int face_no : cell->face_indices()) + if (cell->face(face_no)->at_boundary()) + { + const types::boundary_id boundary_indicator + = cell->face(face_no)->boundary_id(); + + // Use cases for this plugin include a deforming mesh, + // or a fixed mesh with initial topography + if ( (this->get_parameters().mesh_deformation_enabled && + this->get_mesh_deformation_boundary_indicators().find(boundary_indicator) != + this->get_mesh_deformation_boundary_indicators().end()) || + (Plugins::plugin_type_matches>(this->get_initial_topography_model()) && + boundary_indicator == top_boundary_id) ) + { + fe_face_values.reinit(cell, face_no); + + const Tensor<1,dim> normal( fe_face_values.normal_vector(0) ); // Only one q point + const Point midpoint = fe_face_values.quadrature_point(0); + const Tensor<1,dim> gravity = this->get_gravity_model().gravity_vector(midpoint); + + indicators(idx) = std::acos( std::abs ( normal * gravity / gravity.norm() ) ) // Don't care whether gravity is in the opposite direction + * std::pow( cell->diameter(), static_cast(dim-1)); // scale with approximate surface area of the cell + break; // no need to loop over the rest of the faces + } + } + } + + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Slope, + "slope", + "A class that implements a mesh refinement criterion intended for " + "use with deforming mesh boundaries, like the free surface. " + "It calculates a local slope based on " + "the angle between the surface normal and the local gravity vector. " + "Cells with larger angles are marked for refinement." + "\n\n" + "To use this refinement criterion, you may want to combine " + "it with other refinement criteria, setting the 'Normalize " + "individual refinement criteria' flag and using the `max' " + "setting for 'Refinement criteria merge operation'.") + } +} diff --git a/source/mesh_refinement/strain_rate.cc.bak b/source/mesh_refinement/strain_rate.cc.bak new file mode 100644 index 00000000000..e12467a1f18 --- /dev/null +++ b/source/mesh_refinement/strain_rate.cc.bak @@ -0,0 +1,75 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + StrainRate::execute(Vector &indicators) const + { + indicators = 0; + + const QMidpoint quadrature; + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature, + update_quadrature_points | update_values | update_gradients); + + std::vector> strain_rates (quadrature.size()); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + const unsigned int idx = cell->active_cell_index(); + fe_values.reinit(cell); + + fe_values[this->introspection().extractors.velocities].get_function_symmetric_gradients (this->get_solution(), + strain_rates); + + indicators(idx) = strain_rates[0].norm(); + } + + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(StrainRate, + "strain rate", + "A mesh refinement criterion that computes the " + "refinement indicators equal to the strain rate " + "norm computed at the center of the elements.") + } +} diff --git a/source/mesh_refinement/temperature.cc.bak b/source/mesh_refinement/temperature.cc.bak new file mode 100644 index 00000000000..a8216ccc404 --- /dev/null +++ b/source/mesh_refinement/temperature.cc.bak @@ -0,0 +1,83 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + Temperature::execute(Vector &indicators) const + { + indicators = 0; + + const Quadrature &quadrature = this->introspection().face_quadratures.temperature; + KellyErrorEstimator::estimate (this->get_mapping(), + this->get_dof_handler(), + quadrature, + std::map*>(), + this->get_solution(), + indicators, + this->introspection().component_masks.temperature, + nullptr, + 0, + this->get_triangulation().locally_owned_subdomain()); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Temperature, + "temperature", + "A mesh refinement criterion that computes " + "refinement indicators from the temperature field." + "\n\n" + "The way these indicators are computed is by " + "evaluating the `Kelly error indicator' on the " + "temperature field. This error indicator takes the " + "finite element approximation of the temperature " + "field and uses it to compute an approximation " + "of the second derivatives of the temperature for " + "each cell. This approximation is then multiplied " + "by an appropriate power of the cell's diameter " + "to yield an indicator for how large the error " + "is likely going to be on this cell. This " + "construction rests on the observation that for " + "many partial differential equations, the error " + "on each cell is proportional to some power of " + "the cell's diameter times the second derivatives " + "of the solution on that cell." + "\n\n" + "For complex equations such as those we solve " + "here, this observation may not be strictly " + "true in the mathematical sense, but it often " + "yields meshes that are surprisingly good.") + } +} diff --git a/source/mesh_refinement/thermal_energy_density.cc.bak b/source/mesh_refinement/thermal_energy_density.cc.bak new file mode 100644 index 00000000000..61b3d2ed4cc --- /dev/null +++ b/source/mesh_refinement/thermal_energy_density.cc.bak @@ -0,0 +1,144 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + ThermalEnergyDensity::execute(Vector &indicators) const + { + indicators = 0; + + // create a vector in which we set the temperature block to + // be a finite element interpolation of the thermal energy density + // rho*C_p*T. we do so by setting up a quadrature formula with the + // temperature unit support points, then looping over these + // points, compute the output quantity at them, and writing + // the result into the output vector in the same order + // (because quadrature points and temperature dofs are, + // by design of the quadrature formula, numbered in the + // same way) + LinearAlgebra::BlockVector vec_distributed (this->introspection().index_sets.system_partitioning, + this->get_mpi_communicator()); + + const Quadrature quadrature(this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_support_points()); + std::vector local_dof_indices (this->get_fe().dofs_per_cell); + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature, + update_quadrature_points | update_values | update_gradients); + + // the values of the compositional fields are stored as block vectors for each field + // we have to extract them in this structure + std::vector> prelim_composition_values (this->n_compositional_fields(), + std::vector (quadrature.size())); + + MaterialModel::MaterialModelInputs in(quadrature.size(), this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(quadrature.size(), this->n_compositional_fields()); + in.requested_properties = MaterialModel::MaterialProperties::equation_of_state_properties; + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit(cell); + // Set use_strain_rates to false since we don't need viscosity + in.reinit(fe_values, cell, this->introspection(), this->get_solution()); + this->get_material_model().evaluate(in, out); + + cell->get_dof_indices (local_dof_indices); + + // for each temperature dof, write into the output + // vector the density. note that quadrature points and + // dofs are enumerated in the same order + for (unsigned int i=0; iget_fe().base_element(this->introspection().base_elements.temperature).dofs_per_cell; ++i) + { + const unsigned int system_local_dof + = this->get_fe().component_to_system_index(this->introspection().component_indices.temperature, + /*dof index within component=*/i); + + vec_distributed(local_dof_indices[system_local_dof]) + = out.densities[i] + * in.temperature[i] + * out.specific_heat[i]; + } + } + + vec_distributed.compress(VectorOperation::insert); + + // now create a vector with the requisite ghost elements + // and use it for estimating the gradients + LinearAlgebra::BlockVector vec (this->introspection().index_sets.system_partitioning, + this->introspection().index_sets.system_relevant_partitioning, + this->get_mpi_communicator()); + vec = vec_distributed; + + DerivativeApproximation::approximate_gradient (this->get_mapping(), + this->get_dof_handler(), + vec, + indicators, + this->introspection().component_indices.temperature); + + // Scale gradient in each cell with the correct power of h. Otherwise, + // error indicators do not reduce when refined if there is a density + // jump. We need at least order 1 for the error not to grow when + // refining, so anything >1 should work. (note that the gradient + // itself scales like 1/h, so multiplying it with any factor h^s, s>1 + // will yield convergence of the error indicators to zero as h->0) + const double power = 1.5; + { + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + indicators(cell->active_cell_index()) *= std::pow(cell->diameter(), power); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(ThermalEnergyDensity, + "thermal energy density", + "A mesh refinement criterion that computes " + "refinement indicators from a field that describes " + "the spatial variability of the thermal energy density, $\\rho C_p T$. " + "Because this quantity may not be a continuous function ($\\rho$ " + "and $C_p$ may be discontinuous functions along discontinuities in the " + "medium, for example due to phase changes), we approximate the " + "gradient of this quantity to refine the mesh. The error indicator " + "defined here takes the magnitude of the approximate gradient " + "and scales it by $h_K^{1.5}$ where $h_K$ is the diameter of each cell. " + "This scaling ensures that the error indicators converge to zero as " + "$h_K\\rightarrow 0$ even if the energy density is discontinuous, since " + "the gradient of a discontinuous function grows like $1/h_K$.") + } +} diff --git a/source/mesh_refinement/topography.cc.bak b/source/mesh_refinement/topography.cc.bak new file mode 100644 index 00000000000..8606afd221e --- /dev/null +++ b/source/mesh_refinement/topography.cc.bak @@ -0,0 +1,87 @@ +/* + Copyright (C) 2011 - 2019 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + Topography::execute(Vector &indicators) const + { + // For calculating surface topography in the respective postprocessor + // we use the pressure in the middle of the cell. Thus, to get an + // accurate result, all the cells at the upper boundary should have + // the same level of refinement. This postprocessor causes a refinement + // in the uppermost cells, which also makes sure that the upper + // boundary layer is resolved as good as possible. + + indicators = 0; + + // need quadrature formula to calculate the depth + // evaluate a single point per cell + const QMidpoint quadrature_formula; + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_quadrature_points | + update_JxW_values); + + // iterate over all of the cells and choose the ones at the upper + // boundary for refinement (assign the largest error to them) + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + const double depth = this->get_geometry_model().depth(fe_values.quadrature_point(0)); + if (cell->at_boundary() && depth < cell->diameter()) + indicators(cell->active_cell_index()) = 1.0; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Topography, + "topography", + "A class that implements a mesh refinement criterion, which " + "always flags all cells in the uppermost layer for refinement. " + "This is useful to provide high accuracy for processes at or " + "close to the surface." + "\n\n" + "To use this refinement criterion, you may want to combine " + "it with other refinement criteria, setting the 'Normalize " + "individual refinement criteria' flag and using the `max' " + "setting for 'Refinement criteria merge operation'.") + } +} diff --git a/source/mesh_refinement/velocity.cc.bak b/source/mesh_refinement/velocity.cc.bak new file mode 100644 index 00000000000..0690d20f828 --- /dev/null +++ b/source/mesh_refinement/velocity.cc.bak @@ -0,0 +1,83 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + Velocity::execute(Vector &indicators) const + { + indicators = 0; + + const Quadrature &quadrature = this->introspection().face_quadratures.velocities; + KellyErrorEstimator::estimate (this->get_mapping(), + this->get_dof_handler(), + quadrature, + std::map*>(), + this->get_solution(), + indicators, + this->introspection().component_masks.velocities, + nullptr, + 0, + this->get_triangulation().locally_owned_subdomain()); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Velocity, + "velocity", + "A mesh refinement criterion that computes " + "refinement indicators from the velocity field." + "\n\n" + "The way these indicators are computed is by " + "evaluating the `Kelly error indicator' on the " + "velocity field. This error indicator takes the " + "finite element approximation of the velocity " + "field and uses it to compute an approximation " + "of the second derivatives of the velocity for " + "each cell. This approximation is then multiplied " + "by an appropriate power of the cell's diameter " + "to yield an indicator for how large the error " + "is likely going to be on this cell. This " + "construction rests on the observation that for " + "many partial differential equations, the error " + "on each cell is proportional to some power of " + "the cell's diameter times the second derivatives " + "of the solution on that cell." + "\n\n" + "For complex equations such as those we solve " + "here, this observation may not be strictly " + "true in the mathematical sense, but it often " + "yields meshes that are surprisingly good.") + } +} diff --git a/source/mesh_refinement/viscosity.cc.bak b/source/mesh_refinement/viscosity.cc.bak new file mode 100644 index 00000000000..ab4cc0b167a --- /dev/null +++ b/source/mesh_refinement/viscosity.cc.bak @@ -0,0 +1,148 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include +#include +#include + +namespace aspect +{ + namespace MeshRefinement + { + template + void + Viscosity::execute(Vector &indicators) const + { + indicators = 0; + +//TODO: if the viscosity doesn't actually depend on the solution + // then we can get away with simply interpolating it spatially + + + // create a vector in which we set the temperature block to + // be a finite element interpolation of the viscosity. + // we do so by setting up a quadrature formula with the + // temperature unit support points, then looping over these + // points, compute the output quantity at them, and writing + // the result into the output vector in the same order + // (because quadrature points and temperature dofs are, + // by design of the quadrature formula, numbered in the + // same way) + LinearAlgebra::BlockVector vec_distributed (this->introspection().index_sets.system_partitioning, + this->get_mpi_communicator()); + + const Quadrature quadrature(this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_support_points()); + std::vector local_dof_indices (this->get_fe().dofs_per_cell); + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature, + update_quadrature_points | update_values | update_gradients); + + // the values of the compositional fields are stored as block vectors for each field + // we have to extract them in this structure + std::vector> prelim_composition_values (this->n_compositional_fields(), + std::vector (quadrature.size())); + + MaterialModel::MaterialModelInputs in(quadrature.size(), + this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(quadrature.size(), + this->n_compositional_fields()); + in.requested_properties = MaterialModel::MaterialProperties::viscosity; + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit(cell); + in.reinit(fe_values, cell, this->introspection(), this->get_solution()); + this->get_material_model().evaluate(in, out); + + cell->get_dof_indices (local_dof_indices); + + // for each temperature dof, write into the output + // vector the viscosity. note that quadrature points and + // dofs are enumerated in the same order + for (unsigned int i=0; iget_fe().base_element(this->introspection().base_elements.temperature).dofs_per_cell; ++i) + { + const unsigned int system_local_dof + = this->get_fe().component_to_system_index(this->introspection().component_indices.temperature, + /*dof index within component=*/i); + + vec_distributed(local_dof_indices[system_local_dof]) + = std::log(out.viscosities[i]); + } + } + + vec_distributed.compress(VectorOperation::insert); + + // now create a vector with the requisite ghost elements + // and use it for estimating the gradients + LinearAlgebra::BlockVector vec (this->introspection().index_sets.system_partitioning, + this->introspection().index_sets.system_relevant_partitioning, + this->get_mpi_communicator()); + vec = vec_distributed; + + DerivativeApproximation::approximate_gradient (this->get_mapping(), + this->get_dof_handler(), + vec, + indicators, + this->introspection().component_indices.temperature); + + // Scale gradient in each cell with the correct power of h. Otherwise, + // error indicators do not reduce when refined if there is a viscosity + // jump. We need at least order 1 for the error not to grow when + // refining, so anything >1 should work. (note that the gradient + // itself scales like 1/h, so multiplying it with any factor h^s, s>1 + // will yield convergence of the error indicators to zero as h->0) + const double power = 1.0 + dim/2.0; + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + indicators(cell->active_cell_index()) *= std::pow(cell->diameter(), power); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Viscosity, + "viscosity", + "A mesh refinement criterion that computes " + "refinement indicators from a field that describes " + "the spatial variability of the logarithm of the viscosity, $\\log\\eta$. " + "(We choose the logarithm of the viscosity because it can vary by " + "orders of magnitude.)" + "Because this quantity may not be a continuous function ($\\eta$ " + "may be a discontinuous function along discontinuities in the " + "medium, for example due to phase changes), we approximate the " + "gradient of this quantity to refine the mesh. The error indicator " + "defined here takes the magnitude of the approximate gradient " + "and scales it by $h_K^{1+d/2}$ where $h_K$ is the diameter of each cell " + "and $d$ is the dimension. " + "This scaling ensures that the error indicators converge to zero as " + "$h_K\\rightarrow 0$ even if the viscosity is discontinuous, since " + "the gradient of a discontinuous function grows like $1/h_K$.") + } +} diff --git a/source/mesh_refinement/volume_of_fluid_interface.cc.bak b/source/mesh_refinement/volume_of_fluid_interface.cc.bak new file mode 100644 index 00000000000..3bc7d3e2d51 --- /dev/null +++ b/source/mesh_refinement/volume_of_fluid_interface.cc.bak @@ -0,0 +1,345 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include +#include + +#include +#include + +#include + +#include + +#include + +namespace aspect +{ + namespace MeshRefinement + { + + template + void + VolumeOfFluidInterface::tag_additional_cells() const + { + // Break early if DoFs have not been distributed yet. + if (this->get_dof_handler().n_dofs() == 0) + return; + + const QMidpoint qMidC; + + // Create a map from vertices to adjacent cells + const std::vector::active_cell_iterator>> + vertex_to_cells(GridTools::vertex_to_cell_map(this->get_triangulation())); + + std::set::active_cell_iterator> marked_cells; + FEValues fe_values (this->get_mapping(), + this->get_fe(), + qMidC, + update_values | + update_quadrature_points); + + // Create block vector to indicate when other mpi process believes cell + // borders an interface cell and therefore neighbors should be refined + // Use the first vof block, due to being the correct size, and only + // needing one indicator + LinearAlgebra::BlockVector interface_contained_local( + this->introspection().index_sets.system_partitioning, + this->get_mpi_communicator()); + + const FiniteElement &system_fe = this->get_fe(); + + const VolumeOfFluidField vof_field = this->get_volume_of_fluid_handler().field_struct_for_field_index(0); + const unsigned int volume_fraction_block = vof_field.volume_fraction.block_index; + const unsigned int volume_of_fluid_c_index = vof_field.volume_fraction.first_component_index; + const unsigned int volume_of_fluid_ind + = this->get_fe().component_to_system_index(volume_of_fluid_c_index, 0); + + interface_contained_local.block(volume_fraction_block) = 0.0; + + std::vector local_dof_indices (system_fe.dofs_per_cell); + + for (unsigned int f=0; fget_volume_of_fluid_handler().get_n_fields(); ++f) + { + + const double volume_fraction_threshold = this->get_volume_of_fluid_handler().get_volume_fraction_threshold(); + + const FEValuesExtractors::Scalar volume_of_fluid_field = this->get_volume_of_fluid_handler().field_struct_for_field_index(f) + .volume_fraction.extractor_scalar(); + + std::vector volume_of_fluid_values(qMidC.size()); + std::vector neighbor_volume_of_fluid_values(qMidC.size()); + + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (!cell->is_artificial()) + { + bool refine_current_cell = false; + + // Get cell volume_of_fluid + fe_values.reinit(cell); + fe_values[volume_of_fluid_field].get_function_values(this->get_solution(), + volume_of_fluid_values); + + // Handle overshoots + volume_of_fluid_values[0] = std::min(volume_of_fluid_values[0], 1.0); + volume_of_fluid_values[0] = std::max(volume_of_fluid_values[0], 0.0); + + // Check if at interface + if (volume_of_fluid_values[0] > volume_fraction_threshold && volume_of_fluid_values[0] < (1.0 - volume_fraction_threshold)) + { + refine_current_cell = true; + } + + if (!refine_current_cell) + { + for (const unsigned int f : cell->face_indices()) + { + const bool cell_has_periodic_neighbor = cell->has_periodic_neighbor(f); + const typename DoFHandler::face_iterator face = cell->face(f); + + // Skip if face is at boundary, and does not have a periodic neighbor + if (face->at_boundary() && !cell_has_periodic_neighbor) + continue; + + const typename DoFHandler::cell_iterator neighbor = cell->neighbor_or_periodic_neighbor(f); + + Assert(cell.state()==IteratorState::valid, ExcInternalError()); + + if ((!face->at_boundary() && !face->has_children()) + || + (face->at_boundary() && cell->periodic_neighbor_is_coarser(f)) + || + (face->at_boundary() && neighbor->level() == cell->level() && neighbor->is_active())) + { + if (neighbor->is_active() && !neighbor->is_artificial()) + { + fe_values.reinit(neighbor); + fe_values[volume_of_fluid_field].get_function_values(this->get_solution(), + neighbor_volume_of_fluid_values); + + // Handle overshoots + neighbor_volume_of_fluid_values[0] = std::min(neighbor_volume_of_fluid_values[0], 1.0); + neighbor_volume_of_fluid_values[0] = std::max(neighbor_volume_of_fluid_values[0], 0.0); + + if (std::abs(neighbor_volume_of_fluid_values[0]-volume_of_fluid_values[0])>volume_fraction_threshold) + { + refine_current_cell = true; + break; + } + } + } + else + { + for (unsigned int subface=0; subface < face->n_children(); ++subface) + { + const typename DoFHandler::active_cell_iterator neighbor_sub = + (cell_has_periodic_neighbor + ? + cell->periodic_neighbor_child_on_subface(f, subface) + : + cell->neighbor_child_on_subface(f, subface)); + + Assert(neighbor_sub.state()==IteratorState::valid, ExcInternalError()); + + if (neighbor_sub->is_artificial()) + continue; + + fe_values.reinit(neighbor_sub); + fe_values[volume_of_fluid_field].get_function_values(this->get_solution(), + neighbor_volume_of_fluid_values); + + // Handle overshoots + neighbor_volume_of_fluid_values[0] = std::min(neighbor_volume_of_fluid_values[0], 1.0); + neighbor_volume_of_fluid_values[0] = std::max(neighbor_volume_of_fluid_values[0], 0.0); + + if (std::abs(neighbor_volume_of_fluid_values[0]-volume_of_fluid_values[0])>volume_fraction_threshold) + { + refine_current_cell = true; + break; + } + + } + if (refine_current_cell) + break; + } + } + } + + if (refine_current_cell) + { + // Fractional volume + marked_cells.insert(cell); + if (cell->is_locally_owned()) + { + cell->clear_coarsen_flag (); + cell->set_refine_flag (); + // Mark in vector, will be true here if true on any process + cell->get_dof_indices(local_dof_indices); + interface_contained_local(local_dof_indices[volume_of_fluid_ind]) = 1.0; + } + } + + } + } + + // Now communicate and mark any cells not already included, this could be + // reduced to only loop over cells bordering another process + LinearAlgebra::BlockVector interface_contained_global( + this->introspection().index_sets.system_partitioning, + this->introspection().index_sets.system_relevant_partitioning, + this->get_mpi_communicator()); + + interface_contained_global.block(volume_fraction_block) = interface_contained_local.block(volume_fraction_block); + interface_contained_global.update_ghost_values(); + + const FEValuesExtractors::Scalar ic_extract = this->get_volume_of_fluid_handler().field_struct_for_field_index(0) + .volume_fraction.extractor_scalar(); + std::vector ic_values(qMidC.size()); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (!cell->is_artificial()) + { + fe_values.reinit(cell); + fe_values[ic_extract].get_function_values(interface_contained_global, + ic_values); + + // If the cell has been indicated to need refinement add it + if (ic_values[0]>0.5) + { + marked_cells.insert(cell); + } + } + + // Now mark for refinement all cells that are a neighbor of a cell that contains the interface + + std::set::active_cell_iterator> marked_cells_and_neighbors = marked_cells; + typename std::set::active_cell_iterator>::const_iterator mcells = marked_cells.begin(), + endmc = marked_cells.end(); + for (; mcells != endmc; ++mcells) + { + typename parallel::distributed::Triangulation::active_cell_iterator mcell = *mcells; + for (const unsigned int vertex_index : mcell->vertex_indices()) + { + const std::set::active_cell_iterator> &neighbor_cells = vertex_to_cells[mcell->vertex_index(vertex_index)]; + for (const auto &neighbor_cell : neighbor_cells) + { + if (neighbor_cell->is_active() && neighbor_cell->is_locally_owned()) + { + neighbor_cell->clear_coarsen_flag (); + neighbor_cell->set_refine_flag (); + marked_cells_and_neighbors.insert(neighbor_cell); + } + } + } + + // Check for periodic neighbors, and refine if existing + for (const unsigned int f : mcell->face_indices()) + { + if (mcell->has_periodic_neighbor(f)) + { + typename Triangulation::cell_iterator itr_tmp = mcell->periodic_neighbor(f); + + if (itr_tmp->is_active() && itr_tmp->is_locally_owned()) + { + itr_tmp->clear_coarsen_flag (); + itr_tmp->set_refine_flag (); + marked_cells_and_neighbors.insert(itr_tmp); + } + } + } + } + + if (strict_coarsening) + { + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + if (marked_cells_and_neighbors.find(cell) != marked_cells_and_neighbors.end()) + { + //Refinement already requested + } + else + { + if (cell->is_active()) + { + cell->set_coarsen_flag(); + cell->clear_refine_flag(); + } + } + } + + } + + } + + template + void + VolumeOfFluidInterface:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Volume of fluid interface"); + { + prm.declare_entry("Strict coarsening", "false", + Patterns::Bool(), + "If true, then explicitly coarsen any cells not " + "neighboring the VolumeOfFluid interface."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + VolumeOfFluidInterface::parse_parameters (ParameterHandler &prm) + { + AssertThrow(this->get_parameters().volume_of_fluid_tracking_enabled, + ExcMessage("The 'volume_of_fluid boundary' mesh refinement strategy requires that the 'Use interface tracking' parameter is enabled.")); + + prm.enter_subsection("Mesh refinement"); + { + prm.enter_subsection("Volume of fluid interface"); + { + strict_coarsening = prm.get_bool("Strict coarsening"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + } +} + +// explicit instantiations +namespace aspect +{ + namespace MeshRefinement + { + ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(VolumeOfFluidInterface, + "volume of fluid interface", + "A class that implements a mesh refinement criterion, which " + "ensures a minimum level of refinement near the volume of fluid interface boundary.") + } +} diff --git a/source/particle/generator/ascii_file.cc.bak b/source/particle/generator/ascii_file.cc.bak new file mode 100644 index 00000000000..539c55f496f --- /dev/null +++ b/source/particle/generator/ascii_file.cc.bak @@ -0,0 +1,133 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include + + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + template + void + AsciiFile::generate_particles(Particles::ParticleHandler &particle_handler) + { + const std::string filename = data_directory+data_filename; + + // Read data from disk and distribute among processes + std::istringstream in(Utilities::read_and_distribute_file_content(filename, this->get_mpi_communicator())); + + // Skip header lines + while (in.peek() == '#') + { + std::string temp; + std::getline(in,temp); + } + + // Read data lines + types::particle_index particle_index = 0; + Point particle_position; + + while (in >> particle_position) + { + this->insert_particle_at_position(particle_position, particle_index, particle_handler); + ++particle_index; + } + particle_handler.update_cached_numbers(); + } + + + template + void + AsciiFile::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Generator"); + { + prm.enter_subsection("Ascii file"); + { + prm.declare_entry ("Data directory", + "$ASPECT_SOURCE_DIR/data/particle/generator/ascii/", + Patterns::DirectoryName (), + "The name of a directory that contains the particle data. This path " + "may either be absolute (if starting with a '/') or relative to " + "the current directory. The path may also include the special " + "text '$ASPECT_SOURCE_DIR' which will be interpreted as the path " + "in which the ASPECT source files were located when ASPECT was " + "compiled. This interpretation allows, for example, to reference " + "files located in the `data/' subdirectory of ASPECT. "); + prm.declare_entry ("Data file name", "particle.dat", + Patterns::Anything (), + "The name of the particle file."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + AsciiFile::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Generator"); + { + prm.enter_subsection("Ascii file"); + { + data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get ("Data directory")); + + data_filename = prm.get ("Data file name"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Generator + { + ASPECT_REGISTER_PARTICLE_GENERATOR(AsciiFile, + "ascii file", + "Generates a distribution of particles from coordinates " + "specified in an Ascii data file. The file format is " + "a simple text file, with as many columns as spatial " + "dimensions and as many lines as particles to be generated. " + "Initial comment lines starting with `#' will be discarded. " + "Note that this plugin always generates as many particles " + "as there are coordinates in the data file, the " + "``Particles/Number of particles'' parameter " + "has no effect on this plugin. " + "All of the values that define this generator are read " + "from a section ``Particles/Generator/Ascii file'' in the " + "input file, see " + "Section~\\ref{parameters:Particles/Generator/Ascii_20file}.") + } + } +} diff --git a/source/particle/generator/interface.cc.bak b/source/particle/generator/interface.cc.bak new file mode 100644 index 00000000000..f48c36c2525 --- /dev/null +++ b/source/particle/generator/interface.cc.bak @@ -0,0 +1,306 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +#include +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + template + void + Interface::initialize () + { + const unsigned int my_rank = Utilities::MPI::this_mpi_process(this->get_mpi_communicator()); + random_number_generator.seed(5432+my_rank); + } + + + + template + void + Interface::generate_particles(std::multimap> &/*particles*/) + { + AssertThrow(false,ExcInternalError()); + } + + + + template + void + Interface::generate_particles(Particles::ParticleHandler &particle_handler) + { + // This function is implemented to ensure backwards compatibility to an old interface. + // Once the old interface function has been removed this implementation can be removed + // as well and the function can be made pure. + + std::multimap> particles; + + // avoid deprecation warnings about calling the old interface + DEAL_II_DISABLE_EXTRA_DIAGNOSTICS + generate_particles(particles); + DEAL_II_ENABLE_EXTRA_DIAGNOSTICS + + std::multimap::active_cell_iterator, Particles::Particle> new_particles; + + for (const auto &particle : particles) + new_particles.insert(new_particles.end(), + std::make_pair(typename Triangulation::active_cell_iterator(&this->get_triangulation(), + particle.first.first, particle.first.second), + particle.second)); + + particle_handler.insert_particles(new_particles); + } + + + + template + std::pair> + Interface::generate_particle(const Point &position, + const types::particle_index id) const + { + // Try to find the cell of the given position. If the position is not + // in the domain on the local process, throw a ExcParticlePointNotInDomain + // exception. + std::pair::active_cell_iterator, + Point> it = + GridTools::find_active_cell_around_point<> (this->get_mapping(), this->get_triangulation(), position); + + // Only try to add the point if the cell it is in, is on this processor + AssertThrow(it.first.state() == IteratorState::valid && it.first->is_locally_owned(), + ExcParticlePointNotInDomain()); + + const Particle particle(position, it.second, id); + const Particles::internal::LevelInd cell(it.first->level(), it.first->index()); + return std::make_pair(cell,particle); + + // Avoid warnings about missing return + return {}; + } + + + + template + Particles::ParticleIterator + Interface::insert_particle_at_position(const Point &position, + const types::particle_index id, + Particles::ParticleHandler &particle_handler) const + { + // Try to find the cell of the given position. + const std::pair::active_cell_iterator, + Point> it = + GridTools::find_active_cell_around_point<> (this->get_mapping(), this->get_triangulation(), position); + + if (it.first.state() != IteratorState::valid || it.first->is_locally_owned() == false) + return particle_handler.end(); + + return particle_handler.insert_particle(Particle(position, it.second, id), it.first); + } + + + + template + std::pair> + Interface::generate_particle (const typename parallel::distributed::Triangulation::active_cell_iterator &cell, + const types::particle_index id) + { + // Uniform distribution on the interval [0,1]. This + // will be used to generate random particle locations. + std::uniform_real_distribution uniform_distribution_01(0.0, 1.0); + + const BoundingBox cell_bounding_box = cell->bounding_box(); + + // Generate random points in these bounds until one is within the cell + unsigned int iteration = 0; + const unsigned int maximum_iterations = 100; + Point particle_position; + while (iteration < maximum_iterations) + { + // First generate a random point in the bounding box... + for (unsigned int d=0; d p_unit = this->get_mapping().transform_real_to_unit_cell(cell, particle_position); + if ( + cell->reference_cell().contains_point(p_unit) + ) + { + // Add the generated particle to the set + const Particle new_particle(particle_position, p_unit, id); + const Particles::internal::LevelInd cellid(cell->level(), cell->index()); + return std::make_pair(cellid,new_particle); + } + } + catch (typename Mapping::ExcTransformationFailed &) + { + // The point is not in this cell. Do nothing, just try again. + } + ++iteration; + } + + // If the above algorithm has not worked (e.g. because of badly + // deformed cells), retry generating particles + // randomly within the reference cell. This is not generating a + // uniform distribution in real space, but will always succeed. + for (unsigned int d=0; d p_real = this->get_mapping().transform_unit_to_real_cell(cell,particle_position); + + // Add the generated particle to the set + const Particle new_particle(p_real, particle_position, id); + const Particles::internal::LevelInd cellid(cell->level(), cell->index()); + + return std::make_pair(cellid, new_particle); + } + + +// -------------------------------- Deal with registering models and automating +// -------------------------------- their setup and selection at run time + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + register_particle_generator (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + + template + std::unique_ptr> + create_particle_generator (ParameterHandler &prm) + { + std::string name; + name = prm.get ("Particle generator name"); + + return std::get(registered_plugins).create_plugin (name, + "Particle::Generator name"); + } + + + + template + void + declare_parameters (ParameterHandler &prm) + { + // declare the entry in the parameter file + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + + prm.declare_entry ("Particle generator name", "random uniform", + Patterns::Selection (pattern_of_names), + "Select one of the following models:\n\n" + + + std::get(registered_plugins).get_description_string()); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Particle generator interface", + out); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace Particle + { + namespace Generator + { +#define INSTANTIATE(dim) \ + template class Interface; \ + \ + template \ + void \ + register_particle_generator (const std::string &, \ + const std::string &, \ + void ( *) (ParameterHandler &), \ + std::unique_ptr>( *) ()); \ + \ + template \ + void \ + declare_parameters (ParameterHandler &); \ + \ + template \ + void \ + write_plugin_graph (std::ostream &); \ + \ + template \ + std::unique_ptr> \ + create_particle_generator (ParameterHandler &prm); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + } +} diff --git a/source/particle/generator/probability_density_function.cc.bak b/source/particle/generator/probability_density_function.cc.bak new file mode 100644 index 00000000000..d276fd2399e --- /dev/null +++ b/source/particle/generator/probability_density_function.cc.bak @@ -0,0 +1,149 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + template + void + ProbabilityDensityFunction::generate_particles(Particles::ParticleHandler &particle_handler) + { + Particles::Generators::probabilistic_locations(this->get_triangulation(), + function, + random_cell_selection, + n_particles, + particle_handler, + this->get_mapping(), + random_number_seed); + } + + + + template + void + ProbabilityDensityFunction::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Generator"); + { + prm.enter_subsection("Probability density function"); + { + Functions::ParsedFunction::declare_parameters (prm, 1); + + prm.declare_entry ("Number of particles", "1000", + Patterns::Double (0.), + "Total number of particles to create (not per processor or per element). " + "The number is parsed as a floating point number (so that one can " + "specify, for example, '1e4' particles) but it is interpreted as " + "an integer, of course."); + + prm.declare_entry ("Random cell selection", "true", + Patterns::Bool(), + "If true, particle numbers per cell are calculated randomly " + "according to their respective probability density. " + "This means particle numbers per cell can deviate statistically from " + "the integral of the probability density. If false, " + "first determine how many particles each cell should have " + "based on the integral of the density over each of the cells, " + "and then once we know how many particles we want on each cell, " + "choose their locations randomly within each cell."); + + prm.declare_entry ("Random number seed", "5432", + Patterns::Integer(0), + "The seed for the random number generator that controls " + "the particle generation. Keep constant to generate " + "identical particle distributions in subsequent model " + "runs. Change to get a different distribution. In parallel " + "computations the seed is further modified on each process " + "to ensure different particle patterns on different " + "processes. Note that the number of particles per processor " + "is not affected by the seed."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + ProbabilityDensityFunction::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Generator"); + { + prm.enter_subsection("Probability density function"); + { + n_particles = static_cast(prm.get_double ("Number of particles")); + random_cell_selection = prm.get_bool("Random cell selection"); + random_number_seed = prm.get_integer("Random number seed"); + + try + { + function.parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Particle.Generator.Probability density function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'"; + throw; + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Generator + { + ASPECT_REGISTER_PARTICLE_GENERATOR(ProbabilityDensityFunction, + "probability density function", + "Generate a random distribution of " + "particles over the entire simulation domain. " + "The probability density is prescribed in the " + "form of a user-prescribed function. The " + "format of this function follows the syntax " + "understood by the muparser library, see " + "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`. The " + "return value of the function is always " + "checked to be a non-negative probability " + "density but it can be zero in " + "parts of the domain.") + } + } +} diff --git a/source/particle/generator/quadrature_points.cc.bak b/source/particle/generator/quadrature_points.cc.bak new file mode 100644 index 00000000000..5264920e257 --- /dev/null +++ b/source/particle/generator/quadrature_points.cc.bak @@ -0,0 +1,63 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + template + void + QuadraturePoints::generate_particles(Particles::ParticleHandler &particle_handler) + { + const Quadrature &quadrature_formula + = this->introspection().quadratures.velocities; + + Particles::Generators::regular_reference_locations( + this->get_triangulation(), + quadrature_formula.get_points(), + particle_handler, + this->get_mapping()); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Generator + { + ASPECT_REGISTER_PARTICLE_GENERATOR(QuadraturePoints, + "quadrature points", + "Generates particles at the quadrature points of each active cell of " + "the triangulation. Here, Gauss quadrature of degree (velocity\\_degree + 1), " + "is used similarly to the assembly of Stokes matrix.") + } + } +} diff --git a/source/particle/generator/random_uniform.cc.bak b/source/particle/generator/random_uniform.cc.bak new file mode 100644 index 00000000000..3fa2c84efca --- /dev/null +++ b/source/particle/generator/random_uniform.cc.bak @@ -0,0 +1,123 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + template + void + RandomUniform::generate_particles(Particles::ParticleHandler &particle_handler) + { + Particles::Generators::probabilistic_locations(this->get_triangulation(), + Functions::ConstantFunction(1.0), + random_cell_selection, + n_particles, + particle_handler, + this->get_mapping(), + random_number_seed); + } + + + + template + void + RandomUniform::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Generator"); + { + prm.enter_subsection("Probability density function"); + { + prm.declare_entry ("Number of particles", "1000", + Patterns::Double (0.), + "Total number of particles to create (not per processor or per element). " + "The number is parsed as a floating point number (so that one can " + "specify, for example, '1e4' particles) but it is interpreted as " + "an integer, of course."); + + prm.declare_entry ("Random cell selection", "true", + Patterns::Bool(), + "If true, particle numbers per cell are calculated randomly " + "according to their respective probability density. " + "This means particle numbers per cell can deviate statistically from " + "the integral of the probability density. If false, " + "first determine how many particles each cell should have " + "based on the integral of the density over each of the cells, " + "and then once we know how many particles we want on each cell, " + "choose their locations randomly within each cell."); + + prm.declare_entry ("Random number seed", "5432", + Patterns::Integer(0), + "The seed for the random number generator that controls " + "the particle generation. Keep constant to generate " + "identical particle distributions in subsequent model " + "runs. Change to get a different distribution. In parallel " + "computations the seed is further modified on each process " + "to ensure different particle patterns on different " + "processes. Note that the number of particles per processor " + "is not affected by the seed."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + RandomUniform::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Generator"); + { + prm.enter_subsection("Probability density function"); + { + n_particles = static_cast(prm.get_double ("Number of particles")); + random_cell_selection = prm.get_bool("Random cell selection"); + random_number_seed = prm.get_integer("Random number seed"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Generator + { + ASPECT_REGISTER_PARTICLE_GENERATOR(RandomUniform, + "random uniform", + "Generates a random uniform distribution of " + "particles over the entire simulation domain.") + } + } +} diff --git a/source/particle/generator/reference_cell.cc.bak b/source/particle/generator/reference_cell.cc.bak new file mode 100644 index 00000000000..cc63692f827 --- /dev/null +++ b/source/particle/generator/reference_cell.cc.bak @@ -0,0 +1,148 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + template + void + ReferenceCell::generate_particles(Particles::ParticleHandler &particle_handler) + { + const std::vector> reference_locations = generate_particle_positions_in_unit_cell(); + + Particles::Generators::regular_reference_locations(this->get_triangulation(), + reference_locations, + particle_handler, + this->get_mapping()); + } + + + template + std::vector> + ReferenceCell::generate_particle_positions_in_unit_cell() + { + std::vector> particle_positions; + std::array spacing; + + // Calculate separation of particles + for (unsigned int i = 0; i < dim; ++i) + spacing[i] = 1.0 / number_of_particles[i]; + + for (unsigned int i = 0; i < number_of_particles[0]; ++i) + { + for (unsigned int j = 0; j < number_of_particles[1]; ++j) + { + if (dim == 2) + { + const Point position_unit = Point(i * spacing[0] + spacing[0] / 2, + j * spacing[1] + spacing[1] / 2); + particle_positions.push_back(position_unit); + } + else if (dim == 3) + { + for (unsigned int k = 0; k < number_of_particles[2]; ++k) + { + const Point position_unit = Point(i * spacing[0] + spacing[0] / 2, + j * spacing[1] + spacing[1] / 2, + k * spacing[2] + spacing[2] / 2); + particle_positions.push_back(position_unit); + } + } + else + ExcNotImplemented(); + } + } + + return particle_positions; + } + + + template + void + ReferenceCell::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Generator"); + { + prm.enter_subsection("Reference cell"); + { + prm.declare_entry ("Number of particles per cell per direction", "2", + Patterns::List(Patterns::Integer(1)), + "List of number of particles to create per cell and spatial dimension. " + "The size of the list is the number of spatial dimensions. If only " + "one value is given, then each spatial dimension is set to the same value. " + "The list of numbers are parsed as a floating point number (so that one can " + "specify, for example, '1e4' particles) but it is interpreted as " + "an integer, of course."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + ReferenceCell::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Generator"); + { + prm.enter_subsection("Reference cell"); + { + const auto n_particles_per_direction = Utilities::possibly_extend_from_1_to_N ( + Utilities::string_to_int( + Utilities::split_string_list(prm.get("Number of particles per cell per direction"))), + dim, + "Number of particles per cell per direction"); + + for (const auto &n_particle_direction: n_particles_per_direction) + number_of_particles.push_back(static_cast (n_particle_direction)); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Generator + { + ASPECT_REGISTER_PARTICLE_GENERATOR(ReferenceCell, + "reference cell", + "Generates a uniform distribution of particles per cell and spatial direction in " + "the unit cell and transforms each of the particles back to real region in the model " + "domain. Uniform here means the particles will be generated with an equal spacing in " + "each spatial dimension.") + } + } +} diff --git a/source/particle/generator/uniform_box.cc.bak b/source/particle/generator/uniform_box.cc.bak new file mode 100644 index 00000000000..ca452055b7a --- /dev/null +++ b/source/particle/generator/uniform_box.cc.bak @@ -0,0 +1,175 @@ +/* + Copyright (C) 2015 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +#include + +#include +#include + + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + template + void + UniformBox::generate_particles(Particles::ParticleHandler &particle_handler) + { + const Tensor<1,dim> P_diff = P_max - P_min; + + double volume(1.0); + for (unsigned int i = 0; i < dim; ++i) + volume *= P_diff[i]; + + std::array n_particles_per_direction; + std::array spacing; + + // Calculate separation of particles + for (unsigned int i = 0; i < dim; ++i) + { + n_particles_per_direction[i] = static_cast(round(std::pow(n_particles * std::pow(P_diff[i],dim) / volume, 1./dim))); + spacing[i] = P_diff[i] / fmax(n_particles_per_direction[i] - 1,1); + } + + types::particle_index particle_index = 0; + + for (unsigned int i = 0; i < n_particles_per_direction[0]; ++i) + { + for (unsigned int j = 0; j < n_particles_per_direction[1]; ++j) + { + if (dim == 2) + { + const Point particle_position = Point (P_min[0]+i*spacing[0],P_min[1]+j*spacing[1]); + this->insert_particle_at_position(particle_position, particle_index, particle_handler); + ++particle_index; + } + else if (dim == 3) + for (unsigned int k = 0; k < n_particles_per_direction[2]; ++k) + { + const Point particle_position = Point (P_min[0]+i*spacing[0],P_min[1]+j*spacing[1],P_min[2]+k*spacing[2]); + this->insert_particle_at_position(particle_position, particle_index, particle_handler); + ++particle_index; + } + + } + } + + particle_handler.update_cached_numbers(); + } + + + template + void + UniformBox::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Generator"); + { + prm.enter_subsection("Uniform box"); + { + prm.declare_entry ("Number of particles", "1000", + Patterns::Double (0.), + "Total number of particles to create (not per processor or per element). " + "The number is parsed as a floating point number (so that one can " + "specify, for example, '1e4' particles) but it is interpreted as " + "an integer, of course."); + + prm.declare_entry ("Minimum x", "0.", + Patterns::Double (), + "Minimum x coordinate for the region of particles."); + prm.declare_entry ("Maximum x", "1.", + Patterns::Double (), + "Maximum x coordinate for the region of particles."); + prm.declare_entry ("Minimum y", "0.", + Patterns::Double (), + "Minimum y coordinate for the region of particles."); + prm.declare_entry ("Maximum y", "1.", + Patterns::Double (), + "Maximum y coordinate for the region of particles."); + prm.declare_entry ("Minimum z", "0.", + Patterns::Double (), + "Minimum z coordinate for the region of particles."); + prm.declare_entry ("Maximum z", "1.", + Patterns::Double (), + "Maximum z coordinate for the region of particles."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + UniformBox::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Generator"); + { + prm.enter_subsection("Uniform box"); + { + n_particles = static_cast(prm.get_double ("Number of particles")); + + P_min(0) = prm.get_double ("Minimum x"); + P_max(0) = prm.get_double ("Maximum x"); + P_min(1) = prm.get_double ("Minimum y"); + P_max(1) = prm.get_double ("Maximum y"); + + AssertThrow(P_min(0) < P_max(0), ExcMessage("Minimum x must be less than maximum x")); + AssertThrow(P_min(1) < P_max(1), ExcMessage("Minimum y must be less than maximum y")); + + if (dim == 3) + { + P_min(2) = prm.get_double ("Minimum z"); + P_max(2) = prm.get_double ("Maximum z"); + + AssertThrow(P_min(2) < P_max(2), ExcMessage("Minimum z must be less than maximum z")); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Generator + { + ASPECT_REGISTER_PARTICLE_GENERATOR(UniformBox, + "uniform box", + "Generate a uniform distribution of particles " + "over a rectangular domain in 2d or 3d. Uniform here means " + "the particles will be generated with an equal spacing in " + "each spatial dimension. Note that in order " + "to produce a regular distribution the number of generated " + "particles might not exactly match the one specified in the " + "input file.") + } + } +} diff --git a/source/particle/generator/uniform_radial.cc.bak b/source/particle/generator/uniform_radial.cc.bak new file mode 100644 index 00000000000..5604feb5ecb --- /dev/null +++ b/source/particle/generator/uniform_radial.cc.bak @@ -0,0 +1,254 @@ +/* + Copyright (C) 2015 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +#include + + +namespace aspect +{ + namespace Particle + { + namespace Generator + { + template + void + UniformRadial::generate_particles(Particles::ParticleHandler &particle_handler) + { + // Create the array of shell to deal with + const double radial_spacing = (P_max[0] - P_min[0]) / fmax(radial_layers-1,1); + + // Calculate number of particles per shell. + // The number of particles depend on the fraction of the area + // (or length in 2d) that this shell occupies compared to the total domain + std::vector particles_per_layer(radial_layers); + if (dim == 2) + { + double total_radius = 0; + for (unsigned int i = 0; i < radial_layers; ++i) + total_radius += P_min[0] + (radial_spacing * i); + for (unsigned int i = 0; i < radial_layers; ++i) + { + const double radius = P_min[0] + (radial_spacing * i); + particles_per_layer[i] = static_cast(round(n_particles * radius / total_radius)); + } + } + else if (dim == 3) + { + double total_area = 0; + for (unsigned int i = 0; i < radial_layers; ++i) + total_area += std::pow(P_min[0] + (radial_spacing * i),2); + for (unsigned int i = 0; i < radial_layers; ++i) + { + const double area = std::pow(P_min[0] + (radial_spacing * i),2); + particles_per_layer[i] = static_cast(round(n_particles * area / total_area)); + } + } + else + ExcNotImplemented(); + + // Generate particles + + types::particle_index particle_index = 0; + std::array spherical_coordinates; + for (unsigned int i = 0; i < radial_layers; ++i) + { + spherical_coordinates[0] = P_min[0] + (radial_spacing * i); + if (dim == 2) + { + const double phi_spacing = (P_max[1] - P_min[1]) / fmax(particles_per_layer[i]-1,1); + + for (unsigned int j = 0; j < particles_per_layer[i]; ++j) + { + spherical_coordinates[1] = P_min[1] + j * phi_spacing; + const Point particle_position = Utilities::Coordinates::spherical_to_cartesian_coordinates(spherical_coordinates) + P_center; + this->insert_particle_at_position(particle_position, particle_index, particle_handler); + ++particle_index; + } + } + else if (dim == 3) + { + const unsigned int theta_particles = static_cast( + round(sqrt(particles_per_layer[i]))); + const unsigned int phi_particles = static_cast( + round( + static_cast(particles_per_layer[i]) + / + static_cast(theta_particles))); + const double theta_spacing = (P_max[2] - P_min[2]) / fmax(theta_particles-1,1); + + for (unsigned int j = 0; j < theta_particles; ++j) + { + spherical_coordinates[2] = P_min[2] + j * theta_spacing; + + // Average value of sin(n) from 0 to 180 degrees is (2/pi) + const unsigned int adjusted_phi_particles = std::max(static_cast (phi_particles * std::sin(spherical_coordinates[2])), 1u); + const double phi_spacing = (P_max[1] - P_min[1]) / fmax(adjusted_phi_particles-1,1); + for (unsigned int k = 0; k < adjusted_phi_particles; ++k) + { + spherical_coordinates[1] = P_min[1] + k * phi_spacing; + const Point particle_position = Utilities::Coordinates::spherical_to_cartesian_coordinates(spherical_coordinates) + P_center; + this->insert_particle_at_position(particle_position, particle_index, particle_handler); + ++particle_index; + } + } + } + } + + particle_handler.update_cached_numbers(); + } + + + template + void + UniformRadial::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Generator"); + { + prm.enter_subsection("Uniform radial"); + { + prm.declare_entry ("Number of particles", "1000", + Patterns::Double (0.), + "Total number of particles to create (not per processor or per element). " + "The number is parsed as a floating point number (so that one can " + "specify, for example, '1e4' particles) but it is interpreted as " + "an integer, of course."); + + prm.declare_entry ("Center x", "0.", + Patterns::Double (), + "x coordinate for the center of the spherical region, " + "where particles are generated."); + prm.declare_entry ("Center y", "0.", + Patterns::Double (), + "y coordinate for the center of the spherical region, " + "where particles are generated."); + prm.declare_entry ("Center z", "0.", + Patterns::Double (), + "z coordinate for the center of the spherical region, " + "where particles are generated."); + prm.declare_entry ("Minimum radius", "0.", + Patterns::Double (0.), + "Minimum radial coordinate for the region of particles. " + "Measured from the center position."); + prm.declare_entry ("Maximum radius", "1.", + Patterns::Double (), + "Maximum radial coordinate for the region of particles. " + "Measured from the center position."); + prm.declare_entry ("Minimum longitude", "0.", + Patterns::Double (-180., 360.), + "Minimum longitude coordinate for the region of particles " + "in degrees. Measured from the center position."); + prm.declare_entry ("Maximum longitude", "360.", + Patterns::Double (-180., 360.), + "Maximum longitude coordinate for the region of particles " + "in degrees. Measured from the center position."); + prm.declare_entry ("Minimum latitude", "0.", + Patterns::Double (0., 180.), + "Minimum latitude coordinate for the region of particles " + "in degrees. Measured from the center position, and from " + "the north pole."); + prm.declare_entry ("Maximum latitude", "180.", + Patterns::Double (0., 180.), + "Maximum latitude coordinate for the region of particles " + "in degrees. Measured from the center position, and from " + "the north pole."); + prm.declare_entry ("Radial layers", "1", + Patterns::Integer(1), + "The number of radial shells of particles that will be generated " + "around the central point."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + UniformRadial::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Generator"); + { + prm.enter_subsection("Uniform radial"); + { + n_particles = static_cast(prm.get_double ("Number of particles")); + + P_center[0] = prm.get_double ("Center x"); + P_center[1] = prm.get_double ("Center y"); + + P_min[0] = prm.get_double ("Minimum radius"); + P_max[0] = prm.get_double ("Maximum radius"); + P_min[1] = prm.get_double ("Minimum longitude") * constants::degree_to_radians; + P_max[1] = prm.get_double ("Maximum longitude") * constants::degree_to_radians; + + AssertThrow(P_max[1] > P_min[1], + ExcMessage("The maximum longitude you prescribed in the uniform radial" + "particle generator has to be higher than the minimum longitude.")); + AssertThrow(P_max[1] - P_min[1] <= 2.0 * numbers::PI, + ExcMessage("The difference between the maximum and minimum longitude you " + "prescribed in the uniform radial particle generator has to be " + "less than 360 degrees.")); + + if (dim ==3) + { + P_center[2] = prm.get_double ("Center z"); + + P_min[2] = prm.get_double ("Minimum latitude") * constants::degree_to_radians; + P_max[2] = prm.get_double ("Maximum latitude") * constants::degree_to_radians; + + AssertThrow(P_max[2] > P_min[2], + ExcMessage("The maximum latitude you prescribed in the uniform radial" + "particle generator has to be higher than the minimum latitude.")); + } + + radial_layers = prm.get_integer("Radial layers"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Generator + { + ASPECT_REGISTER_PARTICLE_GENERATOR(UniformRadial, + "uniform radial", + "Generate a uniform distribution of particles " + "over a spherical domain in 2d or 3d. Uniform here means " + "the particles will be generated with an equal spacing in " + "each spherical spatial dimension, i.e., the particles are " + "created at positions that increase linearly with equal " + "spacing in radius, colatitude and longitude around a " + "certain center point. Note that in order " + "to produce a regular distribution the number of generated " + "particles might not exactly match the one specified in the " + "input file.") + } + } +} diff --git a/source/particle/integrator/euler.cc.bak b/source/particle/integrator/euler.cc.bak new file mode 100644 index 00000000000..791d7e095df --- /dev/null +++ b/source/particle/integrator/euler.cc.bak @@ -0,0 +1,103 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Integrator + { + template + void + Euler::local_integrate_step(const typename ParticleHandler::particle_iterator &begin_particle, + const typename ParticleHandler::particle_iterator &end_particle, + const std::vector> &old_velocities, + const std::vector> &, + const double dt) + { + Assert(static_cast (std::distance(begin_particle, end_particle)) == old_velocities.size(), + ExcMessage("The particle integrator expects the velocity vector to be of equal size " + "to the number of particles to advect. For some unknown reason they are different, " + "most likely something went wrong in the calling function.")); + + const auto cell = begin_particle->get_surrounding_cell(); + bool at_periodic_boundary = false; + if (this->get_triangulation().get_periodic_face_map().empty() == false) + for (const auto face_index: cell->face_indices()) + if (cell->at_boundary(face_index)) + if (cell->has_periodic_neighbor(face_index)) + { + at_periodic_boundary = true; + break; + } + + typename std::vector>::const_iterator old_velocity = old_velocities.begin(); + + for (typename ParticleHandler::particle_iterator it = begin_particle; + it != end_particle; ++it, ++old_velocity) + { +#if DEAL_II_VERSION_GTE(9, 6, 0) + // Get a reference to the particle location, so that we can update it in-place + Point &location = it->get_location(); +#else + Point location = it->get_location(); +#endif + location += dt * (*old_velocity); + + if (at_periodic_boundary) + this->get_geometry_model().adjust_positions_for_periodicity(location); + +#if !DEAL_II_VERSION_GTE(9, 6, 0) + it->set_location(location); +#endif + } + } + + + + template + std::array + Euler::required_solution_vectors() const + { + return {{false, true, false}}; + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Integrator + { + ASPECT_REGISTER_PARTICLE_INTEGRATOR(Euler, + "euler", + "Explicit Euler scheme integrator, where " + "$y_{n+1} = y_n + \\Delta t \\, v(y_n)$. " + "This requires only one integration substep per timestep.") + } + } +} diff --git a/source/particle/integrator/interface.cc.bak b/source/particle/integrator/interface.cc.bak new file mode 100644 index 00000000000..88a8342876f --- /dev/null +++ b/source/particle/integrator/interface.cc.bak @@ -0,0 +1,248 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Integrator + { + template + bool + Interface::new_integration_step() + { + return false; + } + + + + template + std::size_t + Interface::get_data_size() const + { + return 0; + } + + + + template + const void * + Interface::read_data(const typename ParticleHandler::particle_iterator &/*particle*/, + const void *data) + { + return data; + } + + + + template + void * + Interface::write_data(const typename ParticleHandler::particle_iterator &/*particle*/, + void *data) const + { + return data; + } + + + +// -------------------------------- Deal with registering models and automating +// -------------------------------- their setup and selection at run time + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + register_particle_integrator (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + + template + std::unique_ptr> + create_particle_integrator (ParameterHandler &prm) + { + std::string name; + name = prm.get ("Integration scheme"); + + return std::get(registered_plugins).create_plugin (name, + "Particle::Integrator name"); + } + + + + template + void + declare_parameters (ParameterHandler &prm) + { + // declare the entry in the parameter file + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + + prm.declare_entry ("Integration scheme", "rk2", + Patterns::Selection (pattern_of_names), + "This parameter is used to decide which method to " + "use to solve the equation that describes the position " + "of particles, i.e., $\\frac{d}{dt}\\mathbf x_k(t) = " + "\\mathbf u(\\mathbf x_k(t),t)$, where $k$ is an index " + "that runs over all particles, and $\\mathbf u(\\mathbf x,t)$ " + "is the velocity field that results from the Stokes " + "equations." + "\n\n" + "In practice, the exact velocity $\\mathbf u(\\mathbf x,t)$ " + "is of course not available, but only a numerical " + "approximation $\\mathbf u_h(\\mathbf x,t)$. Furthermore, " + "this approximation is only available at discrete time steps, " + "$\\mathbf u^n(\\mathbf x)=\\mathbf u(\\mathbf x,t^n)$, and " + "these need to be interpolated between time steps if the " + "integrator for the equation above requires an evaluation at " + "time points between the discrete time steps. If we denote this " + "interpolation in time by $\\tilde{\\mathbf u}_h(\\mathbf x,t)$ " + "where $\\tilde{\\mathbf u}_h(\\mathbf x,t^n)=" + "\\mathbf u^n(\\mathbf x)$, then the equation the differential " + "equation solver really tries to solve is " + "$\\frac{d}{dt}\\tilde{\\mathbf x}_k(t) = " + " \\tilde{\\mathbf u}_h(\\mathbf x_k(t),t)$." + "\n\n" + "As a consequence of these considerations, if you try to " + "assess convergence properties of an ODE integrator -- for " + "example to verify that the RK4 integrator converges with " + "fourth order --, it is important to recall that the " + "integrator may not solve the equation you think it " + "solves. If, for example, we call the numerical solution " + "of the ODE $\\tilde{\\mathbf x}_{k,h}(t)$, then the " + "error will typically satisfy a relationship like " + "\\[" + " \\| \\tilde{\\mathbf x}_k(T) - \\tilde{\\mathbf x}_{k,h}(T) \\|" + " \\le" + " C(T) \\Delta t^p" + "\\] " + "where $\\Delta t$ is the time step and $p$ the convergence order " + "of the method, and $C(T)$ is a (generally unknown) constant " + "that depends on the end time $T$ at which one compares the " + "solutions. On the other hand, an analytically computed " + "trajectory would likely use the \\textit{exact} velocity, " + "and one may be tempted to compute " + "$\\| \\mathbf x_k(T) - \\tilde{\\mathbf x}_{k,h}(T) \\|$, " + "but this quantity will, in the best case, only satisfy an " + "estimate of the form " + "\\[" + " \\| \\mathbf x_k(T) - \\tilde{\\mathbf x}_{k,h}(T) \\|" + " \\le" + " C_1(T) \\Delta t^p" + " + C_2(T) \\| \\mathbf u-\\mathbf u_h \\|" + " + C_3(T) \\| \\mathbf u_h-\\tilde{\\mathbf u}_h \\|" + "\\] " + "with appropriately chosen norms for the second and third " + "term. These second and third terms typically converge to " + "zero at relatively low rates (compared to the order $p$ of " + "the integrator, which can often be chosen relatively high) " + "in the mesh size $h$ and the time step size $\\\\Delta t$, " + "limiting the overall accuracy of the ODE integrator." + "\n\n" + "Select one of the following models:\n\n" + + + std::get(registered_plugins).get_description_string()); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Particle integrator interface", + out); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace Particle + { + namespace Integrator + { +#define INSTANTIATE(dim) \ + template class Interface; \ + \ + template \ + void \ + register_particle_integrator (const std::string &, \ + const std::string &, \ + void ( *) (ParameterHandler &), \ + std::unique_ptr>( *) ()); \ + \ + template \ + void \ + declare_parameters (ParameterHandler &); \ + \ + template \ + void \ + write_plugin_graph (std::ostream &); \ + \ + template \ + std::unique_ptr> \ + create_particle_integrator (ParameterHandler &prm); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + } +} diff --git a/source/particle/integrator/rk_2.cc.bak b/source/particle/integrator/rk_2.cc.bak new file mode 100644 index 00000000000..eec91bde25c --- /dev/null +++ b/source/particle/integrator/rk_2.cc.bak @@ -0,0 +1,242 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Integrator + { + template + RK2::RK2() + : + integrator_substep(0) + {} + + + + template + void + RK2::initialize () + { + const auto &property_information = this->get_particle_world(this->get_particle_world_index()).get_property_manager().get_data_info(); + property_index_old_location = property_information.get_position_by_field_name("internal: integrator properties"); + } + + + + template + void + RK2::local_integrate_step(const typename ParticleHandler::particle_iterator &begin_particle, + const typename ParticleHandler::particle_iterator &end_particle, + const std::vector> &old_velocities, + const std::vector> &velocities, + const double dt) + { + Assert(static_cast (std::distance(begin_particle, end_particle)) == old_velocities.size(), + ExcMessage("The particle integrator expects the old velocity vector to be of equal size " + "to the number of particles to advect. For some unknown reason they are different, " + "most likely something went wrong in the calling function.")); + + if (higher_order_in_time == true && integrator_substep == 1) + Assert(old_velocities.size() == velocities.size(), + ExcMessage("The particle integrator expects the velocity vector to be of equal size " + "to the number of particles to advect. For some unknown reason they are different, " + "most likely something went wrong in the calling function.")); + + const auto cell = begin_particle->get_surrounding_cell(); + bool at_periodic_boundary = false; + if (this->get_triangulation().get_periodic_face_map().empty() == false) + for (const auto &face_index: cell->face_indices()) + if (cell->at_boundary(face_index)) + if (cell->has_periodic_neighbor(face_index)) + { + at_periodic_boundary = true; + break; + } + + typename std::vector>::const_iterator old_velocity = old_velocities.begin(); + typename std::vector>::const_iterator velocity = velocities.begin(); + + for (typename ParticleHandler::particle_iterator it = begin_particle; + it != end_particle; ++it, ++velocity, ++old_velocity) + { + ArrayView properties = it->get_properties(); + + if (integrator_substep == 0) + { + const Tensor<1,dim> k1 = dt * (*old_velocity); +#if DEAL_II_VERSION_GTE(9, 6, 0) + // Get a reference to the particle location, so that we can update it in-place + Point &location = it->get_location(); +#else + Point location = it->get_location(); +#endif + Point new_location = location + 0.5 * k1; + + // Check if we crossed a periodic boundary and if necessary adjust positions + if (at_periodic_boundary) + this->get_geometry_model().adjust_positions_for_periodicity(new_location, + ArrayView>(location)); + + for (unsigned int i=0; iset_location(new_location); +#endif + } + else if (integrator_substep == 1) + { + const Tensor<1,dim> k2 = (higher_order_in_time == true) + ? + dt * (*old_velocity + *velocity) * 0.5 + : + dt * (*old_velocity); + +#if DEAL_II_VERSION_GTE(9, 6, 0) + Point &location = it->get_location(); +#else + Point location = it->get_location(); +#endif + + for (unsigned int i=0; iget_geometry_model().adjust_positions_for_periodicity(location); + +#if !DEAL_II_VERSION_GTE(9, 6, 0) + it->set_location(location); +#endif + } + else + { + Assert(false, + ExcMessage("The RK2 integrator should never continue after two integration steps.")); + } + } + } + + + + template + bool + RK2::new_integration_step() + { + integrator_substep = (integrator_substep + 1) % 2; + + // Continue until we're at the last step + return (integrator_substep != 0); + } + + + + template + std::array + RK2::required_solution_vectors() const + { + switch (integrator_substep) + { + case 0: + return {{false, true, false}}; + case 1: + { + if (higher_order_in_time) + return {{false, true, true}}; + else + return {{false, true, false}}; + } + default: + Assert(false, + ExcMessage("The RK4 integrator should never continue after four integration steps.")); + + return {{false, false, false}}; + } + } + + + + template + void + RK2::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Integrator"); + { + prm.enter_subsection("RK2"); + { + prm.declare_entry ("Higher order accurate in time", "true", + Patterns::Bool(), + "Whether to correctly evaluate old and current velocity " + "solution to reach higher-order accuracy in time. If set to " + "'false' only the old velocity solution is evaluated to " + "simulate a first order method in time. This is only " + "recommended for benchmark purposes."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + RK2::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Integrator"); + { + prm.enter_subsection("RK2"); + { + higher_order_in_time = prm.get_bool("Higher order accurate in time"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Integrator + { + ASPECT_REGISTER_PARTICLE_INTEGRATOR(RK2, + "rk2", + "Second Order Runge Kutta integrator " + "$y_{n+1} = y_n + \\Delta t\\, v(t_{n+1/2}, y_{n} + \\frac{1}{2} k_1)$ " + "where $k_1 = \\Delta t\\, v(t_{n}, y_{n})$") + } + } +} diff --git a/source/particle/integrator/rk_4.cc.bak b/source/particle/integrator/rk_4.cc.bak new file mode 100644 index 00000000000..e94b454783f --- /dev/null +++ b/source/particle/integrator/rk_4.cc.bak @@ -0,0 +1,281 @@ +/* + Copyright (C) 2015 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Integrator + { + template + RK4::RK4() + : + integrator_substep(0) + {} + + + + template + void + RK4::initialize () + { + const auto &property_information = this->get_particle_world(this->get_particle_world_index()).get_property_manager().get_data_info(); + + property_indices[0] = property_information.get_position_by_field_name("internal: integrator properties"); + property_indices[1] = property_indices[0] + dim; + property_indices[2] = property_indices[1] + dim; + property_indices[3] = property_indices[2] + dim; + } + + + + template + void + RK4::local_integrate_step(const typename ParticleHandler::particle_iterator &begin_particle, + const typename ParticleHandler::particle_iterator &end_particle, + const std::vector> &old_velocities, + const std::vector> &velocities, + const double dt) + { + if (integrator_substep < 3) + { + Assert(static_cast (std::distance(begin_particle, end_particle)) == old_velocities.size(), + ExcMessage("The particle integrator expects the old velocity vector to be of equal size " + "to the number of particles to advect. For some unknown reason they are different, " + "most likely something went wrong in the calling function.")); + } + + if (integrator_substep >= 1 && integrator_substep < 4) + { + Assert(static_cast (std::distance(begin_particle, end_particle)) == velocities.size(), + ExcMessage("The particle integrator expects the velocity vector to be of equal size " + "to the number of particles to advect. For some unknown reason they are different, " + "most likely something went wrong in the calling function.")); + } + + const auto cell = begin_particle->get_surrounding_cell(); + bool at_periodic_boundary = false; + if (this->get_triangulation().get_periodic_face_map().empty() == false) + for (const auto &face_index: cell->face_indices()) + if (cell->at_boundary(face_index)) + if (cell->has_periodic_neighbor(face_index)) + { + at_periodic_boundary = true; + break; + } + + typename std::vector>::const_iterator old_velocity = old_velocities.begin(); + typename std::vector>::const_iterator velocity = velocities.begin(); + + std::array,4> k; + for (typename ParticleHandler::particle_iterator it = begin_particle; + it != end_particle; ++it, ++velocity, ++old_velocity) + { + ArrayView properties = it->get_properties(); + + if (integrator_substep == 0) + { +#if DEAL_II_VERSION_GTE(9, 6, 0) + // Get a reference to the particle location, so that we can update it in-place + Point &location = it->get_location(); +#else + Point location = it->get_location(); +#endif + k[0] = dt * (*old_velocity); + + Point new_location = location + 0.5 * k[0]; + + // Check if we crossed a periodic boundary and if necessary adjust positions + if (at_periodic_boundary) + this->get_geometry_model().adjust_positions_for_periodicity(new_location, + ArrayView>(&location,1), + ArrayView>(&k[0],1)); + + for (unsigned int i=0; iset_location(new_location); +#endif + } + else if (integrator_substep == 1) + { + k[1] = dt * ((*old_velocity) + (*velocity)) * 0.5; + + Point old_location; + for (unsigned int i=0; i new_location = old_location + 0.5 * k[1]; + + if (at_periodic_boundary) + { + for (unsigned int i=0; iget_geometry_model().adjust_positions_for_periodicity(new_location, + ArrayView>(&old_location,1), + ArrayView>(&k[0],2)); + + for (unsigned int i=0; iset_location(new_location); + } + else if (integrator_substep == 2) + { + k[2] = dt * (*old_velocity + *velocity) * 0.5; + + Point old_location; + for (unsigned int i=0; i new_location = old_location + k[2]; + + if (at_periodic_boundary) + { + for (unsigned int i=0; iget_geometry_model().adjust_positions_for_periodicity(new_location, + ArrayView>(&old_location,1), + ArrayView>(&k[0],3)); + + for (unsigned int i=0; iset_location(new_location); + } + else if (integrator_substep == 3) + { + k[3] = dt * (*velocity); + + Point old_location; + for (unsigned int i=0; i new_location = old_location + (k[0] + 2.0*k[1] + 2.0*k[2] + k[3])/6.0; + + // No need to fix intermediate values, this is the last integrator step + if (at_periodic_boundary) + this->get_geometry_model().adjust_positions_for_periodicity(new_location); + + it->set_location(new_location); + } + else + { + Assert(false, + ExcMessage("The RK4 integrator should never continue after four integration stages.")); + } + } + } + + + + template + bool + RK4::new_integration_step() + { + integrator_substep = (integrator_substep+1)%4; + + // Continue until we're at the last step + return (integrator_substep != 0); + } + + + template + std::array + RK4::required_solution_vectors() const + { + switch (integrator_substep) + { + case 0: + return {{false, true, false}}; + case 1: + return {{false, true, true}}; + case 2: + return {{false, true, true}}; + case 3: + return {{false, false, true}}; + default: + Assert(false, + ExcMessage("The RK4 integrator should never continue after four integration steps.")); + } + + return {{false, false, false}}; + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Integrator + { + ASPECT_REGISTER_PARTICLE_INTEGRATOR(RK4, + "rk4", + "Runge Kutta fourth order integrator, where " + "$y_{n+1} = y_n + \\frac{1}{6} k_1 + \\frac{1}{3} k_2 " + "+ \\frac{1}{3} k_3 + \\frac{1}{6} k_4$ " + "and $k_1$, $k_2$, $k_3$, $k_4$ are defined as usual.") + } + } +} diff --git a/source/particle/interface.cc.bak b/source/particle/interface.cc.bak new file mode 100644 index 00000000000..659e348739c --- /dev/null +++ b/source/particle/interface.cc.bak @@ -0,0 +1,42 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + + +namespace aspect +{ + namespace Particle + { + void + ParticleInterfaceBase::set_particle_world_index(const unsigned int particle_world_index) + { + this->particle_world_index = particle_world_index; + } + + + + unsigned int + ParticleInterfaceBase::get_particle_world_index() const + { + return particle_world_index; + } + } +} diff --git a/source/particle/interpolator/bilinear_least_squares.cc.bak b/source/particle/interpolator/bilinear_least_squares.cc.bak new file mode 100644 index 00000000000..da2fc320bce --- /dev/null +++ b/source/particle/interpolator/bilinear_least_squares.cc.bak @@ -0,0 +1,364 @@ +/* + Copyright (C) 2017 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include + +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + template + std::vector> + BilinearLeastSquares::properties_at_points(const ParticleHandler &particle_handler, + const std::vector> &positions, + const ComponentMask &selected_properties, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const + { + const unsigned int n_particle_properties = particle_handler.n_properties_per_particle(); + const unsigned int property_index = selected_properties.first_selected_component(selected_properties.size()); + + AssertThrow(property_index != numbers::invalid_unsigned_int, + ExcMessage("Internal error: the particle property interpolator was " + "called without a specified component to interpolate.")); + + const typename ParticleHandler::particle_iterator_range particle_range = + particle_handler.particles_in_cell(cell); + + std::vector> cell_properties(positions.size(), + std::vector(n_particle_properties, + numbers::signaling_nan())); + + const unsigned int n_particles = std::distance(particle_range.begin(), particle_range.end()); + const unsigned int n_matrix_columns = (dim == 2) ? 3 : 4; + + // If there are too few particles, we can not perform a least squares interpolation + // fall back to a simpler method instead. + if (n_particles < n_matrix_columns) + return fallback_interpolator.properties_at_points(particle_handler, + positions, + selected_properties, + cell); + + // Noticed that the size of matrix A is n_particles x n_matrix_columns + // which usually is not a square matrix. Therefore, we find the + // least squares solution of Ac=r by solving the reduced QR factorization + // Ac = QRc = b -> Q^TQRc = Rc =Q^Tb + // A is a std::vector of Vectors(which are it's columns) so that we + // create what the ImplicitQR class needs. + std::vector> A(n_matrix_columns, Vector(n_particles)); + std::vector> b(n_particle_properties, Vector(n_particles)); + + unsigned int particle_index = 0; + // The unit cell of deal.II is [0,1]^dim. The limiter needs a 'unit' cell of [-.5,.5]^dim. + const double unit_offset = 0.5; + std::vector property_minimums(n_particle_properties, std::numeric_limits::max()); + std::vector property_maximums(n_particle_properties, std::numeric_limits::lowest()); + for (typename ParticleHandler::particle_iterator particle = particle_range.begin(); + particle != particle_range.end(); ++particle, ++particle_index) + { + const ArrayView particle_property_value = particle->get_properties(); + for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) + { + if (selected_properties[property_index] == true) + { + b[property_index][particle_index] = particle_property_value[property_index]; + if (use_linear_least_squares_limiter[property_index] == true) + { + property_minimums[property_index] = std::min(property_minimums[property_index], particle_property_value[property_index]); + property_maximums[property_index] = std::max(property_maximums[property_index], particle_property_value[property_index]); + } + } + } + Point relative_particle_position = particle->get_reference_location(); + + // A is accessed by A[column][row] here since we will need to append + // columns into the qr matrix + A[0][particle_index] = 1; + for (unsigned int i = 1; i < n_matrix_columns; ++i) + { + relative_particle_position[i - 1] -= unit_offset; + A[i][particle_index] = relative_particle_position[i - 1]; + } + } + + // If the limiter is enabled for at least one property then we know that we can access ghost cell + // particles to determine the bounds of the properties on the mode (due to the assert of + // 'Exchange ghost particles' in parse_parameters). Otherwise we do not need to access those particles + if (use_linear_least_squares_limiter.n_selected_components() != 0) + { + std::vector::active_cell_iterator> active_neighbors; + GridTools::get_active_neighbors>(cell, active_neighbors); + for (const auto &active_neighbor : active_neighbors) + { + if (active_neighbor->is_artificial()) + continue; + const std::vector neighbor_cell_average = fallback_interpolator.properties_at_points(particle_handler, positions, selected_properties, active_neighbor)[0]; + for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) + { + if (selected_properties[property_index] == true && use_linear_least_squares_limiter[property_index] == true) + { + property_minimums[property_index] = std::min(property_minimums[property_index], neighbor_cell_average[property_index]); + property_maximums[property_index] = std::max(property_maximums[property_index], neighbor_cell_average[property_index]); + } + } + } + if (cell->at_boundary()) + { + const std::vector cell_average_values = fallback_interpolator.properties_at_points(particle_handler, {positions[0]}, selected_properties, cell)[0]; + for (unsigned int face_id = 0; face_id < cell->reference_cell().n_faces(); ++face_id) + { + if (cell->at_boundary(face_id)) + { + const unsigned int opposing_face_id = GeometryInfo::opposite_face[face_id]; + const auto &opposing_cell = cell->neighbor(opposing_face_id); + if (opposing_cell.state() == IteratorState::IteratorStates::valid && opposing_cell->is_active() && opposing_cell->is_artificial() == false) + { + const auto neighbor_cell_average = fallback_interpolator.properties_at_points(particle_handler, {positions[0]}, selected_properties, opposing_cell)[0]; + for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) + { + if (selected_properties[property_index] == true && use_boundary_extrapolation[property_index] == true) + { + Assert(cell->reference_cell().is_hyper_cube() == true, ExcNotImplemented()); + const double expected_boundary_value = 1.5 * cell_average_values[property_index] - 0.5 * neighbor_cell_average[property_index]; + property_minimums[property_index] = std::min(property_minimums[property_index], expected_boundary_value); + property_maximums[property_index] = std::max(property_maximums[property_index], expected_boundary_value); + } + } + } + } + } + } + } + + ImplicitQR> qr; + for (const auto &column : A) + qr.append_column(column); + // If A is rank deficent then qr.append_column will not append + // the first column that can be written as a linear combination of + // other columns. We check that all columns were added or we + // rely on the fallback interpolator + if (qr.size() != n_matrix_columns) + return fallback_interpolator.properties_at_points(particle_handler, + positions, + selected_properties, + cell); + + std::vector> QTb(n_particle_properties, Vector(n_matrix_columns)); + std::vector> c(n_particle_properties, Vector(n_matrix_columns)); + for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) + { + if (selected_properties[property_index] == true) + { + qr.multiply_with_QT(QTb[property_index], b[property_index]); + qr.solve(c[property_index], QTb[property_index]); + } + } + const double half_h = .5; + for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) + { + if (selected_properties[property_index] == true) + { + if (use_linear_least_squares_limiter[property_index] == true) + { + c[property_index][0] = std::max(c[property_index][0], property_minimums[property_index]); + c[property_index][0] = std::min(c[property_index][0], property_maximums[property_index]); + + const double max_total_slope = std::min(c[property_index][0] - property_minimums[property_index], + property_maximums[property_index] - c[property_index][0]) + / half_h; + double current_total_slope = 0.0; + for (unsigned int i = 1; i < n_matrix_columns; ++i) + { + current_total_slope += std::abs(c[property_index][i]); + } + + if (current_total_slope > max_total_slope && current_total_slope > std::numeric_limits::min()) + { + double slope_change_ratio = max_total_slope/current_total_slope; + for (unsigned int i = 1; i < n_matrix_columns; ++i) + c[property_index][i] *= slope_change_ratio; + } + } + std::size_t positions_index = 0; + for (typename std::vector>::const_iterator itr = positions.begin(); itr != positions.end(); ++itr, ++positions_index) + { + Point relative_support_point_location = this->get_mapping().transform_real_to_unit_cell(cell, *itr); + double interpolated_value = c[property_index][0]; + for (unsigned int i = 1; i < n_matrix_columns; ++i) + { + relative_support_point_location[i - 1] -= unit_offset; + interpolated_value += c[property_index][i] * relative_support_point_location[i - 1]; + } + if (use_linear_least_squares_limiter[property_index] == true) + { + // Assert that the limiter was reasonably effective. We can not expect perfect accuracy + // due to inaccuracies e.g. in the inversion of the mapping. + const double tolerance = std::sqrt(std::numeric_limits::epsilon()) + * std::max(std::abs(property_minimums[property_index]), + std::abs(property_maximums[property_index])); + (void) tolerance; + Assert(interpolated_value >= property_minimums[property_index] - tolerance, + ExcMessage("The particle interpolation limiter did not succeed. Interpolated value: " + std::to_string(interpolated_value) + + " is smaller than the minimum particle property value: " + std::to_string(property_minimums[property_index]) + ".")); + Assert(interpolated_value <= property_maximums[property_index] + tolerance, + ExcMessage("The particle interpolation limiter did not succeed. Interpolated value: " + std::to_string(interpolated_value) + + " is larger than the maximum particle property value: " + std::to_string(property_maximums[property_index]) + ".")); + + interpolated_value = std::min(interpolated_value, property_maximums[property_index]); + interpolated_value = std::max(interpolated_value, property_minimums[property_index]); + } + cell_properties[positions_index][property_index] = interpolated_value; + } + + } + } + return cell_properties; + } + + + + template + void + BilinearLeastSquares::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Interpolator"); + { + prm.enter_subsection("Bilinear least squares"); + { + prm.declare_entry("Use linear least squares limiter", "false", + Patterns::List(Patterns::Bool()), + "Limit the interpolation of particle properties onto the cell, so that " + "the value of each property is no smaller than its minimum and no " + "larger than its maximum on the particles of each cell, and the " + "average of neighboring cells. If more than one value is given, " + "it will be treated as a list with one component per particle property."); + prm.declare_entry("Use boundary extrapolation", "false", + Patterns::List(Patterns::Bool()), + "Extends the range used by 'Use linear least squares limiter' " + "by linearly interpolating values at cell boundaries from neighboring " + "cells. If more than one value is given, it will be treated as a list " + "with one component per particle property. Enabling 'Use boundary " + "extrapolation' requires enabling 'Use linear least squares " + "limiter'."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + BilinearLeastSquares::parse_parameters (ParameterHandler &prm) + { + fallback_interpolator.parse_parameters(prm); + prm.enter_subsection("Interpolator"); + { + prm.enter_subsection("Bilinear least squares"); + { + const auto &particle_property_information = this->get_particle_world(this->get_particle_world_index()).get_property_manager().get_data_info(); + const unsigned int n_property_components = particle_property_information.n_components(); + const unsigned int n_internal_components = particle_property_information.get_components_by_field_name("internal: integrator properties"); + + std::vector linear_least_squares_limiter_split = Utilities::split_string_list(prm.get("Use linear least squares limiter")); + std::vector linear_least_squares_limiter_parsed; + if (linear_least_squares_limiter_split.size() == 1) + { + linear_least_squares_limiter_parsed = std::vector(n_property_components - n_internal_components, Utilities::string_to_bool(linear_least_squares_limiter_split[0])); + } + else if (linear_least_squares_limiter_split.size() == n_property_components - n_internal_components) + { + for (const auto &component: linear_least_squares_limiter_split) + linear_least_squares_limiter_parsed.push_back(Utilities::string_to_bool(component)); + } + else + { + AssertThrow(false, ExcMessage("The size of 'Use linear least squares limiter' should either be 1 or the number of particle properties")); + } + for (unsigned int i = 0; i < n_internal_components; ++i) + linear_least_squares_limiter_parsed.push_back(false); + use_linear_least_squares_limiter = ComponentMask(linear_least_squares_limiter_parsed); + + + + const std::vector boundary_extrapolation_split = Utilities::split_string_list(prm.get("Use boundary extrapolation")); + std::vector boundary_extrapolation_parsed; + if (boundary_extrapolation_split.size() == 1) + { + boundary_extrapolation_parsed = std::vector(n_property_components - n_internal_components, Utilities::string_to_bool(boundary_extrapolation_split[0])); + } + else if (boundary_extrapolation_split.size() == n_property_components - n_internal_components) + { + for (const auto &component: boundary_extrapolation_split) + boundary_extrapolation_parsed.push_back(Utilities::string_to_bool(component)); + } + else + { + AssertThrow(false, ExcMessage("The size of 'Use boundary extrapolation' should either be 1 or the number of particle properties")); + } + for (unsigned int i = 0; i < n_internal_components; ++i) + boundary_extrapolation_parsed.push_back(false); + use_boundary_extrapolation = ComponentMask(boundary_extrapolation_parsed); + for (unsigned int property_index = 0; property_index < n_property_components - n_internal_components; ++property_index) + { + AssertThrow(use_linear_least_squares_limiter[property_index] || !use_boundary_extrapolation[property_index], + ExcMessage("'Use boundary extrapolation' must be set with 'Use linear least squares limiter' to be valid.")); + } + } + prm.leave_subsection(); + } + prm.leave_subsection(); + const bool limiter_enabled_for_at_least_one_property = (use_linear_least_squares_limiter.n_selected_components() != 0); + AssertThrow(limiter_enabled_for_at_least_one_property == false || prm.get_bool("Update ghost particles") == true, + ExcMessage("If 'Use linear least squares limiter' is enabled for any particle property, then 'Update ghost particles' must be set to true")); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + ASPECT_REGISTER_PARTICLE_INTERPOLATOR(BilinearLeastSquares, + "bilinear least squares", + "Uses linear least squares to obtain the slopes and center of a 2d or " + "3d plane from the particle positions and a particular property value " + "on those particles. " + "Interpolate this property onto a vector of points. If the limiter is " + "enabled then it will ensure the interpolated properties do not exceed the " + "range of the minimum and maximum of the values of the property on the " + "particles. Note that deal.II must be configured with BLAS and LAPACK to " + "support this operation.") + } + } +} diff --git a/source/particle/interpolator/cell_average.cc.bak b/source/particle/interpolator/cell_average.cc.bak new file mode 100644 index 00000000000..1a7f4ddfc35 --- /dev/null +++ b/source/particle/interpolator/cell_average.cc.bak @@ -0,0 +1,161 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + template + std::vector> + CellAverage::properties_at_points(const ParticleHandler &particle_handler, + const std::vector> &positions, + const ComponentMask &selected_properties, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const + { + const typename ParticleHandler::particle_iterator_range particle_range = + particle_handler.particles_in_cell(cell); + + const unsigned int n_particles = std::distance(particle_range.begin(),particle_range.end()); + const unsigned int n_particle_properties = particle_handler.n_properties_per_particle(); + + std::vector cell_properties (n_particle_properties,numbers::signaling_nan()); + + for (unsigned int i = 0; i < n_particle_properties; ++i) + if (selected_properties[i]) + cell_properties[i] = 0.0; + + if (n_particles > 0) + { + for (const auto &particle : particle_range) + { + const ArrayView &particle_properties = particle.get_properties(); + + for (unsigned int i = 0; i < particle_properties.size(); ++i) + if (selected_properties[i]) + cell_properties[i] += particle_properties[i]; + } + + for (unsigned int i = 0; i < n_particle_properties; ++i) + if (selected_properties[i]) + cell_properties[i] /= n_particles; + } + // If there are no particles in this cell use the average of the + // neighboring cells. + else + { + std::vector::active_cell_iterator> neighbors; + GridTools::get_active_neighbors>(cell,neighbors); + + unsigned int non_empty_neighbors = 0; + for (unsigned int i=0; iis_locally_owned()) + continue; + // Only recursively call this function if the neighbor cell contains + // particles (else we end up in an endless recursion) + if (particle_handler.n_particles_in_cell(neighbors[i]) == 0) + continue; + + const std::vector neighbor_properties = properties_at_points(particle_handler, + std::vector> (1,neighbors[i]->center(true,false)), + selected_properties, + neighbors[i])[0]; + + for (unsigned int i = 0; i < n_particle_properties; ++i) + if (selected_properties[i]) + cell_properties[i] += neighbor_properties[i]; + + ++non_empty_neighbors; + } + + if (!allow_cells_without_particles) + { + AssertThrow(non_empty_neighbors != 0, + ExcMessage("A cell and all of its neighbors do not contain any particles. " + "The `cell average' interpolation scheme does not support this case unless specified " + "in Allow cells without particles.")); + } + + for (unsigned int i = 0; i < n_particle_properties; ++i) + { + if (selected_properties[i] && non_empty_neighbors != 0) + cell_properties[i] /= non_empty_neighbors; + // Assume property is zero for any areas with no particles + else if (allow_cells_without_particles && non_empty_neighbors == 0) + cell_properties[i] = 0; + } + + } + + return std::vector> (positions.size(),cell_properties); + } + + + + template + void + CellAverage::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Allow cells without particles", "false", + Patterns::Bool (), + "By default, every cell needs to contain particles to use this interpolator " + "plugin. If this parameter is set to true, cells are allowed to have no particles, " + "In case both the current cell and its neighbors are empty, " + "the interpolator will return 0 for the current cell's properties."); + } + + + + template + void + CellAverage::parse_parameters (ParameterHandler &prm) + { + allow_cells_without_particles = prm.get_bool("Allow cells without particles"); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + ASPECT_REGISTER_PARTICLE_INTERPOLATOR(CellAverage, + "cell average", + "Return the arithmetic average of all particle properties in the given cell, " + "or in the neighboring cells if the given cell is empty. " + "In case the neighboring cells are also empty, and 'Allow cells " + "without particles' is set to true, the interpolator returns 0. " + "Otherwise, an exception is thrown. ") + } + } +} diff --git a/source/particle/interpolator/harmonic_average.cc.bak b/source/particle/interpolator/harmonic_average.cc.bak new file mode 100644 index 00000000000..6ae071041e3 --- /dev/null +++ b/source/particle/interpolator/harmonic_average.cc.bak @@ -0,0 +1,169 @@ +/* + Copyright (C) 2017 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + template + std::vector> + HarmonicAverage::properties_at_points(const ParticleHandler &particle_handler, + const std::vector> &positions, + const ComponentMask &selected_properties, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const + { + const typename ParticleHandler::particle_iterator_range particle_range = + particle_handler.particles_in_cell(cell); + + const unsigned int n_particles = std::distance(particle_range.begin(),particle_range.end()); + const unsigned int n_particle_properties = particle_handler.n_properties_per_particle(); + + std::vector cell_properties (n_particle_properties,numbers::signaling_nan()); + + for (unsigned int i = 0; i < n_particle_properties; ++i) + if (selected_properties[i]) + cell_properties[i] = 0.0; + + if (n_particles > 0) + { + for (const auto &particle : particle_range) + { + const ArrayView &particle_properties = particle.get_properties(); + + for (unsigned int i = 0; i < particle_properties.size(); ++i) + if (selected_properties[i]) + { + AssertThrow(particle_properties[i] > 0, + ExcMessage ("All particle property values must be greater than 0 for harmonic averaging!")); + cell_properties[i] += 1/particle_properties[i]; + } + } + + for (unsigned int i = 0; i < n_particle_properties; ++i) + if (selected_properties[i]) + { + cell_properties[i] = n_particles/cell_properties[i]; + } + } + // If there are no particles in this cell use the average of the + // neighboring cells. + else + { + std::vector::active_cell_iterator> neighbors; + GridTools::get_active_neighbors>(cell,neighbors); + + unsigned int non_empty_neighbors = 0; + for (unsigned int i=0; i neighbor_properties = properties_at_points(particle_handler, + std::vector> (1,neighbors[i]->center(true,false)), + selected_properties, + neighbors[i])[0]; + + for (unsigned int i = 0; i < n_particle_properties; ++i) + if (selected_properties[i]) + { + AssertThrow(neighbor_properties[i] > 0, + ExcMessage ("All particle property values must be greater than 0 for harmonic averaging!")); + cell_properties[i] += 1/neighbor_properties[i]; + } + + ++non_empty_neighbors; + } + + if (!allow_cells_without_particles) + { + AssertThrow(non_empty_neighbors != 0, + ExcMessage("A cell and all of its neighbors do not contain any particles. " + "The `harmonic average' interpolation scheme does not support this case unless specified " + "in Allow cells without particles.")); + } + + for (unsigned int i = 0; i < n_particle_properties; ++i) + { + if (selected_properties[i] && non_empty_neighbors !=0) + cell_properties[i] = non_empty_neighbors/cell_properties[i]; + // Assume property is zero for any areas with no particles + else if (allow_cells_without_particles && non_empty_neighbors == 0) + cell_properties[i] = 0; + } + + } + + return std::vector> (positions.size(),cell_properties); + } + + + + template + void + HarmonicAverage::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Allow cells without particles", "false", + Patterns::Bool (), + "By default, every cell needs to contain particles to use this interpolator " + "plugin. If this parameter is set to true, cells are allowed to have no particles. " + "In case both the current cell and its neighbors are empty, " + "the interpolator will return 0 for the current cell's properties."); + } + + + + template + void + HarmonicAverage::parse_parameters (ParameterHandler &prm) + { + allow_cells_without_particles = prm.get_bool("Allow cells without particles"); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + ASPECT_REGISTER_PARTICLE_INTERPOLATOR(HarmonicAverage, + "harmonic average", + "Return the harmonic average of all particle properties in the " + "given cell. If the cell contains no particles, return the " + "harmonic average of the properties in the neighboring cells. " + "In case the neighboring cells are also empty, and 'Allow cells " + "without particles' is set to true, the interpolator returns 0. " + "Otherwise, an exception is thrown. ") + } + } +} diff --git a/source/particle/interpolator/interface.cc.bak b/source/particle/interpolator/interface.cc.bak new file mode 100644 index 00000000000..83a50104dec --- /dev/null +++ b/source/particle/interpolator/interface.cc.bak @@ -0,0 +1,149 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { +// -------------------------------- Deal with registering models and automating +// -------------------------------- their setup and selection at run time + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + register_particle_interpolator (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + + template + std::unique_ptr> + create_particle_interpolator (ParameterHandler &prm) + { + std::string name; + name = prm.get ("Interpolation scheme"); + + return std::get(registered_plugins).create_plugin (name, + "Particle::Interpolator name"); + } + + + + template + void + declare_parameters (ParameterHandler &prm) + { + // declare the entry in the parameter file + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + + prm.declare_entry ("Interpolation scheme", "cell average", + Patterns::Selection (pattern_of_names), + "Select one of the following models:\n\n" + + + std::get(registered_plugins).get_description_string()); + + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Particle interpolator interface", + out); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace Particle + { + namespace Interpolator + { +#define INSTANTIATE(dim) \ + template class Interface; \ + \ + template \ + void \ + register_particle_interpolator (const std::string &, \ + const std::string &, \ + void ( *) (ParameterHandler &), \ + std::unique_ptr>( *) ()); \ + \ + template \ + void \ + declare_parameters (ParameterHandler &); \ + \ + template \ + void \ + write_plugin_graph (std::ostream &); \ + \ + template \ + std::unique_ptr> \ + create_particle_interpolator (ParameterHandler &prm); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + } +} diff --git a/source/particle/interpolator/nearest_neighbor.cc.bak b/source/particle/interpolator/nearest_neighbor.cc.bak new file mode 100644 index 00000000000..9903cb18a4d --- /dev/null +++ b/source/particle/interpolator/nearest_neighbor.cc.bak @@ -0,0 +1,161 @@ +/* + Copyright (C) 2017 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + template + std::vector> + NearestNeighbor::properties_at_points(const ParticleHandler &particle_handler, + const std::vector> &positions, + const ComponentMask &selected_properties, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const + { + const typename ParticleHandler::particle_iterator_range particle_range = particle_handler.particles_in_cell(cell); + + const unsigned int n_particles = std::distance(particle_range.begin(),particle_range.end()); + const unsigned int n_particle_properties = particle_handler.n_properties_per_particle(); + + std::vector temp(n_particle_properties, 0.0); + std::vector> point_properties(positions.size(), temp); + + for (unsigned int pos_idx=0; pos_idx < positions.size(); ++pos_idx) + { + double minimum_distance = std::numeric_limits::max(); + if (n_particles > 0) + { + typename ParticleHandler::particle_iterator nearest_neighbor; + for (typename ParticleHandler::particle_iterator particle = particle_range.begin(); + particle != particle_range.end(); ++particle) + { + const double dist = (positions[pos_idx] - particle->get_location()).norm_square(); + if (dist < minimum_distance) + { + minimum_distance = dist; + nearest_neighbor = particle; + } + } + const dealii::ArrayView neighbor_props = nearest_neighbor->get_properties(); + for (unsigned int i = 0; i < n_particle_properties; ++i) + if (selected_properties[i]) + point_properties[pos_idx][i] = neighbor_props[i]; + } + else + { + std::vector::active_cell_iterator> neighbors; + GridTools::get_active_neighbors>(cell,neighbors); + + unsigned int nearest_neighbor_cell = numbers::invalid_unsigned_int; + for (unsigned int i=0; icenter()).norm_square(); + if (dist < minimum_distance) + { + minimum_distance = dist; + nearest_neighbor_cell = i; + } + } + + if (!allow_cells_without_particles) + { + AssertThrow(nearest_neighbor_cell != numbers::invalid_unsigned_int, + ExcMessage("A cell and all of its neighbors do not contain any particles. " + "The `nearest neighbor' interpolation scheme does not support this case unless specified " + "in Allow cells without particles.")); + } + + if (nearest_neighbor_cell != numbers::invalid_unsigned_int) + { + point_properties[pos_idx] = properties_at_points(particle_handler, + std::vector> (1,positions[pos_idx]), + selected_properties, + neighbors[nearest_neighbor_cell])[0]; + } + else if (allow_cells_without_particles && nearest_neighbor_cell == numbers::invalid_unsigned_int) + { + for (unsigned int i = 0; i < n_particle_properties; ++i) + if (selected_properties[i]) + point_properties[pos_idx][i] = 0; + } + + } + + } + + return point_properties; + } + + + + template + void + NearestNeighbor::declare_parameters (ParameterHandler &prm) + { + prm.declare_entry ("Allow cells without particles", "false", + Patterns::Bool (), + "By default, every cell needs to contain particles to use this interpolator " + "plugin. If this parameter is set to true, cells are allowed to have no particles. " + "In case both the current cell and its neighbors are empty, " + "the interpolator will return 0 for the current cell's properties."); + } + + + + template + void + NearestNeighbor::parse_parameters (ParameterHandler &prm) + { + allow_cells_without_particles = prm.get_bool("Allow cells without particles"); + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + ASPECT_REGISTER_PARTICLE_INTERPOLATOR(NearestNeighbor, + "nearest neighbor", + "Return the properties of the nearest neighboring particle " + "in the current cell, or nearest particle in nearest neighboring " + "cell if current cell is empty. " + "In case the neighboring cells are also empty, and 'Allow cells " + "without particles' is set to true, the interpolator returns 0. " + "Otherwise, an exception is thrown. ") + } + } +} diff --git a/source/particle/interpolator/quadratic_least_squares.cc.bak b/source/particle/interpolator/quadratic_least_squares.cc.bak new file mode 100644 index 00000000000..4dfdfe715f6 --- /dev/null +++ b/source/particle/interpolator/quadratic_least_squares.cc.bak @@ -0,0 +1,640 @@ +/* + Copyright (C) 2019 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include + +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + template + double QuadraticLeastSquares::evaluate_interpolation_function(const Vector &coefficients, const Point &position) const + { + if (dim == 2) + { + return coefficients[0] + + coefficients[1] * position[0] + + coefficients[2] * position[1] + + coefficients[3] * position[0] * position[1] + + coefficients[4] * position[0] * position[0] + + coefficients[5] * position[1] * position[1]; + } + else + { + return coefficients[0] + + coefficients[1] * position[0] + + coefficients[2] * position[1] + + coefficients[3] * position[2] + + coefficients[4] * position[0] * position[1] + + coefficients[5] * position[0] * position[2] + + coefficients[6] * position[1] * position[2] + + coefficients[7] * position[0] * position[0] + + coefficients[8] * position[1] * position[1] + + coefficients[9] * position[2] * position[2]; + } + } + + + template + std::pair QuadraticLeastSquares::get_interpolation_bounds(const Vector &coefficients) const + { + double interpolation_min = std::numeric_limits::max(); + double interpolation_max = std::numeric_limits::lowest(); + for (const auto &critical_point : get_critical_points(coefficients)) + { + bool critical_point_in_cell = true; + for (unsigned int d = 0; d < dim; ++d) + { + if (critical_point[d] < -0.5 || critical_point[d] > 0.5) + critical_point_in_cell = false; + } + if (critical_point_in_cell) + { + const double value_at_critical_point = evaluate_interpolation_function(coefficients, critical_point); + interpolation_min = std::min(interpolation_min, value_at_critical_point); + interpolation_max = std::max(interpolation_max, value_at_critical_point); + } + } + return {interpolation_min, interpolation_max}; + } + + + template + std::vector> QuadraticLeastSquares::get_critical_points(const Vector &coefficients) const + { + std::vector> critical_points; + const double epsilon = 10. * coefficients.linfty_norm() * std::numeric_limits::epsilon(); + if (dim == 2) + { + // reserve the maximum number of critical points + // in 2d: one inside, 4 edges, and 4 corners + critical_points.reserve(1 + 4 + 4); + // If finding the critical point of the function (or along a cell edge) would + // require division by 0, or the solve of a singular matrix, then there is not + // a unique critical point. There cannot be two critical points to this function, + // so there must be infinitely many points with the same value, so it should be + // caught by one of the other checks of the value of the interpolation + + // compute the location of the global critical point + Tensor<2, dim, double> critical_point_A; + critical_point_A[0][0] = 2 * coefficients[4]; + critical_point_A[0][1] = coefficients[3]; + critical_point_A[1][0] = coefficients[3]; + critical_point_A[1][1] = 2 * coefficients[5]; + Tensor<1, dim, double> critical_point_b; + critical_point_b[0] = -coefficients[1]; + critical_point_b[1] = -coefficients[2]; + if (std::abs(determinant(critical_point_A)) > epsilon) + { + critical_points.emplace_back(invert(critical_point_A) * critical_point_b); + } + + // Compute the critical value for each of the edges. This is necessary even if we found the + // critical point inside the unit cell, because the value at the edges can be a minimum, while + // the critical point inside the cell is a maximum, or vice-versa. Additionally the critical + // point could be a saddle point, in which case we would still need to find a minimum and maximum over the cell. + if (std::abs(coefficients[5]) > epsilon) + { + critical_points.emplace_back(-0.5, -(2 * coefficients[2] - coefficients[3])/(4 * coefficients[5])); + critical_points.emplace_back( 0.5, -(2 * coefficients[2] + coefficients[3])/(4 * coefficients[5])); + } + if (std::abs(coefficients[4]) > epsilon) + { + critical_points.emplace_back(-(2 * coefficients[1] - coefficients[3])/(4 * coefficients[4]), -0.5); + critical_points.emplace_back(-(2 * coefficients[1] + coefficients[3])/(4 * coefficients[4]), 0.5); + } + + // Compute the critical value for each of the corners. This is necessary even if critical points + // have already been found in previous steps, as the global critical point could be a minimum, + // and the edge critical points could also be minimums. + for (double x = -0.5; x <= 0.5; ++x) + { + for (double y = -0.5; y <= 0.5; ++y) + { + critical_points.emplace_back(x,y); + } + } + } + else if (dim == 3) + { + // reserve the maximum number of critical points + // in 3d: one inside, 6 faces, 12 edges, and 8 corners + critical_points.reserve(1 + 6 + 12 + 8); + // If finding the critical point of the function (or along a cell edge) would + // require division by 0, or the solve of a singular matrix, then there is not + // a unique critical point. There cannot be two critical points to this function, + // so there must be infinitely many points with the same value, so it should be + // caught by one of the other checks of the value of the interpolation + + // Compute the location of the global critical point + { + Tensor<2, dim, double> critical_point_A; + critical_point_A[0][0] = 2 * coefficients[7]; + critical_point_A[0][1] = coefficients[4]; + critical_point_A[0][2] = coefficients[5]; + critical_point_A[1][0] = coefficients[4]; + critical_point_A[1][1] = 2 * coefficients[8]; + critical_point_A[1][2] = coefficients[6]; + critical_point_A[2][0] = coefficients[5]; + critical_point_A[2][1] = coefficients[6]; + critical_point_A[2][2] = 2 * coefficients[9]; + Tensor<1, dim, double> critical_point_b; + critical_point_b[0] = -coefficients[1]; + critical_point_b[1] = -coefficients[2]; + critical_point_b[2] = -coefficients[3]; + if (std::abs(determinant(critical_point_A)) > epsilon) + { + critical_points.emplace_back(invert(critical_point_A) * critical_point_b); + } + } + + // Compute the location of critical points along the faces of the cell. + // This is is necessary even if we found a global critical point as it + // could be a minimum and the faces could have a maximum or vice-versa. + Tensor<2, 2, double> critical_point_A; + Tensor<1, 2, double> critical_point_b; + Tensor<1, 2, double> critical_point_X; + // The columns of this critical_point_A correspond to Y and Z. + critical_point_A[0][0] = 2 * coefficients[8]; + critical_point_A[0][1] = coefficients[6]; + critical_point_A[1][0] = coefficients[6]; + critical_point_A[1][1] = 2 * coefficients[9]; + if (std::abs(determinant(critical_point_A)) > epsilon) + { + const Tensor<2, 2, double> critical_point_A_inv = invert(critical_point_A); + double x = -0.5; + critical_point_b[0] = -(coefficients[2] + coefficients[4] * x); + critical_point_b[1] = -(coefficients[3] + coefficients[5] * x); + critical_point_X = critical_point_A_inv * critical_point_b; + critical_points.emplace_back(x, critical_point_X[0], critical_point_X[1]); + x = 0.5; + critical_point_b[0] = -(coefficients[2] + coefficients[4] * x); + critical_point_b[1] = -(coefficients[3] + coefficients[5] * x); + critical_point_X = critical_point_A_inv * critical_point_b; + critical_points.emplace_back(x, critical_point_X[0], critical_point_X[1]); + } + // The columns of this critical_point_A correspond to X and Z. + critical_point_A[0][0] = 2 * coefficients[7]; + critical_point_A[0][1] = coefficients[5]; + critical_point_A[1][0] = coefficients[5]; + critical_point_A[1][1] = 2 * coefficients[9]; + if (std::abs(determinant(critical_point_A)) > epsilon) + { + const Tensor<2, 2, double> critical_point_A_inv = invert(critical_point_A); + double y = -0.5; + critical_point_b[0] = -(coefficients[1] + coefficients[4] * y); + critical_point_b[1] = -(coefficients[3] + coefficients[6] * y); + critical_point_X = critical_point_A_inv * critical_point_b; + critical_points.emplace_back(critical_point_X[0], y, critical_point_X[1]); + y = 0.5; + critical_point_b[0] = -(coefficients[1] + coefficients[4] * y); + critical_point_b[1] = -(coefficients[3] + coefficients[6] * y); + critical_point_X = critical_point_A_inv * critical_point_b; + critical_points.emplace_back(critical_point_X[0], y, critical_point_X[1]); + } + // The columns of this critical_point_A correspond to X and Y. + critical_point_A[0][0] = 2 * coefficients[7]; + critical_point_A[0][1] = coefficients[4]; + critical_point_A[1][0] = coefficients[4]; + critical_point_A[1][1] = 2 * coefficients[8]; + if (std::abs(determinant(critical_point_A)) > epsilon) + { + const Tensor<2, 2, double> critical_point_A_inv = invert(critical_point_A); + double z = -0.5; + critical_point_b[0] = -(coefficients[1] + coefficients[5] * z); + critical_point_b[1] = -(coefficients[2] + coefficients[6] * z); + critical_point_X = critical_point_A_inv * critical_point_b; + critical_points.emplace_back(critical_point_X[0], critical_point_X[1], z); + z = 0.5; + critical_point_b[0] = -(coefficients[1] + coefficients[5] * z); + critical_point_b[1] = -(coefficients[2] + coefficients[6] * z); + critical_point_X = critical_point_A_inv * critical_point_b; + critical_points.emplace_back(critical_point_X[0], critical_point_X[1], z); + } + + // Compute the location of critical points along the edges. + // This is necessary even if critical points have been found in previous + // steps, as the global critial point and critical points on faces could + // all be minimums. + if (std::abs(coefficients[9]) > epsilon) + { + for (double x = -0.5; x <= 0.5; ++x) + { + for (double y = -0.5; y <= 0.5; ++y) + { + critical_points.emplace_back(x,y, -(coefficients[3] + coefficients[5] * x + coefficients[6] * y)/(2 * coefficients[9])); + } + } + } + if (std::abs(coefficients[8]) > epsilon) + { + for (double x = -0.5; x <= 0.5; ++x) + { + for (double z = -0.5; z <= 0.5; ++z) + { + critical_points.emplace_back(x, -(coefficients[2] + coefficients[4] * x + coefficients[6] * z) / (2 * coefficients[8]), z); + } + } + } + if (std::abs(coefficients[7]) > epsilon) + { + for (double y = -0.5; y <= 0.5; ++y) + { + for (double z = -0.5; z <= 0.5; ++z) + { + critical_points.emplace_back(-(coefficients[1] + coefficients[4] * y + coefficients[5] * z)/(2*coefficients[7]), y, z); + } + } + } + + // Compute the location of critical points along the corners + // This is necessary even if critical points have been found in previous + // steps, as the previously found critical points could all be minimums + // and the corners could hold the maximum value over the cell. + for (double x = -0.5; x <= 0.5; ++x) + { + for (double y = -0.5; y <= 0.5; ++y) + { + for (double z = -0.5; z <= 0.5; ++z) + { + critical_points.emplace_back(x, y, z); + } + } + } + } + return critical_points; + } + + template + std::vector> + QuadraticLeastSquares::properties_at_points(const ParticleHandler &particle_handler, + const std::vector> &positions, + const ComponentMask &selected_properties, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const + { + const unsigned int n_particle_properties = particle_handler.n_properties_per_particle(); + + const unsigned int property_index = selected_properties.first_selected_component(selected_properties.size()); + + AssertThrow(property_index != numbers::invalid_unsigned_int, + ExcMessage("Internal error: the particle property interpolator was " + "called without a specified component to interpolate.")); + + const typename ParticleHandler::particle_iterator_range particle_range = + particle_handler.particles_in_cell(cell); + + std::vector> cell_properties(positions.size(), + std::vector(n_particle_properties, + numbers::signaling_nan())); + + const unsigned int n_particles = std::distance(particle_range.begin(), particle_range.end()); + + const unsigned int n_matrix_columns = (dim == 2) ? 6 : 10; + if (n_particles < n_matrix_columns) + return fallback_interpolator.properties_at_points(particle_handler, + positions, + selected_properties, + cell); + const std::vector cell_average_values = fallback_interpolator.properties_at_points(particle_handler, + {positions[0]}, + selected_properties, + cell)[0]; + + + // Notice that the size of matrix A is n_particles x n_matrix_columns + // which usually is not a square matrix. Therefore, we find the + // least squares solution of Ac=r by solving the reduced QR factorization + // Ac = QRc = b -> Q^TQRc = Rc =Q^Tb + // A is a std::vector of Vectors(which are it's columns) so that we + // create what the ImplicitQR class needs. + std::vector> A(n_matrix_columns, Vector(n_particles)); + std::vector> b(n_particle_properties, Vector(n_particles)); + + unsigned int particle_index = 0; + // The unit cell of deal.II is [0, 1]^dim. The limiter needs a 'unit' cell of [-0.5, 0.5]^dim + const double unit_offset = 0.5; + std::vector property_minimums(n_particle_properties, std::numeric_limits::max()); + std::vector property_maximums(n_particle_properties, std::numeric_limits::lowest()); + for (typename ParticleHandler::particle_iterator particle = particle_range.begin(); + particle != particle_range.end(); ++particle, ++particle_index) + { + const ArrayView particle_property_value = particle->get_properties(); + for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) + { + if (selected_properties[property_index] == true) + { + b[property_index][particle_index] = particle_property_value[property_index]; + property_minimums[property_index] = std::min(property_minimums[property_index], particle_property_value[property_index]); + property_maximums[property_index] = std::max(property_maximums[property_index], particle_property_value[property_index]); + } + } + + Point relative_particle_position = particle->get_reference_location(); + for (unsigned int d = 0; d < dim; ++d) + relative_particle_position[d] -= unit_offset; + // A is accessed by A[column][row] here since we need to append + // columns into the qr matrix. + + // There is a potential that in the future we may change to + // interpolate to $Q_2$ instead of the current $P_2$. This would + // involve adding more terms to the interpolation for some problems. + // We for now leave those terms out of the interpolation because they + // would require more particles per cell and we are not yet aware of + // a benchmark where those terms have affected the convegence. + A[0][particle_index] = 1; + A[1][particle_index] = relative_particle_position[0]; + A[2][particle_index] = relative_particle_position[1]; + if (dim == 2) + { + A[3][particle_index] = relative_particle_position[0] * relative_particle_position[1]; + A[4][particle_index] = relative_particle_position[0] * relative_particle_position[0]; + A[5][particle_index] = relative_particle_position[1] * relative_particle_position[1]; + } + else + { + A[3][particle_index] = relative_particle_position[2]; + A[4][particle_index] = relative_particle_position[0] * relative_particle_position[1]; + A[5][particle_index] = relative_particle_position[0] * relative_particle_position[2]; + A[6][particle_index] = relative_particle_position[1] * relative_particle_position[2]; + A[7][particle_index] = relative_particle_position[0] * relative_particle_position[0]; + A[8][particle_index] = relative_particle_position[1] * relative_particle_position[1]; + A[9][particle_index] = relative_particle_position[2] * relative_particle_position[2]; + } + } + + // If the limiter is enabled for at least one property then we know that we can access ghost cell + // particles to determine the bounds of the properties on the model (due to the assert of + // 'Exchange ghost particles' in parse_parameters). Otherwise we do not need to access those particles + if (use_quadratic_least_squares_limiter.n_selected_components(n_particle_properties) != 0) + { + std::vector::active_cell_iterator> active_neighbors; + GridTools::get_active_neighbors>(cell, active_neighbors); + for (const auto &active_neighbor : active_neighbors) + { + if (active_neighbor->is_artificial()) + continue; + const std::vector neighbor_cell_average = fallback_interpolator.properties_at_points(particle_handler, positions, selected_properties, active_neighbor)[0]; + for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) + { + if (selected_properties[property_index] == true && use_quadratic_least_squares_limiter[property_index] == true) + { + property_minimums[property_index] = std::min(property_minimums[property_index], neighbor_cell_average[property_index]); + property_maximums[property_index] = std::max(property_maximums[property_index], neighbor_cell_average[property_index]); + } + } + + } + if (cell->at_boundary()) + { + for (unsigned int face_id = 0; face_id < cell->reference_cell().n_faces(); ++face_id) + { + if (cell->at_boundary(face_id)) + { + const unsigned int opposing_face_id = GeometryInfo::opposite_face[face_id]; + const auto &opposing_cell = cell->neighbor(opposing_face_id); + if (opposing_cell.state() == IteratorState::IteratorStates::valid && opposing_cell->is_active() && !opposing_cell->is_artificial()) + { + + const auto neighbor_cell_average = fallback_interpolator.properties_at_points(particle_handler, {positions[0]}, selected_properties, opposing_cell)[0]; + for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) + { + if (selected_properties[property_index] == true && use_boundary_extrapolation[property_index] == true) + { + Assert(cell->reference_cell().is_hyper_cube() == true, ExcNotImplemented()); + const double expected_boundary_value = 1.5 * cell_average_values[property_index] - 0.5 * neighbor_cell_average[property_index]; + property_minimums[property_index] = std::min(property_minimums[property_index], expected_boundary_value); + property_maximums[property_index] = std::max(property_maximums[property_index], expected_boundary_value); + } + } + } + } + } + } + } + ImplicitQR> qr; + for (const auto &column : A) + qr.append_column(column); + // If A is rank deficent then qr.append_column will not append + // the first column that can be written as a linear combination of + // other columns. We check that all columns were added or we + // rely on the fallback interpolator + if (qr.size() != n_matrix_columns) + return fallback_interpolator.properties_at_points(particle_handler, + positions, + selected_properties, + cell); + std::vector> QTb(n_particle_properties, Vector(n_matrix_columns)); + std::vector> c(n_particle_properties, Vector(n_matrix_columns)); + for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) + { + if (selected_properties[property_index]) + { + qr.multiply_with_QT(QTb[property_index], b[property_index]); + qr.solve(c[property_index], QTb[property_index]); + if (use_quadratic_least_squares_limiter[property_index]) + { + + const std::pair interpolation_bounds = get_interpolation_bounds(c[property_index]); + const double interpolation_min = interpolation_bounds.first; + const double interpolation_max = interpolation_bounds.second; + if ((interpolation_max - cell_average_values[property_index]) > std::numeric_limits::epsilon() && + (cell_average_values[property_index] - interpolation_min) > std::numeric_limits::epsilon()) + { + const double alpha = std::max(std::min((cell_average_values[property_index] - property_minimums[property_index])/(cell_average_values[property_index] - interpolation_min), + (property_maximums[property_index]-cell_average_values[property_index])/(interpolation_max - cell_average_values[property_index])), 0.0); + // If alpha > 1, then using it would make the function grow to meet the bounds. + if (alpha < 1.0) + { + c[property_index] *= alpha; + c[property_index][0] += (1-alpha) * cell_average_values[property_index]; + } + } + } + } + } + unsigned int index_positions = 0; + for (typename std::vector>::const_iterator itr = positions.begin(); itr != positions.end(); ++itr, ++index_positions) + { + Point relative_support_point_location = this->get_mapping().transform_real_to_unit_cell(cell, *itr); + for (unsigned int d = 0; d < dim; ++d) + relative_support_point_location[d] -= unit_offset; + for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) + { + if (selected_properties[property_index] == true) + { + double interpolated_value = evaluate_interpolation_function(c[property_index], relative_support_point_location); + // Overshoot and undershoot correction of interpolated particle property. + if (use_quadratic_least_squares_limiter[property_index]) + { + // Assert that the limiter was reasonably effective. We can not expect perfect accuracy + // due to inaccuracies e.g. in the inversion of the mapping. + const double tolerance = std::sqrt(std::numeric_limits::epsilon()) + * std::max(std::abs(property_minimums[property_index]), + std::abs(property_maximums[property_index])); + (void) tolerance; + Assert(interpolated_value >= property_minimums[property_index] - tolerance, + ExcMessage("The particle interpolation limiter did not succeed. Interpolated value: " + std::to_string(interpolated_value) + + " is smaller than the minimum particle property value: " + std::to_string(property_minimums[property_index]) + ".")); + Assert(interpolated_value <= property_maximums[property_index] + tolerance, + ExcMessage("The particle interpolation limiter did not succeed. Interpolated value: " + std::to_string(interpolated_value) + + " is larger than the maximum particle property value: " + std::to_string(property_maximums[property_index]) + ".")); + + // This chopping is done to avoid values that are just outside + // of the limiting bounds. + interpolated_value = std::min(interpolated_value, property_maximums[property_index]); + interpolated_value = std::max(interpolated_value, property_minimums[property_index]); + } + cell_properties[index_positions][property_index] = interpolated_value; + } + + } + } + return cell_properties; + } + + + + template + void + QuadraticLeastSquares::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Interpolator"); + { + prm.enter_subsection("Quadratic least squares"); + { + prm.declare_entry("Use quadratic least squares limiter", "true", + Patterns::List(Patterns::Bool()), + "Limit the interpolation of particle properties onto the cell, so that " + "the value of each property is no smaller than its minimum and no " + "larger than its maximum on the particles of each cell, and the " + "average of neighboring cells. If more than one value is given, " + "it will be treated as a list with one component per particle property."); + prm.declare_entry("Use boundary extrapolation", "false", + Patterns::List(Patterns::Bool()), + "Extends the range used by 'Use quadratic least squares limiter' " + "by linearly interpolating values at cell boundaries from neighboring " + "cells. If more than one value is given, it will be treated as a list " + "with one component per particle property. Enabling 'Use boundary " + "extrapolation' requires enabling 'Use quadratic least squares " + "limiter'."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + QuadraticLeastSquares::parse_parameters (ParameterHandler &prm) + { + fallback_interpolator.parse_parameters(prm); + + prm.enter_subsection("Interpolator"); + { + prm.enter_subsection("Quadratic least squares"); + { + const auto &particle_property_information = this->get_particle_world(this->get_particle_world_index()).get_property_manager().get_data_info(); + const unsigned int n_property_components = particle_property_information.n_components(); + const unsigned int n_internal_components = particle_property_information.get_components_by_field_name("internal: integrator properties"); + + const std::vector quadratic_least_squares_limiter_split = Utilities::split_string_list(prm.get("Use quadratic least squares limiter")); + std::vector quadratic_least_squares_limiter_parsed; + if (quadratic_least_squares_limiter_split.size() == 1) + { + quadratic_least_squares_limiter_parsed = std::vector(n_property_components - n_internal_components, Utilities::string_to_bool(quadratic_least_squares_limiter_split[0])); + } + else if (quadratic_least_squares_limiter_split.size() == n_property_components - n_internal_components) + { + for (const auto &component: quadratic_least_squares_limiter_split) + quadratic_least_squares_limiter_parsed.push_back(Utilities::string_to_bool(component)); + } + else + { + AssertThrow(false, ExcMessage("The size of 'Use quadratic least squares limiter' should either be 1 or the number of particle properties")); + } + for (unsigned int i = 0; i < n_internal_components; ++i) + quadratic_least_squares_limiter_parsed.push_back(false); + use_quadratic_least_squares_limiter = ComponentMask(quadratic_least_squares_limiter_parsed); + + + const std::vector boundary_extrapolation_split = Utilities::split_string_list(prm.get("Use boundary extrapolation")); + std::vector boundary_extrapolation_parsed; + if (boundary_extrapolation_split.size() == 1) + { + boundary_extrapolation_parsed = std::vector(n_property_components - n_internal_components, Utilities::string_to_bool(boundary_extrapolation_split[0])); + } + else if (boundary_extrapolation_split.size() == n_property_components - n_internal_components) + { + for (const auto &component: boundary_extrapolation_split) + boundary_extrapolation_parsed.push_back(Utilities::string_to_bool(component)); + } + else + { + AssertThrow(false, ExcMessage("The size of 'Use boundary extrapolation' should either be 1 or the number of particle properties")); + } + for (unsigned int i = 0; i < n_internal_components; ++i) + boundary_extrapolation_parsed.push_back(false); + use_boundary_extrapolation = ComponentMask(boundary_extrapolation_parsed); + for (unsigned int property_index = 0; property_index < n_property_components - n_internal_components; ++property_index) + { + AssertThrow(use_quadratic_least_squares_limiter[property_index] || !use_boundary_extrapolation[property_index], + ExcMessage("'Use boundary extrapolation' must be set with 'Use quadratic least squares limiter' to be valid.")); + } + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + + // In general n_selected_components() requests an argument of the ComponentMask's size since it could be initialized to be entirely true without a size. + // Here it is given a size equal to n_property_components, so that argument is not necessary. + const bool limiter_enabled_for_at_least_one_property = (use_quadratic_least_squares_limiter.n_selected_components() != 0); + AssertThrow(limiter_enabled_for_at_least_one_property == false || prm.get_bool("Update ghost particles") == true, + ExcMessage("If 'Use quadratic least squares limiter' is enabled for any particle property, then 'Update ghost particles' must be set to true")); + + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Interpolator + { + ASPECT_REGISTER_PARTICLE_INTERPOLATOR(QuadraticLeastSquares, + "quadratic least squares", + "Interpolates particle properties onto a vector of points using a " + "quadratic least squares method. Note that deal.II must be configured " + "with BLAS/LAPACK.") + } + } +} diff --git a/source/particle/property/composition.cc.bak b/source/particle/property/composition.cc.bak new file mode 100644 index 00000000000..8584d0f65ad --- /dev/null +++ b/source/particle/property/composition.cc.bak @@ -0,0 +1,110 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + void + Composition::initialize_one_particle_property(const Point &position, + std::vector &data) const + { + for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) + data.push_back(this->get_initial_composition_manager().initial_composition(position,i)); + } + + template + void + Composition::update_particle_property(const unsigned int data_position, + const Vector &solution, + const std::vector> &/*gradients*/, + typename ParticleHandler::particle_iterator &particle) const + { + for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) + { + const unsigned int solution_component = this->introspection().component_indices.compositional_fields[i]; + particle->get_properties()[data_position+i] = solution[solution_component]; + } + } + + template + UpdateTimeFlags + Composition::need_update() const + { + return update_time_step; + } + + template + UpdateFlags + Composition::get_needed_update_flags () const + { + return update_values; + } + + template + std::vector> + Composition::get_property_information() const + { + + AssertThrow(this->n_compositional_fields() > 0, + ExcMessage("You have requested the particle property , " + "but the number of compositional fields is 0. " + "Please add compositional fields to your model, or remove " + "this particle property.")); + + std::vector> property_information; + + + + for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) + { + const std::string field_name = this->introspection().name_for_compositional_index(i); + property_information.emplace_back(field_name,1); + } + return property_information; + } + + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(Composition, + "composition", + "Implementation of a plugin in which the particle " + "property is defined by the compositional fields in " + "the model. This can be used to track solid composition" + "evolution over time.") + } + } +} diff --git a/source/particle/property/cpo_bingham_average.cc.bak b/source/particle/property/cpo_bingham_average.cc.bak new file mode 100644 index 00000000000..8ccba63ae27 --- /dev/null +++ b/source/particle/property/cpo_bingham_average.cc.bak @@ -0,0 +1,284 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + void + CpoBinghamAverage::initialize () + { + const unsigned int my_rank = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); + this->random_number_generator.seed(random_number_seed+my_rank); + const auto &manager = this->get_particle_world(this->get_particle_world_index()).get_property_manager(); + AssertThrow(manager.plugin_name_exists("crystal preferred orientation"), + ExcMessage("No crystal preferred orientation property plugin found.")); + + AssertThrow(manager.check_plugin_order("crystal preferred orientation","cpo bingham average"), + ExcMessage("To use the cpo bingham average plugin, the cpo plugin need to be defined before this plugin.")); + + cpo_data_position = manager.get_data_info().get_position_by_plugin_index(manager.get_plugin_index_by_name("crystal preferred orientation")); + + } + + + + template + void + CpoBinghamAverage::initialize_one_particle_property(const Point &, + std::vector &data) const + { + std::vector volume_fractions_grains(n_grains); + std::vector> rotation_matrices_grains(n_grains); + for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) + { + // create volume fractions and rotation matrix vectors in the order that it is stored in the data array + for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) + { + volume_fractions_grains[grain_i] = cpo_particle_property->get_volume_fractions_grains(cpo_data_position,data,mineral_i,grain_i); + rotation_matrices_grains[grain_i] = cpo_particle_property->get_rotation_matrix_grains(cpo_data_position,data,mineral_i,grain_i); + } + + const std::vector> weighted_rotation_matrices = + Utilities::rotation_matrices_random_draw_volume_weighting(volume_fractions_grains, + rotation_matrices_grains, + n_samples, + this->random_number_generator); + const std::array,3> bingham_average = compute_bingham_average(weighted_rotation_matrices); + + for (unsigned int i = 0; i < 3; ++i) + for (unsigned int j = 0; j < 6; ++j) + data.emplace_back(bingham_average[i][j]); + } + } + + + + template + void + CpoBinghamAverage::update_particle_property(const unsigned int data_position, + const Vector &/*solution*/, + const std::vector> &/*gradients*/, + typename ParticleHandler::particle_iterator &particle) const + { + std::vector volume_fractions_grains(n_grains); + std::vector> rotation_matrices_grains(n_grains); + ArrayView data = particle->get_properties(); + for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) + { + // create volume fractions and rotation matrix vectors in the order that it is stored in the data array + for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) + { + volume_fractions_grains[grain_i] = cpo_particle_property->get_volume_fractions_grains(cpo_data_position,data,mineral_i,grain_i); + rotation_matrices_grains[grain_i] = cpo_particle_property->get_rotation_matrix_grains(cpo_data_position,data,mineral_i,grain_i); + } + + const std::vector> weighted_rotation_matrices = Utilities::rotation_matrices_random_draw_volume_weighting(volume_fractions_grains, rotation_matrices_grains, n_samples, this->random_number_generator); + std::array,3> bingham_average = compute_bingham_average(weighted_rotation_matrices); + + for (unsigned int i = 0; i < 3; ++i) + for (unsigned int j = 0; j < 6; ++j) + { + data[data_position + mineral_i*18 + i*3 + j] = bingham_average[i][j]; + } + } + } + + + + template + std::array,3> + CpoBinghamAverage::compute_bingham_average(std::vector> matrices) const + { + SymmetricTensor<2,3> sum_matrix_a; + SymmetricTensor<2,3> sum_matrix_b; + SymmetricTensor<2,3> sum_matrix_c; + + // extracting the a, b and c orientations from the olivine a matrix + // see https://courses.eas.ualberta.ca/eas421/lecturepages/orientation.html + const unsigned int n_matrices = matrices.size(); + for (unsigned int i_grain = 0; i_grain < n_matrices; ++i_grain) + { + sum_matrix_a[0][0] += matrices[i_grain][0][0] * matrices[i_grain][0][0]; // SUM(l^2) + sum_matrix_a[1][1] += matrices[i_grain][0][1] * matrices[i_grain][0][1]; // SUM(m^2) + sum_matrix_a[2][2] += matrices[i_grain][0][2] * matrices[i_grain][0][2]; // SUM(n^2) + sum_matrix_a[0][1] += matrices[i_grain][0][0] * matrices[i_grain][0][1]; // SUM(l*m) + sum_matrix_a[0][2] += matrices[i_grain][0][0] * matrices[i_grain][0][2]; // SUM(l*n) + sum_matrix_a[1][2] += matrices[i_grain][0][1] * matrices[i_grain][0][2]; // SUM(m*n) + + + sum_matrix_b[0][0] += matrices[i_grain][1][0] * matrices[i_grain][1][0]; // SUM(l^2) + sum_matrix_b[1][1] += matrices[i_grain][1][1] * matrices[i_grain][1][1]; // SUM(m^2) + sum_matrix_b[2][2] += matrices[i_grain][1][2] * matrices[i_grain][1][2]; // SUM(n^2) + sum_matrix_b[0][1] += matrices[i_grain][1][0] * matrices[i_grain][1][1]; // SUM(l*m) + sum_matrix_b[0][2] += matrices[i_grain][1][0] * matrices[i_grain][1][2]; // SUM(l*n) + sum_matrix_b[1][2] += matrices[i_grain][1][1] * matrices[i_grain][1][2]; // SUM(m*n) + + + sum_matrix_c[0][0] += matrices[i_grain][2][0] * matrices[i_grain][2][0]; // SUM(l^2) + sum_matrix_c[1][1] += matrices[i_grain][2][1] * matrices[i_grain][2][1]; // SUM(m^2) + sum_matrix_c[2][2] += matrices[i_grain][2][2] * matrices[i_grain][2][2]; // SUM(n^2) + sum_matrix_c[0][1] += matrices[i_grain][2][0] * matrices[i_grain][2][1]; // SUM(l*m) + sum_matrix_c[0][2] += matrices[i_grain][2][0] * matrices[i_grain][2][2]; // SUM(l*n) + sum_matrix_c[1][2] += matrices[i_grain][2][1] * matrices[i_grain][2][2]; // SUM(m*n) + + } + const std::array>, 3> eigenvectors_a = eigenvectors(sum_matrix_a, SymmetricTensorEigenvectorMethod::jacobi); + const std::array>, 3> eigenvectors_b = eigenvectors(sum_matrix_b, SymmetricTensorEigenvectorMethod::jacobi); + const std::array>, 3> eigenvectors_c = eigenvectors(sum_matrix_c, SymmetricTensorEigenvectorMethod::jacobi); + + // average axis = eigenvector * largest eigenvalue + const Tensor<1,3,double> averaged_a = eigenvectors_a[0].second * eigenvectors_a[0].first; + const Tensor<1,3,double> averaged_b = eigenvectors_b[0].second * eigenvectors_b[0].first; + const Tensor<1,3,double> averaged_c = eigenvectors_c[0].second * eigenvectors_a[0].first; + + // eigenvalues of all axes, used in the anisotropic viscosity material model to compute Hill's coefficients + const double eigenvalue_a1 = eigenvectors_a[0].first/matrices.size(); + const double eigenvalue_a2 = eigenvectors_a[1].first/matrices.size(); + const double eigenvalue_a3 = eigenvectors_a[2].first/matrices.size(); + const double eigenvalue_b1 = eigenvectors_b[0].first/matrices.size(); + const double eigenvalue_b2 = eigenvectors_b[1].first/matrices.size(); + const double eigenvalue_b3 = eigenvectors_b[2].first/matrices.size(); + const double eigenvalue_c1 = eigenvectors_c[0].first/matrices.size(); + const double eigenvalue_c2 = eigenvectors_c[1].first/matrices.size(); + const double eigenvalue_c3 = eigenvectors_c[2].first/matrices.size(); + + return + { + { + {{averaged_a[0],averaged_a[1],averaged_a[2], eigenvalue_a1, eigenvalue_a2, eigenvalue_a3}}, + {{averaged_b[0],averaged_b[1],averaged_b[2], eigenvalue_b1, eigenvalue_b2, eigenvalue_b3}}, + {{averaged_c[0],averaged_c[1],averaged_c[2], eigenvalue_c1, eigenvalue_c2, eigenvalue_c3}} + } + }; + + } + + + + template + UpdateTimeFlags + CpoBinghamAverage::need_update() const + { + return update_output_step; + } + + + + template + UpdateFlags + CpoBinghamAverage::get_needed_update_flags () const + { + return update_default; + } + + + + template + std::vector> + CpoBinghamAverage::get_property_information() const + { + std::vector> property_information; + property_information.reserve(6*n_minerals); + for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) + { + property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " bingham average a axis",3); + property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " eigenvalues a axis",3); + property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " bingham average b axis",3); + property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " eigenvalues b axis",3); + property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " bingham average c axis",3); + property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " eigenvalues c axis",3); + } + + return property_information; + } + + + + template + void + CpoBinghamAverage::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("CPO Bingham Average"); + { + prm.declare_entry ("Random number seed", "1", + Patterns::Integer (0), + "The seed used to generate random numbers. This will make sure that " + "results are reproducible as long as the problem is run with the " + "same amount of MPI processes. It is implemented as final seed = " + "Random number seed + MPI Rank. "); + + prm.declare_entry ("Number of samples", "0", + Patterns::Double(0), + "This determines how many samples are taken when using the random " + "draw volume averaging. Setting it to zero means that the number of " + "samples is set to be equal to the number of grains."); + } + prm.leave_subsection (); + } + + + + template + void + CpoBinghamAverage::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("CPO Bingham Average"); + { + // Get a pointer to the CPO particle property. + cpo_particle_property = std::make_unique> ( + this->get_particle_world(this->get_particle_world_index()).get_property_manager().template get_matching_property>()); + + random_number_seed = prm.get_integer ("Random number seed"); + n_grains = cpo_particle_property->get_number_of_grains(); + n_minerals = cpo_particle_property->get_number_of_minerals(); + n_samples = prm.get_integer("Number of samples"); + if (n_samples == 0) + n_samples = n_grains; + } + prm.leave_subsection (); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(CpoBinghamAverage, + "cpo bingham average", + "This is a particle property plugin which computes the Bingham " + "average for the Crystal Preferred Orientation particle property " + "plugin so that it can be visualized.") + } + } +} diff --git a/source/particle/property/cpo_elastic_tensor.cc.bak b/source/particle/property/cpo_elastic_tensor.cc.bak new file mode 100644 index 00000000000..e15c4436b70 --- /dev/null +++ b/source/particle/property/cpo_elastic_tensor.cc.bak @@ -0,0 +1,261 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + + + template + CpoElasticTensor::CpoElasticTensor () + { + // The following values are directly from D-Rex. + // Todo: make them a input parameter + // Stiffness matrix for Olivine (GigaPascals) + stiffness_matrix_olivine[0][0] = 320.71; + stiffness_matrix_olivine[0][1] = 69.84; + stiffness_matrix_olivine[0][2] = 71.22; + stiffness_matrix_olivine[1][1] = 197.25; + stiffness_matrix_olivine[1][2] = 74.8; + stiffness_matrix_olivine[2][2] = 234.32; + stiffness_matrix_olivine[3][3] = 63.77; + stiffness_matrix_olivine[4][4] = 77.67; + stiffness_matrix_olivine[5][5] = 78.36; + + + // Stiffness matrix for Enstatite (GPa) + stiffness_matrix_enstatite[0][0] = 236.9; + stiffness_matrix_enstatite[0][1] = 79.6; + stiffness_matrix_enstatite[0][2] = 63.2; + stiffness_matrix_enstatite[1][1] = 180.5; + stiffness_matrix_enstatite[1][2] = 56.8; + stiffness_matrix_enstatite[2][2] = 230.4; + stiffness_matrix_enstatite[3][3] = 84.3; + stiffness_matrix_enstatite[4][4] = 79.4; + stiffness_matrix_enstatite[5][5] = 80.1; + } + + + + template + void + CpoElasticTensor::initialize () + { + const auto &manager = this->get_particle_world(this->get_particle_world_index()).get_property_manager(); + AssertThrow(manager.plugin_name_exists("crystal preferred orientation"), + ExcMessage("No crystal preferred orientation property plugin found.")); + + AssertThrow(manager.check_plugin_order("crystal preferred orientation","cpo elastic tensor"), + ExcMessage("To use the cpo elastic tensor plugin, the cpo plugin needs to be defined before this plugin.")); + + cpo_data_position = manager.get_data_info().get_position_by_plugin_index(manager.get_plugin_index_by_name("crystal preferred orientation")); + } + + + + template + SymmetricTensor<2,6> + CpoElasticTensor::voigt_average_elastic_tensor (const Particle::Property::CrystalPreferredOrientation &cpo_particle_property, + const unsigned int cpo_data_position, + const ArrayView &data) const + { + SymmetricTensor<2,6> C_average; + const SymmetricTensor<2,6> *stiffness_matrix = &stiffness_matrix_olivine; + for (size_t mineral_i = 0; mineral_i < n_minerals; ++mineral_i) + { + if (cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i) == DeformationType::olivine_a_fabric + || cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i) == DeformationType::olivine_b_fabric + || cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i) == DeformationType::olivine_d_fabric + || cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i) == DeformationType::olivine_c_fabric + || cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i) == DeformationType::olivine_e_fabric + ) + { + stiffness_matrix = &stiffness_matrix_olivine; + } + else if (cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i) == DeformationType::enstatite) + { + stiffness_matrix = &stiffness_matrix_enstatite; + } + else + { + AssertThrow(false, ExcMessage("Stiffness matrix not implemented for deformation type " + + std::to_string(static_cast(cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i))))); + } + + for (size_t grain_i = 0; grain_i < n_grains; grain_i++) + { + const auto rotated_matrix = Utilities::Tensors::rotate_voigt_stiffness_matrix(transpose(cpo_particle_property.get_rotation_matrix_grains(cpo_data_position,data,mineral_i,grain_i)),*stiffness_matrix); + C_average += cpo_particle_property.get_volume_fractions_grains(cpo_data_position,data,mineral_i,grain_i) * cpo_particle_property.get_volume_fraction_mineral(cpo_data_position,data,mineral_i) * rotated_matrix; + } + } + + return C_average; + } + + + + template + void + CpoElasticTensor::initialize_one_particle_property(const Point &, + std::vector &data) const + { + + // At initialization, the deformation type for cpo is initialized to -1. + // Initialize with the stiffness matrix of olivine to avoid errors in the computation. + + for (unsigned int i = 0; i < SymmetricTensor<2,6>::n_independent_components ; ++i) + { + data.push_back(stiffness_matrix_olivine[SymmetricTensor<2,6>::unrolled_to_component_indices(i)]); + } + + + } + + + + template + void + CpoElasticTensor::update_particle_property(const unsigned int data_position, + const Vector &/*solution*/, + const std::vector> &/*gradients*/, + typename ParticleHandler::particle_iterator &particle) const + { + // Get a reference to the CPO particle property. + const Particle::Property::CrystalPreferredOrientation &cpo_particle_property = + this->get_particle_world(this->get_particle_world_index()).get_property_manager().template get_matching_property>(); + + + const SymmetricTensor<2,6> C_average = voigt_average_elastic_tensor(cpo_particle_property, + cpo_data_position, + particle->get_properties()); + + Particle::Property::CpoElasticTensor::set_elastic_tensor(data_position, + particle->get_properties(), + C_average); + + + } + + + + template + SymmetricTensor<2,6> + CpoElasticTensor::get_elastic_tensor(unsigned int cpo_data_position, + const ArrayView &data) + { + return Utilities::Tensors::to_symmetric_tensor<6>(&data[cpo_data_position], + &data[cpo_data_position]+SymmetricTensor<2,6>::n_independent_components); + } + + + + template + void + CpoElasticTensor::set_elastic_tensor(unsigned int cpo_data_position, + const ArrayView &data, + const SymmetricTensor<2,6> &elastic_tensor) + { + Utilities::Tensors::unroll_symmetric_tensor_into_array(elastic_tensor, + &data[cpo_data_position], + &data[cpo_data_position]+SymmetricTensor<2,6>::n_independent_components); + } + + + + template + UpdateTimeFlags + CpoElasticTensor::need_update() const + { + return update_output_step; + } + + + + template + UpdateFlags + CpoElasticTensor::get_needed_update_flags () const + { + return update_default; + } + + + + template + std::vector> + CpoElasticTensor::get_property_information() const + { + std::vector> property_information; + + property_information.emplace_back("cpo_elastic_tensor", SymmetricTensor<2,6>::n_independent_components); + return property_information; + } + + + + template + void + CpoElasticTensor::declare_parameters (ParameterHandler &) + {} + + + + template + void + CpoElasticTensor::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Crystal Preferred Orientation"); + { + n_grains = prm.get_integer("Number of grains per particle"); + prm.enter_subsection("Initial grains"); + { + n_minerals = dealii::Utilities::split_string_list(prm.get("Minerals")).size(); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(CpoElasticTensor, + "cpo elastic tensor", + "A plugin in which the particle property tensor is " + "defined as the Voigt average of the " + "elastic tensors of the minerals in the textured rock." + "Currently only Olivine and Enstatite are supported.") + } + } +} diff --git a/source/particle/property/crystal_preferred_orientation.cc b/source/particle/property/crystal_preferred_orientation.cc index 3f849f0ca4d..58aab2dfdcb 100644 --- a/source/particle/property/crystal_preferred_orientation.cc +++ b/source/particle/property/crystal_preferred_orientation.cc @@ -139,7 +139,7 @@ namespace aspect // // Note that we store exactly the same number of grains of all minerals (e.g. olivine and enstatite // grains), although their volume fractions may not be the same. We need a minimum amount - // of grains per tracer to perform reliable statistics on it. This minimum is the same for all phases. + // of grains per particle to perform reliable statistics on it. This minimum is the same for all phases. // and enstatite. // // Furthermore, for this plugin the following dims are always 3. When using 2d an infinitely thin 3d domain is assumed. diff --git a/source/particle/property/crystal_preferred_orientation.cc.bak b/source/particle/property/crystal_preferred_orientation.cc.bak new file mode 100644 index 00000000000..3f849f0ca4d --- /dev/null +++ b/source/particle/property/crystal_preferred_orientation.cc.bak @@ -0,0 +1,1275 @@ +/* + Copyright (C) 2022 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + + template + void + CrystalPreferredOrientation::initialize () + { + CitationInfo::add("CPO"); + const unsigned int my_rank = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); + this->random_number_generator.seed(random_number_seed+my_rank); + + // Don't assert when called by the unit tester. + if (this->simulator_is_past_initialization()) + { + AssertThrow(this->introspection().compositional_name_exists("water"), + ExcMessage("Particle property CPO only works if" + "there is a compositional field called water.")); + water_index = this->introspection().compositional_index_for_name("water"); + } + } + + + + template + void + CrystalPreferredOrientation::compute_random_rotation_matrix(Tensor<2,3> &rotation_matrix) const + { + + // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120). + // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c + // and is licenced according to this website with the following licence: + // + // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and + // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit + // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems + // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, + // don't be a jerk, and remember that anything free comes with no guarantee."" + // + // The book states in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in + // the public domain, and is yours to study, modify, and use." + + // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2. + + boost::random::uniform_real_distribution uniform_distribution(0,1); + double one = uniform_distribution(this->random_number_generator); + double two = uniform_distribution(this->random_number_generator); + double three = uniform_distribution(this->random_number_generator); + + double theta = 2.0 * M_PI * one; // Rotation about the pole (Z) + double phi = 2.0 * M_PI * two; // For direction of pole deflection. + double z = 2.0* three; //For magnitude of pole deflection. + + // Compute a vector V used for distributing points over the sphere + // via the reflection I - V Transpose(V). This formulation of V + // will guarantee that if x[1] and x[2] are uniformly distributed, + // the reflected points will be uniform on the sphere. Note that V + // has length sqrt(2) to eliminate the 2 in the Householder matrix. + + double r = std::sqrt( z ); + double Vx = std::sin( phi ) * r; + double Vy = std::cos( phi ) * r; + double Vz = std::sqrt( 2.f - z ); + + // Compute the row vector S = Transpose(V) * R, where R is a simple + // rotation by theta about the z-axis. No need to compute Sz since + // it's just Vz. + + double st = std::sin( theta ); + double ct = std::cos( theta ); + double Sx = Vx * ct - Vy * st; + double Sy = Vx * st + Vy * ct; + + // Construct the rotation matrix ( V Transpose(V) - I ) R, which + // is equivalent to V S - R. + + rotation_matrix[0][0] = Vx * Sx - ct; + rotation_matrix[0][1] = Vx * Sy - st; + rotation_matrix[0][2] = Vx * Vz; + rotation_matrix[1][0] = Vy * Sx + st; + rotation_matrix[1][1] = Vy * Sy - ct; + rotation_matrix[1][2] = Vy * Vz; + rotation_matrix[2][0] = Vz * Sx; + rotation_matrix[2][1] = Vz * Sy; + rotation_matrix[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0 + } + + + + template + void + CrystalPreferredOrientation::initialize_one_particle_property(const Point &position, + std::vector &data) const + { + // the layout of the data vector per particle is the following: + // 1. M mineral times + // 1.1 olivine deformation type -> 1 double, at location + // => data_position + 0 + mineral_i * (n_grains * 10 + 2) + // 2.1. Mineral volume fraction -> 1 double, at location + // => data_position + 1 + mineral_i *(n_grains * 10 + 2) + // 2.2. N grains times: + // 2.1. volume fraction grain -> 1 double, at location: + // => data_position + 2 + i_grain * 10 + mineral_i *(n_grains * 10 + 2), or + // => data_position + 2 + i_grain * (2 * Tensor<2,3>::n_independent_components+ 2) + mineral_i * (n_grains * 10 + 2) + // 2.2. rotation matrix grain -> 9 (Tensor<2,dim>::n_independent_components) doubles, starts at: + // => data_position + 3 + i_grain * 10 + mineral_i * (n_grains * 10 + 2), or + // => data_position + 3 + i_grain * (2 * Tensor<2,3>::n_independent_components+ 2) + mineral_i * (n_grains * 10 + 2) + // + // Note that we store exactly the same number of grains of all minerals (e.g. olivine and enstatite + // grains), although their volume fractions may not be the same. We need a minimum amount + // of grains per tracer to perform reliable statistics on it. This minimum is the same for all phases. + // and enstatite. + // + // Furthermore, for this plugin the following dims are always 3. When using 2d an infinitely thin 3d domain is assumed. + // + // The rotation matrix is a direction cosine matrix, representing the orientation of the grain in the domain. + // The fabric is determined later in the computations, so initialize it to -1. + std::vector deformation_type(n_minerals, -1.0); + std::vector>volume_fractions_grains(n_minerals); + std::vector>> rotation_matrices_grains(n_minerals); + + for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) + { + volume_fractions_grains[mineral_i].resize(n_grains); + rotation_matrices_grains[mineral_i].resize(n_grains); + + // This will be set by the initial grain subsection. + if (initial_grains_model == CPOInitialGrainsModel::world_builder) + { +#ifdef ASPECT_WITH_WORLD_BUILDER + WorldBuilder::grains wb_grains = this->get_world_builder().grains(Utilities::convert_point_to_array(position), + -this->get_geometry_model().height_above_reference_surface(position), + mineral_i, + n_grains); + double sum_volume_fractions = 0; + for (unsigned int grain_i = 0; grain_i < n_grains ; ++grain_i) + { + sum_volume_fractions += wb_grains.sizes[grain_i]; + volume_fractions_grains[mineral_i][grain_i] = wb_grains.sizes[grain_i]; + // we are receiving a array,3> from the world builder, + // which needs to be copied in the correct way into a tensor<2,3>. + for (unsigned int component_i = 0; component_i < 3 ; ++component_i) + { + for (unsigned int component_j = 0; component_j < 3 ; ++component_j) + { + Assert(!std::isnan(wb_grains.rotation_matrices[grain_i][component_i][component_j]), ExcMessage("Error: not a number.")); + rotation_matrices_grains[mineral_i][grain_i][component_i][component_j] = wb_grains.rotation_matrices[grain_i][component_i][component_j]; + } + } + } + + AssertThrow(sum_volume_fractions != 0, ExcMessage("Sum of volumes is equal to zero, which is not supposed to happen. " + "Make sure that all parts of the domain which contain particles are covered by the world builder.")); +#else + AssertThrow(false, + ExcMessage("The world builder was requested but not provided. Make sure that aspect is " + "compiled with the World Builder and that you provide a world builder file in the input.")); +#endif + } + else + { + // set volume fraction + const double initial_volume_fraction = 1.0/n_grains; + + for (unsigned int grain_i = 0; grain_i < n_grains ; ++grain_i) + { + // set volume fraction + volume_fractions_grains[mineral_i][grain_i] = initial_volume_fraction; + + // set a uniform random rotation_matrix per grain + this->compute_random_rotation_matrix(rotation_matrices_grains[mineral_i][grain_i]); + } + } + } + + for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) + { + data.emplace_back(deformation_type[mineral_i]); + data.emplace_back(volume_fractions_minerals[mineral_i]); + for (unsigned int grain_i = 0; grain_i < n_grains ; ++grain_i) + { + data.emplace_back(volume_fractions_grains[mineral_i][grain_i]); + for (unsigned int i = 0; i < Tensor<2,3>::n_independent_components ; ++i) + { + const dealii::TableIndices<2> index = Tensor<2,3>::unrolled_to_component_indices(i); + data.emplace_back(rotation_matrices_grains[mineral_i][grain_i][index]); + } + } + } + } + + + + template + void + CrystalPreferredOrientation::update_particle_property(const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const + { + // STEP 1: Load data and preprocess it. + + // need access to the pressure, viscosity, + // get velocity + Tensor<1,dim> velocity; + for (unsigned int i = 0; i < dim; ++i) + velocity[i] = solution[this->introspection().component_indices.velocities[i]]; + + // get velocity gradient tensor. + Tensor<2,dim> velocity_gradient; + for (unsigned int i = 0; i < dim; ++i) + velocity_gradient[i] = gradients[this->introspection().component_indices.velocities[i]]; + + // Calculate strain rate from velocity gradients + const SymmetricTensor<2,dim> strain_rate = symmetrize (velocity_gradient); + const SymmetricTensor<2,dim> deviatoric_strain_rate + = (this->get_material_model().is_compressible() + ? + strain_rate - 1./3 * trace(strain_rate) * unit_symmetric_tensor() + : + strain_rate); + + const double pressure = solution[this->introspection().component_indices.pressure]; + const double temperature = solution[this->introspection().component_indices.temperature]; + const double water_content = solution[this->introspection().component_indices.compositional_fields[water_index]]; + + // get the composition of the particle + std::vector compositions; + for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) + { + const unsigned int solution_component = this->introspection().component_indices.compositional_fields[i]; + compositions.push_back(solution[solution_component]); + } + + const double dt = this->get_timestep(); + + // even in 2d we need 3d strain-rates and velocity gradient tensors. So we make them 3d by + // adding an extra dimension which is zero. + SymmetricTensor<2,3> strain_rate_3d; + strain_rate_3d[0][0] = strain_rate[0][0]; + strain_rate_3d[0][1] = strain_rate[0][1]; + //sym: strain_rate_3d[1][0] = strain_rate[1][0]; + strain_rate_3d[1][1] = strain_rate[1][1]; + + if (dim == 3) + { + strain_rate_3d[0][2] = strain_rate[0][2]; + strain_rate_3d[1][2] = strain_rate[1][2]; + //sym: strain_rate_3d[2][0] = strain_rate[0][2]; + //sym: strain_rate_3d[2][1] = strain_rate[1][2]; + strain_rate_3d[2][2] = strain_rate[2][2]; + } + Tensor<2,3> velocity_gradient_3d; + velocity_gradient_3d[0][0] = velocity_gradient[0][0]; + velocity_gradient_3d[0][1] = velocity_gradient[0][1]; + velocity_gradient_3d[1][0] = velocity_gradient[1][0]; + velocity_gradient_3d[1][1] = velocity_gradient[1][1]; + if (dim == 3) + { + velocity_gradient_3d[0][2] = velocity_gradient[0][2]; + velocity_gradient_3d[1][2] = velocity_gradient[1][2]; + velocity_gradient_3d[2][0] = velocity_gradient[2][0]; + velocity_gradient_3d[2][1] = velocity_gradient[2][1]; + velocity_gradient_3d[2][2] = velocity_gradient[2][2]; + } + + ArrayView data = particle->get_properties(); + + for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) + { + + /** + * Now we have loaded all the data and can do the actual computation. + * The computation consists of two parts. The first part is computing + * the derivatives for the directions and grain sizes. Then those + * derivatives are used to advect the particle properties. + */ + double sum_volume_mineral = 0; + std::pair, std::vector>> + derivatives_grains = this->compute_derivatives(data_position, + data, + mineral_i, + strain_rate_3d, + velocity_gradient_3d, + particle->get_location(), + temperature, + pressure, + velocity, + compositions, + strain_rate, + deviatoric_strain_rate, + water_content); + + switch (advection_method) + { + case AdvectionMethod::forward_euler: + + sum_volume_mineral = this->advect_forward_euler(data_position, + data, + mineral_i, + dt, + derivatives_grains); + + break; + + case AdvectionMethod::backward_euler: + sum_volume_mineral = this->advect_backward_euler(data_position, + data, + mineral_i, + dt, + derivatives_grains); + + break; + } + + // normalize the volume fractions back to a total of 1 for each mineral + const double inv_sum_volume_mineral = 1.0/sum_volume_mineral; + + Assert(std::isfinite(inv_sum_volume_mineral), + ExcMessage("inv_sum_volume_mineral is not finite. sum_volume_enstatite = " + + std::to_string(sum_volume_mineral))); + + for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) + { + const double volume_fraction_grains = get_volume_fractions_grains(data_position,data,mineral_i,grain_i)*inv_sum_volume_mineral; + set_volume_fractions_grains(data_position,data,mineral_i,grain_i,volume_fraction_grains); + Assert(isfinite(get_volume_fractions_grains(data_position,data,mineral_i,grain_i)), + ExcMessage("volume_fractions_grains[mineral_i]" + std::to_string(grain_i) + "] is not finite: " + + std::to_string(get_volume_fractions_grains(data_position,data,mineral_i,grain_i)) + ", inv_sum_volume_mineral = " + + std::to_string(inv_sum_volume_mineral) + ".")); + + /** + * Correct direction rotation matrices numerical error (orthnormality) after integration + * Follows same method as in matlab version from Thissen (see https://github.com/cthissen/Drex-MATLAB/) + * of finding the nearest orthonormal matrix using the SVD + */ + Tensor<2,3> rotation_matrix = get_rotation_matrix_grains(data_position,data,mineral_i,grain_i); + for (size_t i = 0; i < 3; ++i) + { + for (size_t j = 0; j < 3; ++j) + { + Assert(!std::isnan(rotation_matrix[i][j]), ExcMessage("rotation_matrix is nan before orthogonalization.")); + } + } + + rotation_matrix = dealii::project_onto_orthogonal_tensors(rotation_matrix); + for (size_t i = 0; i < 3; ++i) + for (size_t j = 0; j < 3; ++j) + { + // I don't think this should happen with the projection, but D-Rex + // does not do the orthogonal projection, but just clamps the values + // to 1 and -1. + Assert(std::fabs(rotation_matrix[i][j]) <= 1.0, + ExcMessage("The rotation_matrix has a entry larger than 1.")); + + Assert(!std::isnan(rotation_matrix[i][j]), + ExcMessage("rotation_matrix is nan after orthoganalization: " + + std::to_string(rotation_matrix[i][j]))); + + Assert(abs(rotation_matrix[i][j]) <= 1.0, + ExcMessage("3. rotation_matrix[" + std::to_string(i) + "][" + std::to_string(j) + + "] is larger than one: " + + std::to_string(rotation_matrix[i][j]) + " (" + std::to_string(rotation_matrix[i][j]-1.0) + "). rotation_matrix = \n" + + std::to_string(rotation_matrix[0][0]) + " " + std::to_string(rotation_matrix[0][1]) + " " + std::to_string(rotation_matrix[0][2]) + "\n" + + std::to_string(rotation_matrix[1][0]) + " " + std::to_string(rotation_matrix[1][1]) + " " + std::to_string(rotation_matrix[1][2]) + "\n" + + std::to_string(rotation_matrix[2][0]) + " " + std::to_string(rotation_matrix[2][1]) + " " + std::to_string(rotation_matrix[2][2]))); + } + } + } + } + + + + template + UpdateTimeFlags + CrystalPreferredOrientation::need_update() const + { + return update_time_step; + } + + + + template + InitializationModeForLateParticles + CrystalPreferredOrientation::late_initialization_mode () const + { + return InitializationModeForLateParticles::interpolate; + } + + + + template + UpdateFlags + CrystalPreferredOrientation::get_needed_update_flags () const + { + return update_values | update_gradients; + } + + + + template + std::vector> + CrystalPreferredOrientation::get_property_information() const + { + std::vector> property_information; + property_information.reserve(n_minerals * n_grains * (1+Tensor<2,3>::n_independent_components)); + + for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) + { + property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " type",1); + property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " volume fraction",1); + + for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) + { + property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " grain " + std::to_string(grain_i) + " volume fraction",1); + + for (unsigned int index = 0; index < Tensor<2,3>::n_independent_components; ++index) + { + property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " grain " + std::to_string(grain_i) + " rotation_matrix " + std::to_string(index),1); + } + } + } + + return property_information; + } + + + + template + double + CrystalPreferredOrientation::advect_forward_euler(const unsigned int cpo_index, + const ArrayView &data, + const unsigned int mineral_i, + const double dt, + const std::pair, std::vector>> &derivatives) const + { + double sum_volume_fractions = 0; + Tensor<2,3> rotation_matrix; + for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) + { + // Do the volume fraction of the grain + Assert(std::isfinite(get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i)),ExcMessage("volume_fractions[grain_i] is not finite before it is set.")); + double volume_fraction_grains = get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i); + volume_fraction_grains = volume_fraction_grains + dt * volume_fraction_grains * derivatives.first[grain_i]; + set_volume_fractions_grains(cpo_index,data,mineral_i,grain_i, volume_fraction_grains); + Assert(std::isfinite(get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i)),ExcMessage("volume_fractions[grain_i] is not finite. grain_i = " + + std::to_string(grain_i) + ", volume_fractions[grain_i] = " + std::to_string(get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i)) + + ", derivatives.first[grain_i] = " + std::to_string(derivatives.first[grain_i]))); + + sum_volume_fractions += get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i); + + // Do the rotation matrix for this grain + rotation_matrix = get_rotation_matrix_grains(cpo_index,data,mineral_i,grain_i); + rotation_matrix += dt * rotation_matrix * derivatives.second[grain_i]; + set_rotation_matrix_grains(cpo_index,data,mineral_i,grain_i,rotation_matrix); + } + + Assert(sum_volume_fractions != 0, ExcMessage("The sum of all grain volume fractions of a mineral is equal to zero. This should not happen.")); + return sum_volume_fractions; + } + + + + template + double + CrystalPreferredOrientation::advect_backward_euler(const unsigned int cpo_index, + const ArrayView &data, + const unsigned int mineral_i, + const double dt, + const std::pair, std::vector>> &derivatives) const + { + double sum_volume_fractions = 0; + Tensor<2,3> cosine_ref; + for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) + { + // Do the volume fraction of the grain + double vf_old = get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i); + double vf_new = get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i); + Assert(std::isfinite(vf_new),ExcMessage("vf_new is not finite before it is set.")); + for (size_t iteration = 0; iteration < property_advection_max_iterations; ++iteration) + { + Assert(std::isfinite(vf_new),ExcMessage("vf_new is not finite before it is set. grain_i = " + + std::to_string(grain_i) + ", volume_fractions[grain_i] = " + std::to_string(get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i)) + + ", derivatives.first[grain_i] = " + std::to_string(derivatives.first[grain_i]))); + + vf_new = get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i) + dt * vf_new * derivatives.first[grain_i]; + + Assert(std::isfinite(get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i)),ExcMessage("volume_fractions[grain_i] is not finite. grain_i = " + + std::to_string(grain_i) + ", volume_fractions[grain_i] = " + std::to_string(get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i)) + + ", derivatives.first[grain_i] = " + std::to_string(derivatives.first[grain_i]))); + if (std::fabs(vf_new-vf_old) < property_advection_tolerance) + { + break; + } + vf_old = vf_new; + } + + set_volume_fractions_grains(cpo_index,data,mineral_i,grain_i,vf_new); + sum_volume_fractions += vf_new; + + // Do the rotation matrix for this grain + cosine_ref = get_rotation_matrix_grains(cpo_index,data,mineral_i,grain_i); + Tensor<2,3> cosine_old = cosine_ref; + Tensor<2,3> cosine_new = cosine_ref; + + for (size_t iteration = 0; iteration < property_advection_max_iterations; ++iteration) + { + cosine_new = cosine_ref + dt * cosine_new * derivatives.second[grain_i]; + + if ((cosine_new-cosine_old).norm() < property_advection_tolerance) + { + break; + } + cosine_old = cosine_new; + } + + set_rotation_matrix_grains(cpo_index,data,mineral_i,grain_i,cosine_new); + + } + + + Assert(sum_volume_fractions != 0, ExcMessage("The sum of all grain volume fractions of a mineral is equal to zero. This should not happen.")); + return sum_volume_fractions; + } + + + + template + std::pair, std::vector>> + CrystalPreferredOrientation::compute_derivatives(const unsigned int cpo_index, + const ArrayView &data, + const unsigned int mineral_i, + const SymmetricTensor<2,3> &strain_rate_3d, + const Tensor<2,3> &velocity_gradient_tensor, + const Point &position, + const double temperature, + const double pressure, + const Tensor<1,dim> &velocity, + const std::vector &compositions, + const SymmetricTensor<2,dim> &strain_rate, + const SymmetricTensor<2,dim> &deviatoric_strain_rate, + const double water_content) const + { + std::pair, std::vector>> derivatives; + switch (cpo_derivative_algorithm) + { + case CPODerivativeAlgorithm::spin_tensor: + { + return compute_derivatives_spin_tensor(velocity_gradient_tensor); + break; + } + case CPODerivativeAlgorithm::drex_2004: + { + + const DeformationType deformation_type = determine_deformation_type(deformation_type_selector[mineral_i], + position, + temperature, + pressure, + velocity, + compositions, + strain_rate, + deviatoric_strain_rate, + water_content); + + set_deformation_type(cpo_index,data,mineral_i,deformation_type); + + const std::array ref_resolved_shear_stress = reference_resolved_shear_stress_from_deformation_type(deformation_type); + + return compute_derivatives_drex_2004(cpo_index, + data, + mineral_i, + strain_rate_3d, + velocity_gradient_tensor, + ref_resolved_shear_stress); + break; + } + default: + AssertThrow(false, ExcMessage("Internal error.")); + break; + } + AssertThrow(false, ExcMessage("Internal error.")); + return derivatives; + } + + + + template + std::pair, std::vector>> + CrystalPreferredOrientation::compute_derivatives_spin_tensor(const Tensor<2,3> &velocity_gradient_tensor) const + { + // dA/dt = W * A, where W is the spin tensor and A is the rotation matrix + // The spin tensor is defined as W = 0.5 * ( L - L^T ), where L is the velocity gradient tensor. + const Tensor<2,3> spin_tensor = -0.5 *(velocity_gradient_tensor - dealii::transpose(velocity_gradient_tensor)); + + return std::pair, std::vector>>(std::vector(n_grains,0.0), std::vector>(n_grains, spin_tensor)); + } + + + template + std::pair, std::vector>> + CrystalPreferredOrientation::compute_derivatives_drex_2004(const unsigned int cpo_index, + const ArrayView &data, + const unsigned int mineral_i, + const SymmetricTensor<2,3> &strain_rate_3d, + const Tensor<2,3> &velocity_gradient_tensor, + const std::array ref_resolved_shear_stress, + const bool prevent_nondimensionalization) const + { + // This if statement is only there for the unit test. In normal situations it should always be set to false, + // because the nondimensionalization should always be done (in this exact way), unless you really know what + // you are doing. + double nondimensionalization_value = 1.0; + if (!prevent_nondimensionalization) + { + const std::array< double, 3 > eigenvalues = dealii::eigenvalues(strain_rate_3d); + nondimensionalization_value = std::max(std::abs(eigenvalues[0]),std::abs(eigenvalues[2])); + + Assert(!std::isnan(nondimensionalization_value), ExcMessage("The second invariant of the strain rate is not a number.")); + } + + + // Make the strain-rate and velocity gradient tensor non-dimensional + // by dividing it through the second invariant + const Tensor<2,3> strain_rate_nondimensional = nondimensionalization_value != 0 ? strain_rate_3d/nondimensionalization_value : strain_rate_3d; + const Tensor<2,3> velocity_gradient_tensor_nondimensional = nondimensionalization_value != 0 ? velocity_gradient_tensor/nondimensionalization_value : velocity_gradient_tensor; + + // create output variables + std::vector deriv_volume_fractions(n_grains); + std::vector> deriv_a_cosine_matrices(n_grains); + + // create shortcuts + const std::array &tau = ref_resolved_shear_stress; + + std::vector strain_energy(n_grains); + double mean_strain_energy = 0; + + for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) + { + // Compute the Schmidt tensor for this grain (nu), s is the slip system. + // We first compute beta_s,nu (equation 5, Kaminski & Ribe, 2001) + // Then we use the beta to calculate the Schmidt tensor G_{ij} (Eq. 5, Kaminski & Ribe, 2001) + Tensor<2,3> G; + Tensor<1,3> w; + Tensor<1,4> beta({1.0, 1.0, 1.0, 1.0}); + std::array,4> slip_normal_reference {{Tensor<1,3>({0,1,0}),Tensor<1,3>({0,0,1}),Tensor<1,3>({0,1,0}),Tensor<1,3>({1,0,0})}}; + std::array,4> slip_direction_reference {{Tensor<1,3>({1,0,0}),Tensor<1,3>({1,0,0}),Tensor<1,3>({0,0,1}),Tensor<1,3>({0,0,1})}}; + + // these are variables we only need for olivine, but we need them for both + // within this if block and the next ones + // Ordered vector where the first entry is the max/weakest and the last entry is the inactive slip system. + std::array indices {}; + + // compute G and beta + Tensor<1,4> bigI; + const Tensor<2,3> rotation_matrix = get_rotation_matrix_grains(cpo_index,data,mineral_i,grain_i); + const Tensor<2,3> rotation_matrix_transposed = transpose(rotation_matrix); + for (unsigned int slip_system_i = 0; slip_system_i < 4; ++slip_system_i) + { + const Tensor<1,3> slip_normal_global = rotation_matrix_transposed*slip_normal_reference[slip_system_i]; + const Tensor<1,3> slip_direction_global = rotation_matrix_transposed*slip_direction_reference[slip_system_i]; + const Tensor<2,3> slip_cross_product = outer_product(slip_direction_global,slip_normal_global); + bigI[slip_system_i] = scalar_product(slip_cross_product,strain_rate_nondimensional); + } + + if (bigI.norm() < 1e-10) + { + // In this case there is no shear, only (possibly) a rotation. So \gamma_y and/or G should be zero. + // Which is the default value, so do nothing. + } + else + { + // compute the element wise absolute value of the element wise + // division of BigI by tau (tau = ref_resolved_shear_stress). + std::array q_abs; + for (unsigned int i = 0; i < 4; ++i) + { + q_abs[i] = std::abs(bigI[i] / tau[i]); + } + + // here we find the indices starting at the largest value and ending at the smallest value + // and assign them to special variables. Because all the variables are absolute values, + // we can set them to a negative value to ignore them. This should be faster then deleting + // the element, which would require allocation. (not tested) + for (unsigned int slip_system_i = 0; slip_system_i < 4; ++slip_system_i) + { + indices[slip_system_i] = std::distance(q_abs.begin(),std::max_element(q_abs.begin(), q_abs.end())); + q_abs[indices[slip_system_i]] = -1; + } + + // compute the ordered beta vector, which is the relative slip rates of the active slip systems. + // Test whether the max element is not equal to zero. + Assert(bigI[indices[0]] != 0.0, ExcMessage("Internal error: bigI is zero.")); + beta[indices[0]] = 1.0; // max q_abs, weak system (most deformation) "s=1" + + const double ratio = tau[indices[0]]/bigI[indices[0]]; + for (unsigned int slip_system_i = 1; slip_system_i < 4-1; ++slip_system_i) + { + beta[indices[slip_system_i]] = std::pow(std::abs(ratio * (bigI[indices[slip_system_i]]/tau[indices[slip_system_i]])), stress_exponent); + } + beta[indices.back()] = 0.0; + + // Now compute the crystal rate of deformation tensor. equation 4 of Kaminski&Ribe 2001 + // rotation_matrix_transposed = inverse of rotation matrix + // (see Engler et al., 2024 book: Intro to Texture analysis chp 2.3.2 The Rotation Matrix) + // this transform the crystal reference frame to specimen reference frame + for (unsigned int slip_system_i = 0; slip_system_i < 4; ++slip_system_i) + { + const Tensor<1,3> slip_normal_global = rotation_matrix_transposed*slip_normal_reference[slip_system_i]; + const Tensor<1,3> slip_direction_global = rotation_matrix_transposed*slip_direction_reference[slip_system_i]; + const Tensor<2,3> slip_cross_product = outer_product(slip_direction_global,slip_normal_global); + G += 2.0 * beta[slip_system_i] * slip_cross_product; + } + } + + // Now calculate the analytic solution to the deformation minimization problem + // compute gamma (equation 7, Kaminiski & Ribe, 2001) + + // Top is the numerator and bottom is the denominator in equation 7. + double top = 0; + double bottom = 0; + for (unsigned int i = 0; i < 3; ++i) + { + // Following the actual Drex implementation we use i+2, which differs + // from the EPSL paper, which says gamma_nu depends on i+1 + const unsigned int i_offset = (i==0) ? (i+2) : (i-1); + + top = top - (velocity_gradient_tensor_nondimensional[i][i_offset]-velocity_gradient_tensor_nondimensional[i_offset][i])*(G[i][i_offset]-G[i_offset][i]); + bottom = bottom - (G[i][i_offset]-G[i_offset][i])*(G[i][i_offset]-G[i_offset][i]); + + for (unsigned int j = 0; j < 3; ++j) + { + top = top + 2.0 * G[i][j]*velocity_gradient_tensor_nondimensional[i][j]; + bottom = bottom + 2.0* G[i][j] * G[i][j]; + } + } + // see comment on if all BigI are zero. In that case gamma should be zero. + const double gamma = (bottom != 0.0) ? top/bottom : 0.0; + + // compute w (equation 8, Kaminiski & Ribe, 2001) + // w is the Rotation rate vector of the crystallographic axes of grain + w[0] = 0.5*(velocity_gradient_tensor_nondimensional[2][1]-velocity_gradient_tensor_nondimensional[1][2]) - 0.5*(G[2][1]-G[1][2])*gamma; + w[1] = 0.5*(velocity_gradient_tensor_nondimensional[0][2]-velocity_gradient_tensor_nondimensional[2][0]) - 0.5*(G[0][2]-G[2][0])*gamma; + w[2] = 0.5*(velocity_gradient_tensor_nondimensional[1][0]-velocity_gradient_tensor_nondimensional[0][1]) - 0.5*(G[1][0]-G[0][1])*gamma; + + // Compute strain energy for this grain (abbreviated Estr) + // For olivine: DREX only sums over 1-3. But Christopher Thissen's matlab + // code (https://github.com/cthissen/Drex-MATLAB) corrected + // this and writes each term using the indices created when calculating bigI. + // Note tau = RRSS = (tau_m^s/tau_o), this why we get tau^(p-n) + for (unsigned int slip_system_i = 0; slip_system_i < 4; ++slip_system_i) + { + const double rhos = std::pow(tau[indices[slip_system_i]],exponent_p-stress_exponent) * + std::pow(std::abs(gamma*beta[indices[slip_system_i]]),exponent_p/stress_exponent); + strain_energy[grain_i] += rhos * std::exp(-nucleation_efficiency * rhos * rhos); + + Assert(isfinite(strain_energy[grain_i]), ExcMessage("strain_energy[" + std::to_string(grain_i) + "] is not finite: " + std::to_string(strain_energy[grain_i]) + + ", rhos (" + std::to_string(slip_system_i) + ") = " + std::to_string(rhos) + + ", nucleation_efficiency = " + std::to_string(nucleation_efficiency) + ".")); + } + + + // compute the derivative of the rotation matrix: \frac{\partial a_{ij}}{\partial t} + // (Eq. 9, Kaminski & Ribe 2001) + deriv_a_cosine_matrices[grain_i] = 0; + const double volume_fraction_grain = get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i); + if (volume_fraction_grain >= threshold_GBS/n_grains) + { + deriv_a_cosine_matrices[grain_i] = Utilities::Tensors::levi_civita<3>() * w * nondimensionalization_value; + + // volume averaged strain energy + mean_strain_energy += volume_fraction_grain * strain_energy[grain_i]; + + Assert(isfinite(mean_strain_energy), ExcMessage("mean_strain_energy when adding grain " + std::to_string(grain_i) + " is not finite: " + std::to_string(mean_strain_energy) + + ", volume_fraction_grain = " + std::to_string(volume_fraction_grain) + ".")); + } + else + { + strain_energy[grain_i] = 0; + } + } + + // Change of volume fraction of grains by grain boundary migration + for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) + { + // Different than D-Rex. Here we actually only compute the derivative and do not multiply it with the volume_fractions. We do that when we advect. + deriv_volume_fractions[grain_i] = get_volume_fraction_mineral(cpo_index,data,mineral_i) * mobility * (mean_strain_energy - strain_energy[grain_i]) * nondimensionalization_value; + + Assert(isfinite(deriv_volume_fractions[grain_i]), + ExcMessage("deriv_volume_fractions[" + std::to_string(grain_i) + "] is not finite: " + + std::to_string(deriv_volume_fractions[grain_i]))); + } + + return std::pair, std::vector>>(deriv_volume_fractions, deriv_a_cosine_matrices); + } + + + template + DeformationType + CrystalPreferredOrientation::determine_deformation_type(const DeformationTypeSelector deformation_type_selector, + const Point &position, + const double temperature, + const double pressure, + const Tensor<1,dim> &velocity, + const std::vector &compositions, + const SymmetricTensor<2,dim> &strain_rate, + const SymmetricTensor<2,dim> &deviatoric_strain_rate, + const double water_content) const + { + // Now compute what type of deformation takes place. + switch (deformation_type_selector) + { + case DeformationTypeSelector::passive: + return DeformationType::passive; + case DeformationTypeSelector::olivine_a_fabric: + return DeformationType::olivine_a_fabric; + case DeformationTypeSelector::olivine_b_fabric: + return DeformationType::olivine_b_fabric; + case DeformationTypeSelector::olivine_c_fabric: + return DeformationType::olivine_c_fabric; + case DeformationTypeSelector::olivine_d_fabric: + return DeformationType::olivine_d_fabric; + case DeformationTypeSelector::olivine_e_fabric: + return DeformationType::olivine_e_fabric; + case DeformationTypeSelector::enstatite: + return DeformationType::enstatite; + case DeformationTypeSelector::olivine_karato_2008: + // construct the material model inputs and outputs + // Since this function is only evaluating one particle, + // we use 1 for the amount of quadrature points. + MaterialModel::MaterialModelInputs material_model_inputs(1,this->n_compositional_fields()); + material_model_inputs.position[0] = position; + material_model_inputs.temperature[0] = temperature; + material_model_inputs.pressure[0] = pressure; + material_model_inputs.velocity[0] = velocity; + material_model_inputs.composition[0] = compositions; + material_model_inputs.strain_rate[0] = strain_rate; + + MaterialModel::MaterialModelOutputs material_model_outputs(1,this->n_compositional_fields()); + this->get_material_model().evaluate(material_model_inputs, material_model_outputs); + double eta = material_model_outputs.viscosities[0]; + + const SymmetricTensor<2,dim> stress = 2*eta*deviatoric_strain_rate + + pressure * unit_symmetric_tensor(); + const std::array< double, dim > eigenvalues = dealii::eigenvalues(stress); + double differential_stress = eigenvalues[0]-eigenvalues[dim-1]; + return determine_deformation_type_karato_2008(differential_stress, water_content); + + } + + AssertThrow(false, ExcMessage("Internal error. Deformation type not implemented.")); + return DeformationType::passive; + } + + + template + DeformationType + CrystalPreferredOrientation::determine_deformation_type_karato_2008(const double stress, const double water_content) const + { + constexpr double MPa = 1e6; + constexpr double ec_line_slope = -500./1050.; + if (stress > (380. - 0.05 * water_content)*MPa) + { + if (stress > (625. - 2.5 * water_content)*MPa) + { + return DeformationType::olivine_b_fabric; + } + else + { + return DeformationType::olivine_d_fabric; + } + } + else + { + if (stress < (625.0 -2.5 * water_content)*MPa) + { + return DeformationType::olivine_a_fabric; + } + else + { + if (stress < (500.0 + ec_line_slope*-100. + ec_line_slope * water_content)*MPa) + { + return DeformationType::olivine_e_fabric; + } + else + { + return DeformationType::olivine_c_fabric; + } + } + } + } + + + template + std::array + CrystalPreferredOrientation::reference_resolved_shear_stress_from_deformation_type(DeformationType deformation_type, + double max_value) const + { + std::array ref_resolved_shear_stress; + switch (deformation_type) + { + // from Kaminski and Ribe, GJI 2004 and + // Becker et al., 2007 (http://www-udc.ig.utexas.edu/external/becker/preprints/bke07.pdf) + case DeformationType::olivine_a_fabric : + ref_resolved_shear_stress[0] = 1; + ref_resolved_shear_stress[1] = 2; + ref_resolved_shear_stress[2] = 3; + ref_resolved_shear_stress[3] = max_value; + break; + + // from Kaminski and Ribe, GJI 2004 and + // Becker et al., 2007 (http://www-udc.ig.utexas.edu/external/becker/preprints/bke07.pdf) + case DeformationType::olivine_b_fabric : + ref_resolved_shear_stress[0] = 3; + ref_resolved_shear_stress[1] = 2; + ref_resolved_shear_stress[2] = 1; + ref_resolved_shear_stress[3] = max_value; + break; + + // from Kaminski and Ribe, GJI 2004 and + // Becker et al., 2007 (http://www-udc.ig.utexas.edu/external/becker/preprints/bke07.pdf) + case DeformationType::olivine_c_fabric : + ref_resolved_shear_stress[0] = 3; + ref_resolved_shear_stress[1] = max_value; + ref_resolved_shear_stress[2] = 2; + ref_resolved_shear_stress[3] = 1; + break; + + // from Kaminski and Ribe, GRL 2002 and + // Becker et al., 2007 (http://www-udc.ig.utexas.edu/external/becker/preprints/bke07.pdf) + case DeformationType::olivine_d_fabric : + ref_resolved_shear_stress[0] = 1; + ref_resolved_shear_stress[1] = 1; + ref_resolved_shear_stress[2] = 3; + ref_resolved_shear_stress[3] = max_value; + break; + + // Kaminski, Ribe and Browaeys, GJI, 2004 (same as in the matlab code) and + // Becker et al., 2007 (http://www-udc.ig.utexas.edu/external/becker/preprints/bke07.pdf) + case DeformationType::olivine_e_fabric : + ref_resolved_shear_stress[0] = 2; + ref_resolved_shear_stress[1] = 1; + ref_resolved_shear_stress[2] = max_value; + ref_resolved_shear_stress[3] = 3; + break; + + // from Kaminski and Ribe, GJI 2004. + // Todo: this one is not used in practice, since there is an optimization in + // the code. So maybe remove it in the future. + case DeformationType::enstatite : + ref_resolved_shear_stress[0] = max_value; + ref_resolved_shear_stress[1] = max_value; + ref_resolved_shear_stress[2] = max_value; + ref_resolved_shear_stress[3] = 1; + break; + + default: + AssertThrow(false, + ExcMessage("Deformation type enum with number " + std::to_string(static_cast(deformation_type)) + + " was not found.")); + break; + } + return ref_resolved_shear_stress; + } + + template + unsigned int + CrystalPreferredOrientation::get_number_of_grains() const + { + return n_grains; + } + + + + template + unsigned int + CrystalPreferredOrientation::get_number_of_minerals() const + { + return n_minerals; + } + + + + template + void + CrystalPreferredOrientation::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Crystal Preferred Orientation"); + { + prm.declare_entry ("Random number seed", "1", + Patterns::Integer (0), + "The seed used to generate random numbers. This will make sure that " + "results are reproducible as long as the problem is run with the " + "same number of MPI processes. It is implemented as final seed = " + "user seed + MPI Rank. "); + + prm.declare_entry ("Number of grains per particle", "50", + Patterns::Integer (1), + "The number of grains of each different mineral " + "each particle contains."); + + prm.declare_entry ("Property advection method", "Backward Euler", + Patterns::Anything(), + "Options: Forward Euler, Backward Euler"); + + prm.declare_entry ("Property advection tolerance", "1e-10", + Patterns::Double(0), + "The Backward Euler property advection method involve internal iterations. " + "This option allows for setting a tolerance. When the norm of tensor new - tensor old is " + "smaller than this tolerance, the iteration is stopped."); + + prm.declare_entry ("Property advection max iterations", "100", + Patterns::Integer(0), + "The Backward Euler property advection method involve internal iterations. " + "This option allows for setting the maximum number of iterations. Note that when the iteration " + "is ended by the max iteration amount an assert is thrown."); + + prm.declare_entry ("CPO derivatives algorithm", "Spin tensor", + Patterns::List(Patterns::Anything()), + "Options: Spin tensor"); + + prm.enter_subsection("Initial grains"); + { + prm.declare_entry("Model name","Uniform grains and random uniform rotations", + Patterns::Anything(), + "The model used to initialize the CPO for all particles. " + "Currently 'Uniform grains and random uniform rotations' and 'World Builder' are the only valid option."); + + prm.declare_entry ("Minerals", "Olivine: Karato 2008, Enstatite", + Patterns::List(Patterns::Anything()), + "This determines what minerals and fabrics or fabric selectors are used used for the LPO/CPO calculation. " + "The options are Olivine: Passive, A-fabric, Olivine: B-fabric, Olivine: C-fabric, Olivine: D-fabric, " + "Olivine: E-fabric, Olivine: Karato 2008 or Enstatite. Passive sets all RRSS entries to the maximum. The " + "Karato 2008 selector selects a fabric based on stress and water content as defined in " + "figure 4 of the Karato 2008 review paper (doi: 10.1146/annurev.earth.36.031207.124120)."); + + + prm.declare_entry ("Volume fractions minerals", "0.7, 0.3", + Patterns::List(Patterns::Double(0)), + "The volume fractions for the different minerals. " + "There need to be the same number of values as there are minerals." + "Note that the currently implemented scheme is incompressible and " + "does not allow chemical interaction or the formation of new phases"); + } + prm.leave_subsection (); + + prm.enter_subsection("D-Rex 2004"); + { + + prm.declare_entry ("Mobility", "50", + Patterns::Double(0), + "The dimensionless intrinsic grain boundary mobility for both olivine and enstatite."); + + prm.declare_entry ("Volume fractions minerals", "0.5, 0.5", + Patterns::List(Patterns::Double(0)), + "The volume fraction for the different minerals. " + "There need to be the same amount of values as there are minerals"); + + prm.declare_entry ("Stress exponents", "3.5", + Patterns::Double(0), + "This is the power law exponent that characterizes the rheology of the " + "slip systems. It is used in equation 11 of Kaminski et al., 2004."); + + prm.declare_entry ("Exponents p", "1.5", + Patterns::Double(0), + "This is exponent p as defined in equation 11 of Kaminski et al., 2004. "); + + prm.declare_entry ("Nucleation efficiency", "5", + Patterns::Double(0), + "This is the dimensionless nucleation rate as defined in equation 8 of " + "Kaminski et al., 2004. "); + + prm.declare_entry ("Threshold GBS", "0.3", + Patterns::Double(0), + "The Dimensionless Grain Boundary Sliding (GBS) threshold. " + "This is a grain size threshold below which grain deform by GBS and " + "become strain-free grains."); + } + prm.leave_subsection(); + } + prm.leave_subsection (); + } + + + + template + void + CrystalPreferredOrientation::parse_parameters (ParameterHandler &prm) + { + AssertThrow(dim == 3, ExcMessage("CPO computations are currently only supported for 3d models. " + "2d computations will work when this assert is removed, but you will need to make sure that the " + "correct 3d strain-rate and velocity gradient tensors are provided to the algorithm.")); + + prm.enter_subsection("Crystal Preferred Orientation"); + { + random_number_seed = prm.get_integer ("Random number seed"); + n_grains = prm.get_integer("Number of grains per particle"); + + property_advection_tolerance = prm.get_double("Property advection tolerance"); + property_advection_max_iterations = prm.get_integer ("Property advection max iterations"); + + const std::string temp_cpo_derivative_algorithm = prm.get("CPO derivatives algorithm"); + + if (temp_cpo_derivative_algorithm == "Spin tensor") + { + cpo_derivative_algorithm = CPODerivativeAlgorithm::spin_tensor; + } + else if (temp_cpo_derivative_algorithm == "D-Rex 2004") + { + cpo_derivative_algorithm = CPODerivativeAlgorithm::drex_2004; + } + else + { + AssertThrow(false, + ExcMessage("The CPO derivatives algorithm needs to be one of the following: " + "Spin tensor, D-Rex 2004.")); + } + + const std::string temp_advection_method = prm.get("Property advection method"); + if (temp_advection_method == "Forward Euler") + { + advection_method = AdvectionMethod::forward_euler; + } + else if (temp_advection_method == "Backward Euler") + { + advection_method = AdvectionMethod::backward_euler; + } + else + { + AssertThrow(false, ExcMessage("particle property advection method not found: \"" + temp_advection_method + "\"")); + } + + prm.enter_subsection("Initial grains"); + { + const std::string model_name = prm.get("Model name"); + if (model_name == "Uniform grains and random uniform rotations") + { + initial_grains_model = CPOInitialGrainsModel::uniform_grains_and_random_uniform_rotations; + } + else if (model_name == "World Builder") + { + initial_grains_model = CPOInitialGrainsModel::world_builder; + } + else + { + AssertThrow(false, + ExcMessage("No model named " + model_name + "for CPO particle property initialization. " + + "Only the model \"Uniform grains and random uniform rotations\" and " + "\"World Builder\" are available.")); + } + + const std::vector temp_deformation_type_selector = dealii::Utilities::split_string_list(prm.get("Minerals")); + n_minerals = temp_deformation_type_selector.size(); + deformation_type_selector.resize(n_minerals); + + for (size_t mineral_i = 0; mineral_i < n_minerals; ++mineral_i) + { + if (temp_deformation_type_selector[mineral_i] == "Passive") + { + deformation_type_selector[mineral_i] = DeformationTypeSelector::passive; + } + else if (temp_deformation_type_selector[mineral_i] == "Olivine: Karato 2008") + { + deformation_type_selector[mineral_i] = DeformationTypeSelector::olivine_karato_2008; + } + else if (temp_deformation_type_selector[mineral_i] == "Olivine: A-fabric") + { + deformation_type_selector[mineral_i] = DeformationTypeSelector::olivine_a_fabric; + } + else if (temp_deformation_type_selector[mineral_i] == "Olivine: B-fabric") + { + deformation_type_selector[mineral_i] = DeformationTypeSelector::olivine_b_fabric; + } + else if (temp_deformation_type_selector[mineral_i] == "Olivine: C-fabric") + { + deformation_type_selector[mineral_i] = DeformationTypeSelector::olivine_c_fabric; + } + else if (temp_deformation_type_selector[mineral_i] == "Olivine: D-fabric") + { + deformation_type_selector[mineral_i] = DeformationTypeSelector::olivine_d_fabric; + } + else if (temp_deformation_type_selector[mineral_i] == "Olivine: E-fabric") + { + deformation_type_selector[mineral_i] = DeformationTypeSelector::olivine_e_fabric; + } + else if (temp_deformation_type_selector[mineral_i] == "Enstatite") + { + deformation_type_selector[mineral_i] = DeformationTypeSelector::enstatite; + } + else + { + AssertThrow(false, + ExcMessage("The fabric needs to be assigned one of the following comma-delimited values: Olivine: Karato 2008, " + "Olivine: A-fabric, Olivine: B-fabric, Olivine: C-fabric, Olivine: D-fabric," + "Olivine: E-fabric, Enstatite, Passive.")); + } + } + + volume_fractions_minerals = Utilities::string_to_double(dealii::Utilities::split_string_list(prm.get("Volume fractions minerals"))); + double volume_fractions_minerals_sum = 0; + for (auto fraction : volume_fractions_minerals) + { + volume_fractions_minerals_sum += fraction; + } + + AssertThrow(abs(volume_fractions_minerals_sum-1.0) < 2.0 * std::numeric_limits::epsilon(), + ExcMessage("The sum of the CPO volume fractions should be one.")); + } + prm.leave_subsection(); + + prm.enter_subsection("D-Rex 2004"); + { + mobility = prm.get_double("Mobility"); + volume_fractions_minerals = Utilities::string_to_double(dealii::Utilities::split_string_list(prm.get("Volume fractions minerals"))); + stress_exponent = prm.get_double("Stress exponents"); + exponent_p = prm.get_double("Exponents p"); + nucleation_efficiency = prm.get_double("Nucleation efficiency"); + threshold_GBS = prm.get_double("Threshold GBS"); + } + prm.leave_subsection(); + } + prm.leave_subsection (); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(CrystalPreferredOrientation, + "crystal preferred orientation", + "WARNING: all the CPO plugins are a work in progress and not ready for production use yet. " + "See https://github.com/geodynamics/aspect/issues/3885 for current status and alternatives. " + "The plugin manages and computes the evolution of Lattice/Crystal Preferred Orientations (LPO/CPO) " + "on particles. Each ASPECT particle can be assigned many grains. Each grain is assigned a size and a orientation " + "matrix. This allows for CPO evolution tracking with polycrystalline kinematic CrystalPreferredOrientation evolution models such " + "as D-Rex (Kaminski and Ribe, 2001; Kaminski et al., 2004).") + } + } +} diff --git a/source/particle/property/elastic_stress.cc.bak b/source/particle/property/elastic_stress.cc.bak new file mode 100644 index 00000000000..f0be9a72362 --- /dev/null +++ b/source/particle/property/elastic_stress.cc.bak @@ -0,0 +1,199 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + ElasticStress::ElasticStress () + : + material_inputs(1,0), + material_outputs(1,0) + {} + + + + template + void + ElasticStress::initialize () + { + material_inputs = MaterialModel::MaterialModelInputs(1, this->n_compositional_fields()); + + material_outputs = MaterialModel::MaterialModelOutputs(1, this->n_compositional_fields()); + + AssertThrow((Plugins::plugin_type_matches>(this->get_material_model()) + || + Plugins::plugin_type_matches>(this->get_material_model())), + ExcMessage("This particle property only makes sense in combination with the viscoelastic or visco_plastic material model.")); + + AssertThrow(this->get_parameters().enable_elasticity == true, + ExcMessage ("This particle property should only be used if 'Enable elasticity' is set to true")); + + } + + + + template + void + ElasticStress::initialize_one_particle_property(const Point &position, + std::vector &data) const + { + // Give each elastic stress field its initial composition if one is prescribed. + data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_xx"))); + + data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_yy"))); + + if (dim == 2) + { + data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_xy"))); + } + else if (dim == 3) + { + data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_zz"))); + + data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_xy"))); + + data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_xz"))); + + data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_yz"))); + } + + } + + + + template + void + ElasticStress::update_particle_property(const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const + { + material_inputs.position[0] = particle->get_location(); + + + material_inputs.current_cell = typename DoFHandler::active_cell_iterator(*particle->get_surrounding_cell(), + &(this->get_dof_handler())); + + material_inputs.temperature[0] = solution[this->introspection().component_indices.temperature]; + + material_inputs.pressure[0] = solution[this->introspection().component_indices.pressure]; + + for (unsigned int d = 0; d < dim; ++d) + material_inputs.velocity[0][d] = solution[this->introspection().component_indices.velocities[d]]; + + for (unsigned int n = 0; n < this->n_compositional_fields(); ++n) + material_inputs.composition[0][n] = solution[this->introspection().component_indices.compositional_fields[n]]; + + Tensor<2,dim> grad_u; + for (unsigned int d=0; dget_material_model().evaluate (material_inputs,material_outputs); + + for (unsigned int i = 0; i < SymmetricTensor<2,dim>::n_independent_components ; ++i) + particle->get_properties()[data_position + i] += material_outputs.reaction_terms[0][i]; + } + + + + template + UpdateTimeFlags + ElasticStress::need_update() const + { + return update_time_step; + } + + + + template + UpdateFlags + ElasticStress::get_needed_update_flags () const + { + return update_values | update_gradients; + } + + + + template + std::vector> + ElasticStress::get_property_information() const + { + std::vector> property_information; + + //Check which fields are used in model and make an output for each. + if (this->introspection().compositional_name_exists("ve_stress_xx")) + property_information.emplace_back("ve_stress_xx",1); + + if (this->introspection().compositional_name_exists("ve_stress_yy")) + property_information.emplace_back("ve_stress_yy",1); + + if (dim == 2) + { + if (this->introspection().compositional_name_exists("ve_stress_xy")) + property_information.emplace_back("ve_stress_xy",1); + } + else if (dim == 3) + { + if (this->introspection().compositional_name_exists("ve_stress_zz")) + property_information.emplace_back("ve_stress_zz",1); + + if (this->introspection().compositional_name_exists("ve_stress_xy")) + property_information.emplace_back("ve_stress_xy",1); + + if (this->introspection().compositional_name_exists("ve_stress_xz")) + property_information.emplace_back("ve_stress_xz",1); + + if (this->introspection().compositional_name_exists("ve_stress_yz")) + property_information.emplace_back("ve_stress_yz",1); + } + + return property_information; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(ElasticStress, + "elastic stress", + "A plugin in which the particle property tensor is " + "defined as the total elastic stress a particle has " + "accumulated. See the viscoelastic material model " + "documentation for more detailed information.") + + } + } +} diff --git a/source/particle/property/elastic_tensor_decomposition.cc.bak b/source/particle/property/elastic_tensor_decomposition.cc.bak new file mode 100644 index 00000000000..25308ff2623 --- /dev/null +++ b/source/particle/property/elastic_tensor_decomposition.cc.bak @@ -0,0 +1,468 @@ +/* + Copyright (C) 2023 by the authors of the ASPECT code. + This file is part of ASPECT. + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + ASPECT 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 General Public License for more details. + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + namespace Utilities + { + std::array + indexed_even_permutation(const unsigned int index) + { + // there are 6 permutations, but only the odd or even are needed. We use the even + // permutation here. + switch (index) + { + case 0 : + return {{0,1,2}}; + case 1 : + return {{1,2,0}}; + case 2: + return {{2,0,1}}; + /*case 3: + return {0,2,1}; + case 4 : + return {1,0,2}; + case 5: + return {2,1,0};*/ + default: + AssertThrow(false,ExcMessage("Provided index larger then 2 (" + std::to_string(index)+ ").")); + return {{0,0,0}}; + } + + } + + + + SymmetricTensor<2,3> + compute_voigt_stiffness_tensor(const SymmetricTensor<2,6> &elastic_matrix) + { + /** + * the Voigt stiffness tensor (see Browaeys and Chevrot, 2004) + * It defines the stress needed to cause an isotropic strain in the + * material + */ + SymmetricTensor<2,3> voigt_stiffness_tensor; + voigt_stiffness_tensor[0][0]=elastic_matrix[0][0]+elastic_matrix[5][5]+elastic_matrix[4][4]; + voigt_stiffness_tensor[1][1]=elastic_matrix[5][5]+elastic_matrix[1][1]+elastic_matrix[3][3]; + voigt_stiffness_tensor[2][2]=elastic_matrix[4][4]+elastic_matrix[3][3]+elastic_matrix[2][2]; + voigt_stiffness_tensor[1][0]=elastic_matrix[0][5]+elastic_matrix[1][5]+elastic_matrix[3][4]; + voigt_stiffness_tensor[2][0]=elastic_matrix[0][4]+elastic_matrix[2][4]+elastic_matrix[3][5]; + voigt_stiffness_tensor[2][1]=elastic_matrix[1][3]+elastic_matrix[2][3]+elastic_matrix[4][5]; + + return voigt_stiffness_tensor; + } + + + + SymmetricTensor<2,3> + compute_dilatation_stiffness_tensor(const SymmetricTensor<2,6> &elastic_matrix) + { + /** + * The dilatational stiffness tensor (see Browaeys and Chevrot, 2004) + * It defines the stress to cause isotropic dilatation in the material. + */ + SymmetricTensor<2,3> dilatation_stiffness_tensor; + for (size_t i = 0; i < 3; i++) + { + dilatation_stiffness_tensor[0][0]=elastic_matrix[0][i]+dilatation_stiffness_tensor[0][0]; + dilatation_stiffness_tensor[1][1]=elastic_matrix[1][i]+dilatation_stiffness_tensor[1][1]; + dilatation_stiffness_tensor[2][2]=elastic_matrix[2][i]+dilatation_stiffness_tensor[2][2]; + dilatation_stiffness_tensor[1][0]=elastic_matrix[5][i]+dilatation_stiffness_tensor[1][0]; + dilatation_stiffness_tensor[2][0]=elastic_matrix[4][i]+dilatation_stiffness_tensor[2][0]; + dilatation_stiffness_tensor[2][1]=elastic_matrix[3][i]+dilatation_stiffness_tensor[2][1]; + } + return dilatation_stiffness_tensor; + } + + + + Tensor<2,3> + compute_unpermutated_SCCS(const SymmetricTensor<2,3> &dilatation_stiffness_tensor, + const SymmetricTensor<2,3> &voigt_stiffness_tensor) + { + // computing the eigenvector of the dilation and Voigt stiffness matrices and then averaging them by bysection. + const std::array>, 3> voigt_eigenvectors_a = eigenvectors(voigt_stiffness_tensor, SymmetricTensorEigenvectorMethod::jacobi); + const std::array>, 3> dilatation_eigenvectors_a = eigenvectors(dilatation_stiffness_tensor, SymmetricTensorEigenvectorMethod::jacobi); + + + std::array,3> unpermutated_SCCS; + // Averaging dilatation and voigt eigenvectors + // To do this we need to find the eigenvectors which are closest to each other and average those. + // The next function looks for the smallest angle and returns the corresponding vector index for + // that vector. + int vector_index_signed = 0; + for (unsigned int i1 = 0; i1 < 3; i1++) + { + vector_index_signed = 0; + double smallest_angle = std::numeric_limits::max(); // angle D VeCtor + for (unsigned int i2 = 0; i2 < 3; i2++) + { + double dv_dot_product = dilatation_eigenvectors_a[i1].second*voigt_eigenvectors_a[i2].second; + // limit the dot product between 1 and -1 so we can use the arccos function safely. + if (std::abs(dv_dot_product) >= 1.0) + dv_dot_product = std::copysign(1.0,dv_dot_product); + // Compute the angle between the vectors and account for that vector in the opposite + // direction are the same (0 == 180 degrees). So limit the direction of the vectors between + // 0 and 90 degrees such that it represents the minimum angle between the two lines. + const double angle = dv_dot_product < 0.0 ? std::acos(-1.0)-std::acos(dv_dot_product) : std::acos(dv_dot_product); + // store this if the angle is smaller + if (angle < smallest_angle) + { + vector_index_signed = (dv_dot_product < 0.0) ? -i2 : i2; + smallest_angle = angle; + } + } + + // Adds to the dilatation eigenvectors to the Voigt eigenvectors with the smallest angle + // Note that the voigt eigenvector is multiplied with a value which can be negative, which means it would be a subtraction. + // Lastly we normalize the unpermutated_SCCS. + unpermutated_SCCS[i1] = 0.5*(dilatation_eigenvectors_a[i1].second + static_cast(vector_index_signed)*voigt_eigenvectors_a[std::abs(vector_index_signed)].second); + unpermutated_SCCS[i1] /= unpermutated_SCCS[i1].norm(); + } + + return Tensor<2,3>( + { + {unpermutated_SCCS[0][0],unpermutated_SCCS[0][1],unpermutated_SCCS[0][2]}, + {unpermutated_SCCS[1][0],unpermutated_SCCS[1][1],unpermutated_SCCS[1][2]}, + {unpermutated_SCCS[2][0],unpermutated_SCCS[2][1],unpermutated_SCCS[2][2]} + }); + } + + + + std::array,7> + compute_elastic_tensor_SCCS_decompositions( + const Tensor<2,3> &unpermutated_SCCS, + const SymmetricTensor<2,6> &elastic_matrix) + { + /** + * Try the different permutations to determine what is the best hexagonal projection. + * This is based on Browaeys and Chevrot (2004), GJI (doi: 10.1111/j.1365-246X.2004.024115.x), + * which states at the end of paragraph 3.3 that "... an important property of an orthogonal projection + * is that the distance between a vector $X$ and its orthogonal projection $X_H = p(X)$ on a given + * subspace is minimum. These two features ensure that the decomposition is optimal once a 3-D Cartesian + * coordinate system is chosen.". The other property they talk about is that "The space of elastic + * vectors has a finite dimension [...], i.e. using a different norm from eq. (2.3 will change distances + * but not the resulting decomposition.". + */ + std::array,3> permutated; + std::array,3> rotated_elastic_matrix; + // The norms variable contains the square norms of the different symmetry approximations of the elastic tensor. + std::array,7> squared_norms_to_projections; + + for (unsigned int permutation_i = 0; permutation_i < 3; permutation_i++) + { + std::array permutation = indexed_even_permutation(permutation_i); + + for (size_t j = 0; j < 3; j++) + { + permutated[permutation_i][j] = unpermutated_SCCS[permutation[j]]; + } + + rotated_elastic_matrix[permutation_i] = aspect::Utilities::Tensors::rotate_voigt_stiffness_matrix((permutated[permutation_i]),elastic_matrix); + + const Tensor<1,21> full_elastic_vector_rotated = aspect::Utilities::Tensors::to_voigt_stiffness_vector(rotated_elastic_matrix[permutation_i]); + + + const double full_norm_square = full_elastic_vector_rotated.norm_square(); + squared_norms_to_projections[6][permutation_i] = full_norm_square; + + // Get the monoclinic and higher symmetry axes, which can be comptued by taking specific elements from the full vector. + // This means that this vector contains all symmetry axes, but the isotropic part is removed. + // The following line would do the same as the lines below, but is is very slow. It has therefore been + // replaced by the lines below. + //auto monoclinic_and_higher_vector = projection_matrix_triclinic_to_monoclinic*full_elastic_vector_rotated; + dealii::Tensor<1,21> monoclinic_and_higher_vector; + monoclinic_and_higher_vector[0] = full_elastic_vector_rotated[0]; + monoclinic_and_higher_vector[1] = full_elastic_vector_rotated[1]; + monoclinic_and_higher_vector[2] = full_elastic_vector_rotated[2]; + monoclinic_and_higher_vector[3] = full_elastic_vector_rotated[3]; + monoclinic_and_higher_vector[4] = full_elastic_vector_rotated[4]; + monoclinic_and_higher_vector[5] = full_elastic_vector_rotated[5]; + monoclinic_and_higher_vector[6] = full_elastic_vector_rotated[6]; + monoclinic_and_higher_vector[7] = full_elastic_vector_rotated[7]; + monoclinic_and_higher_vector[8] = full_elastic_vector_rotated[8]; + monoclinic_and_higher_vector[11] = full_elastic_vector_rotated[11]; + monoclinic_and_higher_vector[14] = full_elastic_vector_rotated[14]; + monoclinic_and_higher_vector[17] = full_elastic_vector_rotated[17]; + monoclinic_and_higher_vector[20] = full_elastic_vector_rotated[20]; + + // The triclinic vector is the full elastic tensor minux the monoclinic and higher symmetry axes vector. + auto triclinic_vector = full_elastic_vector_rotated-monoclinic_and_higher_vector; + squared_norms_to_projections[0][permutation_i] = triclinic_vector.norm_square(); + + // Only the first 9 elements are now non-zero, so crop the vector to the first 9 elements. + // The following line would do the same as the lines below, but it is slow. It has therefore been + // replaced by the lines below. + //auto orthorhombic_and_higher_vector = projection_matrix_monoclinic_to_orthorhombic*monoclinic_and_higher_vector; + dealii::Tensor<1,9> monoclinic_and_higher_vector_cropped; + monoclinic_and_higher_vector_cropped[0] = monoclinic_and_higher_vector[0]; + monoclinic_and_higher_vector_cropped[1] = monoclinic_and_higher_vector[1]; + monoclinic_and_higher_vector_cropped[2] = monoclinic_and_higher_vector[2]; + monoclinic_and_higher_vector_cropped[3] = monoclinic_and_higher_vector[3]; + monoclinic_and_higher_vector_cropped[4] = monoclinic_and_higher_vector[4]; + monoclinic_and_higher_vector_cropped[5] = monoclinic_and_higher_vector[5]; + monoclinic_and_higher_vector_cropped[6] = monoclinic_and_higher_vector[6]; + monoclinic_and_higher_vector_cropped[7] = monoclinic_and_higher_vector[7]; + monoclinic_and_higher_vector_cropped[8] = monoclinic_and_higher_vector[8]; + dealii::Tensor<1,9> orthorhombic_and_higher_vector; + orthorhombic_and_higher_vector[0] = monoclinic_and_higher_vector[0]; + orthorhombic_and_higher_vector[1] = monoclinic_and_higher_vector[1]; + orthorhombic_and_higher_vector[2] = monoclinic_and_higher_vector[2]; + orthorhombic_and_higher_vector[3] = monoclinic_and_higher_vector[3]; + orthorhombic_and_higher_vector[4] = monoclinic_and_higher_vector[4]; + orthorhombic_and_higher_vector[5] = monoclinic_and_higher_vector[5]; + orthorhombic_and_higher_vector[6] = monoclinic_and_higher_vector[6]; + orthorhombic_and_higher_vector[7] = monoclinic_and_higher_vector[7]; + orthorhombic_and_higher_vector[8] = monoclinic_and_higher_vector[8]; + + // The monoclinic vector is the monoclinic and higher symmetry axes vector minux the orthoclinic and higher symmetry axes vector. + auto monoclinic_vector = monoclinic_and_higher_vector_cropped-orthorhombic_and_higher_vector; + squared_norms_to_projections[1][permutation_i] = monoclinic_vector.norm_square(); + + + auto tetragonal_and_higher_vector = projection_matrix_orthorhombic_to_tetragonal*orthorhombic_and_higher_vector; + auto orthorhombic_vector = orthorhombic_and_higher_vector-tetragonal_and_higher_vector; + squared_norms_to_projections[2][permutation_i] = orthorhombic_vector.norm_square(); + + auto hexagonal_and_higher_vector = projection_matrix_tetragonal_to_hexagonal*tetragonal_and_higher_vector; + auto tetragonal_vector = tetragonal_and_higher_vector-hexagonal_and_higher_vector; + squared_norms_to_projections[3][permutation_i] = tetragonal_vector.norm_square(); + + auto isotropic_vector = projection_matrix_hexagonal_to_isotropic*hexagonal_and_higher_vector; + auto hexagonal_vector = hexagonal_and_higher_vector-isotropic_vector; + squared_norms_to_projections[4][permutation_i] = hexagonal_vector.norm_square(); + squared_norms_to_projections[5][permutation_i] = isotropic_vector.norm_square(); + + } + return squared_norms_to_projections; + + } + } + + + + template + void + ElasticTensorDecomposition::initialize () + { + const Particle::Property::Manager &manager = this->get_particle_world(this->get_particle_world_index()).get_property_manager(); + AssertThrow(manager.plugin_name_exists("crystal preferred orientation"), + ExcMessage("No cpo property plugin found.")); + AssertThrow(manager.plugin_name_exists("cpo elastic tensor"), + ExcMessage("No cpo elastic tensor property plugin found.")); + + AssertThrow(manager.check_plugin_order("crystal preferred orientation","elastic tensor decomposition"), + ExcMessage("To use the elastic tensor decomposition plugin, the cpo plugin needs to be defined before this plugin.")); + + AssertThrow(manager.check_plugin_order("cpo elastic tensor","elastic tensor decomposition"), + ExcMessage("To use the elastic tensor decomposition plugin, the cpo elastic tensor plugin needs to be defined before this plugin.")); + + cpo_elastic_tensor_data_position = manager.get_data_info().get_position_by_plugin_index(manager.get_plugin_index_by_name("cpo elastic tensor")); + } + + + + template + void + ElasticTensorDecomposition::initialize_one_particle_property(const Point &, + std::vector &data) const + { + const SymmetricTensor<2,6> elastic_matrix = Particle::Property::CpoElasticTensor::get_elastic_tensor(cpo_elastic_tensor_data_position, + data); + + const SymmetricTensor<2,3> dilatation_stiffness_tensor_full = Property::Utilities::compute_dilatation_stiffness_tensor(elastic_matrix); + const SymmetricTensor<2,3> voigt_stiffness_tensor_full = Property::Utilities::compute_voigt_stiffness_tensor(elastic_matrix); + const Tensor<2,3> SCCS_full = Property::Utilities::compute_unpermutated_SCCS(dilatation_stiffness_tensor_full, voigt_stiffness_tensor_full); + + const std::array,7 > norms = Property::Utilities::compute_elastic_tensor_SCCS_decompositions(SCCS_full, elastic_matrix); + + // get max hexagonal element index, which is the same as the permutation index + const size_t max_hexagonal_element_index = std::max_element(norms[4].begin(),norms[4].end())-norms[4].begin(); + std::array permutation = Property::Utilities::indexed_even_permutation(max_hexagonal_element_index); + // reorder the SCCS be the SCCS permutation which yields the largest hexagonal vector (percentage of anisotropy) + Tensor<2,3> hexagonal_permutated_SCCS; + for (size_t index = 0; index < 3; ++index) + { + hexagonal_permutated_SCCS[index] = SCCS_full[permutation[index]]; + } + + data.push_back(SCCS_full[0][0]); + data.push_back(SCCS_full[0][1]); + data.push_back(SCCS_full[0][2]); + data.push_back(SCCS_full[1][0]); + data.push_back(SCCS_full[1][1]); + data.push_back(SCCS_full[1][2]); + data.push_back(SCCS_full[2][0]); + data.push_back(SCCS_full[2][1]); + data.push_back(SCCS_full[2][2]); + data.push_back(hexagonal_permutated_SCCS[2][0]); + data.push_back(hexagonal_permutated_SCCS[2][1]); + data.push_back(hexagonal_permutated_SCCS[2][2]); + data.push_back(norms[6][0]); + data.push_back(norms[0][0]); // triclinic + data.push_back(norms[0][1]); // triclinic + data.push_back(norms[0][2]); // triclinic + data.push_back(norms[1][0]); // monoclinic + data.push_back(norms[1][1]); // monoclinic + data.push_back(norms[1][2]); // monoclinic + data.push_back(norms[2][0]); // orthorhomic + data.push_back(norms[2][1]); // orthorhomic + data.push_back(norms[2][2]); // orthorhomic + data.push_back(norms[3][0]); // tetragonal + data.push_back(norms[3][1]); // tetragonal + data.push_back(norms[3][2]); // tetragonal + data.push_back(norms[4][0]); // hexagonal + data.push_back(norms[4][1]); // hexagonal + data.push_back(norms[4][2]); // hexagonal + data.push_back(norms[5][0]); // isotropic + + } + + + + template + void + ElasticTensorDecomposition::update_particle_property(const unsigned int data_position, + const Vector &/*solution*/, + const std::vector> &/*gradients*/, + typename ParticleHandler::particle_iterator &particle) const + { + ArrayView data = particle->get_properties(); + const SymmetricTensor<2,6> elastic_matrix = Particle::Property::CpoElasticTensor::get_elastic_tensor(cpo_elastic_tensor_data_position, + data); + + const SymmetricTensor<2,3> dilatation_stiffness_tensor_full = Utilities::compute_dilatation_stiffness_tensor(elastic_matrix); + const SymmetricTensor<2,3> voigt_stiffness_tensor_full = Utilities::compute_voigt_stiffness_tensor(elastic_matrix); + const Tensor<2,3> SCCS_full = Utilities::compute_unpermutated_SCCS(dilatation_stiffness_tensor_full, voigt_stiffness_tensor_full); + + const std::array,7 > norms = Utilities::compute_elastic_tensor_SCCS_decompositions(SCCS_full, elastic_matrix); + + // get max hexagonal element index, which is the same as the permutation index + const size_t max_hexagonal_element_index = std::max_element(norms[4].begin(),norms[4].end())-norms[4].begin(); + std::array permutation = Utilities::indexed_even_permutation(max_hexagonal_element_index); + // reorder the SCCS by the SCCS permutation which yields the largest hexagonal vector (percentage of anisotropy) + Tensor<2,3> hexagonal_permutated_SCCS; + for (size_t index = 0; index < 3; ++index) + { + hexagonal_permutated_SCCS[index] = SCCS_full[permutation[index]]; + } + + data[data_position] = SCCS_full[0][0]; + data[data_position+1] = SCCS_full[0][1]; + data[data_position+2] = SCCS_full[0][2]; + data[data_position+3] = SCCS_full[1][0]; + data[data_position+4] = SCCS_full[1][1]; + data[data_position+5] = SCCS_full[1][2]; + data[data_position+6] = SCCS_full[2][0]; + data[data_position+7] = SCCS_full[2][1]; + data[data_position+8] = SCCS_full[2][2]; + data[data_position+9] = hexagonal_permutated_SCCS[2][0]; + data[data_position+10] = hexagonal_permutated_SCCS[2][1]; + data[data_position+11] = hexagonal_permutated_SCCS[2][2]; + data[data_position+12] = norms[6][0]; + data[data_position+13] = norms[0][0]; // triclinic + data[data_position+14] = norms[0][1]; // triclinic + data[data_position+15] = norms[0][2]; // triclinic + data[data_position+16] = norms[1][0]; // monoclinic + data[data_position+17] = norms[1][1]; // monoclinic + data[data_position+18] = norms[1][2]; // monoclinic + data[data_position+19] = norms[2][0]; // orthorhomic + data[data_position+20] = norms[2][1]; // orthorhomic + data[data_position+21] = norms[2][2]; // orthorhomic + data[data_position+22] = norms[3][0]; // tetragonal + data[data_position+23] = norms[3][1]; // tetragonal + data[data_position+24] = norms[3][2]; // tetragonal + data[data_position+25] = norms[4][0]; // hexagonal + data[data_position+26] = norms[4][1]; // hexagonal + data[data_position+27] = norms[4][2]; // hexagonal + data[data_position+28] = norms[5][0]; // isotropic + } + + + + template + UpdateTimeFlags + ElasticTensorDecomposition::need_update() const + { + return update_output_step; + } + + + + template + std::vector> + ElasticTensorDecomposition::get_property_information() const + { + std::vector> property_information = + { + {"cpo elastic axis e1",3}, + {"cpo elastic axis e2",3}, + {"cpo elastic axis e3",3}, + {"cpo elastic hexagonal axis",3}, + {"cpo elastic vector norm square",1}, + {"cpo elastic triclinic vector norm square p1",1}, + {"cpo elastic triclinic vector norm square p2",1}, + {"cpo elastic triclinic vector norm square p3",1}, + {"cpo elastic monoclinic vector norm square p1",1}, + {"cpo elastic monoclinic vector norm square p2",1}, + {"cpo elastic monoclinic vector norm square p3",1}, + {"cpo elastic orthorhombic vector norm square p1",1}, + {"cpo elastic orthorhombic vector norm square p2",1}, + {"cpo elastic orthorhombic vector norm square p3",1}, + {"cpo elastic tetragonal vector norm square p1",1}, + {"cpo elastic tetragonal vector norm square p2",1}, + {"cpo elastic tetragonal vector norm square p3",1}, + {"cpo elastic hexagonal vector norm square p1",1}, + {"cpo elastic hexagonal vector norm square p2",1}, + {"cpo elastic hexagonal vector norm square p3",1}, + {"cpo elastic isotropic vector norm square",1} + }; + + return property_information; + } + } + } +} + + + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(ElasticTensorDecomposition, + "elastic tensor decomposition", + "A plugin which decomposes the elastic tensor into different approximations " + "(Isotropic, Hexagonal, Tetragonal, Orthorhombic, Monoclinic and Triclinic) " + "and provides the eigenvectors of the tensor.") + } + } +} diff --git a/source/particle/property/function.cc.bak b/source/particle/property/function.cc.bak new file mode 100644 index 00000000000..d88dd252001 --- /dev/null +++ b/source/particle/property/function.cc.bak @@ -0,0 +1,113 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + Function::Function() + : + n_components (0) + {} + + template + void + Function::initialize_one_particle_property(const Point &position, + std::vector &data) const + { + for (unsigned int i = 0; i < n_components; ++i) + data.push_back(function->value(position, i)); + } + + template + std::vector> + Function::get_property_information() const + { + const std::vector> property_information (1,std::make_pair("function",n_components)); + return property_information; + } + + + template + void + Function::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Function"); + { + prm.declare_entry ("Number of components", "1", + Patterns::Integer (0), + "The number of function components where each component is described " + "by a function expression delimited by a ';'."); + Functions::ParsedFunction::declare_parameters (prm, 1); + } + prm.leave_subsection(); + } + + + template + void + Function::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Function"); + n_components = prm.get_integer ("Number of components"); + try + { + function = std::make_unique>(n_components); + function->parse_parameters (prm); + } + catch (...) + { + std::cerr << "ERROR: FunctionParser failed to parse\n" + << "\t'Particles.Function'\n" + << "with expression\n" + << "\t'" << prm.get("Function expression") << "'"; + throw; + } + prm.leave_subsection(); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(Function, + "function", + "Implementation of a model in which the particle " + "property is set by evaluating an explicit function " + "at the initial position of each particle. The " + "function is defined in the parameters in section " + "``Particles|Function''. The format of these " + "functions follows the syntax understood by the " + "muparser library, see " + "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") + } + } +} diff --git a/source/particle/property/grain_size.cc.bak b/source/particle/property/grain_size.cc.bak new file mode 100644 index 00000000000..145d00f267c --- /dev/null +++ b/source/particle/property/grain_size.cc.bak @@ -0,0 +1,173 @@ +/* + Copyright (C) 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + GrainSize::GrainSize () + : + material_inputs(1,0), + material_outputs(1,0) + {} + + + + template + void + GrainSize::initialize () + { + material_inputs = MaterialModel::MaterialModelInputs(1, this->n_compositional_fields()); + material_outputs = MaterialModel::MaterialModelOutputs(1, this->n_compositional_fields()); + + AssertThrow(this->introspection().compositional_name_exists("grain_size"), + ExcMessage("This particle property only makes sense if " + "there is a compositional field named 'grain_size'.")); + + grain_size_index = this->introspection().compositional_index_for_name("grain_size"); + } + + + + template + void + GrainSize::initialize_one_particle_property(const Point &position, + std::vector &data) const + { + // Set the initial composition to the initial grain size. + data.push_back(this->get_initial_composition_manager().initial_composition(position,grain_size_index)); + } + + + + template + void + GrainSize::update_particle_properties(const unsigned int data_position, + const std::vector> &solution, + const std::vector>> &gradients, + typename ParticleHandler::particle_iterator_range &particles) const + { + material_inputs = MaterialModel::MaterialModelInputs(solution.size(), this->n_compositional_fields()); + material_outputs = MaterialModel::MaterialModelOutputs(solution.size(), this->n_compositional_fields()); + material_inputs.requested_properties = MaterialModel::MaterialProperties::reaction_terms; + material_inputs.current_cell = typename DoFHandler::active_cell_iterator(*particles.begin()->get_surrounding_cell(), + &(this->get_dof_handler())); + + unsigned int i = 0; + for (auto particle: particles) + { + // Make sure all particles are in the same cell + Assert(particle.get_surrounding_cell() == particles.begin()->get_surrounding_cell(), + ExcMessage("All particles must be in the same cell.")); + + material_inputs.position[i] = particle.get_location(); + material_inputs.temperature[i] = solution[i][this->introspection().component_indices.temperature]; + material_inputs.pressure[i] = solution[i][this->introspection().component_indices.pressure]; + + for (unsigned int d = 0; d < dim; ++d) + material_inputs.velocity[i][d] = solution[i][this->introspection().component_indices.velocities[d]]; + + for (unsigned int n = 0; n < this->n_compositional_fields(); ++n) + material_inputs.composition[i][n] = solution[i][this->introspection().component_indices.compositional_fields[n]]; + + material_inputs.composition[i][grain_size_index] = particle.get_properties()[data_position]; + + Tensor<2,dim> grad_u; + for (unsigned int d=0; dget_material_model().evaluate(material_inputs, + material_outputs); + + i = 0; + for (auto particle: particles) + { + particle.get_properties()[data_position] += material_outputs.reaction_terms[i][grain_size_index]; + ++i; + } + } + + + + template + InitializationModeForLateParticles + GrainSize::late_initialization_mode () const + { + return interpolate_respect_boundary; + } + + + + template + UpdateTimeFlags + GrainSize::need_update() const + { + return update_time_step; + } + + + + template + UpdateFlags + GrainSize::get_needed_update_flags () const + { + return update_values | update_gradients; + } + + + + template + std::vector> + GrainSize::get_property_information() const + { + return {{"grain_size",1}}; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(GrainSize, + "grain size", + "A plugin in which the particle property is " + "defined as the evolving grain size of a particle. " + "See the grain_size material model " + "documentation for more detailed information.") + + } + } +} diff --git a/source/particle/property/initial_composition.cc.bak b/source/particle/property/initial_composition.cc.bak new file mode 100644 index 00000000000..4c603e02744 --- /dev/null +++ b/source/particle/property/initial_composition.cc.bak @@ -0,0 +1,91 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + void + InitialComposition::initialize_one_particle_property(const Point &position, + std::vector &data) const + { + for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) + data.push_back(this->get_initial_composition_manager().initial_composition(position,i)); + } + + + + template + InitializationModeForLateParticles + InitialComposition::late_initialization_mode () const + { + return interpolate_respect_boundary; + } + + + + template + std::vector> + InitialComposition::get_property_information() const + { + AssertThrow(this->n_compositional_fields() > 0, + ExcMessage("You have requested the particle property , but the number of compositional fields is 0. " + "Please add compositional fields to your model, or remove " + "this particle property.")); + + std::vector> property_information; + + for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) + { + std::ostringstream field_name; + field_name << "initial " << this->introspection().name_for_compositional_index(i); + property_information.emplace_back(field_name.str(),1); + } + + return property_information; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(InitialComposition, + "initial composition", + "Implementation of a plugin in which the particle " + "property is given as the initial composition " + "at the particle's initial position. The particle " + "gets as many properties as there are " + "compositional fields.") + } + } +} diff --git a/source/particle/property/initial_position.cc.bak b/source/particle/property/initial_position.cc.bak new file mode 100644 index 00000000000..ee44d3f0874 --- /dev/null +++ b/source/particle/property/initial_position.cc.bak @@ -0,0 +1,72 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + void + InitialPosition::initialize_one_particle_property(const Point &position, + std::vector &data) const + { + for (unsigned int i = 0; i < dim; ++i) + data.push_back(position[i]); + } + + template + std::vector> + InitialPosition::get_property_information() const + { + const std::vector> property_information (1,std::make_pair("initial position",static_cast (dim))); + return property_information; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(InitialPosition, + "initial position", + "Implementation of a plugin in which the particle " + "property is given as the initial position " + "of the particle. This property is vector-valued with " + "as many components as there are space dimensions. " + "In practice, it is often most useful to only " + "visualize one of the components of this vector, " + "or the magnitude of the vector. For example, in " + "a spherical mantle simulation, the magnitude of this " + "property equals the starting radius of a particle, " + "and is thereby indicative of which part of the " + "mantle a particle comes from.") + } + } +} diff --git a/source/particle/property/integrated_strain.cc.bak b/source/particle/property/integrated_strain.cc.bak new file mode 100644 index 00000000000..7afa788bad3 --- /dev/null +++ b/source/particle/property/integrated_strain.cc.bak @@ -0,0 +1,124 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + void + IntegratedStrain::initialize_one_particle_property(const Point &, + std::vector &data) const + { + const static Tensor<2,dim> identity = unit_symmetric_tensor(); + for (unsigned int i = 0; i < Tensor<2,dim>::n_independent_components ; ++i) + data.push_back(identity[Tensor<2,dim>::unrolled_to_component_indices(i)]); + } + + template + void + IntegratedStrain::update_particle_property(const unsigned int data_position, + const Vector &/*solution*/, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const + { + const Tensor<2,dim> old_strain(make_array_view(&particle->get_properties()[data_position], + &particle->get_properties()[data_position] + Tensor<2,dim>::n_independent_components)); + + Tensor<2,dim> grad_u; + for (unsigned int d=0; dget_timestep(); + + Tensor<2,dim> new_strain; + + // here we integrate the equation + // new_deformation_gradient = velocity_gradient * old_deformation_gradient + // using a RK4 integration scheme. + const Tensor<2,dim> k1 = grad_u * old_strain * dt; + new_strain = old_strain + 0.5*k1; + + const Tensor<2,dim> k2 = grad_u * new_strain * dt; + new_strain = old_strain + 0.5*k2; + + const Tensor<2,dim> k3 = grad_u * new_strain * dt; + new_strain = old_strain + k3; + + const Tensor<2,dim> k4 = grad_u * new_strain * dt; + + // the new strain is the rotated old strain plus the + // strain of the current time step + new_strain = old_strain + (k1 + 2.0*k2 + 2.0*k3 + k4)/6.0; + + // unroll and store the new strain + new_strain.unroll(&particle->get_properties()[data_position], + &particle->get_properties()[data_position] + Tensor<2,dim>::n_independent_components); + } + + template + UpdateTimeFlags + IntegratedStrain::need_update() const + { + return update_time_step; + } + + template + UpdateFlags + IntegratedStrain::get_needed_update_flags () const + { + return update_gradients; + } + + template + std::vector> + IntegratedStrain::get_property_information() const + { + const unsigned int n_components = Tensor<2,dim>::n_independent_components; + const std::vector> property_information (1,std::make_pair("integrated strain",n_components)); + return property_information; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(IntegratedStrain, + "integrated strain", + "A plugin in which the particle property tensor is " + "defined as the deformation gradient tensor " + "$\\mathbf F$ this particle has experienced. " + "$\\mathbf F$ can be polar-decomposed into the left stretching tensor " + "$\\mathbf L$ (the finite strain we are interested in), and the " + "rotation tensor $\\mathbf Q$. See the corresponding cookbook in " + "the manual for more detailed information.") + } + } +} diff --git a/source/particle/property/integrated_strain_invariant.cc.bak b/source/particle/property/integrated_strain_invariant.cc.bak new file mode 100644 index 00000000000..a0d13bb0f82 --- /dev/null +++ b/source/particle/property/integrated_strain_invariant.cc.bak @@ -0,0 +1,118 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + void + IntegratedStrainInvariant::initialize_one_particle_property(const Point &, + std::vector &data) const + { + data.push_back(0.0); + } + + + + template + void + IntegratedStrainInvariant::update_particle_property(const unsigned int data_position, + const Vector &/*solution*/, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const + { + // Integrated strain invariant from prior time step + const auto data = particle->get_properties(); + double old_strain = data[data_position]; + + // Current timestep + const double dt = this->get_timestep(); + + // Velocity gradients + Tensor<2,dim> grad_u; + for (unsigned int d=0; d strain_rate = symmetrize (grad_u); + + // Calculate strain rate second invariant + const double edot_ii = std::sqrt(std::max(-second_invariant(deviator(strain_rate)), 0.)); + + // New strain is the old strain plus dt*edot_ii + const double new_strain = old_strain + dt*edot_ii; + data[data_position] = new_strain; + } + + + + template + UpdateTimeFlags + IntegratedStrainInvariant::need_update() const + { + return update_time_step; + } + + + + template + UpdateFlags + IntegratedStrainInvariant::get_needed_update_flags () const + { + return update_gradients; + } + + + + template + std::vector> + IntegratedStrainInvariant::get_property_information() const + { + const std::vector> property_information (1,std::make_pair("integrated strain invariant",1)); + return property_information; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(IntegratedStrainInvariant, + "integrated strain invariant", + "A plugin in which the particle property is defined as " + "the finite strain invariant ($\\varepsilon_{ii}$). " + "This property is calculated with the timestep ($dt$) and " + "the second invariant of the deviatoric strain rate tensor " + "($\\dot{\\varepsilon}_{ii}$), where the value at time step $n$ is " + "$\\varepsilon_{ii}^{n} = \\varepsilon_{ii}^{n-1} + " + "dt\\dot{\\varepsilon}_{ii}$.") + } + } +} diff --git a/source/particle/property/interface.cc.bak b/source/particle/property/interface.cc.bak new file mode 100644 index 00000000000..47027dc7d45 --- /dev/null +++ b/source/particle/property/interface.cc.bak @@ -0,0 +1,820 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include + +#include +#include +#include + + +#include + +#include + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + ParticlePropertyInformation::ParticlePropertyInformation() + : + number_of_components(numbers::invalid_unsigned_int), + number_of_fields(numbers::invalid_unsigned_int), + number_of_plugins(numbers::invalid_unsigned_int) + {} + + + + ParticlePropertyInformation::ParticlePropertyInformation(const std::vector< + std::vector< + std::pair>> &properties) + { + unsigned int global_component_index = 0; + for (const auto &property : properties) + { + unsigned int component_per_plugin = 0; + unsigned int field_per_plugin = 0; + + position_per_plugin.push_back(global_component_index); + + for (const auto &entry : property) + { + const std::string name = entry.first; + const unsigned int n_components = entry.second; + + field_names.push_back(name); + components_per_field.push_back(n_components); + position_per_field.push_back(global_component_index); + component_per_plugin += n_components; + global_component_index += n_components; + ++field_per_plugin; + } + + fields_per_plugin.push_back(field_per_plugin); + components_per_plugin.push_back(component_per_plugin); + } + + number_of_components = global_component_index; + number_of_fields = field_names.size(); + number_of_plugins = properties.size(); + } + + + + bool + ParticlePropertyInformation::fieldname_exists(const std::string &name) const + { + return (std::find(field_names.begin(),field_names.end(),name) != field_names.end()); + } + + unsigned int + ParticlePropertyInformation::get_field_index_by_name(const std::string &name) const + { + const std::vector::const_iterator field = std::find(field_names.begin(), + field_names.end(), + name); + + AssertThrow(field != field_names.end(), + ExcMessage("The particle property manager was asked for a property " + "field with the name <" + name + ">, but no such field could " + "be found.")); + return std::distance(field_names.begin(),field); + } + + std::string + ParticlePropertyInformation::get_field_name_by_index(const unsigned int field_index) const + { + Assert(field_index < field_names.size(), + ExcMessage("The number of field names (" + std::to_string(field_names.size()) + + ") is smaller than the requested field index (" + + std::to_string(field_index) + ").")); + + return field_names[field_index]; + } + + + + unsigned int + ParticlePropertyInformation::get_position_by_field_name(const std::string &name) const + { + const unsigned int field_index = get_field_index_by_name(name); + return position_per_field[field_index]; + } + + + + unsigned int + ParticlePropertyInformation::get_components_by_field_name(const std::string &name) const + { + const unsigned int field_index = get_field_index_by_name(name); + return components_per_field[field_index]; + } + + + + unsigned int + ParticlePropertyInformation::get_position_by_field_index(const unsigned int field_index) const + { + return position_per_field[field_index]; + } + + + + unsigned int + ParticlePropertyInformation::get_components_by_field_index(const unsigned int field_index) const + { + return components_per_field[field_index]; + } + + + + unsigned int + ParticlePropertyInformation::get_position_by_plugin_index(const unsigned int plugin_index) const + { + return position_per_plugin[plugin_index]; + } + + + + unsigned int + ParticlePropertyInformation::get_components_by_plugin_index(const unsigned int plugin_index) const + { + return components_per_plugin[plugin_index]; + } + + + + unsigned int + ParticlePropertyInformation::get_fields_by_plugin_index(const unsigned int plugin_index) const + { + return fields_per_plugin[plugin_index]; + } + + + + unsigned int + ParticlePropertyInformation::n_plugins() const + { + return number_of_plugins; + } + + + + unsigned int + ParticlePropertyInformation::n_fields() const + { + return number_of_fields; + } + + + + unsigned int + ParticlePropertyInformation::n_components() const + { + return number_of_components; + } + + + + template + void + Interface::initialize_one_particle_property (const Point &, + std::vector &) const + {} + + + + DEAL_II_DISABLE_EXTRA_DIAGNOSTICS + template + void + Interface::update_particle_properties (const unsigned int data_position, + const std::vector> &solution, + const std::vector>> &gradients, + typename ParticleHandler::particle_iterator_range &particles) const + { + unsigned int i = 0; + for (typename ParticleHandler::particle_iterator particle = particles.begin(); + particle != particles.end(); ++particle, ++i) + { + // call the deprecated version of this function + update_particle_property(data_position, + solution[i], + gradients[i], + particle); + } + } + DEAL_II_ENABLE_EXTRA_DIAGNOSTICS + + + + template + void + Interface::update_particle_property (const unsigned int /*data_position*/, + const Vector &/*solution*/, + const std::vector> &/*gradients*/, + typename ParticleHandler::particle_iterator &/*particle*/) const + {} + + + + template + UpdateTimeFlags + Interface::need_update () const + { + return update_never; + } + + + + template + UpdateFlags + Interface::get_needed_update_flags () const + { + return update_default; + } + + + + template + InitializationModeForLateParticles + Interface::late_initialization_mode () const + { + return interpolate; + } + + + + template + void + IntegratorProperties::initialize_one_particle_property(const Point &/*position*/, + std::vector &data) const + { + data.resize(data.size() + n_integrator_properties, 0.0); + } + + + + template + std::vector> + IntegratorProperties::get_property_information() const + { + return {{"internal: integrator properties", n_integrator_properties}}; + } + + + + template + void + IntegratorProperties::parse_parameters (ParameterHandler &prm) + { + std::string name; + name = prm.get ("Integration scheme"); + + if (name == "rk2") + n_integrator_properties = Particle::Integrator::RK2::n_integrator_properties; + else if (name == "rk4") + n_integrator_properties = Particle::Integrator::RK4::n_integrator_properties; + else if (name == "euler") + n_integrator_properties = Particle::Integrator::Euler::n_integrator_properties; + else + AssertThrow(false, + ExcMessage("Unknown integrator scheme. The particle property 'Integrator properties' " + "does not know how many particle properties to store for this integration scheme.")); + } + + + + template + inline + Manager::Manager () + = default; + + + + template + inline + Manager::~Manager () + = default; + + + + template + void + Manager::initialize () + { + std::vector>> info; + + // Get the property information of the selected plugins + for (const auto &p : this->plugin_objects) + { + info.push_back(p->get_property_information()); + } + + // Initialize our property information + property_information = ParticlePropertyInformation(info); + for (const auto &p : this->plugin_objects) + { + p->initialize(); + } + } + + + + template + void + Manager::update () + { + for (const auto &p : this->plugin_objects) + p->update(); + } + + + + template + void + Manager::initialize_one_particle (typename ParticleHandler::particle_iterator &particle) const + { + if (property_information.n_components() == 0) + return; + + std::vector particle_properties; + particle_properties.reserve(property_information.n_components()); + + for (const auto &p : this->plugin_objects) + { + p->initialize_one_particle_property(particle->get_location(), + particle_properties); + } + + Assert(particle_properties.size() == property_information.n_components(), + ExcMessage("The reported numbers of particle property components do not sum up " + "to the number of particle properties that were initialized by " + "the property plugins. Check the selected property plugins for " + "consistency between reported size and actually set properties.")); + + particle->set_properties(particle_properties); + } + + + + template + std::vector + Manager::initialize_late_particle (const Point &particle_location, + const ParticleHandler &particle_handler, + const Interpolator::Interface &interpolator, + const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const + { + if (property_information.n_components() == 0) + return {}; + + std::vector particle_properties; + particle_properties.reserve(property_information.n_components()); + + unsigned int property_index = 0; + for (typename std::list>>::const_iterator + p = this->plugin_objects.begin(); p!=this->plugin_objects.end(); ++p, ++property_index) + { + switch ((*p)->late_initialization_mode()) + { + case aspect::Particle::Property::initialize_to_zero: + { + for (unsigned int property_component = 0; property_component < property_information.get_components_by_plugin_index(property_index); ++property_component) + particle_properties.push_back(0.0); + break; + } + + case aspect::Particle::Property::initialize: + { + (*p)->initialize_one_particle_property(particle_location, + particle_properties); + break; + } + + case aspect::Particle::Property::interpolate: + { + typename parallel::distributed::Triangulation::cell_iterator found_cell; + + if (cell == typename parallel::distributed::Triangulation::active_cell_iterator()) + { + found_cell = (GridTools::find_active_cell_around_point<> (this->get_mapping(), + this->get_triangulation(), + particle_location)).first; + } + else + found_cell = cell; + + std::vector> interpolated_properties; + + try + { + interpolated_properties = interpolator.properties_at_points(particle_handler, + std::vector> (1,particle_location), + ComponentMask(property_information.n_components(),true), + found_cell); + } + // interpolators that throw exceptions usually do not result in + // anything good, because they result in an unwinding of the stack + // and, if only one processor triggers an exception, the + // destruction of objects often causes a deadlock or completely + // unrelated MPI error messages. Thus, if an exception is + // generated, catch it, print an error message, and abort the program. + catch (std::exception &exc) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on MPI process <" + << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) + << "> while generating new particle properties: " + << std::endl + << exc.what() << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + // terminate the program! + MPI_Abort (MPI_COMM_WORLD, 1); + } + + for (unsigned int property_component = 0; property_component < property_information.get_components_by_plugin_index(property_index); ++property_component) + particle_properties.push_back(interpolated_properties[0][property_information.get_position_by_plugin_index(property_index)+property_component]); + break; + } + + case aspect::Particle::Property::interpolate_respect_boundary: + { + typename parallel::distributed::Triangulation::cell_iterator found_cell; + + if (cell == typename parallel::distributed::Triangulation::active_cell_iterator()) + { + found_cell = (GridTools::find_active_cell_around_point<> (this->get_mapping(), + this->get_triangulation(), + particle_location)).first; + } + else + found_cell = cell; + + const auto &manager = this->get_boundary_composition_manager(); + const auto &fixed_boundaries = manager.get_fixed_composition_boundary_indicators(); + + // Determine if the current cell is at a Dirichlet boundary + bool cell_at_fixed_boundary = false; + unsigned int boundary_face = numbers::invalid_unsigned_int; + double minimum_face_distance = std::numeric_limits::max(); + for (const unsigned int f : cell->face_indices()) + if (cell->at_boundary(f) && fixed_boundaries.count(cell->face(f)->boundary_id()) == 1) + { + const double face_center_distance = particle_location.distance_square(cell->face(f)->center(true)); + if (face_center_distance < minimum_face_distance) + { + minimum_face_distance = face_center_distance; + boundary_face = f; + cell_at_fixed_boundary = true; + } + } + + // If no Dirichlet boundary, interpolate + if (cell_at_fixed_boundary == false) + { + const std::vector> interpolated_properties = interpolator.properties_at_points(particle_handler, + std::vector> (1,particle_location), + ComponentMask(property_information.n_components(),true), + found_cell); + for (unsigned int property_component = 0; property_component < property_information.get_components_by_plugin_index(property_index); ++property_component) + particle_properties.push_back(interpolated_properties[0][property_information.get_position_by_plugin_index(property_index)+property_component]); + } + // Otherwise use the boundary condition + else + { + Assert(property_information.get_components_by_plugin_index(property_index) == this->n_compositional_fields(), + ExcInternalError()); + + const types::boundary_id boundary_id = cell->face(boundary_face)->boundary_id(); + + for (unsigned int c=0; cn_compositional_fields(); ++c) + { + const double composition = manager.boundary_composition(boundary_id,particle_location,c); + particle_properties.push_back(composition); + } + } + + break; + } + + default: + Assert (false, ExcInternalError()); + } + } + + Assert (particle_properties.size() == property_information.n_components(), ExcInternalError()); + + return particle_properties; + } + + + + template + void + Manager::update_particles (typename ParticleHandler::particle_iterator_range &particles, + const std::vector> &solution, + const std::vector>> &gradients) const + { + unsigned int plugin_index = 0; + for (typename std::list>>::const_iterator + p = this->plugin_objects.begin(); p!=this->plugin_objects.end(); ++p,++plugin_index) + { + (*p)->update_particle_properties(property_information.get_position_by_plugin_index(plugin_index), + solution, + gradients, + particles); + } + } + + + + template + UpdateTimeFlags + Manager::need_update () const + { + UpdateTimeFlags update = update_never; + for (const auto &p : this->plugin_objects) + { + update = std::max(update, p->need_update()); + } + return update; + } + + + + template + UpdateFlags + Manager::get_needed_update_flags () const + { + UpdateFlags update = update_default; + for (const auto &p : this->plugin_objects) + { + update |= p->get_needed_update_flags(); + } + + return (update & (update_default | update_values | update_gradients)); + } + + + + template + bool + Manager::plugin_name_exists(const std::string &name) const + { + return (std::find(plugin_names.begin(),plugin_names.end(),name) != plugin_names.end()); + } + + + + template + bool + Manager::check_plugin_order(const std::string &first, const std::string &second) const + { + + AssertThrow(first != second, + ExcMessage("The first and second string are the same, so can not check the order.")); + AssertThrow(plugin_name_exists(first), + ExcMessage("Could not find a plugin with the name <" + first + ">.")); + AssertThrow(plugin_name_exists(second), + ExcMessage("Could not find a plugin with the name <" + second + ">.")); + + return (std::find(plugin_names.begin(),plugin_names.end(),first) + < std::find(plugin_names.begin(),plugin_names.end(),second)); + } + + + + template + unsigned int + Manager::get_plugin_index_by_name(const std::string &name) const + { + const std::vector::const_iterator plugin = std::find(plugin_names.begin(), + plugin_names.end(), + name); + + AssertThrow(plugin != plugin_names.end(), + ExcMessage("The particle property manager was asked for a plugin " + "with the name <" + name + ">, but no such plugin could " + "be found.")); + return std::distance(plugin_names.begin(),plugin); + } + + + + template + unsigned int + Manager::get_n_property_components () const + { + return property_information.n_components(); + } + + + + template + std::size_t + Manager::get_particle_size () const + { + return (property_information.n_components()+2*dim) * sizeof(double) + sizeof(types::particle_index); + } + + + + template + const ParticlePropertyInformation & + Manager::get_data_info () const + { + return property_information; + } + + + + template + unsigned int + Manager::get_property_component_by_name(const std::string &name) const + { + return property_information.get_position_by_field_name(name); + } + + + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + Manager::declare_parameters (ParameterHandler &prm) + { + // finally also construct a string for Patterns::MultipleSelection that + // contains the names of all registered particle properties + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + + prm.declare_entry("List of particle properties", + "", + Patterns::MultipleSelection(pattern_of_names), + "A comma separated list of particle properties that should be tracked. " + "By default none is selected, which means only position, velocity " + "and id of the particles are output. \n\n" + "The following properties are available:\n\n" + + + std::get(registered_plugins).get_description_string()); + + // now declare the parameters of each of the registered + // particle properties in turn + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + Manager::parse_parameters (ParameterHandler &prm) + { + Assert (std::get(registered_plugins).plugins != nullptr, + ExcMessage ("No postprocessors registered!?")); + + // now also see which derived quantities we are to compute + plugin_names = Utilities::split_string_list(prm.get("List of particle properties")); + AssertThrow(Utilities::has_unique_entries(plugin_names), + ExcMessage("The list of strings for the parameter " + "'Particles/List of particle properties' contains entries more than once. " + "This is not allowed. Please check your parameter file.")); + + // see if 'all' was selected (or is part of the list). if so + // simply replace the list with one that contains all names + if (std::find (plugin_names.begin(), + plugin_names.end(), + "all") != plugin_names.end()) + { + plugin_names.clear(); + for (typename std::list>::PluginInfo>::const_iterator + p = std::get(registered_plugins).plugins->begin(); + p != std::get(registered_plugins).plugins->end(); ++p) + plugin_names.push_back (std::get<0>(*p)); + } + + // then go through the list, create objects and let them parse + // their own parameters + for (auto &plugin_name : plugin_names) + { + this->plugin_objects.emplace_back (std::get(registered_plugins) + .create_plugin (plugin_name, + "Particle property plugins")); + + if (SimulatorAccess *sim = dynamic_cast*>(this->plugin_objects.back().get())) + sim->initialize_simulator (this->get_simulator()); + + this->plugin_objects.back()->parse_parameters (prm); + } + + // lastly store internal integrator properties + this->plugin_objects.emplace_back (std::make_unique>()); + this->plugin_objects.back()->parse_parameters (prm); + } + + + + template + void + Manager::set_particle_world_index(unsigned int particle_world_index) + { + for (auto &property : this->plugin_objects) + { + property->set_particle_world_index(particle_world_index); + } + } + + + + template + void + Manager:: + register_particle_property (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + + template + void + Manager::write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Particle property interface", + out); + } + + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace Particle + { + namespace Property + { +#define INSTANTIATE(dim) \ + template class Interface; \ + template class Manager; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + } +} diff --git a/source/particle/property/melt_particle.cc.bak b/source/particle/property/melt_particle.cc.bak new file mode 100644 index 00000000000..fa80b32bee3 --- /dev/null +++ b/source/particle/property/melt_particle.cc.bak @@ -0,0 +1,126 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + void + MeltParticle::initialize_one_particle_property(const Point &/*position*/, + std::vector &data) const + { + data.push_back(0.0); + } + + template + void + MeltParticle::update_particle_property(const unsigned int data_position, + const Vector &solution, + const std::vector> &/*gradients*/, + typename ParticleHandler::particle_iterator &particle) const + { + AssertThrow(this->introspection().compositional_name_exists("porosity"), + ExcMessage("Particle property melt particle only works if" + "there is a compositional field called porosity.")); + const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); + + if (solution[this->introspection().component_indices.compositional_fields[porosity_idx]] > threshold_for_melt_presence) + particle->get_properties()[data_position] = 1.0; + else + particle->get_properties()[data_position] = 0.0; + } + + template + UpdateTimeFlags + MeltParticle::need_update() const + { + return update_time_step; + } + + template + UpdateFlags + MeltParticle::get_needed_update_flags () const + { + return update_values; + } + + template + std::vector> + MeltParticle::get_property_information() const + { + std::vector> property_information (1,std::make_pair("melt_presence",1)); + return property_information; + } + + template + void + MeltParticle::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Melt particle"); + { + prm.declare_entry ("Threshold for melt presence", "1e-3", + Patterns::Double (0., 1.), + "The minimum porosity that has to be present at the position of a particle " + "for it to be considered a melt particle (in the sense that the melt presence " + "property is set to 1)."); + } + prm.leave_subsection(); + } + + + template + void + MeltParticle::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Melt particle"); + { + threshold_for_melt_presence = prm.get_double ("Threshold for melt presence"); + } + prm.leave_subsection(); + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(MeltParticle, + "melt particle", + "Implementation of a plugin in which the particle " + "property is defined as presence of melt above a " + "threshold, which can be set as an input parameter. " + "This property is set to 0 if melt is not present and " + "set to 1 if melt is present.") + } + } +} diff --git a/source/particle/property/pT_path.cc.bak b/source/particle/property/pT_path.cc.bak new file mode 100644 index 00000000000..ffff2519a9e --- /dev/null +++ b/source/particle/property/pT_path.cc.bak @@ -0,0 +1,123 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + void + PTPath::initialize() + { + // Make sure we keep track of the initial temperature manager and + // that it continues to live beyond the time when the simulator + // class releases its pointer to it. + initial_temperature = this->get_initial_temperature_manager_pointer(); + } + + + + + template + void + PTPath::initialize_one_particle_property(const Point &position, + std::vector &data) const + { + // The following is strictly only correct whenever a particle is + // created in the first time step. After that, taking pressure and + // temperature from adiabatic and initial temperature objects is + // not quite correct -- instead, we should be initializing from + // the current pressure and temperature, but that is substantially + // more complicated since we are not passed this information. + // + // The issue is probably not terribly important because at least for + // all following time steps, we set temperature and pressure to + // their correct then-current values. + data.push_back(this->get_adiabatic_conditions().pressure(position)); + data.push_back(initial_temperature->initial_temperature(position)); + } + + + + template + void + PTPath::update_particle_property(const unsigned int data_position, + const Vector &solution, + const std::vector> &/*gradients*/, + typename ParticleHandler::particle_iterator &particle) const + { + particle->get_properties()[data_position] = solution[this->introspection().component_indices.pressure]; + particle->get_properties()[data_position+1] = solution[this->introspection().component_indices.temperature]; + } + + + + template + UpdateTimeFlags + PTPath::need_update() const + { + return update_output_step; + } + + + + template + UpdateFlags + PTPath::get_needed_update_flags () const + { + return update_values; + } + + + + template + std::vector> + PTPath::get_property_information() const + { + return {{"p", 1}, {"T", 1}}; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(PTPath, + "pT path", + "Implementation of a plugin in which the particle " + "property is defined as the current pressure and " + "temperature at this position. This can be used " + "to generate pressure-temperature paths of " + "material points over time.") + } + } +} diff --git a/source/particle/property/position.cc.bak b/source/particle/property/position.cc.bak new file mode 100644 index 00000000000..a21a0837482 --- /dev/null +++ b/source/particle/property/position.cc.bak @@ -0,0 +1,80 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + void + Position::initialize_one_particle_property(const Point &position, + std::vector &data) const + { + for (unsigned int i = 0; i < dim; ++i) + data.push_back(position[i]); + } + + template + void + Position::update_particle_property(const unsigned int data_position, + const Vector &/*solution*/, + const std::vector> &/*gradients*/, + typename ParticleHandler::particle_iterator &particle) const + { + for (unsigned int i = 0; i < dim; ++i) + particle->get_properties()[data_position+i] = particle->get_location()[i]; + } + + template + UpdateTimeFlags + Position::need_update() const + { + return update_output_step; + } + + template + std::vector> + Position::get_property_information() const + { + const std::vector> property_information (1,std::make_pair("position",dim)); + return property_information; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(Position, + "position", + "Implementation of a plugin in which the particle " + "property is defined as the current position.") + } + } +} diff --git a/source/particle/property/reference_position.cc.bak b/source/particle/property/reference_position.cc.bak new file mode 100644 index 00000000000..6d5fa5f978e --- /dev/null +++ b/source/particle/property/reference_position.cc.bak @@ -0,0 +1,80 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + void + ReferencePosition::initialize_one_particle_property(const Point &position, + std::vector &data) const + { + for (unsigned int i = 0; i < dim; ++i) + data.push_back(position[i]); + } + + template + void + ReferencePosition::update_particle_property(const unsigned int data_position, + const Vector &/*solution*/, + const std::vector> &/*gradients*/, + typename ParticleHandler::particle_iterator &particle) const + { + for (unsigned int i = 0; i < dim; ++i) + particle->get_properties()[data_position+i] = particle->get_reference_location()[i]; + } + + template + UpdateTimeFlags + ReferencePosition::need_update() const + { + return update_output_step; + } + + template + std::vector> + ReferencePosition::get_property_information() const + { + const std::vector> property_information (1,std::make_pair("reference position",dim)); + return property_information; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(ReferencePosition, + "reference position", + "Implementation of a plugin in which the particle " + "property is defined as the current reference position.") + } + } +} diff --git a/source/particle/property/strain_rate.cc.bak b/source/particle/property/strain_rate.cc.bak new file mode 100644 index 00000000000..be79a182387 --- /dev/null +++ b/source/particle/property/strain_rate.cc.bak @@ -0,0 +1,102 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + void + StrainRate::initialize_one_particle_property(const Point &, + std::vector &data) const + { + const static Tensor<2,dim> identity = unit_symmetric_tensor(); + for (unsigned int i = 0; i < Tensor<2,dim>::n_independent_components ; ++i) + data.push_back(identity[Tensor<2,dim>::unrolled_to_component_indices(i)]); + + } + + template + void + StrainRate::update_particle_property(const unsigned int data_position, + const Vector &/*solution*/, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const + { + const auto data = particle->get_properties(); + // Velocity gradients + Tensor<2,dim> grad_u; + for (unsigned int d=0; d strain_rate = symmetrize (grad_u); + + for (unsigned int i = 0; i < Tensor<2,dim>::n_independent_components ; ++i) + data[data_position + i] = strain_rate[Tensor<2,dim>::unrolled_to_component_indices(i)]; + + } + + template + UpdateTimeFlags + StrainRate::need_update() const + { + return update_time_step; + } + + template + UpdateFlags + StrainRate::get_needed_update_flags () const + { + return update_gradients; + } + + template + std::vector> + StrainRate::get_property_information() const + { + const unsigned int n_components = Tensor<2,dim>::n_independent_components; + const std::vector> property_information (1,std::make_pair("strainrate",n_components)); + return property_information; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(StrainRate, + "strain rate", + "Implementation of a plugin in which the time evolution of " + "strain rate is saved and stored on the particles.") + } + } +} diff --git a/source/particle/property/velocity.cc.bak b/source/particle/property/velocity.cc.bak new file mode 100644 index 00000000000..82270e8db5b --- /dev/null +++ b/source/particle/property/velocity.cc.bak @@ -0,0 +1,88 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include + +namespace aspect +{ + namespace Particle + { + namespace Property + { + template + void + Velocity::initialize_one_particle_property(const Point &, + std::vector &data) const + { + for (unsigned int i = 0; i < dim; ++i) + data.push_back(0.0); + } + + template + void + Velocity::update_particle_property(const unsigned int data_position, + const Vector &solution, + const std::vector> &/*gradients*/, + typename ParticleHandler::particle_iterator &particle) const + { + for (unsigned int i = 0; i < dim; ++i) + particle->get_properties()[data_position+i] = solution[this->introspection().component_indices.velocities[i]]; + } + + template + UpdateTimeFlags + Velocity::need_update() const + { + return update_output_step; + } + + template + UpdateFlags + Velocity::get_needed_update_flags () const + { + return update_values; + } + + template + std::vector> + Velocity::get_property_information() const + { + const std::vector> property_information (1,std::make_pair("velocity",dim)); + return property_information; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(Velocity, + "velocity", + "Implementation of a plugin in which the particle " + "property is defined as the recent velocity at " + "this position.") + } + } +} diff --git a/source/particle/property/viscoplastic_strain_invariants.cc.bak b/source/particle/property/viscoplastic_strain_invariants.cc.bak new file mode 100644 index 00000000000..8ea89a2cda2 --- /dev/null +++ b/source/particle/property/viscoplastic_strain_invariants.cc.bak @@ -0,0 +1,243 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include + + +namespace aspect +{ + namespace Particle + { + namespace Property + { + + template + ViscoPlasticStrainInvariant::ViscoPlasticStrainInvariant () + : + n_components(0), + material_inputs(1,0) + {} + + + + template + void + ViscoPlasticStrainInvariant::initialize () + { + AssertThrow(Plugins::plugin_type_matches> + (this->get_material_model()), + ExcMessage("This initial condition only makes sense in combination " + "with the visco_plastic material model.")); + + n_components = 0; + material_inputs = MaterialModel::MaterialModelInputs(1,this->n_compositional_fields()); + + // Find out which fields are used. + if (this->introspection().compositional_name_exists("plastic_strain")) + n_components += 1; + + if (this->introspection().compositional_name_exists("viscous_strain")) + n_components += 1; + + if (this->introspection().compositional_name_exists("total_strain")) + n_components += 1; + + if (this->introspection().compositional_name_exists("noninitial_plastic_strain")) + n_components += 1; + + if (n_components == 0) + AssertThrow(false, + ExcMessage("This particle property requires a compositional " + "strain field (plastic_strain, viscous_strain, " + "or total_strain).")); + } + + + + template + void + ViscoPlasticStrainInvariant::initialize_one_particle_property(const Point &position, + std::vector &data) const + { + // Give each strain field its initial composition if one is prescribed. + if (this->introspection().compositional_name_exists("plastic_strain")) + data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("plastic_strain"))); + + if (this->introspection().compositional_name_exists("viscous_strain")) + data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("viscous_strain"))); + + if (this->introspection().compositional_name_exists("total_strain")) + data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("total_strain"))); + + if (this->introspection().compositional_name_exists("noninitial_plastic_strain")) + data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("noninitial_plastic_strain"))); + + } + + + + template + void + ViscoPlasticStrainInvariant::update_particle_property(const unsigned int data_position, + const Vector &solution, + const std::vector> &gradients, + typename ParticleHandler::particle_iterator &particle) const + { + // Current timestep + const double dt = this->get_timestep(); + + // Velocity gradients + Tensor<2,dim> grad_u; + for (unsigned int d=0; dintrospection().component_indices.pressure]; + material_inputs.temperature[0] = solution[this->introspection().component_indices.temperature]; + material_inputs.position[0] = particle->get_location(); + + // Calculate strain rate from velocity gradients + material_inputs.strain_rate[0] = symmetrize (grad_u); + + // Put compositional fields into single variable + for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) + { + material_inputs.composition[0][i] = solution[this->introspection().component_indices.compositional_fields[i]]; + } + + // Find out plastic yielding by calling function in material model. + const MaterialModel::ViscoPlastic &viscoplastic + = Plugins::get_plugin_as_type>(this->get_material_model()); + + const bool plastic_yielding = viscoplastic.is_yielding(material_inputs); + + // Next take the integrated strain invariant from the prior time step. + const auto data = particle->get_properties(); + + // Calculate strain rate second invariant + const double edot_ii = std::sqrt(std::max(-second_invariant(deviator(material_inputs.strain_rate[0])), 0.)); + + // Calculate strain invariant magnitude over the last time step + const double strain_update = dt*edot_ii; + + /* Update the strain values that are used in the simulation, which use the following assumptions + * to identify the correct position in the data vector for each value: + * (1) Total strain cannot be used in combination with any other strain field + * (2) If plastic strain is tracked, it will always be in the first data position + * (3) If noninitial plastic strain is tracked, it will always be in the last data position + * (4) If noninitial plastic strain is tracked, plastic strain is also being tracked + * (5) If only viscous strain is tracked, it will be in the first data position. + * (6) If both viscous and plastic strain are tracked, viscous strain will be in the second data position + * If these assumptions change in the future, they will need to be updated. + * */ + + if (this->introspection().compositional_name_exists("plastic_strain") && plastic_yielding == true) + data[data_position] += strain_update; + + if (this->introspection().compositional_name_exists("viscous_strain") && plastic_yielding == false) + { + // Not yielding and only one field, which tracks the viscous strain. + if (n_components == 1) + data[data_position] += strain_update; + + // Not yielding and either two or three fields are tracked. If two fields are tracked, + // they represent plastic strain (first data position) and viscous strain (second data + // data position, updated below). If three fields are tracked, they represent plastic + // strain (first data position), viscous strain (second data position, updated below), + // and noninitial plastic strain (third data position). In either case, the viscous + // strain is in the second data position, allowing us to use a single expression. + if (n_components > 1) + data[data_position+1] += strain_update; + } + + // Only one field, which tracks total strain and is updated regardless of whether the + // material is yielding or not. + if (this->introspection().compositional_name_exists("total_strain")) + data[data_position] += strain_update; + + // Yielding, and noninitial plastic strain (last data position, updated below) is tracked. + if (this->introspection().compositional_name_exists("noninitial_plastic_strain") && plastic_yielding == true) + data[data_position+(n_components-1)] += strain_update; + } + + + + template + UpdateTimeFlags + ViscoPlasticStrainInvariant::need_update() const + { + return update_time_step; + } + + + + template + UpdateFlags + ViscoPlasticStrainInvariant::get_needed_update_flags () const + { + // Need to update both of these to send into material model. + return update_values | update_gradients; + } + + template + std::vector> + ViscoPlasticStrainInvariant::get_property_information() const + { + std::vector> property_information; + + //Check which fields are used in model and make an output for each. + if (this->introspection().compositional_name_exists("plastic_strain")) + property_information.emplace_back("plastic_strain", 1); + + if (this->introspection().compositional_name_exists("viscous_strain")) + property_information.emplace_back("viscous_strain", 1); + + if (this->introspection().compositional_name_exists("total_strain")) + property_information.emplace_back("total_strain", 1); + + if (this->introspection().compositional_name_exists("noninitial_plastic_strain")) + property_information.emplace_back("noninitial_plastic_strain", 1); + + return property_information; + } + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Particle + { + namespace Property + { + ASPECT_REGISTER_PARTICLE_PROPERTY(ViscoPlasticStrainInvariant, + "viscoplastic strain invariants", + "A plugin that calculates the finite strain invariant a particle has " + "experienced and assigns it to either the plastic and/or viscous strain field based " + "on whether the material is plastically yielding, or the total strain field " + "used in the visco plastic material model. The implementation of this property " + "is equivalent to the implementation for compositional fields that is located in " + "the plugin in \\texttt{benchmarks/buiter\\_et\\_al\\_2008\\_jgr/plugin/}," + "and is effectively the same as what the visco plastic material model uses for compositional fields.") + } + } +} diff --git a/source/particle/world.cc.bak b/source/particle/world.cc.bak new file mode 100644 index 00000000000..0c558f8a996 --- /dev/null +++ b/source/particle/world.cc.bak @@ -0,0 +1,1384 @@ +/* + Copyright (C) 2015 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +namespace aspect +{ + namespace Particle + { + template + World::World() + = default; + + template + World::~World() + = default; + + template + void + World::initialize() + { + CitationInfo::add("particles"); + if (particle_load_balancing & ParticleLoadBalancing::repartition) + this->get_triangulation().signals.weight.connect( +#if DEAL_II_VERSION_GTE(9,6,0) + [&] (const typename parallel::distributed::Triangulation::cell_iterator &cell, + const CellStatus status) + -> unsigned int +#else + [&] (const typename parallel::distributed::Triangulation::cell_iterator &cell, + const typename parallel::distributed::Triangulation::CellStatus status) + -> unsigned int +#endif + { + return this->cell_weight(cell, status); + }); + + // Create a particle handler that stores the future particles. + // If we restarted from a checkpoint we will fill this particle handler + // later with its serialized variables and stored particles + particle_handler = std::make_unique>(this->get_triangulation(), + this->get_mapping(), + property_manager->get_n_property_components()); + + particle_handler_backup.initialize(this->get_triangulation(), + this->get_mapping(), + property_manager->get_n_property_components()); + + connect_to_signals(this->get_signals()); + + AssertThrow(this->introspection().get_composition_base_element_indices().size()<=1, + ExcNotImplemented("Particles are not supported in computations with compositional fields with different finite element types.")); + } + + + + template + void + World::update() + { + generator->update(); + integrator->update(); + interpolator->update(); + property_manager->update(); + } + + + + template + const Property::Manager & + World::get_property_manager() const + { + return *property_manager; + } + + + + template + const Particles::ParticleHandler & + World::get_particle_handler() const + { + return *particle_handler.get(); + } + + + + template + Particles::ParticleHandler & + World::get_particle_handler() + { + return *particle_handler.get(); + } + + + + template + void + World::copy_particle_handler (const Particles::ParticleHandler &from_particle_handler, + Particles::ParticleHandler &to_particle_handler) const + { + { + TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Copy"); + + to_particle_handler.copy_from(from_particle_handler); + } + } + + + + template + void + World::backup_particles () + { + copy_particle_handler (*particle_handler.get(), particle_handler_backup); + } + + + + template + void + World::restore_particles () + { + copy_particle_handler (particle_handler_backup, *particle_handler.get()); + } + + + + template + const Interpolator::Interface & + World::get_interpolator() const + { + return *interpolator; + } + + + + template + types::particle_index + World::n_global_particles() const + { + return particle_handler->n_global_particles(); + } + + + + template + void + World::connect_to_signals(aspect::SimulatorSignals &signals) + { + signals.post_set_initial_state.connect( + [&] (const SimulatorAccess &) + { + this->setup_initial_state(); + }); + + connect_particle_handler_signals(signals,*particle_handler); + // Particle handler backup will not be stored for checkpointing + connect_particle_handler_signals(signals, particle_handler_backup, false); + + signals.post_refinement_load_user_data.connect( + [&] (typename parallel::distributed::Triangulation &) + { + this->apply_particle_per_cell_bounds(); + }); + + signals.post_resume_load_user_data.connect( + [&] (typename parallel::distributed::Triangulation &) + { + this->apply_particle_per_cell_bounds(); + }); + } + + + + template + void + World::connect_particle_handler_signals(aspect::SimulatorSignals &signals, + ParticleHandler &particle_handler_, + const bool connect_to_checkpoint_signals) const + { + signals.pre_refinement_store_user_data.connect( + [&] (typename parallel::distributed::Triangulation &) + { + particle_handler_.prepare_for_coarsening_and_refinement(); + }); + + signals.post_refinement_load_user_data.connect( + [&] (typename parallel::distributed::Triangulation &) + { + particle_handler_.unpack_after_coarsening_and_refinement(); + }); + + // Only connect to checkpoint signals if requested + if (connect_to_checkpoint_signals) + { + signals.pre_checkpoint_store_user_data.connect( + [&] (typename parallel::distributed::Triangulation &) + { + particle_handler_.prepare_for_serialization(); + }); + + signals.post_resume_load_user_data.connect( + [&] (typename parallel::distributed::Triangulation &) + { + particle_handler_.deserialize(); + }); + } + + if (update_ghost_particles && + dealii::Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()) > 1) + { + auto do_ghost_exchange = [&] (typename parallel::distributed::Triangulation &) + { + particle_handler_.exchange_ghost_particles(); + }; + signals.post_refinement_load_user_data.connect(do_ghost_exchange); + signals.post_resume_load_user_data.connect(do_ghost_exchange); + } + + signals.post_mesh_deformation.connect( + [&] (const SimulatorAccess &) + { + particle_handler->sort_particles_into_subdomains_and_cells(); + }, + boost::signals2::at_front); + } + + + + template + void + World::apply_particle_per_cell_bounds() + { + // If any load balancing technique is selected that creates/destroys particles + if (particle_load_balancing & ParticleLoadBalancing::remove_and_add_particles) + { + // First do some preparation for particle generation in poorly + // populated areas. For this we need to know which particle ids to + // generate so that they are globally unique. + // Ensure this by communicating the number of particles that every + // process is going to generate. + particle_handler->update_cached_numbers(); + types::particle_index local_next_particle_index = particle_handler->get_next_free_particle_index(); + if (particle_load_balancing & ParticleLoadBalancing::add_particles) + { + types::particle_index particles_to_add_locally = 0; + + // Loop over all cells and determine the number of particles to generate + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + const unsigned int particles_in_cell = particle_handler->n_particles_in_cell(cell); + + if (particles_in_cell < min_particles_per_cell) + particles_to_add_locally += static_cast (min_particles_per_cell - particles_in_cell); + } + + // Determine the starting particle index of this process, which + // is the highest currently existing particle index plus the sum + // of the number of newly generated particles of all + // processes with a lower rank. + + types::particle_index local_start_index = 0.0; + + const int ierr = MPI_Scan(&particles_to_add_locally, &local_start_index, 1, DEAL_II_PARTICLE_INDEX_MPI_TYPE, MPI_SUM, this->get_mpi_communicator()); + AssertThrowMPI(ierr); + + local_start_index -= particles_to_add_locally; + local_next_particle_index += local_start_index; + + const types::particle_index globally_generated_particles = + dealii::Utilities::MPI::sum(particles_to_add_locally,this->get_mpi_communicator()); + + AssertThrow (particle_handler->get_next_free_particle_index() + <= std::numeric_limits::max() - globally_generated_particles, + ExcMessage("There is no free particle index left to generate a new particle id. Please check if your " + "model generates unusually many new particles (by repeatedly deleting and regenerating particles), or " + "recompile deal.II with the DEAL_II_WITH_64BIT_INDICES option enabled, to use 64-bit integers for " + "particle ids.")); + } + + std::mt19937 random_number_generator; + + // Loop over all cells and generate or remove the particles cell-wise + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + const unsigned int n_particles_in_cell = particle_handler->n_particles_in_cell(cell); + + // Add particles if necessary + if ((particle_load_balancing & ParticleLoadBalancing::add_particles) && + (n_particles_in_cell < min_particles_per_cell)) + { + for (unsigned int i = n_particles_in_cell; i < min_particles_per_cell; ++i,++local_next_particle_index) + { + std::pair> new_particle = generator->generate_particle(cell,local_next_particle_index); + + const std::vector particle_properties = + property_manager->initialize_late_particle(new_particle.second.get_location(), + *particle_handler, + *interpolator, + cell); + + typename ParticleHandler::particle_iterator particle = particle_handler->insert_particle(new_particle.second, + typename parallel::distributed::Triangulation::cell_iterator (&this->get_triangulation(), + new_particle.first.first, + new_particle.first.second)); + particle->set_properties(particle_properties); + } + } + + // Remove particles if necessary + else if ((particle_load_balancing & ParticleLoadBalancing::remove_particles) && + (n_particles_in_cell > max_particles_per_cell)) + { + const unsigned int n_particles_to_remove = n_particles_in_cell - max_particles_per_cell; + for (unsigned int i=0; i < n_particles_to_remove; ++i) + { + const unsigned int current_n_particles_in_cell = particle_handler->n_particles_in_cell(cell); + const unsigned int index_to_remove = std::uniform_int_distribution + (0,current_n_particles_in_cell-1)(random_number_generator); + + auto particle_to_remove = particle_handler->particles_in_cell(cell).begin(); + std::advance(particle_to_remove, index_to_remove); + particle_handler->remove_particle(particle_to_remove); + } + + } + } + + particle_handler->update_cached_numbers(); + } + } + + template + unsigned int + World::cell_weight(const typename parallel::distributed::Triangulation::cell_iterator &cell, +#if DEAL_II_VERSION_GTE(9,6,0) + const CellStatus status +#else + const typename parallel::distributed::Triangulation::CellStatus status +#endif + ) + { + if (cell->is_active() && !cell->is_locally_owned()) + return 0; + + const unsigned int base_weight = 1000; + unsigned int n_particles_in_cell = 0; + switch (status) + { +#if DEAL_II_VERSION_GTE(9,6,0) + case CellStatus::cell_will_persist: + case CellStatus::cell_will_be_refined: + n_particles_in_cell = particle_handler->n_particles_in_cell(cell); + break; + + case CellStatus::cell_invalid: + break; + + case CellStatus::children_will_be_coarsened: + for (const auto &child : cell->child_iterators()) + n_particles_in_cell += particle_handler->n_particles_in_cell(child); + break; +#else + case parallel::distributed::Triangulation::CELL_PERSIST: + case parallel::distributed::Triangulation::CELL_REFINE: + n_particles_in_cell = particle_handler->n_particles_in_cell(cell); + break; + + case parallel::distributed::Triangulation::CELL_INVALID: + break; + + case parallel::distributed::Triangulation::CELL_COARSEN: + for (const auto &child : cell->child_iterators()) + n_particles_in_cell += particle_handler->n_particles_in_cell(child); + break; +#endif + default: + Assert(false, ExcInternalError()); + break; + } + return base_weight + n_particles_in_cell * particle_weight; + } + + + template + std::map + World::get_subdomain_id_to_neighbor_map() const + { + std::map subdomain_id_to_neighbor_map; + const std::set ghost_owners = this->get_triangulation().ghost_owners(); + std::set::const_iterator ghost_owner = ghost_owners.begin(); + + for (unsigned int neighbor_id=0; neighbor_id + void + World::local_initialize_particles(const typename ParticleHandler::particle_iterator &begin_particle, + const typename ParticleHandler::particle_iterator &end_particle) + { + for (typename ParticleHandler::particle_iterator it = begin_particle; it!=end_particle; ++it) + property_manager->initialize_one_particle(it); + } + + + + template + void + World::local_update_particles(const typename DoFHandler::active_cell_iterator &cell, + internal::SolutionEvaluators &evaluators) + { + const unsigned int n_particles_in_cell = particle_handler->n_particles_in_cell(cell); + typename ParticleHandler::particle_iterator_range particles = particle_handler->particles_in_cell(cell); + + std::vector> positions; + positions.reserve(n_particles_in_cell); + + for (const auto &particle : particles) + positions.push_back(particle.get_reference_location()); + + const UpdateFlags update_flags = property_manager->get_needed_update_flags(); + + boost::container::small_vector solution_values(this->get_fe().dofs_per_cell); + + cell->get_dof_values(this->get_solution(), + solution_values.begin(), + solution_values.end()); + + if (update_flags & (update_values | update_gradients)) + evaluators.reinit(cell, positions, {solution_values.data(), solution_values.size()}, update_flags); + + std::vector> solution; + if (update_flags & update_values) + solution.resize(n_particles_in_cell,Vector(this->introspection().n_components)); + + std::vector>> gradients; + if (update_flags & update_gradients) + gradients.resize(n_particles_in_cell,std::vector>(this->introspection().n_components)); + + for (unsigned int i = 0; iupdate_particles(particles, + solution, + gradients); + } + + + + template + void + World::local_advect_particles(const typename DoFHandler::active_cell_iterator &cell, + const typename ParticleHandler::particle_iterator &begin_particle, + const typename ParticleHandler::particle_iterator &end_particle, + internal::SolutionEvaluators &evaluators) + { + const unsigned int n_particles_in_cell = particle_handler->n_particles_in_cell(cell); + + boost::container::small_vector, 100> positions; + positions.reserve(n_particles_in_cell); + for (auto particle = begin_particle; particle!=end_particle; ++particle) + positions.push_back(particle->get_reference_location()); + + const std::array required_solution_vectors = integrator->required_solution_vectors(); + + AssertThrow (required_solution_vectors[0] == false, + ExcMessage("The integrator requires the old old solution vector, but it is not available.")); + + + const bool use_fluid_velocity = this->include_melt_transport() && + property_manager->get_data_info().fieldname_exists("melt_presence"); + + auto &evaluator = evaluators.get_velocity_or_fluid_velocity_evaluator(use_fluid_velocity); + auto &mapping_info = evaluators.get_mapping_info(); + mapping_info.reinit(cell, {positions.data(),positions.size()}); + + std::vector> velocities; + std::vector> old_velocities; + + if (required_solution_vectors[1] == true) + { + boost::container::small_vector old_solution_values(this->get_fe().dofs_per_cell); + cell->get_dof_values(this->get_old_solution(), + old_solution_values.begin(), + old_solution_values.end()); + + evaluator.evaluate({old_solution_values.data(),old_solution_values.size()}, + EvaluationFlags::values); + + old_velocities.resize(n_particles_in_cell); + for (unsigned int i=0; i solution_values(this->get_fe().dofs_per_cell); + cell->get_dof_values(this->get_current_linearization_point(), + solution_values.begin(), + solution_values.end()); + evaluator.evaluate({solution_values.data(),solution_values.size()}, + EvaluationFlags::values); + + velocities.resize(n_particles_in_cell); + for (unsigned int i=0; ilocal_integrate_step(begin_particle, + end_particle, + old_velocities, + velocities, + this->get_timestep()); + } + + + + template + void + World::setup_initial_state () + { + // If we are in the first adaptive refinement cycle generate particles + if (this->get_pre_refinement_step() == 0) + generate_particles(); + + // And initialize the particle properties according to the initial + // conditions on the current mesh + initialize_particles(); + } + + + + template + void + World::generate_particles() + { + TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Generate"); + generator->generate_particles(*particle_handler); + } + + + + template + void + World::initialize_particles() + { + // TODO: Change this loop over all cells to use the WorkStream interface + if (property_manager->get_n_property_components() > 0) + { + TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Initialize properties"); + + particle_handler->get_property_pool().reserve(2 * particle_handler->n_locally_owned_particles()); + + + if (particle_handler->n_locally_owned_particles() > 0) + local_initialize_particles(particle_handler->begin(), + particle_handler->end()); + + if (update_ghost_particles && + dealii::Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()) > 1) + { + TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Exchange ghosts"); + particle_handler->exchange_ghost_particles(); + } + } + } + + + + namespace internal + { + // This class evaluates the solution vector at arbitrary positions inside a cell. + // It uses the deal.II class FEPointEvaluation to do this efficiently. Because + // FEPointEvaluation only supports a single finite element, but ASPECT uses a FESystem with + // many components, this class creates several FEPointEvaluation objects that are used for + // the individual finite elements of our solution (pressure, velocity, temperature, and + // all other optional variables). Because FEPointEvaluation is templated based on the + // number of components, but ASPECT only knows the number of components at runtime + // we create this derived class with an additional template. This makes it possible + // to access the functionality through the base class, but create an object of this + // derived class with the correct number of components at runtime. + template + class SolutionEvaluatorsImplementation: public SolutionEvaluators + { + public: + // Constructor. Create the member variables given a simulator and a set of + // update flags. The update flags control if only the solution or also the gradients + // should be evaluated. + SolutionEvaluatorsImplementation(const SimulatorAccess &simulator, + const UpdateFlags update_flags); + + // Reinitialize all variables to evaluate the given solution for the given cell + // and the given positions. The update flags control if only the solution or + // also the gradients should be evaluated. + // If other flags are set an assertion is triggered. + void + reinit(const typename DoFHandler::active_cell_iterator &cell, + const ArrayView> &positions, + const ArrayView &solution_values, + const UpdateFlags update_flags) override; + + // Return the value of all solution components at the given evaluation point. Note + // that this function only works after a successful call to reinit(), + // because this function only returns the results of the computation that + // happened in reinit(). + void get_solution(const unsigned int evaluation_point, + Vector &solution) override; + + // Return the value of all solution gradients at the given evaluation point. Note + // that this function only works after a successful call to reinit(), + // because this function only returns the results of the computation that + // happened in reinit(). + void get_gradients(const unsigned int evaluation_point, + std::vector> &gradients) override; + + // Return the evaluator for velocity or fluid velocity. This is the only + // information necessary for advecting particles. + FEPointEvaluation & + get_velocity_or_fluid_velocity_evaluator(const bool use_fluid_velocity) override; + + // Return the cached mapping information. + NonMatching::MappingInfo & + get_mapping_info() override; + private: + // MappingInfo object for the FEPointEvaluation objects + NonMatching::MappingInfo mapping_info; + + // FEPointEvaluation objects for all common + // components of ASPECT's finite element solution. + // These objects are used inside of the member functions of this class. + FEPointEvaluation velocity; + std::unique_ptr> pressure; + FEPointEvaluation<1, dim> temperature; + + // If instantiated evaluate multiple compositions at once, if + // not fall back to evaluating them individually. + FEPointEvaluation compositions; + std::vector> additional_compositions; + + // Pointers to FEPointEvaluation objects for all melt + // components of ASPECT's finite element solution, which only + // point to valid objects in case we use melt transport. Other + // documentation like for the objects directly above. + std::unique_ptr> fluid_velocity; + std::unique_ptr> compaction_pressure; + std::unique_ptr> fluid_pressure; + + // The component indices for the three melt formulation + // variables fluid velocity, compaction pressure, and + // fluid pressure (in this order). They are cached + // to avoid repeated expensive lookups. + std::array melt_component_indices; + + // Reference to the active simulator access object. Provides + // access to the general simulation variables. + const SimulatorAccess &simulator_access; + }; + + + + template + SolutionEvaluatorsImplementation::SolutionEvaluatorsImplementation(const SimulatorAccess &simulator, + const UpdateFlags update_flags) + : + mapping_info(simulator.get_mapping(), + update_flags), + velocity(mapping_info, + simulator.get_fe(), + simulator.introspection().component_indices.velocities[0]), + pressure(std::make_unique>(mapping_info, + simulator.get_fe(), + simulator.introspection().component_indices.pressure)), + temperature(mapping_info, + simulator.get_fe(), + simulator.introspection().component_indices.temperature), + compositions(mapping_info, + simulator.get_fe(), + simulator.n_compositional_fields() > 0 ? simulator.introspection().component_indices.compositional_fields[0] : simulator.introspection().component_indices.temperature), + + melt_component_indices(), + simulator_access(simulator) + { + // Create the evaluators for all compositional fields beyond the ones this class was + // instantiated for + const unsigned int n_total_compositional_fields = simulator_access.n_compositional_fields(); + const auto &component_indices = simulator_access.introspection().component_indices.compositional_fields; + for (unsigned int composition = n_compositional_fields; composition < n_total_compositional_fields; ++composition) + additional_compositions.emplace_back(FEPointEvaluation<1, dim>(mapping_info, + simulator_access.get_fe(), + component_indices[composition])); + + // The FE_DGP pressure element used in locally conservative discretization is not + // supported by the fast path of FEPointEvaluation. Replace with slow path. + if (simulator_access.get_parameters().use_locally_conservative_discretization == true) + pressure = std::make_unique>(simulator_access.get_mapping(), + simulator_access.get_fe(), + update_flags, + simulator.introspection().component_indices.pressure); + + // Create the melt evaluators, but only if we use melt transport in the model + if (simulator_access.include_melt_transport()) + { + // Store the melt component indices to avoid repeated string lookups later on + melt_component_indices[0] = simulator_access.introspection().variable("fluid velocity").first_component_index; + melt_component_indices[1] = simulator_access.introspection().variable("fluid pressure").first_component_index; + melt_component_indices[2] = simulator_access.introspection().variable("compaction pressure").first_component_index; + + fluid_velocity = std::make_unique>(mapping_info, + simulator_access.get_fe(), + melt_component_indices[0]); + if (simulator_access.get_parameters().use_locally_conservative_discretization == false) + fluid_pressure = std::make_unique>(mapping_info, + simulator_access.get_fe(), + melt_component_indices[1]); + else + { + fluid_pressure = std::make_unique>(simulator_access.get_mapping(), + simulator_access.get_fe(), + update_flags, + melt_component_indices[1]); + } + + if (simulator_access.get_melt_handler().melt_parameters.use_discontinuous_p_c == false) + compaction_pressure = std::make_unique>(mapping_info, + simulator_access.get_fe(), + melt_component_indices[2]); + else + compaction_pressure = std::make_unique>(simulator_access.get_mapping(), + simulator_access.get_fe(), + update_flags, + melt_component_indices[2]); + + + } + } + + + + template + void + SolutionEvaluatorsImplementation::reinit(const typename DoFHandler::active_cell_iterator &cell, + const ArrayView> &positions, + const ArrayView &solution_values, + const UpdateFlags update_flags) + { + // FEPointEvaluation uses different evaluation flags than the common UpdateFlags. + // Translate between the two. + EvaluationFlags::EvaluationFlags evaluation_flags = EvaluationFlags::nothing; + + if (update_flags & update_values) + evaluation_flags = evaluation_flags | EvaluationFlags::values; + + if (update_flags & update_gradients) + evaluation_flags = evaluation_flags | EvaluationFlags::gradients; + + // Make sure only the flags are set that we can deal with at the moment + Assert ((update_flags & ~(update_gradients | update_values)) == false, + ExcNotImplemented()); + + // Reinitialize and evaluate all evaluators. + // TODO: It would be nice to be able to hand over a ComponentMask + // to specify which evaluators to use. Currently, this is only + // possible by manually accessing the public members of this class. + mapping_info.reinit(cell,positions); + + if (simulator_access.get_parameters().use_locally_conservative_discretization == true) + { + pressure->reinit(cell, positions); + + if (simulator_access.include_melt_transport()) + { + fluid_pressure->reinit (cell, positions); + } + } + + if (simulator_access.include_melt_transport() + && simulator_access.get_melt_handler().melt_parameters.use_discontinuous_p_c == true) + { + compaction_pressure->reinit (cell, positions); + } + + + velocity.evaluate (solution_values, evaluation_flags); + pressure->evaluate (solution_values, evaluation_flags); + temperature.evaluate (solution_values, evaluation_flags); + compositions.evaluate (solution_values, evaluation_flags); + + for (auto &evaluator_composition: additional_compositions) + evaluator_composition.evaluate (solution_values, evaluation_flags); + + if (simulator_access.include_melt_transport()) + { + fluid_velocity->evaluate (solution_values, evaluation_flags); + fluid_pressure->evaluate (solution_values, evaluation_flags); + compaction_pressure->evaluate (solution_values, evaluation_flags); + } + } + + namespace + { + template + double + get_value(const Tensor<1,n_compositional_fields> &solution, + const unsigned int component_index) + { + AssertIndexRange(component_index, n_compositional_fields); + return solution[component_index]; + } + + template + double + get_value(const double &solution, + const unsigned int component_index) + { + (void) component_index; + AssertIndexRange(component_index, 1); + return solution; + } + + template + Tensor<1,dim> + get_gradient(const Tensor<1,n_compositional_fields,Tensor<1,dim>> &gradient, + const unsigned int component_index) + { + AssertIndexRange(component_index, n_compositional_fields); + return gradient[component_index]; + } + + + template + Tensor<1,dim> + get_gradient(const Tensor<1,dim> &gradient, + const unsigned int component_index) + { + (void) component_index; + AssertIndexRange(component_index, 1); + return gradient; + } + } + + + template + void + SolutionEvaluatorsImplementation::get_solution(const unsigned int evaluation_point, + Vector &solution) + { + Assert(solution.size() == simulator_access.introspection().n_components, + ExcDimensionMismatch(solution.size(), simulator_access.introspection().n_components)); + + const auto &component_indices = simulator_access.introspection().component_indices; + + const Tensor<1,dim> velocity_value = velocity.get_value(evaluation_point); + for (unsigned int j=0; jget_value(evaluation_point); + solution[component_indices.temperature] = temperature.get_value(evaluation_point); + + if (n_compositional_fields > 0) + for (unsigned int j=0; j( + compositions.get_value(evaluation_point), + j); + + const unsigned int n_additional_compositions = additional_compositions.size(); + for (unsigned int j=0; j fluid_velocity_value = velocity.get_value(evaluation_point); + for (unsigned int j=0; jget_value(evaluation_point); + solution[melt_component_indices[2]] = compaction_pressure->get_value(evaluation_point); + } + } + + + + template + void + SolutionEvaluatorsImplementation::get_gradients(const unsigned int evaluation_point, + std::vector> &gradients) + { + Assert(gradients.size() == simulator_access.introspection().n_components, + ExcDimensionMismatch(gradients.size(), simulator_access.introspection().n_components)); + + const auto &component_indices = simulator_access.introspection().component_indices; + + const Tensor<2,dim> velocity_gradient = velocity.get_gradient(evaluation_point); + for (unsigned int j=0; jget_gradient(evaluation_point); + gradients[component_indices.temperature] = temperature.get_gradient(evaluation_point); + + if (n_compositional_fields > 0) + for (unsigned int j=0; j( + compositions.get_gradient(evaluation_point), + j); + + const unsigned int n_additional_compositions = additional_compositions.size(); + for (unsigned int j=0; j fluid_velocity_gradient = velocity.get_gradient(evaluation_point); + for (unsigned int j=0; jget_gradient(evaluation_point); + gradients[melt_component_indices[2]] = compaction_pressure->get_gradient(evaluation_point); + } + } + + + template + FEPointEvaluation & + SolutionEvaluatorsImplementation::get_velocity_or_fluid_velocity_evaluator(const bool use_fluid_velocity) + { + if (use_fluid_velocity) + return *fluid_velocity; + else + return velocity; + + return velocity; + } + template + NonMatching::MappingInfo & + SolutionEvaluatorsImplementation::get_mapping_info() + { + return mapping_info; + } + + + + // A function to create a pointer to a SolutionEvaluators object. + template + std::unique_ptr> + construct_solution_evaluators (const SimulatorAccess &simulator_access, + const UpdateFlags update_flags) + { + switch (simulator_access.n_compositional_fields()) + { + case 0: + return std::make_unique>(simulator_access, update_flags); + case 1: + return std::make_unique>(simulator_access, update_flags); + case 2: + return std::make_unique>(simulator_access, update_flags); + case 3: + return std::make_unique>(simulator_access, update_flags); + case 4: + return std::make_unique>(simulator_access, update_flags); + case 5: + return std::make_unique>(simulator_access, update_flags); + case 6: + return std::make_unique>(simulator_access, update_flags); + case 7: + return std::make_unique>(simulator_access, update_flags); + case 8: + return std::make_unique>(simulator_access, update_flags); + case 9: + return std::make_unique>(simulator_access, update_flags); + case 10: + return std::make_unique>(simulator_access, update_flags); + case 11: + return std::make_unique>(simulator_access, update_flags); + case 12: + return std::make_unique>(simulator_access, update_flags); + case 13: + return std::make_unique>(simulator_access, update_flags); + case 14: + return std::make_unique>(simulator_access, update_flags); + case 15: + return std::make_unique>(simulator_access, update_flags); + case 16: + return std::make_unique>(simulator_access, update_flags); + case 17: + return std::make_unique>(simulator_access, update_flags); + case 18: + return std::make_unique>(simulator_access, update_flags); + case 19: + return std::make_unique>(simulator_access, update_flags); + // Return the maximally instantiated object. The class will handle additional compositional fields + // by dynamically allocating additional scalar evaluators. + default: + return std::make_unique>(simulator_access, update_flags); + } + } + } + + + + template + void + World::update_particles() + { + // TODO: Change this loop over all cells to use the WorkStream interface + + if (property_manager->get_n_property_components() > 0) + { + TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Update properties"); + + Assert(dealii::internal::FEPointEvaluation::is_fast_path_supported(this->get_mapping()) == true, + ExcMessage("The particle system was optimized for deal.II mappings that support the fast evaluation path " + "of the class FEPointEvaluation. The mapping currently in use does not support this path. " + "It is safe to uncomment this assertion, but you can expect a performance penalty.")); + + const UpdateFlags update_flags = property_manager->get_needed_update_flags(); + + std::unique_ptr> evaluators = internal::construct_solution_evaluators(*this, + update_flags); + + // Loop over all cells and update the particles cell-wise + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + // Only update particles if there are any in this cell + if (particle_handler->n_particles_in_cell(cell) > 0) + { + local_update_particles(cell, + *evaluators); + } + + } + } + } + + + + template + void + World::advect_particles() + { + { + // TODO: Change this loop over all cells to use the WorkStream interface + TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Advect"); + + Assert(dealii::internal::FEPointEvaluation::is_fast_path_supported(this->get_mapping()) == true, + ExcMessage("The particle system was optimized for deal.II mappings that support the fast evaluation path " + "of the class FEPointEvaluation. The mapping currently in use does not support this path. " + "It is safe to uncomment this assertion, but you can expect a performance penalty.")); + + std::unique_ptr> evaluators = + std::make_unique>(*this, + update_values); + + // Loop over all cells and advect the particles cell-wise + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + const typename ParticleHandler::particle_iterator_range + particles_in_cell = particle_handler->particles_in_cell(cell); + + // Only advect particles, if there are any in this cell + if (particles_in_cell.begin() != particles_in_cell.end()) + { + local_advect_particles(cell, + particles_in_cell.begin(), + particles_in_cell.end(), + *evaluators); + } + } + } + + { + TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Sort"); + // Find the cells that the particles moved to + particle_handler->sort_particles_into_subdomains_and_cells(); + } + } + + + + template + void + World::advance_timestep() + { + this->get_pcout() << " Advecting particles... " << std::flush; + do + { + advect_particles(); + } + // Keep calling the integrator until it indicates it is finished + while (integrator->new_integration_step()); + + apply_particle_per_cell_bounds(); + + // Update particle properties + if (property_manager->need_update() == Property::update_time_step) + update_particles(); + + // Now that all particle information was updated, exchange the new + // ghost particles. + if (update_ghost_particles && + dealii::Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()) > 1) + { + TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Exchange ghosts"); + particle_handler->exchange_ghost_particles(); + } + this->get_pcout() << " done." << std::endl; + } + + + + template + void + World::save (std::ostringstream &os) const + { + aspect::oarchive oa (os); + oa << (*this); + } + + + + template + void + World::load (std::istringstream &is) + { + aspect::iarchive ia (is); + ia >> (*this); + } + + + + template + void + World::declare_parameters (ParameterHandler &prm) + { + constexpr unsigned int number_of_particle_worlds = 1; + for (unsigned int world_index = 0; world_index < number_of_particle_worlds; ++world_index) + { + if (world_index == 0) + { + prm.enter_subsection("Particles"); + } + else + { + prm.enter_subsection("Particles " + std::to_string(world_index+1)); + } + { + prm.declare_entry ("Load balancing strategy", "repartition", + Patterns::MultipleSelection ("none|remove particles|add particles|" + "remove and add particles|repartition"), + "Strategy that is used to balance the computational " + "load across processors for adaptive meshes."); + prm.declare_entry ("Minimum particles per cell", "0", + Patterns::Integer (0), + "Lower limit for particle number per cell. This limit is " + "useful for adaptive meshes to prevent fine cells from being empty " + "of particles. It will be checked and enforced after mesh " + "refinement and after particle movement. " + "If there are " + "\\texttt{n\\_number\\_of\\_particles} $<$ \\texttt{min\\_particles\\_per\\_cell} " + "particles in one cell then " + "\\texttt{min\\_particles\\_per\\_cell} - \\texttt{n\\_number\\_of\\_particles} " + "particles are generated and randomly placed in " + "this cell. If the particles carry properties the " + "individual property plugins control how the " + "properties of the new particles are initialized."); + prm.declare_entry ("Maximum particles per cell", "100", + Patterns::Integer (0), + "Upper limit for particle number per cell. This limit is " + "useful for adaptive meshes to prevent coarse cells from slowing down " + "the whole model. It will be checked and enforced after mesh " + "refinement, after MPI transfer of particles and after particle " + "movement. If there are " + "\\texttt{n\\_number\\_of\\_particles} $>$ \\texttt{max\\_particles\\_per\\_cell} " + "particles in one cell then " + "\\texttt{n\\_number\\_of\\_particles} - \\texttt{max\\_particles\\_per\\_cell} " + "particles in this cell are randomly chosen and destroyed."); + prm.declare_entry ("Particle weight", "10", + Patterns::Integer (0), + "Weight that is associated with the computational load of " + "a single particle. The sum of particle weights will be added " + "to the sum of cell weights to determine the partitioning of " + "the mesh if the `repartition' particle load balancing strategy " + "is selected. The optimal weight depends on the used " + "integrator and particle properties. In general for a more " + "expensive integrator and more expensive properties a larger " + "particle weight is recommended. Before adding the weights " + "of particles, each cell already carries a weight of 1000 to " + "account for the cost of field-based computations."); + prm.declare_entry ("Update ghost particles", "false", + Patterns::Bool (), + "Some particle interpolation algorithms require knowledge " + "about particles in neighboring cells. To allow this, " + "particles in ghost cells need to be exchanged between the " + "processes neighboring this cell. This parameter determines " + "whether this transport is happening."); + + Generator::declare_parameters(prm); + Integrator::declare_parameters(prm); + Interpolator::declare_parameters(prm); + + Property::Manager::declare_parameters(prm); + } + prm.leave_subsection (); + } + + } + + + + template + void + World::parse_parameters (ParameterHandler &prm, const unsigned int world_index) + { + // First do some error checking. The current algorithm does not find + // the cells around particles, if the particles moved more than one + // cell in one timestep and we are running in parallel, because they + // skip the layer of ghost cells around our local domain. Assert this + // is not possible. + const double CFL_number = prm.get_double ("CFL number"); + const unsigned int n_processes = Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()); + + AssertThrow((n_processes == 1) || (CFL_number <= 1.0), + ExcMessage("The current particle algorithm does not work in " + "parallel if the CFL number is larger than 1.0, because " + "in this case particles can move more than one cell " + "diameter in one time step and therefore skip the layer " + "of ghost cells around the local subdomain.")); + + if (world_index == 0) + { + prm.enter_subsection("Particles"); + } + else + { + prm.enter_subsection("Particles " + std::to_string(world_index+1)); + } + { + min_particles_per_cell = prm.get_integer("Minimum particles per cell"); + max_particles_per_cell = prm.get_integer("Maximum particles per cell"); + + AssertThrow(min_particles_per_cell <= max_particles_per_cell, + ExcMessage("Please select a 'Minimum particles per cell' parameter " + "that is smaller than or equal to the 'Maximum particles per cell' parameter.")); + + particle_weight = prm.get_integer("Particle weight"); + + update_ghost_particles = prm.get_bool("Update ghost particles"); + + const std::vector strategies = Utilities::split_string_list(prm.get ("Load balancing strategy")); + AssertThrow(Utilities::has_unique_entries(strategies), + ExcMessage("The list of strings for the parameter " + "'Particles/Load balancing strategy' contains entries more than once. " + "This is not allowed. Please check your parameter file.")); + + particle_load_balancing = ParticleLoadBalancing::no_balancing; + + for (std::vector::const_iterator strategy = strategies.begin(); strategy != strategies.end(); ++strategy) + { + if (*strategy == "remove particles") + particle_load_balancing = typename ParticleLoadBalancing::Kind(particle_load_balancing | ParticleLoadBalancing::remove_particles); + else if (*strategy == "add particles") + particle_load_balancing = typename ParticleLoadBalancing::Kind(particle_load_balancing | ParticleLoadBalancing::add_particles); + else if (*strategy == "remove and add particles") + particle_load_balancing = typename ParticleLoadBalancing::Kind(particle_load_balancing | ParticleLoadBalancing::remove_and_add_particles); + else if (*strategy == "repartition") + particle_load_balancing = typename ParticleLoadBalancing::Kind(particle_load_balancing | ParticleLoadBalancing::repartition); + else if (*strategy == "none") + { + particle_load_balancing = ParticleLoadBalancing::no_balancing; + AssertThrow(strategies.size() == 1, + ExcMessage("The particle load balancing strategy `none' is not compatible " + "with any other strategy, yet it seems another is selected as well. " + "Please check the parameter file.")); + } + else + AssertThrow(false, + ExcMessage("The 'Load balancing strategy' parameter contains an unknown value: <" + *strategy + + ">. This value does not correspond to any known load balancing strategy. Possible values " + "are listed in the corresponding manual subsection.")); + } + + + TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Initialization"); + + // Create a generator object depending on what the parameters specify + generator = Generator::create_particle_generator (prm); + if (SimulatorAccess *sim = dynamic_cast*>(generator.get())) + sim->initialize_simulator (this->get_simulator()); + generator->set_particle_world_index(world_index); + generator->parse_parameters(prm); + generator->initialize(); + + // Create a property_manager object and initialize its properties + property_manager = std::make_unique> (); + SimulatorAccess *sim = dynamic_cast*>(property_manager.get()); + sim->initialize_simulator (this->get_simulator()); + property_manager->set_particle_world_index(world_index); + property_manager->parse_parameters(prm); + property_manager->initialize(); + + // Create an integrator object depending on the specified parameter + integrator = Integrator::create_particle_integrator (prm); + if (SimulatorAccess *sim = dynamic_cast*>(integrator.get())) + sim->initialize_simulator (this->get_simulator()); + integrator->set_particle_world_index(world_index); + integrator->parse_parameters(prm); + integrator->initialize(); + + // Create an interpolator object depending on the specified parameter + interpolator = Interpolator::create_particle_interpolator (prm); + if (SimulatorAccess *sim = dynamic_cast*>(interpolator.get())) + sim->initialize_simulator (this->get_simulator()); + interpolator->set_particle_world_index(world_index); + interpolator->parse_parameters(prm); + interpolator->initialize(); + + } + prm.leave_subsection (); + } + } +} + + +// explicit instantiation of the functions we implement in this file +namespace aspect +{ + namespace Particle + { +#define INSTANTIATE(dim) \ + template class World; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/plugins.cc.bak b/source/plugins.cc.bak new file mode 100644 index 00000000000..2964077a074 --- /dev/null +++ b/source/plugins.cc.bak @@ -0,0 +1,50 @@ +/* + Copyright (C) 2024 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + +#include + +namespace aspect +{ + namespace Plugins + { + void + InterfaceBase::initialize () + {} + + + + void + InterfaceBase::update () + {} + + + + void + InterfaceBase:: + declare_parameters (dealii::ParameterHandler &) + {} + + + + void + InterfaceBase::parse_parameters (dealii::ParameterHandler &) + {} + } +} diff --git a/source/postprocess/ODE_statistics.cc.bak b/source/postprocess/ODE_statistics.cc.bak new file mode 100644 index 00000000000..263bf22f7ba --- /dev/null +++ b/source/postprocess/ODE_statistics.cc.bak @@ -0,0 +1,108 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include +#include + + + +namespace aspect +{ + namespace Postprocess + { + template + void + ODEStatistics::initialize() + { + this->get_signals().post_ARKode_solve.connect( + [&](const SimulatorAccess &/*simulator_access*/, + const unsigned int iteration_count) + { + this->store_ODE_solver_history(iteration_count); + }); + + this->clear_data(); + } + + + + template + void + ODEStatistics::clear_data() + { + total_iteration_count = 0; + number_of_solves = 0; + } + + + + template + void + ODEStatistics::store_ODE_solver_history(const unsigned int iteration_count) + { + total_iteration_count += iteration_count; + number_of_solves += 1; + } + + + + template + std::pair + ODEStatistics::execute (TableHandler &statistics) + { +#if DEAL_II_VERSION_GTE(9,6,0) + const double average_iteration_count = number_of_solves > 0 + ? + total_iteration_count / number_of_solves + : + total_iteration_count; +#else + // The computation is not correct for dealii versions older than + // June 2024. + const double average_iteration_count = std::numeric_limits::quiet_NaN(); +#endif + statistics.add_value("Average iterations for ODE solver", + average_iteration_count); + + clear_data(); + + return std::make_pair (std::string(),std::string()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(ODEStatistics, + "ODE statistics", + "A postprocessor that computes some statistics about " + "ODEs solved during the model evolution, specifically, " + "how many iterations are needed to solve these ODEs " + "on average. ") + } +} diff --git a/source/postprocess/basic_statistics.cc.bak b/source/postprocess/basic_statistics.cc.bak new file mode 100644 index 00000000000..ae0cea991ba --- /dev/null +++ b/source/postprocess/basic_statistics.cc.bak @@ -0,0 +1,165 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + BasicStatistics::execute (TableHandler &) + { + if (!Plugins::plugin_type_matches>(this->get_material_model())) + return std::make_pair (std::string(),std::string()); + + if ((this->get_timestep_number() == 0) && + (this->get_pre_refinement_step() == std::numeric_limits::max())) + { + // Define the representative point (in this case a point with depth 0 -> at the surface) + const double reference_depth = 0.0; + const Point representative_point = this->get_geometry_model().representative_point(reference_depth); + const double gravity = this->get_gravity_model().gravity_vector(representative_point).norm(); + const double model_depth = this->get_geometry_model().maximal_depth(); + + // temperature contrast is only meaningful if boundary temperatures are prescribed, otherwise it is 0 + const double temperature_contrast = (this->has_boundary_temperature() + ? + this->get_boundary_temperature_manager().maximal_temperature(this->get_fixed_temperature_boundary_indicators()) + - this->get_boundary_temperature_manager().minimal_temperature(this->get_fixed_temperature_boundary_indicators()) + : + 0); + + // Compute material properties at the reference point using the adiabatic + // profile as reference temperature and pressure + const double temperature = this->get_adiabatic_conditions().temperature(representative_point); + const double pressure = this->get_adiabatic_conditions().pressure(representative_point); + + MaterialModel::MaterialModelInputs in (1, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out (1, this->n_compositional_fields()); + in.requested_properties = MaterialModel::MaterialProperties::thermal_conductivity | + MaterialModel::MaterialProperties::equation_of_state_properties | + MaterialModel::MaterialProperties::viscosity; + + in.position[0] = representative_point; + in.temperature[0] = temperature; + in.pressure[0] = pressure; + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + in.composition[0][c] = 0.0; + + this->get_material_model().evaluate(in, out); + + const double thermal_diffusivity = ( (this->get_parameters().formulation_temperature_equation == + Parameters::Formulation::TemperatureEquation::reference_density_profile) + ? + out.thermal_conductivities[0] / + (this->get_adiabatic_conditions().density(in.position[0]) * out.specific_heat[0]) + : + out.thermal_conductivities[0] / (out.densities[0] * out.specific_heat[0]) + ); + + // check whether diffusivity is set to 0 (in case of backward advection) + const double Ra = (thermal_diffusivity != 0) ? + out.densities[0] * + gravity * + out.thermal_expansion_coefficients[0] * + temperature_contrast * std::pow(model_depth,3)/ + (thermal_diffusivity * out.viscosities[0]) + : + std::numeric_limits::infinity(); + + this->get_pcout() << std::endl; + this->get_pcout() << " Model domain depth (m): " + << model_depth + << std::endl; + this->get_pcout() << " Temperature contrast across model domain (K): " + << temperature_contrast + << std::endl; + this->get_pcout() << " Reference depth (m): " + << reference_depth + << std::endl; + this->get_pcout() << " Reference temperature (K): " + << temperature + << std::endl; + this->get_pcout() << " Reference pressure (Pa): " + << pressure + << std::endl; + this->get_pcout() << " Reference gravity (m/s^2): " + << gravity + << std::endl; + this->get_pcout() << " Reference density (kg/m^3): " + << out.densities[0] + << std::endl; + this->get_pcout() << " Reference thermal expansion coefficient (1/K): " + << out.thermal_expansion_coefficients[0] + << std::endl; + this->get_pcout() << " Reference specific heat capacity (J/(K*kg)): " + << out.specific_heat[0] + << std::endl; + this->get_pcout() << " Reference thermal conductivity (W/(m*K)): " + << out.thermal_conductivities[0] + << std::endl; + this->get_pcout() << " Reference viscosity (Pa*s): " + << out.viscosities[0] + << std::endl; + this->get_pcout() << " Reference thermal diffusivity (m^2/s): " + << thermal_diffusivity + << std::endl; + this->get_pcout() << " Rayleigh number: " + << Ra + << std::endl; + + this->get_pcout() << std::endl; + } + return std::make_pair (std::string(),std::string()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(BasicStatistics, + "basic statistics", + "A postprocessor that outputs some simplified statistics " + "like the Rayleigh number and other quantities that only " + "make sense in certain model setups. The output is written " + "after completing initial adaptive refinement steps. " + "The postprocessor assumes a point at the surface at the adiabatic " + "surface temperature and pressure is a reasonable reference condition " + "for computing these properties. Furthermore, the Rayleigh " + "number is computed using the model depth (i.e. not the " + "radius of the Earth), as we need a definition that is geometry " + "independent. Take care when comparing these values to published " + "studies and make sure they use the same definitions.") + } +} diff --git a/source/postprocess/boundary_densities.cc.bak b/source/postprocess/boundary_densities.cc.bak new file mode 100644 index 00000000000..ce4d9b71df1 --- /dev/null +++ b/source/postprocess/boundary_densities.cc.bak @@ -0,0 +1,177 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + BoundaryDensities::execute (TableHandler &statistics) + { + const Quadrature &quadrature_formula = this->introspection().face_quadratures.temperature; + + FEFaceValues fe_face_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_gradients | + update_quadrature_points | + update_JxW_values); + + double local_top_density = 0.; + double local_bottom_density = 0.; + double local_top_area = 0.; + double local_bottom_area = 0.; + + typename MaterialModel::Interface::MaterialModelInputs in(fe_face_values.n_quadrature_points, this->n_compositional_fields()); + typename MaterialModel::Interface::MaterialModelOutputs out(fe_face_values.n_quadrature_points, this->n_compositional_fields()); + in.requested_properties = MaterialModel::MaterialProperties::density; + std::vector> composition_values(this->n_compositional_fields(), std::vector(fe_face_values.n_quadrature_points)); + + const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + const types::boundary_id bottom_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); + + // loop over all of the surface cells and if one less than h/3 away from + // the top or bottom surface, evaluate the density on that face + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + for (const unsigned int f : cell->face_indices()) + { + bool cell_at_top = false; + bool cell_at_bottom = false; + + // Test for top or bottom surface cell faces + if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) + cell_at_top = true; + if (cell->at_boundary(f) && cell->face(f)->boundary_id() == bottom_boundary_id) + cell_at_bottom = true; + + if (cell_at_top || cell_at_bottom) + { + // handle surface cells + fe_face_values.reinit (cell, f); + fe_face_values[this->introspection().extractors.temperature] + .get_function_values (this->get_solution(), in.temperature); + fe_face_values[this->introspection().extractors.pressure] + .get_function_values (this->get_solution(), in.pressure); + fe_face_values[this->introspection().extractors.velocities] + .get_function_symmetric_gradients (this->get_solution(), in.strain_rate); + + in.position = fe_face_values.get_quadrature_points(); + + for (unsigned int c=0; cn_compositional_fields(); ++c) + fe_face_values[this->introspection().extractors.compositional_fields[c]] + .get_function_values(this->get_solution(), + composition_values[c]); + for (unsigned int i=0; in_compositional_fields(); ++c) + in.composition[i][c] = composition_values[c][i]; + } + + this->get_material_model().evaluate(in, out); + + // calculate the top/bottom properties + if (cell_at_top) + for ( unsigned int q = 0; q < fe_face_values.n_quadrature_points; ++q) + { + local_top_density += out.densities[q] * fe_face_values.JxW(q); + local_top_area += fe_face_values.JxW(q); + } + if (cell_at_bottom) + for ( unsigned int q = 0; q < fe_face_values.n_quadrature_points; ++q) + { + local_bottom_density += out.densities[q] * fe_face_values.JxW(q); + local_bottom_area += fe_face_values.JxW(q); + } + } + } + + // vector for packing local values before MPI summing them + double values[4] = {local_bottom_area, local_top_area, local_bottom_density, local_top_density}; + + Utilities::MPI::sum( values, this->get_mpi_communicator(), values ); + + top_density = values[3] / values[1]; // density over area + bottom_density = values[2] / values[0]; // density over area + + statistics.add_value ("Density at top (kg/m^3)", + top_density); + statistics.add_value ("Density at bottom (kg/m^3)", + bottom_density); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + { + const char *columns[] = { "Density at top (kg/m^3)", + "Density at bottom (kg/m^3)" + }; + for (auto &column : columns) + { + statistics.set_precision (column, 8); + statistics.set_scientific (column, true); + } + } + + std::ostringstream output; + output.precision(4); + output << top_density << " kg/m^3, " + << bottom_density << " kg/m^3"; + + return std::pair ("Density at top/bottom of domain:", + output.str()); + } + + template + double + BoundaryDensities::density_at_top() const + { + return top_density; + } + + template + double + BoundaryDensities::density_at_bottom() const + { + return bottom_density; + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(BoundaryDensities, + "boundary densities", + "A postprocessor that computes the laterally averaged " + "density at the top and bottom of the domain.") + } +} diff --git a/source/postprocess/boundary_pressures.cc.bak b/source/postprocess/boundary_pressures.cc.bak new file mode 100644 index 00000000000..4e52f793394 --- /dev/null +++ b/source/postprocess/boundary_pressures.cc.bak @@ -0,0 +1,156 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + BoundaryPressures::execute (TableHandler &statistics) + { + const Quadrature &quadrature_formula = this->introspection().face_quadratures.pressure; + + FEFaceValues fe_face_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_gradients | + update_quadrature_points | + update_JxW_values); + + double local_top_pressure = 0.; + double local_bottom_pressure = 0.; + double local_top_area = 0.; + double local_bottom_area = 0.; + + std::vector pressure_vals (fe_face_values.n_quadrature_points); + + const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + const types::boundary_id bottom_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); + + // loop over all of the surface cells and if one less than h/3 away from + // the top or bottom surface, evaluate the pressure on that face + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + for (const unsigned int f : cell->face_indices()) + { + bool cell_at_top = false; + bool cell_at_bottom = false; + + // Test for top or bottom surface cell faces + if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) + cell_at_top = true; + if (cell->at_boundary(f) && cell->face(f)->boundary_id() == bottom_boundary_id) + cell_at_bottom = true; + + + if (cell_at_top || cell_at_bottom) + { + // evaluate the pressure on the face + fe_face_values.reinit (cell, f); + fe_face_values[this->introspection().extractors.pressure].get_function_values (this->get_solution(), pressure_vals); + + // calculate the top properties + if (cell_at_top) + for ( unsigned int q = 0; q < fe_face_values.n_quadrature_points; ++q) + { + local_top_pressure += pressure_vals[q] * fe_face_values.JxW(q); + local_top_area += fe_face_values.JxW(q); + } + if (cell_at_bottom) + for ( unsigned int q = 0; q < fe_face_values.n_quadrature_points; ++q) + { + local_bottom_pressure += pressure_vals[q] * fe_face_values.JxW(q); + local_bottom_area += fe_face_values.JxW(q); + } + } + } + + // vector for packing local values before MPI summing them + double values[4] = {local_bottom_area, local_top_area, local_bottom_pressure, local_top_pressure}; + + Utilities::MPI::sum( values, this->get_mpi_communicator(), values ); + + top_pressure = values[3] / values[1]; // density over area + bottom_pressure = values[2] / values[0]; // density over area + + statistics.add_value ("Pressure at top (Pa)", + top_pressure); + statistics.add_value ("Pressure at bottom (Pa)", + bottom_pressure); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + { + const char *columns[] = { "Pressure at top (Pa)", + "Pressure at bottom (Pa)" + }; + for (auto &column : columns) + { + statistics.set_precision (column, 8); + statistics.set_scientific (column, true); + } + } + + std::ostringstream output; + output.precision(4); + output << top_pressure << " Pa, " + << bottom_pressure << " Pa"; + + return std::pair ("Pressure at top/bottom of domain:", + output.str()); + } + + template + double + BoundaryPressures::pressure_at_top() const + { + return top_pressure; + } + + template + double + BoundaryPressures::pressure_at_bottom() const + { + return bottom_pressure; + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(BoundaryPressures, + "boundary pressures", + "A postprocessor that computes the laterally averaged " + "pressure at the top and bottom of the domain.") + } +} diff --git a/source/postprocess/boundary_strain_rate_residual_statistics.cc.bak b/source/postprocess/boundary_strain_rate_residual_statistics.cc.bak new file mode 100644 index 00000000000..251880b9451 --- /dev/null +++ b/source/postprocess/boundary_strain_rate_residual_statistics.cc.bak @@ -0,0 +1,332 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + void + BoundaryStrainRateResidualStatistics::initialize () + { + strain_rate_data_lookup = std::make_unique>(1, scale_factor); + strain_rate_data_lookup->load_file(data_directory + data_file_name, this->get_mpi_communicator()); + } + + + + template + double + BoundaryStrainRateResidualStatistics::get_data_surface_strain_rate (const Point &p) const + { + Point internal_position = p; + + if (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical) + { + const std::array spherical_position = this->get_geometry_model(). + cartesian_to_natural_coordinates(p); + + for (unsigned int d = 0; d < dim; ++d) + internal_position[d] = spherical_position[d]; + } + + const double data_surface_strain_rate = strain_rate_data_lookup->get_data(internal_position, 0); + + return data_surface_strain_rate; + } + + + + template + std::pair + BoundaryStrainRateResidualStatistics::execute (TableHandler &statistics) + { + // create a quadrature formula for the velocity. + const Quadrature &quadrature_formula = this->introspection().face_quadratures.velocities; + + FEFaceValues fe_face_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_gradients | + update_JxW_values | + update_quadrature_points); + + // This variable stores the strain rates computed at the quadrature points. + std::vector> strain_rate (fe_face_values.n_quadrature_points); + + std::map local_max_eii; + std::map local_min_eii; + std::map local_eii_square_integral; + std::map local_boundary_area; + + std::set boundary_indicators; + boundary_indicators.insert(this->get_geometry_model().translate_symbolic_boundary_name_to_id("top")); + + AssertThrow (boundary_indicators.size() == 1, + ExcMessage("The plugin is only tested " + "to work correctly for a single boundary indicator, " + "but more than one was specified.")); + + for (const auto boundary_id : boundary_indicators) + { + local_max_eii[boundary_id] = std::numeric_limits::lowest(); + local_min_eii[boundary_id] = std::numeric_limits::max(); + } + + // for every face that is part of the selected geometry boundary + // and that is owned by this processor, + // compute the maximum, minimum, and squared*area strain rate invariant residual + // magnitude, and the face area. + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + for (const unsigned int f : cell->face_indices()) + for (const auto current_boundary_id : boundary_indicators) + if (cell->face(f)->at_boundary() && cell->face(f)->boundary_id() == current_boundary_id) + { + fe_face_values.reinit (cell, f); + + fe_face_values[this->introspection().extractors.velocities].get_function_symmetric_gradients + (this->get_solution(), strain_rate); + + // determine the max, min, and area integral of squared strain rate residual on the face + // also determine the face area + double local_max = std::numeric_limits::lowest(); + double local_min = std::numeric_limits::max(); + double local_square_strain_rate = 0.0; + double local_fe_face_area = 0.0; + for (unsigned int q=0; q point_at_surface = fe_face_values.quadrature_point(q); + + // Extract the strain rate invariant output here. + const double e_ii = std::sqrt(std::fabs(second_invariant(deviator(strain_rate[q])))); + + // Extract data strain rate invartiant. + double e_ii_data = get_data_surface_strain_rate(point_at_surface); + + if (this->convert_output_to_years() == true) + e_ii_data = e_ii_data/year_in_seconds; + + // The strain rate invariant residual is calculated here. Ignore the computation if we + // encounter nan or 1e300 in the input data. + double strain_invariant_residual = 0; + if (e_ii_data < 1e300 || !std::isnan(e_ii_data)) + strain_invariant_residual = std::abs(e_ii_data - e_ii); + else + continue; + + local_max = std::max(strain_invariant_residual, + local_max); + local_min = std::min(strain_invariant_residual, + local_min); + local_square_strain_rate += ((strain_invariant_residual * strain_invariant_residual) * fe_face_values.JxW(q)); + local_fe_face_area += fe_face_values.JxW(q); + } + // then merge them with the min/max/squared strain rates + // and face areas we found for other faces with the same boundary indicator + local_max_eii[current_boundary_id] = std::max(local_max, + local_max_eii[current_boundary_id]); + local_min_eii[current_boundary_id] = std::min(local_min, + local_min_eii[current_boundary_id]); + local_eii_square_integral[current_boundary_id] += local_square_strain_rate; + local_boundary_area[current_boundary_id] += local_fe_face_area; + } + + // now communicate to get the global values + std::map global_max_eii; + std::map global_min_eii; + std::map global_rms_eii; + { + // first collect local values in the same order in which they are listed + // in the set of boundary indicators + std::vector local_max_values; + std::vector local_min_values; + std::vector local_eii_square_integral_values; + std::vector local_boundary_area_values; + + for (const auto p : boundary_indicators) + { + local_max_values.push_back (local_max_eii[p]); + local_min_values.push_back (local_min_eii[p]); + + local_eii_square_integral_values.push_back (local_eii_square_integral[p]); + local_boundary_area_values.push_back (local_boundary_area[p]); + } + + // then collect contributions from all processors + std::vector global_max_values (local_max_values.size()); + Utilities::MPI::max (local_max_values, this->get_mpi_communicator(), global_max_values); + std::vector global_min_values (local_min_values.size()); + Utilities::MPI::min (local_min_values, this->get_mpi_communicator(), global_min_values); + + std::vector global_eii_square_integral_values (local_eii_square_integral_values.size()); + Utilities::MPI::sum(local_eii_square_integral_values,this->get_mpi_communicator(),global_eii_square_integral_values); + std::vector global_boundary_area_values (local_boundary_area_values.size()); + Utilities::MPI::sum(local_boundary_area_values,this->get_mpi_communicator(),global_boundary_area_values); + + // and now take them apart into the global map again + // At the same time, calculate the rms strain rate invariant for each boundary + unsigned int index = 0; + for (const auto boundary_id: boundary_indicators) + { + global_max_eii[boundary_id] = global_max_values[index]; + global_min_eii[boundary_id] = global_min_values[index]; + global_rms_eii[boundary_id] = std::sqrt(global_eii_square_integral_values[index] / global_boundary_area_values[index]); + ++index; + } + } + + // now add the computed max, min, and rms strain rates to the statistics object + // and create a single string that can be output to the screen + const std::string units = (this->convert_output_to_years() == true) ? "1/yr" : "1/s"; + const double unit_scale_factor = (this->convert_output_to_years() == true) ? year_in_seconds : 1.0; + std::ostringstream screen_text; + unsigned int index = 0; + + for (std::map::const_iterator + max_eii = global_max_eii.begin(), min_eii = global_min_eii.begin(), rms = global_rms_eii.begin(); + max_eii != global_max_eii.end() && min_eii != global_min_eii.end() && rms != global_rms_eii.end(); + ++max_eii, ++min_eii, ++rms, ++index) + { + const std::string name_max = "Maximum strain rate invariant residual magnitude on boundary with indicator " + + Utilities::int_to_string(max_eii->first) + + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() + .translate_id_to_symbol_name (max_eii->first)) + + " (" + units + ")"; + statistics.add_value (name_max, max_eii->second*unit_scale_factor); + const std::string name_min = "Minimum strain rate invariant residual magnitude on boundary with indicator " + + Utilities::int_to_string(min_eii->first) + + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() + .translate_id_to_symbol_name (min_eii->first)) + + " (" + units + ")"; + statistics.add_value (name_min, min_eii->second*unit_scale_factor); + const std::string name_rms = "RMS strain rate invariant residual on boundary with indicator " + + Utilities::int_to_string(rms->first) + + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() + .translate_id_to_symbol_name (rms->first)) + + " (" + units + ")"; + statistics.add_value (name_rms, rms->second*unit_scale_factor); + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name_max, 8); + statistics.set_scientific (name_max, true); + statistics.set_precision (name_min, 8); + statistics.set_scientific (name_min, true); + statistics.set_precision (name_rms, 8); + statistics.set_scientific (name_rms, true); + + screen_text << max_eii->second *unit_scale_factor << " " << units << ", " + << min_eii->second *unit_scale_factor << " " << units << ", " + << rms->second *unit_scale_factor << " " << units + << (index == global_max_eii.size()-1 ? "" : ", "); + + } + + return std::pair ("Max, min, and RMS residual strain rate invariant along boundary parts:", + screen_text.str()); + } + + + + template + void + BoundaryStrainRateResidualStatistics::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Boundary strain rate residual statistics"); + { + prm.declare_entry ("Data directory", + "$ASPECT_SOURCE_DIR/data/postprocess/boundary-strain-rate-residual/", + Patterns::DirectoryName (), + "The name of a directory that contains the ascii data. " + "This path may either be absolute (if starting with a " + "`/') or relative to the current directory. The path may also " + "include the special text `$ASPECT_SOURCE_DIR' which will be " + "interpreted as the path in which the ASPECT source files were " + "located when ASPECT was compiled. This interpretation allows, " + "for example, to reference files located in the `data/' subdirectory " + "of ASPECT."); + prm.declare_entry ("Data file name", "box_3d_boundary_strain_rate.txt", + Patterns::Anything (), + "The file name of the input surface strain rate an ascii data. " + "The file has one column in addition to the coordinate columns " + "corresponding to the second invariant of strain rate. "); + prm.declare_entry ("Scale factor", "1.", + Patterns::Double (), + "Scalar factor, which is applied to the model data. " + "You might want to use this to scale the input to a " + "reference model."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + BoundaryStrainRateResidualStatistics::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Boundary strain rate residual statistics"); + { + // Get the path to the data files. If it contains a reference + // to $ASPECT_SOURCE_DIR, replace it by what CMake has given us + // as a #define + data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get ("Data directory")); + data_file_name = prm.get ("Data file name"); + scale_factor = prm.get_double ("Scale factor"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(BoundaryStrainRateResidualStatistics, + "boundary strain rate residual statistics", + "A postprocessor that computes some statistics about " + "the surface strain rate residual along the top boundary. The residual " + "is the difference between the second invariant of the model strain rate and " + "the second strain rate invariant read from the input data file. " + "Currently, the strain residual statistics, i.e., min, max and the rms magnitude, " + "are computed at the top surface.") + } +} diff --git a/source/postprocess/boundary_velocity_residual_statistics.cc.bak b/source/postprocess/boundary_velocity_residual_statistics.cc.bak new file mode 100644 index 00000000000..2390c4e7be6 --- /dev/null +++ b/source/postprocess/boundary_velocity_residual_statistics.cc.bak @@ -0,0 +1,376 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + void + BoundaryVelocityResidualStatistics::initialize () + { + if (use_ascii_data) + { + // The input ascii table contains dim data columns (velocity components) in addition to the coordinate columns. + data_lookup = std::make_unique>(dim, scale_factor); + data_lookup->load_file(data_directory + data_file_name, this->get_mpi_communicator()); + } + else + { + // The two points are used in GPlates to find the 2d plane in which + // the model lies. These values are not used for 3d geometries and + // are thus set to the default. + Point<2> point_one(numbers::PI/2., 0.); + Point<2> point_two(numbers::PI/2., numbers::PI/2.); + + gplates_lookup = std::make_unique> ( + point_one, point_two); + + gplates_lookup->load_file(data_directory + data_file_name, this->get_mpi_communicator()); + } + } + + + + template + Tensor<1,dim> + BoundaryVelocityResidualStatistics::get_data_velocity (const Point &p) const + { + Tensor<1,dim> data_velocity; + if (use_ascii_data) + { + Point internal_position = p; + + if (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical) + { + const std::array spherical_position = this->get_geometry_model(). + cartesian_to_natural_coordinates(p); + + for (unsigned int d = 0; d < dim; ++d) + internal_position[d] = spherical_position[d]; + } + + for (unsigned int d = 0; d < dim; ++d) + data_velocity[d] = data_lookup->get_data(internal_position, d); + if (use_spherical_unit_vectors == true) + data_velocity = Utilities::Coordinates::spherical_to_cartesian_vector(data_velocity, p); + } + else + { + data_velocity = gplates_lookup->surface_velocity(p); + } + + return data_velocity; + } + + + + template + std::pair + BoundaryVelocityResidualStatistics::execute (TableHandler &statistics) + { + // create a quadrature formula for the velocity. + const Quadrature &quadrature_formula = this->introspection().face_quadratures.velocities; + + FEFaceValues fe_face_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_JxW_values | + update_quadrature_points); + + std::vector> velocities (fe_face_values.n_quadrature_points); + + std::map local_max_vel; + std::map local_min_vel; + std::map local_velocity_square_integral; + std::map local_boundary_area; + + std::set boundary_indicators; + boundary_indicators.insert(this->get_geometry_model().translate_symbolic_boundary_name_to_id("top")); + + AssertThrow (boundary_indicators.size() == 1, + ExcMessage("The plugin is only tested " + "to work correctly for a single boundary indicator, " + "but more than one was specified.")); + + for (const auto p : boundary_indicators) + { + local_max_vel[p] = std::numeric_limits::lowest(); + local_min_vel[p] = std::numeric_limits::max(); + } + + // for every face that is part of the selected geometry boundary + // and that is owned by this processor, + // compute the maximum, minimum, and squared*area velocity residual + // magnitude and the face area. + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + for (const unsigned int f : cell->face_indices()) + for (const auto current_boundary_id : boundary_indicators) + if (cell->face(f)->at_boundary() && cell->face(f)->boundary_id() == current_boundary_id) + { + fe_face_values.reinit (cell, f); + + fe_face_values[this->introspection().extractors.velocities].get_function_values (this->get_solution(), + velocities); + + // determine the max, min, and squared velocity residual on the face + // also determine the face area + double local_max = std::numeric_limits::lowest(); + double local_min = std::numeric_limits::max(); + double local_sqvel = 0.0; + double local_fe_face_area = 0.0; + for (unsigned int q=0; q point_at_surface = fe_face_values.quadrature_point(q); + // Extract data velocity. + Tensor<1,dim> data_velocity = get_data_velocity(point_at_surface); + + if (this->convert_output_to_years() == true) + data_velocity = data_velocity/year_in_seconds; + + // The velocity residual is calculated here. + const double vel_residual_mag = (velocities[q] - data_velocity).norm(); + + local_max = std::max(vel_residual_mag, + local_max); + local_min = std::min(vel_residual_mag, + local_min); + local_sqvel += ((vel_residual_mag * vel_residual_mag) * fe_face_values.JxW(q)); + local_fe_face_area += fe_face_values.JxW(q); + } + + // then merge them with the min/max/squared velocities + // and face areas we found for other faces with the same boundary indicator + local_max_vel[current_boundary_id] = std::max(local_max, + local_max_vel[current_boundary_id]); + local_min_vel[current_boundary_id] = std::min(local_min, + local_min_vel[current_boundary_id]); + local_velocity_square_integral[current_boundary_id] += local_sqvel; + local_boundary_area[current_boundary_id] += local_fe_face_area; + } + + // now communicate to get the global values + std::map global_max_vel; + std::map global_min_vel; + std::map global_rms_vel; + { + // first collect local values in the same order in which they are listed + // in the set of boundary indicators + std::vector local_max_values; + std::vector local_min_values; + std::vector local_velocity_square_integral_values; + std::vector local_boundary_area_values; + + for (const auto p : boundary_indicators) + { + local_max_values.push_back (local_max_vel[p]); + local_min_values.push_back (local_min_vel[p]); + + local_velocity_square_integral_values.push_back (local_velocity_square_integral[p]); + local_boundary_area_values.push_back (local_boundary_area[p]); + } + + // then collect contributions from all processors + std::vector global_max_values (local_max_values.size()); + Utilities::MPI::max (local_max_values, this->get_mpi_communicator(), global_max_values); + std::vector global_min_values (local_min_values.size()); + Utilities::MPI::min (local_min_values, this->get_mpi_communicator(), global_min_values); + + std::vector global_velocity_square_integral_values (local_velocity_square_integral_values.size()); + Utilities::MPI::sum(local_velocity_square_integral_values,this->get_mpi_communicator(),global_velocity_square_integral_values); + std::vector global_boundary_area_values (local_boundary_area_values.size()); + Utilities::MPI::sum(local_boundary_area_values,this->get_mpi_communicator(),global_boundary_area_values); + + // and now take them apart into the global map again + // At the same time, calculate the rms velocity for each boundary + unsigned int index = 0; + for (const auto boundary_id: boundary_indicators) + { + global_max_vel[boundary_id] = global_max_values[index]; + global_min_vel[boundary_id] = global_min_values[index]; + global_rms_vel[boundary_id] = std::sqrt(global_velocity_square_integral_values[index] / global_boundary_area_values[index]); + ++index; + } + } + + // now add the computed max, min, and rms velocities to the statistics object + // and create a single string that can be output to the screen + const std::string units = (this->convert_output_to_years() == true) ? "m/year" : "m/s"; + const double unit_scale_factor = (this->convert_output_to_years() == true) ? year_in_seconds : 1.0; + std::ostringstream screen_text; + unsigned int index = 0; + + for (std::map::const_iterator + max_velocity = global_max_vel.begin(), min_velocity = global_min_vel.begin(), rms = global_rms_vel.begin(); + max_velocity != global_max_vel.end() && min_velocity != global_min_vel.end() && rms != global_rms_vel.end(); + ++max_velocity, ++min_velocity, ++rms, ++index) + { + const std::string name_max = "Maximum velocity residual magnitude on boundary with indicator " + + Utilities::int_to_string(max_velocity->first) + + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() + .translate_id_to_symbol_name (max_velocity->first)) + + " (" + units + ")"; + statistics.add_value (name_max, max_velocity->second*unit_scale_factor); + const std::string name_min = "Minimum velocity residual magnitude on boundary with indicator " + + Utilities::int_to_string(min_velocity->first) + + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() + .translate_id_to_symbol_name (min_velocity->first)) + + " (" + units + ")"; + statistics.add_value (name_min, min_velocity->second*unit_scale_factor); + const std::string name_rms = "RMS velocity residual on boundary with indicator " + + Utilities::int_to_string(rms->first) + + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() + .translate_id_to_symbol_name (rms->first)) + + " (" + units + ")"; + statistics.add_value (name_rms, rms->second*unit_scale_factor); + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name_max, 8); + statistics.set_scientific (name_max, true); + statistics.set_precision (name_min, 8); + statistics.set_scientific (name_min, true); + statistics.set_precision (name_rms, 8); + statistics.set_scientific (name_rms, true); + + // finally have something for the screen + screen_text.precision(4); + screen_text << max_velocity->second *unit_scale_factor << ' ' << units << ", " + << min_velocity->second *unit_scale_factor << ' ' << units << ", " + << rms->second *unit_scale_factor << ' ' << units + << (index == global_max_vel.size()-1 ? "" : ", "); + } + + return std::pair ("Max, min, and RMS residual velocity along boundary parts:", + screen_text.str()); + } + + + + template + void + BoundaryVelocityResidualStatistics::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Boundary velocity residual statistics"); + { + prm.declare_entry ("Data directory", + "$ASPECT_SOURCE_DIR/data/boundary-velocity/gplates/", + Patterns::DirectoryName (), + "The name of a directory that contains the GPlates model or the " + "ascii data. This path may either be absolute (if starting with a " + "`/') or relative to the current directory. The path may also " + "include the special text `$ASPECT_SOURCE_DIR' which will be " + "interpreted as the path in which the ASPECT source files were " + "located when ASPECT was compiled. This interpretation allows, " + "for example, to reference files located in the `data/' subdirectory " + "of ASPECT."); + prm.declare_entry ("Data file name", "current_day.gpml", + Patterns::Anything (), + "The file name of the input velocity as a GPlates model or an ascii data. " + "For the GPlates model, provide file in the same format as described " + "in the 'gplates' boundary velocity plugin. " + "For the ascii data, provide file in the same format as described in " + " 'ascii data' initial composition plugin." ); + prm.declare_entry ("Scale factor", "1.", + Patterns::Double (), + "Scalar factor, which is applied to the model data. " + "You might want to use this to scale the input to a " + "reference model. Another way to use this factor is to " + "convert units of the input files. For instance, if you " + "provide velocities in cm/year set this factor to 0.01."); + prm.declare_entry ("Use spherical unit vectors", "false", + Patterns::Bool (), + "Specify velocity as r, phi, and theta components " + "instead of x, y, and z. Positive velocities point up, east, " + "and north (in 3d) or out and clockwise (in 2d). " + "This setting only makes sense for spherical geometries." + "GPlates data is always interpreted to be in east and north directions " + "and is not affected by this parameter."); + prm.declare_entry ("Use ascii data", "false", + Patterns::Bool (), + "Use ascii data files (e.g., GPS) for computing residual velocities " + "instead of GPlates data."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + BoundaryVelocityResidualStatistics::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Boundary velocity residual statistics"); + { + // Get the path to the data files. If it contains a reference + // to $ASPECT_SOURCE_DIR, replace it by what CMake has given us + // as a #define + data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get ("Data directory")); + data_file_name = prm.get ("Data file name"); + scale_factor = prm.get_double ("Scale factor"); + + use_spherical_unit_vectors = prm.get_bool("Use spherical unit vectors"); + use_ascii_data = prm.get_bool("Use ascii data"); + + if (use_spherical_unit_vectors) + AssertThrow (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical, + ExcMessage ("Spherical unit vectors should not be used " + "when geometry model is not spherical.")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(BoundaryVelocityResidualStatistics, + "boundary velocity residual statistics", + "A postprocessor that computes some statistics about " + "the velocity residual along the top boundary. The velocity residual " + "is the difference between the model solution velocities and the input " + "velocities (GPlates model or ascii data). Currently, the velocity residual " + "statistics, i.e., min, max and the rms magnitude, is computed at the top " + "surface.") + } +} diff --git a/source/postprocess/command.cc.bak b/source/postprocess/command.cc.bak new file mode 100644 index 00000000000..9160c73fea3 --- /dev/null +++ b/source/postprocess/command.cc.bak @@ -0,0 +1,131 @@ +/* + Copyright (C) 2016 - 2018 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + Command::execute (TableHandler &) + { + if (on_all_processes || + (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0)) + { + + // Check if a command-processor is available by calling system() with a + // null pointer. System is guaranteed to return non-zero if it finds + // a terminal and zero if there is none (like on the compute nodes of + // some cluster architectures, e.g. IBM BlueGene/Q) + AssertThrow(system(nullptr) != 0, + ExcMessage("The \"command\" postprocessor required a command-processor, " + "which appears to be unavailable on this system.")); + + const int error = system(command.c_str()); + + if (error != 0) + { + std::string err_str = (error<0 ? "-" : "") + + Utilities::int_to_string(std::abs(error)); + + + if (terminate_on_failure) + { + AssertThrow(false, ExcMessage("Command <" + + command + + "> failed with error code: " + + err_str + + ". Terminating process.")); + } + else + { + std::cerr << "*** WARNING: Command <" << command + << "> failed with error code: " + << err_str + << ". Continuing anyway." + << std::endl; + } + } + } + + return std::make_pair (std::string("Running command:"), + command); + } + + template + void + Command::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Command"); + { + prm.declare_entry ("Terminate on failure", "false", + Patterns::Bool(), + "Select whether \\aspect{} should terminate if the " + "command returns a non-zero exit status."); + + prm.declare_entry ("Run on all processes", "false", + Patterns::Bool(), + "Whether to run command from all processes (true), " + "or only on process 0 (false)."); + + prm.declare_entry ("Command", "", + Patterns::Anything(), + "Command to execute."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + Command::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Command"); + { + terminate_on_failure = prm.get_bool ("Terminate on failure"); + on_all_processes = prm.get_bool ("Run on all processes"); + command = prm.get ("Command"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(Command, + "command", + "A postprocessor that executes a command line " + "process.") + } +} diff --git a/source/postprocess/composition_statistics.cc.bak b/source/postprocess/composition_statistics.cc.bak new file mode 100644 index 00000000000..d0073fcf11c --- /dev/null +++ b/source/postprocess/composition_statistics.cc.bak @@ -0,0 +1,168 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + CompositionStatistics::execute (TableHandler &statistics) + { + if (this->n_compositional_fields() == 0) + return {"", ""}; + + // create a quadrature formula based on the compositional element alone. + const Quadrature &quadrature_formula = this->introspection().quadratures.compositional_fields; + const unsigned int n_q_points = quadrature_formula.size(); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_quadrature_points | + update_JxW_values); + + std::vector compositional_values(n_q_points); + + std::vector local_compositional_integrals (this->n_compositional_fields()); + + // compute the integral quantities by quadrature + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + + for (unsigned int c=0; cn_compositional_fields(); ++c) + { + fe_values[this->introspection().extractors.compositional_fields[c]].get_function_values (this->get_solution(), + compositional_values); + for (unsigned int q=0; q global_compositional_integrals (local_compositional_integrals.size()); + Utilities::MPI::sum (local_compositional_integrals, + this->get_mpi_communicator(), + global_compositional_integrals); + + // compute min/max by simply + // looping over the elements of the + // solution vector. + std::vector local_min_compositions (this->n_compositional_fields(), + std::numeric_limits::max()); + std::vector local_max_compositions (this->n_compositional_fields(), + std::numeric_limits::lowest()); + + for (unsigned int c=0; cn_compositional_fields(); ++c) + { + IndexSet range = this->get_solution().block(this->introspection().block_indices.compositional_fields[c]).locally_owned_elements(); + for (unsigned int i=0; iget_solution().block(this->introspection().block_indices.compositional_fields[c])(idx); + + local_min_compositions[c] = std::min (local_min_compositions[c], val); + local_max_compositions[c] = std::max (local_max_compositions[c], val); + } + + } + + // now do the reductions over all processors + std::vector global_min_compositions (this->n_compositional_fields(), + std::numeric_limits::max()); + std::vector global_max_compositions (this->n_compositional_fields(), + std::numeric_limits::lowest()); + { + Utilities::MPI::min (local_min_compositions, + this->get_mpi_communicator(), + global_min_compositions); + Utilities::MPI::max (local_max_compositions, + this->get_mpi_communicator(), + global_max_compositions); + } + + // finally produce something for the statistics file + for (unsigned int c=0; cn_compositional_fields(); ++c) + { + statistics.add_value ("Minimal value for composition " + this->introspection().name_for_compositional_index(c), + global_min_compositions[c]); + statistics.add_value ("Maximal value for composition " + this->introspection().name_for_compositional_index(c), + global_max_compositions[c]); + statistics.add_value ("Global mass for composition " + this->introspection().name_for_compositional_index(c), + global_compositional_integrals[c]); + } + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + for (unsigned int c=0; cn_compositional_fields(); ++c) + { + const std::string columns[] = { "Minimal value for composition " + this->introspection().name_for_compositional_index(c), + "Maximal value for composition " + this->introspection().name_for_compositional_index(c), + "Global mass for composition " + this->introspection().name_for_compositional_index(c) + }; + for (const auto &col : columns) + { + statistics.set_precision (col, 8); + statistics.set_scientific (col, true); + } + } + + std::ostringstream output; + output.precision(4); + for (unsigned int c=0; cn_compositional_fields(); ++c) + { + output << global_min_compositions[c] << '/' + << global_max_compositions[c] << '/' + << global_compositional_integrals[c]; + if (c+1 != this->n_compositional_fields()) + output << " // "; + } + + return std::pair ("Compositions min/max/mass:", + output.str()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(CompositionStatistics, + "composition statistics", + "A postprocessor that computes some statistics about " + "the compositional fields, if present in this simulation. " + "In particular, it computes maximal and minimal values of " + "each field, as well as the total mass contained in this " + "field as defined by the integral " + "$m_i(t) = \\int_\\Omega c_i(\\mathbf x,t) \\; \\text{d}x$.") + } +} diff --git a/source/postprocess/composition_velocity_statistics.cc.bak b/source/postprocess/composition_velocity_statistics.cc.bak new file mode 100644 index 00000000000..ce2244a748c --- /dev/null +++ b/source/postprocess/composition_velocity_statistics.cc.bak @@ -0,0 +1,205 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + CompositionVelocityStatistics::execute (TableHandler &statistics) + { + const QGauss quadrature_formula (this->get_fe() + .base_element(this->introspection().base_elements.velocities).degree+1); + const unsigned int n_q_points = quadrature_formula.size(); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_quadrature_points | + update_JxW_values); + + std::vector> velocity_values(n_q_points); + std::vector compositional_values(n_q_points); + + std::vector local_velocity_square_integral(this->n_compositional_fields()); + std::vector local_area_integral(this->n_compositional_fields()); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + fe_values[this->introspection().extractors.velocities].get_function_values (this->get_solution(), + velocity_values); + + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + { + fe_values[this->introspection().extractors.compositional_fields[c]].get_function_values(this->get_solution(), + compositional_values); + + for (unsigned int q = 0; q < n_q_points; ++q) + { + if (compositional_values[q] >= 0.5) + { + local_velocity_square_integral[c] += ((velocity_values[q] * velocity_values[q]) * + fe_values.JxW(q)); + local_area_integral[c] += fe_values.JxW(q); + } + } + } + } + + std::vector global_velocity_square_integral(local_velocity_square_integral.size()); + Utilities::MPI::sum(local_velocity_square_integral, this->get_mpi_communicator(), global_velocity_square_integral); + std::vector global_area_integral(local_area_integral.size()); + Utilities::MPI::sum(local_area_integral, this->get_mpi_communicator(), global_area_integral); + + // compute the RMS velocity for each compositional field and for the selected compositonal fields combined + std::vector vrms_per_composition(local_area_integral.size()); + double velocity_square_integral_selected_fields = 0., area_integral_selected_fields = 0.; + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + { + vrms_per_composition[c] = std::sqrt(global_velocity_square_integral[c]) / + std::sqrt(global_area_integral[c]); + + const std::vector::iterator selected_field_it = std::find(selected_fields.begin(), selected_fields.end(), this->introspection().name_for_compositional_index(c)); + if (selected_field_it != selected_fields.end()) + { + velocity_square_integral_selected_fields += global_velocity_square_integral[c]; + area_integral_selected_fields += global_area_integral[c]; + } + } + + const double vrms_selected_fields = std::sqrt(velocity_square_integral_selected_fields) / std::sqrt(area_integral_selected_fields); + + const std::string unit = (this->convert_output_to_years()) ? "m/year" : "m/s"; + const double time_scaling = (this->convert_output_to_years()) ? year_in_seconds : 1.0; + + // finally produce something for the statistics file + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + { + statistics.add_value("RMS velocity (" + unit + ") for composition " + this->introspection().name_for_compositional_index(c), + time_scaling * vrms_per_composition[c]); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + const std::string columns[] = {"RMS velocity (" + unit + ") for composition " + + this->introspection().name_for_compositional_index(c) + }; + + for (const auto &column : columns) + { + statistics.set_precision(column, 8); + statistics.set_scientific(column, true); + } + } + + // Also output the selected fields vrms + statistics.add_value("RMS velocity (" + unit + ") for the selected field ", + time_scaling * vrms_selected_fields); + + const std::string column = {"RMS velocity (" + unit + ") for the selected field "}; + + statistics.set_precision(column, 8); + statistics.set_scientific(column, true); + + std::ostringstream output; + output.precision(4); + + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + { + output << time_scaling *vrms_per_composition[c] + << " " << unit; + output << " // "; + } + output << time_scaling *vrms_selected_fields; + + return std::pair("RMS velocity for compositions and combined selected fields:", + output.str()); + } + + + + template + void + CompositionVelocityStatistics::declare_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Composition velocity statistics"); + { + prm.declare_entry("Names of selected compositional fields", "", + Patterns::List(Patterns::Anything()), + "A list of names for each of the compositional fields that " + "you want to compute the combined RMS velocity for."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + CompositionVelocityStatistics::parse_parameters(ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Composition velocity statistics"); + { + selected_fields = Utilities::split_string_list(prm.get("Names of selected compositional fields")); + + AssertThrow((selected_fields.size() > 0) && + (selected_fields.size() <= this->n_compositional_fields()), + ExcMessage("The length of the list of names for the compositional " + "fields for which the RMS velocity is to be summed must be larger than zero " + "and smaller or equal to the number of compositional fields.")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(CompositionVelocityStatistics, + "composition velocity statistics", + "A postprocessor that computes the root mean square velocity " + "over the area spanned by each compositional field (i.e. where " + "the field values are larger or equal to 0.5.") + } +} diff --git a/source/postprocess/core_statistics.cc.bak b/source/postprocess/core_statistics.cc.bak new file mode 100644 index 00000000000..1179c83a4ff --- /dev/null +++ b/source/postprocess/core_statistics.cc.bak @@ -0,0 +1,236 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + CoreStatistics::CoreStatistics() + { + core_data.is_initialized = false; + } + + template + std::pair + CoreStatistics::execute (TableHandler &statistics) + { + // now add all of the computed heat fluxes to the statistics object + // and create a single string that can be output to the screen + std::ostringstream screen_text; + + const BoundaryTemperature::DynamicCore &dynamic_core = + this->get_boundary_temperature_manager().template get_matching_boundary_temperature_model>(); + + core_data = dynamic_core.get_core_data(); + + // now add core mantle boundary heat flux to the statistics object + // and create a single string that can be output to the screen + const std::string name = "CMB heat flux out of the core (TW)"; + statistics.add_value (name, -core_data.Q/1e12); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name, 3); + statistics.set_scientific (name, true); + + // finally have something for the screen + screen_text.precision(3); + screen_text << -core_data.Q/1e12 << " TW,"; + + + const std::string name1 = "CMB Temperature (K)"; + statistics.add_value (name1, core_data.Ti); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name1, 2); + statistics.set_scientific (name1, false); + + const std::string name2 = "Inner core radius (km)"; + statistics.add_value (name2, core_data.Ri*1e-3); + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name2, 2); + statistics.set_scientific (name2, false); + + const std::string name3 = "Light element concentration (%)"; + statistics.add_value (name3, core_data.Xi*100); + statistics.set_precision (name3, 4); + statistics.set_scientific (name3, false); + + if (excess_entropy_only) + { + const std::string name4 = "Excess entropy (W/K)"; + const double delta_E = core_data.Es*core_data.dT_dt + + core_data.Er + + core_data.Eh*core_data.dR_dt + + core_data.El*core_data.dR_dt + + core_data.Eg*core_data.dR_dt + - core_data.Ek; + statistics.add_value (name4, delta_E); + statistics.set_precision (name4, 3); + statistics.set_scientific (name4, true); + } + else + { + const std::string name5 = "Es (W/K)"; + statistics.add_value (name5, core_data.Es*core_data.dT_dt); + statistics.set_precision (name5, 3); + statistics.set_scientific (name5, true); + + const std::string name6 = "Er (W/K)"; + statistics.add_value (name6, core_data.Er); + statistics.set_precision (name6, 3); + statistics.set_scientific (name6, true); + + const std::string name7 = "Eh (W/K)"; + statistics.add_value (name7, core_data.Eh*core_data.dR_dt); + statistics.set_precision (name7, 3); + statistics.set_scientific (name7, true); + + const std::string name8 = "El (W/K)"; + statistics.add_value (name8, core_data.El*core_data.dR_dt); + statistics.set_precision (name8, 3); + statistics.set_scientific (name8, true); + + const std::string name9 = "Eg (W/K)"; + statistics.add_value (name9, core_data.Eg*core_data.dR_dt); + statistics.set_precision (name9, 3); + statistics.set_scientific (name9, true); + + const std::string name10 = "Ek (W/K)"; + statistics.add_value (name10, core_data.Ek); + statistics.set_precision (name10, 3); + statistics.set_scientific (name10, true); + } + + if (dynamic_core.is_OES_used()) + { + const std::string name11 = "Other energy source (W)"; + statistics.add_value (name11, core_data.Q_OES); + statistics.set_precision (name11, 3); + statistics.set_scientific (name11, true); + } + + return std::pair ("CMB heat flux out of the core", + screen_text.str()); + } + + template + void + CoreStatistics::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Dynamic core statistics"); + { + prm.declare_entry("Excess entropy only","false", + Patterns::Bool(), + "Output the excess entropy only instead the each entropy terms."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + void + CoreStatistics::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Dynamic core statistics"); + { + excess_entropy_only = prm.get_bool("Excess entropy only"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + template + const BoundaryTemperature::internal::CoreData & + CoreStatistics::get_core_data() const + { + return core_data; + } + + template + template + void CoreStatistics::serialize (Archive &ar, const unsigned int) + { + ar &(core_data.Ti); + ar &(core_data.Ri); + ar &(core_data.Xi); + ar &(core_data.Q); + ar &(core_data.dR_dt); + ar &(core_data.dT_dt); + ar &(core_data.dX_dt); + ar &(core_data.is_initialized); + } + + template + void CoreStatistics::save (std::map &status_strings) const + { + std::ostringstream os; + aspect::oarchive oa (os); + oa << (*this); + + status_strings["CoreStatistics"] = os.str(); + } + + template + void CoreStatistics::load (const std::map &status_strings) + { + // see if something was saved + if (status_strings.find("CoreStatistics") != status_strings.end()) + { + std::istringstream is (status_strings.find("CoreStatistics")->second); + aspect::iarchive ia (is); + ia >> (*this); + } + } + + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(CoreStatistics, + "core statistics", + "A postprocessor that computes some statistics about " + "the core evolution. (Working only with dynamic core boundary temperature plugin)") + } +} diff --git a/source/postprocess/crystal_preferred_orientation.cc.bak b/source/postprocess/crystal_preferred_orientation.cc.bak new file mode 100644 index 00000000000..974ffa07e79 --- /dev/null +++ b/source/postprocess/crystal_preferred_orientation.cc.bak @@ -0,0 +1,870 @@ +/* + Copyright (C) 2022 by the authors of the ASPECT code. + This file is part of ASPECT. + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + ASPECT 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 General Public License for more details. + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + template + CrystalPreferredOrientation::CrystalPreferredOrientation () + : + // the following value is later read from the input file + output_interval (0), + // initialize this to a nonsensical value; set it to the actual time + // the first time around we get to check it + last_output_time (std::numeric_limits::quiet_NaN()), + output_file_number (numbers::invalid_unsigned_int), + group_files(0), + write_in_background_thread(false) + {} + + + + template + CrystalPreferredOrientation::~CrystalPreferredOrientation () + { + // make sure a thread that may still be running in the background, + // writing data, finishes + if (background_thread_main.joinable()) + background_thread_main.join (); + + if (background_thread_content_raw.joinable()) + background_thread_content_raw.join (); + + if (background_thread_content_draw_volume_weighting.joinable()) + background_thread_content_draw_volume_weighting.join (); + } + + + + template + void + CrystalPreferredOrientation::initialize () + { + const unsigned int my_rank = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); + this->random_number_generator.seed(random_number_seed+my_rank); + } + + + + template + std::list + CrystalPreferredOrientation::required_other_postprocessors () const + { + return {"particles"}; + } + + + + template + // We need to pass the arguments by value, as this function can be called on a separate thread: + void CrystalPreferredOrientation::writer (const std::string &filename, + const std::string &temporary_output_location, + const std::string &file_contents, + const bool compress_contents) + { + std::string tmp_filename = filename; + if (temporary_output_location != "") + { + tmp_filename = temporary_output_location + "/aspect.tmp.XXXXXX"; + + // Create the temporary file; get at the actual filename + // by using a C-style string that mkstemp will then overwrite + std::vector tmp_filename_x (tmp_filename.size()+1); + std::strcpy(tmp_filename_x.data(), tmp_filename.c_str()); + const int tmp_file_desc = mkstemp(tmp_filename_x.data()); + tmp_filename = tmp_filename_x.data(); + + // If we failed to create the temp file, just write directly to the target file. + // We also provide a warning about this fact. There are places where + // this fails *on every node*, so we will get a lot of warning messages + // into the output; in these cases, just writing multiple pieces to + // std::cerr will produce an unreadable mass of text; rather, first + // assemble the error message completely, and then output it atomically + if (tmp_file_desc == -1) + { + const std::string x = ("***** WARNING: could not create temporary file <" + + + tmp_filename + + + ">, will output directly to final location. This may negatively " + "affect performance. (On processor " + + Utilities::int_to_string(Utilities::MPI::this_mpi_process (MPI_COMM_WORLD)) + + ".)\n"); + + std::cerr << x << std::flush; + + tmp_filename = filename; + } + else + close(tmp_file_desc); + } + + std::ofstream out(tmp_filename.c_str(), std::ofstream::binary); + + AssertThrow (out, ExcMessage(std::string("Trying to write to file <") + + filename + + ">, but the file can't be opened!")); + + // now write and then move the tmp file to its final destination + // if necessary + if (compress_contents) + { + namespace bio = boost::iostreams; + + std::stringstream origin(file_contents); + + bio::filtering_streambuf compress_out; + compress_out.push(bio::zlib_compressor()); + compress_out.push(origin); + bio::copy(compress_out, out); + } + else + { + out << file_contents; + } + + out.close (); + + if (tmp_filename != filename) + { + std::string command = std::string("mv ") + tmp_filename + " " + filename; + int error = system(command.c_str()); + + AssertThrow(error == 0, + ExcMessage("Could not move " + tmp_filename + " to " + + filename + ". On processor " + + Utilities::int_to_string(Utilities::MPI::this_mpi_process (MPI_COMM_WORLD)) + ".")); + } + } + + + + template + std::pair + CrystalPreferredOrientation::execute (TableHandler &statistics) + { + + const Particle::Property::Manager &manager = this->get_particle_world(0).get_property_manager(); + const Particle::Property::ParticleHandler &particle_handler = this->get_particle_world(0).get_particle_handler(); + + const bool cpo_elastic_decomposition_plugin_exists = manager.plugin_name_exists("elastic tensor decomposition"); + + // Get a reference to the CPO particle property. + const Particle::Property::CrystalPreferredOrientation &cpo_particle_property = + manager.template get_matching_property>(); + + const unsigned int n_grains = cpo_particle_property.get_number_of_grains(); + const unsigned int n_minerals = cpo_particle_property.get_number_of_minerals(); + + // if this is the first time we get here, set the last output time + // to the current time - output_interval. this makes sure we + // always produce data during the first time step + if (std::isnan(last_output_time)) + last_output_time = this->get_time() - output_interval; + + // If it's not time to generate an output file or we do not write output + // return early. + if (this->get_time() < last_output_time + output_interval && this->get_time() != end_time) + return std::make_pair("",""); + + if (output_file_number == numbers::invalid_unsigned_int) + output_file_number = 0; + else + ++output_file_number; + + // Now prepare everything for writing the output + std::string particle_file_prefix_main = this->get_output_directory() + "particles_cpo/particles-" + Utilities::int_to_string (output_file_number, 5); + std::string particle_file_prefix_content_raw = this->get_output_directory() + "particles_cpo/CPO-" + Utilities::int_to_string (output_file_number, 5); + std::string particle_file_prefix_content_draw_volume_weighting = this->get_output_directory() + "particles_cpo/weighted_CPO-" + Utilities::int_to_string (output_file_number, 5); + + std::stringstream string_stream_main; + std::stringstream string_stream_content_raw; + std::stringstream string_stream_content_draw_volume_weighting; + + string_stream_main << "id x y" << (dim == 3 ? " z" : "") << " olivine_deformation_type" + << (cpo_elastic_decomposition_plugin_exists ? (std::string(" full_norm_square ") + + "triclinic_norm_square_p1 triclinic_norm_square_p2 triclinic_norm_square_p3 " + + "monoclinic_norm_square_p1 monoclinic_norm_square_p2 monoclinic_norm_square_p3 " + + "orthohombic_norm_square_p1 orthohombic_norm_square_p2 orthohombic_norm_square_p3 " + + "tetragonal_norm_square_p1 tetragonal_norm_square_p2 tetragonal_norm_square_p3 " + + "hexagonal_norm_square_p1 hexagonal_norm_square_p2 hexagonal_norm_square_p3 " + + "isotropic_norm_square") : "") << std::endl; + + // get particle data + const Particle::Property::ParticlePropertyInformation &property_information = this->get_particle_world(0).get_property_manager().get_data_info(); + + AssertThrow(property_information.fieldname_exists("cpo mineral 0 type") , + ExcMessage("No CPO particle properties found. Make sure that the CPO particle property plugin is selected.")); + + + + const unsigned int cpo_data_position = property_information.n_fields() == 0 + ? + 0 + : + property_information.get_position_by_field_name("cpo mineral 0 type"); + + std::vector>> rotation_matrices (n_minerals, {n_grains,Tensor<2,3>()}); + std::vector>> euler_angles(n_minerals, {n_grains,{{0}}}); + + // write unweighted header + if (write_raw_cpo.size() != 0) + { + string_stream_content_raw << "id" << " " << std::setprecision(12); + for (unsigned int property_i = 0; property_i < write_raw_cpo.size(); ++property_i) + { + switch (write_raw_cpo[property_i].second) + { + case Output::VolumeFraction: + string_stream_content_raw << "mineral_" << write_raw_cpo[property_i].first << "_volume_fraction" << " "; + break; + + case Output::RotationMatrix: + string_stream_content_raw << "mineral_" << write_raw_cpo[property_i].first << "_RM_0" << " " + << "mineral_" << write_raw_cpo[property_i].first << "_RM_1" << " " + << "mineral_" << write_raw_cpo[property_i].first << "_RM_2" << " " + << "mineral_" << write_raw_cpo[property_i].first << "_RM_3" << " " + << "mineral_" << write_raw_cpo[property_i].first << "_RM_4" << " " + << "mineral_" << write_raw_cpo[property_i].first << "_RM_5" << " " + << "mineral_" << write_raw_cpo[property_i].first << "_RM_6" << " " + << "mineral_" << write_raw_cpo[property_i].first << "_RM_7" << " " + << "mineral_" << write_raw_cpo[property_i].first << "_RM_8" << " "; + break; + + case Output::EulerAngles: + string_stream_content_raw << "mineral_" << write_raw_cpo[property_i].first << "_EA_phi" << " " + << "mineral_" << write_raw_cpo[property_i].first << "_EA_theta" << " " + << "mineral_" << write_raw_cpo[property_i].first << "_EA_z" << " "; + break; + default: + Assert(false, ExcMessage("Internal error: raw CPO postprocess case not found.")); + break; + } + } + string_stream_content_raw << std::endl; + } + + + // write weighted header + if (write_draw_volume_weighted_cpo.size() != 0) + { + string_stream_content_draw_volume_weighting << "id" << " "; + for (unsigned int property_i = 0; property_i < write_draw_volume_weighted_cpo.size(); ++property_i) + { + switch (write_draw_volume_weighted_cpo[property_i].second) + { + case Output::VolumeFraction: + string_stream_content_draw_volume_weighting << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_volume_fraction" << " "; + break; + + case Output::RotationMatrix: + string_stream_content_draw_volume_weighting << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_0" << " " + << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_1" << " " + << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_2" << " " + << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_3" << " " + << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_4" << " " + << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_5" << " " + << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_6" << " " + << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_7" << " " + << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_8" << " "; + break; + + case Output::EulerAngles: + string_stream_content_draw_volume_weighting << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_EA_phi" << " " + << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_EA_theta" << " " + << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_EA_z" << " "; + break; + default: + Assert(false, ExcMessage("Internal error: raw CPO postprocess case not found.")); + break; + } + } + string_stream_content_draw_volume_weighting << std::endl; + + } + + for (const auto &particle: particle_handler) + { + AssertThrow(particle.has_properties(), + ExcMessage("No particle properties found. Make sure that the CPO particle property plugin is selected.")); + + const unsigned int id = particle.get_id(); + const ArrayView properties = particle.get_properties(); + + const Point position = particle.get_location(); + + // always make a vector of rotation matrices + for (unsigned int mineral = 0; mineral < n_minerals; ++mineral) + { + rotation_matrices[mineral].resize(n_grains); + for (unsigned int i_grain = 0; i_grain < n_grains; ++i_grain) + { + rotation_matrices[mineral][i_grain] = cpo_particle_property.get_rotation_matrix_grains( + cpo_data_position, + properties, + mineral, + i_grain); + } + } + + const unsigned int lpo_hex_data_position = property_information.n_fields() == 0 || cpo_elastic_decomposition_plugin_exists == false + ? + 0 + : + property_information.get_position_by_field_name("cpo elastic axis e1"); + + // write main file + string_stream_main << id << " " << position << " " << properties[cpo_data_position]; + + if (cpo_elastic_decomposition_plugin_exists == true) + { + string_stream_main << " " << properties[lpo_hex_data_position+12] << " " << properties[lpo_hex_data_position+13] + << " " << properties[lpo_hex_data_position+14] << " " << properties[lpo_hex_data_position+15] + << " " << properties[lpo_hex_data_position+16] << " " << properties[lpo_hex_data_position+17] + << " " << properties[lpo_hex_data_position+18] << " " << properties[lpo_hex_data_position+19] + << " " << properties[lpo_hex_data_position+20] << " " << properties[lpo_hex_data_position+21] + << " " << properties[lpo_hex_data_position+22] << " " << properties[lpo_hex_data_position+23] + << " " << properties[lpo_hex_data_position+24] << " " << properties[lpo_hex_data_position+25] + << " " << properties[lpo_hex_data_position+26] << " " << properties[lpo_hex_data_position+27] + << " " << properties[lpo_hex_data_position+28]; + } + string_stream_main << std::endl; + + // write content file + if (compute_raw_euler_angles == true) + { + euler_angles.resize(n_minerals); + for (unsigned int mineral = 0; mineral < n_minerals; ++mineral) + { + euler_angles[mineral].resize(n_grains); + for (unsigned int i_grain = 0; i_grain < n_grains; ++i_grain) + { + euler_angles[mineral][i_grain] = Utilities::zxz_euler_angles_from_rotation_matrix( + rotation_matrices[mineral][i_grain]); + } + } + } + + if (write_raw_cpo.size() != 0) + { + // write unweighted data + for (unsigned int grain = 0; grain < n_grains; ++grain) + { + string_stream_content_raw << id << " "; + for (unsigned int property_i = 0; property_i < write_raw_cpo.size(); ++property_i) + { + switch (write_raw_cpo[property_i].second) + { + case Output::VolumeFraction: + string_stream_content_raw << cpo_particle_property.get_volume_fractions_grains( + cpo_data_position, + properties, + write_raw_cpo[property_i].first, + grain) << " "; + break; + + case Output::RotationMatrix: + string_stream_content_raw << rotation_matrices[write_raw_cpo[property_i].first][grain]<< " "; + break; + + case Output::EulerAngles: + Assert(compute_raw_euler_angles == true, + ExcMessage("Internal error: writing out raw Euler angles, without them being computed.")); + string_stream_content_raw << euler_angles[write_raw_cpo[property_i].first][grain][0] << " " + << euler_angles[write_raw_cpo[property_i].first][grain][1] << " " + << euler_angles[write_raw_cpo[property_i].first][grain][2] << " "; + break; + default: + Assert(false, ExcMessage("Internal error: raw CPO postprocess case not found.")); + break; + } + } + string_stream_content_raw << std::endl; + } + + } + + if (write_draw_volume_weighted_cpo.size() != 0) + { + std::vector>> weighted_rotation_matrices; + std::vector>> weighted_euler_angles; + + weighted_euler_angles.resize(n_minerals); + weighted_rotation_matrices.resize(n_minerals); + std::vector> volume_fractions_grains(n_minerals,std::vector(n_grains,-1.)); + for (unsigned int mineral = 0; mineral < n_minerals; ++mineral) + { + for (unsigned int i_grain = 0; i_grain < n_grains; ++i_grain) + { + weighted_euler_angles[mineral].resize(n_grains); + weighted_rotation_matrices[mineral].resize(n_grains); + volume_fractions_grains[mineral][i_grain] = cpo_particle_property.get_volume_fractions_grains( + cpo_data_position, + properties, + mineral, + i_grain); + } + weighted_rotation_matrices[mineral] = Utilities::rotation_matrices_random_draw_volume_weighting(volume_fractions_grains[mineral], rotation_matrices[mineral], n_grains, this->random_number_generator); + + Assert(weighted_rotation_matrices[mineral].size() == euler_angles[mineral].size(), + ExcMessage("Weighted rotation matrices vector (size = " + std::to_string(weighted_rotation_matrices[mineral].size()) + + ") has different size from input angles (size = " + std::to_string(euler_angles[mineral].size()) + ").")); + + for (unsigned int i_grain = 0; i_grain < n_grains; ++i_grain) + { + weighted_euler_angles[mineral][i_grain] = Utilities::zxz_euler_angles_from_rotation_matrix( + weighted_rotation_matrices[mineral][i_grain]); + } + } + string_stream_content_draw_volume_weighting << std::endl; + + // write data + for (unsigned int grain = 0; grain < n_grains; ++grain) + { + string_stream_content_draw_volume_weighting << id << " "; + for (unsigned int property_i = 0; property_i < write_draw_volume_weighted_cpo.size(); ++property_i) + { + switch (write_draw_volume_weighted_cpo[property_i].second) + { + case Output::VolumeFraction: + string_stream_content_draw_volume_weighting << volume_fractions_grains[write_draw_volume_weighted_cpo[property_i].first][grain] << " "; + break; + + case Output::RotationMatrix: + string_stream_content_draw_volume_weighting << weighted_rotation_matrices[write_draw_volume_weighted_cpo[property_i].first][grain] << " "; + break; + + case Output::EulerAngles: + Assert(compute_raw_euler_angles == true, + ExcMessage("Internal error: writing out raw Euler angles, without them being computed.")); + string_stream_content_draw_volume_weighting << weighted_euler_angles[write_draw_volume_weighted_cpo[property_i].first][grain][0] << " " + << weighted_euler_angles[write_draw_volume_weighted_cpo[property_i].first][grain][1] << " " + << weighted_euler_angles[write_draw_volume_weighted_cpo[property_i].first][grain][2] << " "; + break; + + default: + Assert(false, ExcMessage("Internal error: raw CPO postprocess case not found.")); + break; + } + } + string_stream_content_draw_volume_weighting << std::endl; + } + } + } + + std::string filename_main = particle_file_prefix_main + "." + Utilities::int_to_string(dealii::Utilities::MPI::this_mpi_process (this->get_mpi_communicator()),4) + ".dat"; + std::string filename_raw = particle_file_prefix_content_raw + "." + Utilities::int_to_string(dealii::Utilities::MPI::this_mpi_process (this->get_mpi_communicator()),4) + ".dat"; + std::string filename_draw_volume_weighting = particle_file_prefix_content_draw_volume_weighting + "." + Utilities::int_to_string(dealii::Utilities::MPI::this_mpi_process (this->get_mpi_communicator()),4) + ".dat"; + + std::unique_ptr file_contents_main = std::make_unique(string_stream_main.str()); + std::unique_ptr file_contents_raw = std::make_unique(string_stream_content_raw.str()); + std::unique_ptr file_contents_draw_volume_weighting = std::make_unique(string_stream_content_draw_volume_weighting.str()); + + if (write_in_background_thread) + { + // Wait for all previous write operations to finish, should + // any be still active, + if (background_thread_main.joinable()) + background_thread_main.join (); + + // then continue with writing the main file + background_thread_main + = std::thread([ my_filename = std::move(filename_main), + my_temporary_output_location = temporary_output_location, + my_file_contents = std::move(file_contents_main)]() + { + writer (my_filename, my_temporary_output_location, *my_file_contents, false); + }); + + if (write_raw_cpo.size() != 0) + { + // Wait for all previous write operations to finish, should + // any be still active, + if (background_thread_content_raw.joinable()) + background_thread_content_raw.join (); + + // then continue with writing our own data. + background_thread_content_raw + = std::thread([ my_filename = std::move(filename_raw), + my_temporary_output_location = temporary_output_location, + my_file_contents = std::move(file_contents_raw), + my_compress_cpo_data_files = compress_cpo_data_files]() + { + writer (my_filename, my_temporary_output_location, *my_file_contents, my_compress_cpo_data_files); + }); + } + + if (write_draw_volume_weighted_cpo.size() != 0) + { + // Wait for all previous write operations to finish, should + // any be still active, + if (background_thread_content_draw_volume_weighting.joinable()) + background_thread_content_draw_volume_weighting.join (); + + // then continue with writing our own data. + background_thread_content_draw_volume_weighting + = std::thread([ my_filename = std::move(filename_draw_volume_weighting), + my_temporary_output_location = temporary_output_location, + my_file_contents = std::move(file_contents_draw_volume_weighting), + my_compress_cpo_data_files = compress_cpo_data_files]() + { + writer (my_filename, my_temporary_output_location, *my_file_contents, my_compress_cpo_data_files); + }); + } + } + else + { + writer(filename_main,temporary_output_location,*file_contents_main, false); + if (write_raw_cpo.size() != 0) + writer(filename_raw,temporary_output_location,*file_contents_raw, compress_cpo_data_files); + if (write_draw_volume_weighted_cpo.size() != 0) + writer(filename_draw_volume_weighting,temporary_output_location,*file_contents_draw_volume_weighting, compress_cpo_data_files); + } + + + // up the next time we need output + set_last_output_time (this->get_time()); + + const std::string &particles_cpo_output = particle_file_prefix_content_raw; + + // record the file base file name in the output file + statistics.add_value ("Particle CPO file name", particles_cpo_output); + return std::make_pair("Writing particle cpo output:", particles_cpo_output); + } + + + + template + void + CrystalPreferredOrientation::set_last_output_time (const double current_time) + { + // if output_interval is positive, then update the last supposed output + // time + if (output_interval > 0) + { + // We need to find the last time output was supposed to be written. + // this is the last_output_time plus the largest positive multiple + // of output_intervals that passed since then. We need to handle the + // edge case where last_output_time+output_interval==current_time, + // we did an output and std::floor sadly rounds to zero. This is done + // by forcing std::floor to round 1.0-eps to 1.0. + const double magic = 1.0+2.0*std::numeric_limits::epsilon(); + last_output_time = last_output_time + std::floor((current_time-last_output_time)/output_interval*magic) * output_interval/magic; + } + } + + + + template + typename CrystalPreferredOrientation::Output + CrystalPreferredOrientation::string_to_output_enum(const std::string &string) + { + // olivine volume fraction, olivine rotation matrix, olivine Euler angles, enstatite volume fraction, enstatite rotation matrix, enstatite Euler angles + if (string == "volume fraction") + return Output::VolumeFraction; + if (string == "rotation matrix") + return Output::RotationMatrix; + if (string == "Euler angles") + return Output::EulerAngles; + return Output::not_found; + } + + + + template + void + CrystalPreferredOrientation::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Crystal Preferred Orientation"); + { + prm.declare_entry ("Time between data output", "1e8", + Patterns::Double (0), + "The time interval between each generation of " + "output files. A value of zero indicates that " + "output should be generated every time step.\n\n" + "Units: years if the " + "'Use years in output instead of seconds' parameter is set; " + "seconds otherwise."); + + prm.declare_entry ("Random number seed", "1", + Patterns::Integer (0), + "The seed used to generate random numbers. This will make sure that " + "results are reproducible as long as the problem is run with the " + "same amount of MPI processes. It is implemented as final seed = " + "random number seed + MPI Rank. "); + + prm.declare_entry ("Write in background thread", "false", + Patterns::Bool(), + "File operations can potentially take a long time, blocking the " + "progress of the rest of the model run. Setting this variable to " + "`true' moves this process into background threads, while the " + "rest of the model continues."); + + prm.declare_entry ("Temporary output location", "", + Patterns::Anything(), + "On large clusters it can be advantageous to first write the " + "output to a temporary file on a local file system and later " + "move this file to a network file system. If this variable is " + "set to a non-empty string it will be interpreted as a " + "temporary storage location."); + + prm.declare_entry ("Write out raw cpo data", + "olivine volume fraction,olivine Euler angles,enstatite volume fraction,enstatite Euler angles", + Patterns::List(Patterns::Anything()), + "A list containing what particle cpo data needs " + "to be written out after the particle id. This writes out the raw " + "cpo data files for each MPI process. It can write out the following data: " + "olivine volume fraction, olivine rotation matrix, olivine Euler angles, " + "enstatite volume fraction, enstatite rotation matrix, enstatite Euler angles. \n" + "Note that the rotation matrix and Euler angles both contain the same " + "information, but in a different format. Euler angles are recommended " + "over the rotation matrix since they only require to write 3 values instead " + "of 9. If the list is empty, this file will not be written." + "Furthermore, the entries will be written out in the order given, " + "and if entries are entered multiple times, they will be written " + "out multiple times."); + + prm.declare_entry ("Write out draw volume weighted cpo data", + "olivine Euler angles,enstatite Euler angles", + Patterns::List(Patterns::Anything()), + "A list containing the what part of the random draw volume " + "weighted particle cpo data needs to be written out after " + "the particle id. after using a random draw volume weighting. " + "The random draw volume weigthing uses a uniform random distribution " + "This writes out the raw cpo data files for " + "each MPI process. It can write out the following data: " + "olivine volume fraction, olivine rotation matrix, olivine Euler angles, " + "enstatite volume fraction, enstatite rotation matrix, enstatite Euler angles. \n" + "Note that the rotation matrix and Euler angles both contain the same " + "information, but in a different format. Euler angles are recommended " + "over the rotation matrix since they only require to write 3 values instead " + "of 9. If the list is empty, this file will not be written. " + "Furthermore, the entries will be written out in the order given, " + "and if entries are entered multiple times, they will be written " + "out multiple times."); + prm.declare_entry ("Compress cpo data files", "true", + Patterns::Bool(), + "Whether to compress the raw and weighted cpo data output files with zlib."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + } + + + + template + void + CrystalPreferredOrientation::parse_parameters (ParameterHandler &prm) + { + end_time = prm.get_double ("End time"); + if (this->convert_output_to_years()) + end_time *= year_in_seconds; + + unsigned int n_minerals; + + prm.enter_subsection("Particles"); + { + prm.enter_subsection("Crystal Preferred Orientation"); + { + prm.enter_subsection("Initial grains"); + { + // Static variable of CPO has not been initialize yet, so we need to get it directly. + n_minerals = dealii::Utilities::split_string_list(prm.get("Minerals")).size(); + } + prm.leave_subsection(); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Crystal Preferred Orientation"); + { + output_interval = prm.get_double ("Time between data output"); + if (this->convert_output_to_years()) + output_interval *= year_in_seconds; + + random_number_seed = prm.get_integer ("Random number seed"); + + AssertThrow(this->get_parameters().run_postprocessors_on_nonlinear_iterations == false, + ExcMessage("Postprocessing nonlinear iterations in models with " + "particles is currently not supported.")); + + aspect::Utilities::create_directory (this->get_output_directory() + "particles_cpo/", + this->get_mpi_communicator(), + true); + + write_in_background_thread = prm.get_bool("Write in background thread"); + temporary_output_location = prm.get("Temporary output location"); + + if (temporary_output_location != "") + { + // Check if a command-processor is available by calling system() with a + // null pointer. System is guaranteed to return non-zero if it finds + // a terminal and zero if there is none (like on the compute nodes of + // some cluster architectures, e.g. IBM BlueGene/Q) + AssertThrow(system((char *)nullptr) != 0, + ExcMessage("Usage of a temporary storage location is only supported if " + "there is a terminal available to move the files to their final location " + "after writing. The system() command did not succeed in finding such a terminal.")); + } + + std::vector write_raw_cpo_list = Utilities::split_string_list(prm.get("Write out raw cpo data")); + write_raw_cpo.resize(write_raw_cpo_list.size()); + bool found_euler_angles = false; + for (unsigned int i = 0; i < write_raw_cpo_list.size(); ++i) + { + std::vector split_raw_cpo_instructions = Utilities::split_string_list(write_raw_cpo_list[i],':'); + + AssertThrow(split_raw_cpo_instructions.size() == 2, + ExcMessage("Value \""+ write_raw_cpo_list[i] +"\", set in \"Write out raw cpo data\", is not a correct option " + + "because it should contain a mineral identification and a output specifier separated by a colon (:). This entry " + + "does not follow those rules.")); + + // get mineral number + std::vector mineral_instructions = Utilities::split_string_list(split_raw_cpo_instructions[0],' '); + AssertThrow(mineral_instructions.size() == 2, + ExcMessage("Value \""+ write_raw_cpo_list[i] +"\", set in \"Write out raw cpo data\", is not a correct option " + + "because the mineral identification part should contain two elements, the word mineral and a number.")); + + AssertThrow(mineral_instructions[0] == "mineral", + ExcMessage("Value \""+ write_raw_cpo_list[i] +"\", set in \"Write out raw cpo data\", is not a correct option " + + "because the mineral identification part should start with the word mineral and it starts with \"" + + mineral_instructions[0] + "\".")); + + int mineral_number = Utilities::string_to_int(mineral_instructions[1]); + Assert(mineral_number >= 0, ExcMessage("Internal error: mineral_number is negative: " + std::to_string(mineral_number) + ".")); + + AssertThrow((unsigned int) mineral_number < n_minerals, + ExcMessage("Value \""+ write_raw_cpo_list[i] +"\", set in \"Write out raw cpo data\", is not a correct option " + + "because the mineral number (" + std::to_string(mineral_number) + ") is larger than the number of minerals " + + "provided in the CPO subsection (" + std::to_string(n_minerals) + ").")); + + // get mineral fabric/deformation type + Output cpo_fabric_instruction = string_to_output_enum(split_raw_cpo_instructions[1]); + + AssertThrow(cpo_fabric_instruction != Output::not_found, + ExcMessage("Value \""+ write_raw_cpo_list[i] +"\", set in \"Write out raw cpo data\", is not a correct option.")); + + if (cpo_fabric_instruction == Output::EulerAngles) + found_euler_angles = true; + + write_raw_cpo[i] = std::make_pair(mineral_number,cpo_fabric_instruction); + } + + std::vector write_draw_volume_weighted_cpo_list = Utilities::split_string_list(prm.get("Write out draw volume weighted cpo data")); + write_draw_volume_weighted_cpo.resize(write_draw_volume_weighted_cpo_list.size()); + bool found_rotation_matrix = false; + for (unsigned int i = 0; i < write_draw_volume_weighted_cpo_list.size(); ++i) + { + std::vector split_draw_volume_weighted_cpo_instructions = Utilities::split_string_list(write_draw_volume_weighted_cpo_list[i],':'); + + AssertThrow(split_draw_volume_weighted_cpo_instructions.size() == 2, + ExcMessage("Value \""+ write_draw_volume_weighted_cpo_list[i] +"\", set in \"Write out draw volume weighted cpo data\", is not a correct option " + + "because it should contain a mineral identification and a output specifier separated by a colon (:). This entry " + + "does not follow those rules.")); + + // get mineral number + std::vector mineral_instructions = Utilities::split_string_list(split_draw_volume_weighted_cpo_instructions[0],' '); + AssertThrow(mineral_instructions.size() == 2, + ExcMessage("Value \""+ write_draw_volume_weighted_cpo_list[i] +"\", set in \"Write out draw volume weighted cpo data\", is not a correct option " + + "because the mineral identification part should contain two elements, the word mineral and a number.")); + + AssertThrow(mineral_instructions[0] == "mineral", + ExcMessage("Value \""+ write_draw_volume_weighted_cpo_list[i] +"\", set in \"Write out draw volume weighted cpo data\", is not a correct option " + + "because the mineral identification part should start with the word mineral and it starts with \"" + + mineral_instructions[0] + "\".")); + + int mineral_number = Utilities::string_to_int(mineral_instructions[1]); + Assert(mineral_number >= 0, ExcMessage("Internal error: mineral_number is negative: " + std::to_string(mineral_number) + ".")); + + AssertThrow((unsigned int) mineral_number < n_minerals, + ExcMessage("Value \""+ write_raw_cpo_list[i] +"\", set in \"Write out raw cpo data\", is not a correct option " + + "because the mineral number (" + std::to_string(mineral_number) + ") is larger than the number of minerals " + + "provided in the CPO subsection (" + std::to_string(n_minerals) + ").")); + + // get mineral fabric/deformation type + Output cpo_fabric_instruction = string_to_output_enum(split_draw_volume_weighted_cpo_instructions[1]); + + AssertThrow(cpo_fabric_instruction != Output::not_found, + ExcMessage("Value \""+ write_draw_volume_weighted_cpo_list[i] +"\", set in \"Write out draw volume weighted cpo data\", is not a correct option.")); + + if (cpo_fabric_instruction == Output::RotationMatrix) + found_rotation_matrix = true; + + write_draw_volume_weighted_cpo[i] = std::make_pair(mineral_number,cpo_fabric_instruction); + } + + if (write_draw_volume_weighted_cpo_list.size() != 0 || found_euler_angles == true) + compute_raw_euler_angles = true; + else + compute_raw_euler_angles = false; + + if (write_draw_volume_weighted_cpo_list.size() != 0 && found_rotation_matrix == true) + compute_weighted_rotation_matrix = true; + else + compute_weighted_rotation_matrix = false; + + compress_cpo_data_files = prm.get_bool("Compress cpo data files"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(CrystalPreferredOrientation, + "crystal preferred orientation", + "A Postprocessor that writes out CPO specific particle data." + "It can write out the CPO data as it is stored (raw) and/or as a" + "random draw volume weighted representation. The latter one" + "is recommended for plotting against real data. For both representations" + "the specific output fields and their order can be set." + "The work of this postprocessor should better be done by the main particles " + "postprocessor, however we need to be able to process the data before outputting it, " + "which does not work with that postprocessor. If this is added to the other " + "postprocessor in the future this one becomes obsolete.") + } +} diff --git a/source/postprocess/depth_average.cc.bak b/source/postprocess/depth_average.cc.bak new file mode 100644 index 00000000000..c753fef2467 --- /dev/null +++ b/source/postprocess/depth_average.cc.bak @@ -0,0 +1,517 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +#include + +namespace aspect +{ + namespace Postprocess + { + template + template + void DepthAverage::DataPoint::serialize (Archive &ar, + const unsigned int) + { + ar &time &values; + } + + + template + DepthAverage::DepthAverage () + : + // the following value is later read from the input file + output_interval (0), + // initialize this to a nonsensical value; set it to the actual time + // the first time around we get to check it + last_output_time (std::numeric_limits::quiet_NaN()), + n_depth_zones (numbers::invalid_unsigned_int) + {} + + + + template + std::pair + DepthAverage::execute (TableHandler &) + { + // if this is the first time we get here, set the next output time + // to the current time. this makes sure we always produce data during + // the first time step + if (std::isnan(last_output_time)) + last_output_time = this->get_time() - output_interval; + + // see if output is requested at this time + if (this->get_time() < last_output_time + output_interval) + return {"", ""}; + + DataPoint data_point; + data_point.time = this->get_time(); + + // Add all the requested fields + data_point.values = this->get_lateral_averaging().compute_lateral_averages(depth_bounds,variables); + entries.push_back (data_point); + + // On the root process, write out the file. do this using the DataOutStack + // class on a piece-wise constant finite element space on + // a 1d mesh with the correct subdivisions + const std::string filename_prefix (this->get_output_directory() + "depth_average"); + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + Triangulation<1> mesh; + const Point<1> p(depth_bounds[0]); + std::vector> spacing(1,std::vector(depth_bounds.size()-1,0.0)); + for (unsigned int i=0; i material_id(spacing[0].size()); + + GridGenerator::subdivided_hyper_rectangle(mesh, spacing, p, material_id); + + FE_DGQ<1> fe(0); + DoFHandler<1> dof_handler (mesh); + dof_handler.distribute_dofs(fe); + Assert (dof_handler.n_dofs() == n_depth_zones, ExcInternalError()); + + DataOutStack<1> data_out_stack; + + for (const auto &output_format_string: output_formats) + { + if (output_format_string != "txt") + { + for (const auto &variable : variables) + data_out_stack.declare_data_vector (variable, + DataOutStack<1>::cell_vector); + + for (unsigned int i=0; iconvert_output_to_years() + ? + entries[i].time / year_in_seconds + : + entries[i].time), + // declare the time step, which here is the difference + // between successive output times. we don't have anything + // for the first time step, however. we could do a zero + // delta, but that leads to invisible output. rather, we + // use an artificial value of one tenth of the first interval, + // if available + (i == 0 ? + (entries.size() > 1 ? (entries[1].time - entries[0].time)/10 : 0) : + entries[i].time - entries[i-1].time) / + (this->convert_output_to_years() + ? + year_in_seconds + : + 1)); + + data_out_stack.attach_dof_handler (dof_handler); + + Vector tmp(n_depth_zones); + for (unsigned int j=0; j did not succeed in the `point values' " + "postprocessor.")); + } + else + { + const std::string filename (this->get_output_directory() + "depth_average.txt"); + std::ofstream f(filename, std::ofstream::out); + + // Write the header + f << "# time" << " depth"; + for (const auto &variable : variables) + f << ' ' << variable; + f << std::endl; + + // Output each data point in the entries object + for (const auto &point : entries) + { + for (unsigned int d = 0; d < point.values[0].size(); ++d) + { + const double depth = (depth_bounds[d] + depth_bounds[d+1]) / 2.0; + f << std::setw(12) + << (this->convert_output_to_years() ? point.time/year_in_seconds : point.time) + << ' ' << std::setw(12) << depth; + for ( unsigned int i = 0; i < variables.size(); ++i ) + f << ' ' << std::setw(12) << point.values[i][d]; + f << std::endl; + } + } + + AssertThrow (f, ExcMessage("Writing data to <" + filename + + "> did not succeed in the `point values' " + "postprocessor.")); + } + } + } + + set_last_output_time (this->get_time()); + + // return what should be printed to the screen. note that we had + // just incremented the number, so use the previous value + return std::make_pair (std::string ("Writing depth average:"), + filename_prefix); + } + + + template + void + DepthAverage::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Depth average"); + { + prm.declare_entry ("Time between graphical output", "1e8", + Patterns::Double (0.), + "The time interval between each generation of " + "graphical output files. A value of zero indicates " + "that output should be generated in each time step. " + "Units: years if the " + "'Use years in output instead of seconds' parameter is set; " + "seconds otherwise."); + prm.declare_entry ("Number of zones", "10", + Patterns::Integer (1), + "The number of zones in depth direction within which we " + "are to compute averages. By default, we subdivide the entire " + "domain into 10 depth zones and compute temperature and other " + "averages within each of these zones. However, if you have a " + "very coarse mesh, it may not make much sense to subdivide " + "the domain into so many zones and you may wish to choose " + "less than this default. It may also make computations slightly " + "faster. On the other hand, if you have an extremely highly " + "resolved mesh, choosing more zones might also make sense."); + prm.declare_entry ("Depth boundaries of zones", "", + Patterns::List (Patterns::Double()), + "The depth boundaries of zones within which we " + "are to compute averages. By default this list is empty " + "and we subdivide the entire " + "domain into equidistant depth zones and compute " + "averages within each of these zones. If this list is not " + "empty it has to contain one more entry " + "than the 'Number of zones' parameter, representing the upper " + "and lower depth boundary of each zone. It is not necessary to " + "cover the whole depth-range (i.e. you can select to only average in " + "a single layer by choosing 2 arbitrary depths as the boundaries " + "of that layer)."); + prm.declare_entry ("Output format", "gnuplot, txt", + Patterns::MultipleSelection(DataOutBase::get_output_format_names().append("|txt")), + "A list of formats in which the output shall be produced. The " + "format in which the output is generated also determines " + "the extension of the file into which data is written. " + "The list of possible output formats that can be given " + "here is documented in the appendix of the manual where " + "the current parameter is described. By default the output " + "is written as gnuplot file (for plotting), and as a simple " + "text file."); + const std::string variables = + "all|temperature|composition|" + "adiabatic temperature|adiabatic pressure|adiabatic density|adiabatic density derivative|" + "velocity magnitude|sinking velocity|rising velocity|Vs|Vp|log viscosity|" + "viscosity|vertical heat flux|vertical mass flux|composition mass"; + prm.declare_entry("List of output variables", "all", + Patterns::MultipleSelection(variables), + "A comma separated list which specifies which quantities to " + "average in each depth slice. It defaults to averaging all " + "available quantities, but this can be an expensive operation, " + "so you may want to select only a few.\n\n" + "Specifically, the sinking velocity is defined as the scalar " + "product of the velocity and a unit vector in the direction of " + "gravity, if positive (being zero if this product is negative, " + "which would correspond to an upward velocity). " + "The rising velocity is the opposite: the scalar product of " + "the velocity and a unit vector in the direction opposite of " + "gravity, if positive (being zero for downward velocities). " + "\n\n" + "List of options:\n" + +variables); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + DepthAverage::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Depth average"); + { + n_depth_zones = prm.get_integer ("Number of zones"); + depth_bounds = Utilities::string_to_double(Utilities::split_string_list( + prm.get("Depth boundaries of zones"))); + + AssertThrow(depth_bounds.size() == 0 || depth_bounds.size() == n_depth_zones + 1, + ExcMessage("The parameter 'Depth boundaries of zones' has to be either empty, or have exactly " + "one more entry than the 'Number of zones' parameter.")); + + if (depth_bounds.size() == 0) + { + const double maximal_depth = this->get_geometry_model().maximal_depth(); + depth_bounds.resize(n_depth_zones+1); + + // Leave index 0 at 0.0, and generate an increasing range of equidistant depth bounds + for (unsigned int i=1; idepth_bounds[i-1], + ExcMessage("The entries in the parameter 'Depth boundaries of zones' have " + "to be sorted in increasing order.")); + } + + output_interval = prm.get_double ("Time between graphical output"); + if (this->convert_output_to_years()) + output_interval *= year_in_seconds; + + if (output_interval > 0.0) + { + // since we increase the time indicating when to write the next graphical output + // every time we execute the depth average postprocessor, there is no good way to + // figure out when to write graphical output for the nonlinear iterations if we do + // not want to output every time step + AssertThrow(this->get_parameters().run_postprocessors_on_nonlinear_iterations == false, + ExcMessage("Postprocessing nonlinear iterations is only supported if every time " + "step is visualized, or in other words, if the 'Time between graphical " + "output' in the Depth average postprocessor is set to zero.")); + } + + std::vector output_variables = Utilities::split_string_list(prm.get("List of output variables")); + AssertThrow(Utilities::has_unique_entries(output_variables), + ExcMessage("The list of strings for the parameter " + "'Postprocess/Depth average/List of output variables' contains entries more than once. " + "This is not allowed. Please check your parameter file.")); + + bool output_all_variables = false; + if ( std::find( output_variables.begin(), output_variables.end(), "all") != output_variables.end()) + output_all_variables = true; + + // we have to parse the list in this order to match the output columns + { + if (output_all_variables || std::find( output_variables.begin(), output_variables.end(), "temperature") != output_variables.end() ) + variables.emplace_back("temperature"); + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "composition") != output_variables.end() ) + for (unsigned int c=0; cn_compositional_fields(); ++c) + variables.emplace_back(this->introspection().name_for_compositional_index(c)); + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "adiabatic temperature") != output_variables.end() ) + variables.emplace_back("adiabatic_temperature"); + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "adiabatic pressure") != output_variables.end() ) + variables.emplace_back("adiabatic_pressure"); + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "adiabatic density") != output_variables.end() ) + variables.emplace_back("adiabatic_density"); + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "adiabatic density derivative") != output_variables.end() ) + variables.emplace_back("adiabatic_density_derivative"); + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "velocity magnitude") != output_variables.end() ) + variables.emplace_back("velocity_magnitude"); + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "sinking velocity") != output_variables.end() ) + variables.emplace_back("sinking_velocity"); + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "rising velocity") != output_variables.end() ) + variables.emplace_back("rising_velocity"); + + // handle seismic velocities, because they may, or may not be provided by the material model + { + MaterialModel::MaterialModelOutputs out(1, this->n_compositional_fields()); + this->get_material_model().create_additional_named_outputs(out); + + const bool material_model_provides_seismic_output = + (out.template get_additional_output>() != nullptr); + + const bool output_vs = std::find( output_variables.begin(), output_variables.end(), "Vs") != output_variables.end(); + const bool output_vp = std::find( output_variables.begin(), output_variables.end(), "Vp") != output_variables.end(); + + if (output_vs || output_vp) + AssertThrow(material_model_provides_seismic_output, + ExcMessage("You requested seismic velocities from the 'Depth average' postprocessor, " + "but the material model does not provide seismic velocities. Either remove 'Vs' and " + "'Vp' from the 'List of output variables' parameter, or use a material model that " + "provides these velocities.")); + + if (output_all_variables && material_model_provides_seismic_output) + { + variables.emplace_back("Vs"); + variables.emplace_back("Vp"); + } + + if (output_vs) + variables.emplace_back("Vs"); + + if (output_vp) + variables.emplace_back("Vp"); + } + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "viscosity") != output_variables.end() ) + variables.emplace_back("viscosity"); + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "log viscosity") != output_variables.end() ) + variables.emplace_back("log_viscosity"); + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "vertical heat flux") != output_variables.end() ) + variables.emplace_back("vertical_heat_flux"); + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "vertical mass flux") != output_variables.end() ) + variables.emplace_back("vertical_mass_flux"); + + if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "composition mass") != output_variables.end() ) + for (unsigned int c=0; cn_compositional_fields(); ++c) + variables.emplace_back(this->introspection().name_for_compositional_index(c) + std::string("_mass")); + } + + output_formats = Utilities::split_string_list(prm.get("Output format")); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + template + void DepthAverage::serialize (Archive &ar, const unsigned int) + { + ar &last_output_time + & entries; + } + + + template + void + DepthAverage::save (std::map &status_strings) const + { + std::ostringstream os; + aspect::oarchive oa (os); + oa << (*this); + + status_strings["DepthAverage"] = os.str(); + } + + + template + void + DepthAverage::load (const std::map &status_strings) + { + // see if something was saved + if (status_strings.find("DepthAverage") != status_strings.end()) + { + std::istringstream is (status_strings.find("DepthAverage")->second); + aspect::iarchive ia (is); + ia >> (*this); + } + } + + + template + void + DepthAverage::set_last_output_time (const double current_time) + { + // if output_interval is positive, then set the next output interval to + // a positive multiple. + if (output_interval > 0) + { + // We need to find the last time output was supposed to be written. + // this is the last_output_time plus the largest positive multiple + // of output_intervals that passed since then. We need to handle the + // edge case where last_output_time+output_interval==current_time, + // we did an output and std::floor sadly rounds to zero. This is done + // by forcing std::floor to round 1.0-eps to 1.0. + const double magic = 1.0+2.0*std::numeric_limits::epsilon(); + last_output_time = last_output_time + std::floor((current_time-last_output_time)/output_interval*magic) * output_interval/magic; + } + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(DepthAverage, + "depth average", + "A postprocessor that computes depth averaged " + "quantities and writes them into a file " + "in the output directory, where the extension of the file " + "is determined by the output format you select. In addition " + "to the output format, a number of other parameters also influence " + "this postprocessor, and they can be set in the section " + "\\texttt{Postprocess/Depth average} in the input file." + "\n\n" + "In the output files, the $x$-value of each data point corresponds " + "to the depth, whereas the $y$-value corresponds to the " + "simulation time. The time is provided in seconds or, if the " + "global ``Use years in output instead of seconds'' parameter is " + "set, in years.") + } +} diff --git a/source/postprocess/domain_volume_statistics.cc.bak b/source/postprocess/domain_volume_statistics.cc.bak new file mode 100644 index 00000000000..c6220190fd3 --- /dev/null +++ b/source/postprocess/domain_volume_statistics.cc.bak @@ -0,0 +1,69 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + DomainVolume::execute (TableHandler &statistics) + { + // Retrieve the current domain volume + const double global_volume = this->get_volume(); + + // add the volume to the statistics object + const std::string unit = (dim == 2) ? "m^2" : "m^3"; + const std::string name = "Model domain volume (" + unit + ")"; + statistics.add_value (name, global_volume); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name, 8); + statistics.set_scientific (name, true); + + // create a single string to output to the screen + std::ostringstream screen_text; + screen_text.precision(4); + screen_text << global_volume << " " << unit; + + return std::pair ("Model domain volume:", + screen_text.str()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(DomainVolume, + "domain volume statistics", + "A postprocessor that computes the total area (in 2d) " + "or volume (in 3d) of the computational domain. ") + } +} diff --git a/source/postprocess/dynamic_topography.cc.bak b/source/postprocess/dynamic_topography.cc.bak new file mode 100644 index 00000000000..8751c8f9463 --- /dev/null +++ b/source/postprocess/dynamic_topography.cc.bak @@ -0,0 +1,548 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include + +#include + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + DynamicTopography::execute (TableHandler &) + { + const Postprocess::BoundaryPressures &boundary_pressures = + this->get_postprocess_manager().template get_matching_postprocessor>(); + + // Get the average pressure at the top and bottom boundaries. + // This will be used to compute the dynamic pressure at the boundaries. + const double surface_pressure = boundary_pressures.pressure_at_top(); + const double bottom_pressure = boundary_pressures.pressure_at_bottom(); + + const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + const types::boundary_id bottom_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); + + // If the gravity vector is pointed *up*, as determined by representative points + // at the surface and at depth, then we are running backwards advection, and need + // to reverse the dynamic topography values. + const bool backward_advection = (this->get_gravity_model().gravity_vector(this->get_geometry_model().representative_point(0.)) * + (this->get_geometry_model().representative_point(0.) - + this->get_geometry_model().representative_point(this->get_geometry_model().maximal_depth()))) >= 0.; + + const unsigned int quadrature_degree = this->get_fe().base_element(this->introspection().base_elements.velocities).degree+1; + // Gauss quadrature in the interior for best accuracy. + const QGauss quadrature_formula(quadrature_degree); + // GLL quadrature on the surface to get a diagonal mass matrix. + const QGaussLobatto quadrature_formula_face(quadrature_degree); + + const unsigned int dofs_per_cell = this->get_fe().dofs_per_cell; + const unsigned int dofs_per_face = this->get_fe().dofs_per_face; + const unsigned int n_q_points = quadrature_formula.size(); + const unsigned int n_face_q_points = quadrature_formula_face.size(); + + // The CBF method involves both boundary and volume integrals on the + // cells at the boundary. Construct FEValues objects for each of these integrations. + FEValues fe_volume_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_gradients | + update_quadrature_points | + update_JxW_values); + + FEFaceValues fe_face_values (this->get_mapping(), + this->get_fe(), + quadrature_formula_face, + update_JxW_values | + update_values | + update_gradients | + update_quadrature_points); + + // Storage for shape function values for the current solution. + // Used for constructing the known side of the CBF system. + std::vector> phi_u (dofs_per_cell); + std::vector> epsilon_phi_u (dofs_per_cell); + std::vector div_phi_u (dofs_per_cell); + std::vector div_solution(n_q_points); + + // Vectors for solving CBF system. + Vector local_vector(dofs_per_cell); + Vector local_mass_matrix(dofs_per_cell); + + LinearAlgebra::BlockVector rhs_vector(this->introspection().index_sets.system_partitioning, this->get_mpi_communicator()); + // The mass matrix may be stored in a vector as it is a + // diagonal matrix. + LinearAlgebra::BlockVector mass_matrix(this->introspection().index_sets.system_partitioning, this->get_mpi_communicator()); + + LinearAlgebra::BlockVector distributed_topo_vector(this->introspection().index_sets.system_partitioning, this->get_mpi_communicator()); + + topo_vector.reinit(this->introspection().index_sets.system_partitioning, + this->introspection().index_sets.system_relevant_partitioning, + this->get_mpi_communicator()); + distributed_topo_vector = 0.; + topo_vector = 0.; + + // Possibly keep track of the dynamic topography values for + // later surface output. + std::vector, double>> stored_values_surface; + std::vector, double>> stored_values_bottom; + visualization_values.reinit(this->get_triangulation().n_active_cells()); + visualization_values = 0.; + + // Loop over all of the surface cells and if one less than h/3 away from + // one of the top or bottom boundaries, assemble CBF system for it. + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + { + // see if the cell is at the *top* or *bottom* boundary, not just any boundary + unsigned int face_idx = numbers::invalid_unsigned_int; + for (const unsigned int f : cell->face_indices()) + { + if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) + { + // If the cell is at the top boundary, assign face_idx. + face_idx = f; + break; + } + else if (cell->at_boundary(f) && cell->face(f)->boundary_id() == bottom_boundary_id) + { + // If the cell is at the bottom boundary, assign face_idx. + face_idx = f; + break; + } + } + // If the cell is not at the boundary, jump to the next cell. + if (face_idx == numbers::invalid_unsigned_int) + continue; + + fe_volume_values.reinit (cell); + fe_face_values.reinit (cell, face_idx); + + local_vector = 0.; + local_mass_matrix = 0.; + + // Evaluate the material model in the cell volume. + MaterialModel::MaterialModelInputs in_volume(fe_volume_values, cell, this->introspection(), this->get_solution()); + MaterialModel::MaterialModelOutputs out_volume(fe_volume_values.n_quadrature_points, this->n_compositional_fields()); + in_volume.requested_properties = MaterialModel::MaterialProperties::density | MaterialModel::MaterialProperties::viscosity; + this->get_material_model().evaluate(in_volume, out_volume); + + // Get solution values for the divergence of the velocity, which is not + // computed by the material model. + fe_volume_values[this->introspection().extractors.velocities].get_function_divergences (this->get_solution(), div_solution); + + for (unsigned int q=0; qget_material_model().is_compressible(); + const Tensor<1,dim> gravity = this->get_gravity_model().gravity_vector(in_volume.position[q]); + + // Set up shape function values + for (unsigned int k=0; kintrospection().extractors.velocities].value(k,q); + epsilon_phi_u[k] = fe_volume_values[this->introspection().extractors.velocities].symmetric_gradient(k,q); + div_phi_u[k] = fe_volume_values[this->introspection().extractors.velocities].divergence (k, q); + } + + for (unsigned int i = 0; iintrospection().extractors.velocities].value(i,q) * + fe_face_values[this->introspection().extractors.velocities].value(i,q) * + fe_face_values.JxW(q); + + cell->distribute_local_to_global(local_vector, rhs_vector); + cell->distribute_local_to_global(local_mass_matrix, mass_matrix); + } + + rhs_vector.compress(VectorOperation::add); + mass_matrix.compress(VectorOperation::add); + + // Since the mass matrix is diagonal, we can just solve for the stress vector by dividing. + const IndexSet local_elements = mass_matrix.locally_owned_elements(); + for (unsigned int k=0; k 1.e-15) + distributed_topo_vector[global_index] = rhs_vector[global_index]/mass_matrix[global_index]; + } + distributed_topo_vector.compress(VectorOperation::insert); + topo_vector = distributed_topo_vector; + + // Now loop over the cells again and solve for the dynamic topography. + // We solve for it on the support points of the system, since it can be + // directly put into a system vector of the right size. + std::vector> face_support_points = this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_face_support_points(); + Quadrature support_quadrature(face_support_points); + FEFaceValues fe_support_values (this->get_mapping(), + this->get_fe(), + support_quadrature, + update_values | update_normal_vectors + | update_gradients | update_quadrature_points); + + std::vector> stress_support_values( support_quadrature.size() ); + std::vector topo_values( support_quadrature.size() ); + std::vector face_dof_indices (dofs_per_face); + + // Also construct data structures for getting the dynamic topography at the cell face + // midpoints. This is a more practical thing for text output and visualization. + const QGauss output_quadrature(quadrature_degree); + FEFaceValues fe_output_values (this->get_mapping(), + this->get_fe(), + output_quadrature, + update_values | update_normal_vectors | update_gradients | + update_quadrature_points | update_JxW_values); + std::vector> stress_output_values( output_quadrature.size() ); + + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + { + // see if the cell is at the *top* boundary, not just any boundary + unsigned int face_idx = numbers::invalid_unsigned_int; + // if the face is at the upper surface 'at_upper_surface' will be true, if + // it is at the lower surface 'at_upper_surface' will be false. The default + // is true and will be changed to false if it's at the lower boundary. If the + // cell is at neither boundary the loop will continue to the next cell. + bool at_upper_surface = true; + for (const unsigned int f : cell->face_indices()) + { + if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) + { + // If the cell is at the top boundary, assign face_idx. + face_idx = f; + at_upper_surface = true; + break; + } + else if (cell->at_boundary(f) && cell->face(f)->boundary_id() == bottom_boundary_id) + { + // If the cell is at the bottom boundary, assign face_idx. + face_idx = f; + at_upper_surface = false; + break; + } + } + // If the cell is not at the boundary, jump to the next cell. + if (face_idx == numbers::invalid_unsigned_int) + continue; + + fe_support_values.reinit (cell, face_idx); + + // Evaluate the material model on the cell face. + MaterialModel::MaterialModelInputs in_support(fe_support_values, cell, this->introspection(), this->get_solution()); + MaterialModel::MaterialModelOutputs out_support(fe_support_values.n_quadrature_points, this->n_compositional_fields()); + in_support.requested_properties = MaterialModel::MaterialProperties::density; + this->get_material_model().evaluate(in_support, out_support); + + fe_support_values[this->introspection().extractors.velocities].get_function_values(topo_vector, stress_support_values); + cell->face(face_idx)->get_dof_indices (face_dof_indices); + for (unsigned int i = 0; i < face_dof_indices.size(); ++i) + { + // Given the face dof, we get the component and overall cell dof index. + const std::pair component_index = this->get_fe().face_system_to_component_index(i); + const unsigned int component = component_index.first; + const unsigned int support_index = component_index.second; + // Dynamic topography is stored in the temperature component. + if (component == this->introspection().component_indices.temperature) + { + // Compute the local gravity at the support point. + const Point point = fe_support_values.quadrature_point(support_index); + const double gravity_norm = this->get_gravity_model().gravity_vector(point).norm(); + const Tensor<1,dim> normal = fe_support_values.normal_vector(support_index); + + // Compute the dynamic topography, formulae are slightly different + // for upper and lower boundaries. + double dynamic_topography; + if (at_upper_surface) + { + const double delta_rho = out_support.densities[support_index] - density_above; + AssertThrow(std::abs(delta_rho) > std::numeric_limits::min(), + ExcMessage("delta_rho is close or equal to zero at the surface.")); + dynamic_topography = (-stress_support_values[support_index]*normal - surface_pressure) + / delta_rho / gravity_norm; + } + else + { + const double delta_rho = out_support.densities[support_index] - density_below; + AssertThrow(std::abs(delta_rho) > std::numeric_limits::min(), + ExcMessage("delta_rho is close or equal to zero at the bottom.")); + dynamic_topography = (-stress_support_values[support_index]*normal - bottom_pressure) + / delta_rho / gravity_norm; + } + distributed_topo_vector[face_dof_indices[i]] = dynamic_topography * (backward_advection ? -1. : 1.); + } + } + + // Also evaluate the dynamic topography on the cell faces. This is more convenient + // for ASCII output, as well as for use with the visualization postprocessor. + fe_output_values.reinit(cell, face_idx); + + // Evaluate the material model on the cell face. + MaterialModel::MaterialModelInputs in_output(fe_output_values, cell, this->introspection(), this->get_solution()); + MaterialModel::MaterialModelOutputs out_output(fe_output_values.n_quadrature_points, this->n_compositional_fields()); + in_output.requested_properties = MaterialModel::MaterialProperties::density; + this->get_material_model().evaluate(in_output, out_output); + + fe_output_values[this->introspection().extractors.velocities].get_function_values(topo_vector, stress_output_values); + + // Compute the average dynamic topography at the cell face. + double face_area = 0.; + double dynamic_topography = 0.; + for (unsigned int q=0; q < output_quadrature.size(); ++q) + { + const Point point = fe_output_values.quadrature_point(q); + const Tensor<1,dim> normal = fe_output_values.normal_vector(q); + const double gravity_norm = this->get_gravity_model().gravity_vector(point).norm(); + + if (at_upper_surface) + { + const double delta_rho = out_output.densities[q] - density_above; + dynamic_topography += (-stress_output_values[q]*normal - surface_pressure) + / delta_rho / gravity_norm * fe_output_values.JxW(q); + } + else + { + const double delta_rho = out_output.densities[q] - density_below; + + dynamic_topography += (-stress_output_values[q]*normal - bottom_pressure) + / delta_rho / gravity_norm * fe_output_values.JxW(q); + } + face_area += fe_output_values.JxW(q); + } + // Get the average dynamic topography for the cell + dynamic_topography = dynamic_topography * (backward_advection ? -1. : 1.) / face_area; + + // Maybe keep track of surface output vector. + const bool respect_manifold = true; + if (output_surface && at_upper_surface) + stored_values_surface.push_back(std::make_pair(cell->face(face_idx)->center(respect_manifold), dynamic_topography)); + // Maybe keep track of bottom output vector. + if (output_bottom && !at_upper_surface) + stored_values_bottom.push_back(std::make_pair(cell->face(face_idx)->center(respect_manifold), dynamic_topography)); + + // Add the value to the vector for the visualization postprocessor. + visualization_values(cell->active_cell_index()) = dynamic_topography; + } + distributed_topo_vector.compress(VectorOperation::insert); + topo_vector = distributed_topo_vector; + + // Possibly output the result to file. + if (output_surface) + output_to_file(top_boundary_id, stored_values_surface); + if (output_bottom) + output_to_file(bottom_boundary_id, stored_values_bottom); + + return std::pair("Computing dynamic topography", ""); + } + + /** + * Return the topography vector as calculated by CBF formulation + */ + template + const LinearAlgebra::BlockVector & + DynamicTopography:: + topography_vector() const + { + return topo_vector; + } + + /** + * Return the cellwise topography vector as calculated by CBF formulation + */ + template + const Vector & + DynamicTopography:: + cellwise_topography() const + { + return visualization_values; + } + + /** + * Register the other postprocessor that we need: BoundaryPressures + */ + template + std::list + DynamicTopography::required_other_postprocessors() const + { + return {"boundary pressures"}; + } + + + /** + * Output the dynamic topography solution to + * a file. + */ + template + void + DynamicTopography::output_to_file(const types::boundary_id boundary_id, + const std::vector,double>> &position_and_topography) + { + // get boundary name and avoid spaces for file output + std::string boundary_name = this->get_geometry_model().translate_id_to_symbol_name(boundary_id); + std::replace(boundary_name.begin(), boundary_name.end(), ' ', '_'); + + std::ostringstream output; + + // On processor 0, write header lines + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + output << "# " + << ((dim==2)? "x y " : "x y z ") + << "dynamic_topography_" << boundary_name << std::endl; + } + + for (unsigned int i = 0; i < position_and_topography.size(); ++i) + { + output << std::setprecision(10) + << position_and_topography[i].first + << ' ' + << std::setprecision(10) + << position_and_topography[i].second + << std::endl; + } + + std::string filename = this->get_output_directory() + + "dynamic_topography_" + boundary_name + "." + + Utilities::int_to_string(this->get_timestep_number(), 5); + if (this->get_parameters().run_postprocessors_on_nonlinear_iterations) + filename.append("." + Utilities::int_to_string (this->get_nonlinear_iteration(), 4)); + + Utilities::collect_and_write_file_content(filename, output.str(), this->get_mpi_communicator()); + } + + + /** + * Declare the parameters for the postprocessor. + */ + template + void + DynamicTopography:: + declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Dynamic topography"); + { + prm.declare_entry ("Density above","0.", + Patterns::Double (0.), + "Dynamic topography is calculated as the excess or lack of mass that is supported by mantle flow. " + "This value depends on the density of material that is moved up or down, i.e. crustal rock, and the " + "density of the material that is displaced (generally water or air). While the density of crustal rock " + "is part of the material model, this parameter `Density above' allows the user to specify the density " + "value of material that is displaced above the solid surface. By default this material is assumed to " + "be air, with a density of 0. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Density below","9900.", + Patterns::Double (0.), + "Dynamic topography is calculated as the excess or lack of mass that is supported by mantle flow. " + "This value depends on the density of material that is moved up or down, i.e. mantle above CMB, and the " + "density of the material that is displaced (generally outer core material). While the density of mantle rock " + "is part of the material model, this parameter `Density below' allows the user to specify the density " + "value of material that is displaced below the solid surface. By default this material is assumed to " + "be outer core material with a density of 9900. " + "Units: \\si{\\kilogram\\per\\meter\\cubed}."); + prm.declare_entry ("Output surface", "true", + Patterns::Bool(), + "Whether to output a file containing the surface dynamic topography."); + prm.declare_entry ("Output bottom", "true", + Patterns::Bool(), + "Whether to output a file containing the bottom (i.e., CMB) dynamic topography."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + /** + * Declare the parameters for the postprocessor. + */ + template + void + DynamicTopography::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Dynamic topography"); + { + density_above = prm.get_double ("Density above"); + density_below = prm.get_double ("Density below"); + output_surface = prm.get_bool ("Output surface"); + output_bottom = prm.get_bool ("Output bottom"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(DynamicTopography, + "dynamic topography", + "A postprocessor that computes a measure of dynamic topography " + "based on the stress at the boundary. The data is written into text " + "files named `dynamic\\_topography_\\X.NNNNN' in the output directory, " + "where X is the name of the boundary and NNNNN is the number of the time step." + "\n\n" + "The exact approach works as follows: At each selected boundary, we compute " + "the traction that acts normal to the boundary faces using the " + "consistent boundary flux method as described in " + "``Gresho, Lee, Sani, Maslanik, Eaton (1987). " + "The consistent Galerkin FEM for computing derived boundary " + "quantities in thermal and or fluids problems. International " + "Journal for Numerical Methods in Fluids, 7(4), 371-394.'' " + "From this traction, the dynamic topography is computed using the formula " + "$h=\\frac{\\sigma_{n}}{g \\rho}$ where $g$ is the norm of the gravity and $\\rho$ " + "is the density. For the bottom surface we chose the convention " + "that positive values are up and negative values are down, analogous to " + "the deformation of the upper surface. Note that this implementation takes " + "the direction of gravity into account, which means that reversing the flow " + "in backward advection calculations will not reverse the instantaneous topography " + "because the reverse flow will be divided by the reverse surface gravity. " + "\n" + "The file format then consists of lines with Euclidean coordinates " + "followed by the corresponding topography value.") + } +} diff --git a/source/postprocess/entropy_viscosity_statistics.cc.bak b/source/postprocess/entropy_viscosity_statistics.cc.bak new file mode 100644 index 00000000000..0df4a943994 --- /dev/null +++ b/source/postprocess/entropy_viscosity_statistics.cc.bak @@ -0,0 +1,118 @@ +/* + Copyright (C) 2019 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + EntropyViscosityStatistics::execute (TableHandler &statistics) + { + Vector entropy_viscosity(this->get_triangulation().n_active_cells()); + this->get_artificial_viscosity(entropy_viscosity); + + // The entropy viscosity is cell-wise constant, so a simple midpoint quadrature + // will be sufficient to integrate the value over cells. + const QMidpoint quadrature_formula; + const unsigned int n_q_points = quadrature_formula.size(); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_JxW_values); + + double local_maximum_viscosity = 0.0; + double local_integrated_viscosity = 0.0; + double local_volume = 0.0; + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + + for (unsigned int q = 0; q < n_q_points; ++q) + { + const double entropy_viscosity_cell = entropy_viscosity[cell->active_cell_index()]; + local_maximum_viscosity = std::max(local_maximum_viscosity,entropy_viscosity_cell); + local_volume += fe_values.JxW(q); + local_integrated_viscosity += entropy_viscosity_cell * fe_values.JxW(q); + } + } + + const double global_integrated_viscosity + = Utilities::MPI::sum (local_integrated_viscosity, this->get_mpi_communicator()); + const double global_integrated_volume + = Utilities::MPI::sum (local_volume, this->get_mpi_communicator()); + const double global_maximum_viscosity + = Utilities::MPI::max (local_maximum_viscosity, this->get_mpi_communicator()); + + const double average_viscosity = global_integrated_viscosity / global_integrated_volume; + + statistics.add_value ("Max entropy viscosity (W/(m*K))", + global_maximum_viscosity); + statistics.add_value ("Average entropy viscosity (W/(m*K))", + average_viscosity); + + // also make sure that the columns filled by this plugin + // show up with sufficient accuracy and in scientific notation + const char *columns[] = { "Max entropy viscosity (W/(m*K))", + "Average entropy viscosity (W/(m*K))" + }; + for (auto &column : columns) + { + statistics.set_precision (column, 8); + statistics.set_scientific (column, true); + } + + std::ostringstream output; + output.precision(3); + output << global_maximum_viscosity + << " W/(m*K), " + << average_viscosity + << " W/(m*K)"; + + + return std::pair ("Max / average entropy viscosity:", + output.str()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(EntropyViscosityStatistics, + "entropy viscosity statistics", + "A postprocessor that computes the maximum and volume averaged" + "entropy viscosity stabilization for the temperature field.") + } +} diff --git a/source/postprocess/geoid.cc.bak b/source/postprocess/geoid.cc.bak new file mode 100644 index 00000000000..96789262ce4 --- /dev/null +++ b/source/postprocess/geoid.cc.bak @@ -0,0 +1,1060 @@ +/* + Copyright (C) 2015 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair,std::vector> + Geoid::to_spherical_harmonic_coefficients(const std::vector> &spherical_function) const + { + std::vector cosi(spherical_function.size(),0); + std::vector sini(spherical_function.size(),0); + std::vector coecos; + std::vector coesin; + + for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) + { + for (unsigned int iord = 0; iord < ideg+1; ++iord) + { + // Do the spherical harmonic expansion. + for (unsigned int ds_num = 0; ds_num < spherical_function.size(); ++ds_num) + { + // Normalization after Dahlen and Tromp (1986) Appendix B.6. + const std::pair sph_harm_vals = aspect::Utilities::real_spherical_harmonic(ideg,iord,spherical_function.at(ds_num).at(0),spherical_function.at(ds_num).at(1)); + const double cos_component = sph_harm_vals.first; // real / cos part + const double sin_component = sph_harm_vals.second; // imaginary / sin part + + cosi.at(ds_num) = (spherical_function.at(ds_num).at(3) * cos_component); + sini.at(ds_num) = (spherical_function.at(ds_num).at(3) * sin_component); + } + // Integrate the contribution of each spherical infinitesimal. + double cosii = 0; + double sinii = 0; + for (unsigned int ds_num = 0; ds_num < spherical_function.size(); ++ds_num) + { + cosii += cosi.at(ds_num) * spherical_function.at(ds_num).at(2); + sinii += sini.at(ds_num) * spherical_function.at(ds_num).at(2); + } + coecos.push_back(cosii); + coesin.push_back(sinii); + } + } + // Sum over each processor. + dealii::Utilities::MPI::sum (coecos,this->get_mpi_communicator(),coecos); + dealii::Utilities::MPI::sum (coesin,this->get_mpi_communicator(),coesin); + + return std::make_pair(coecos,coesin); + } + + template + std::pair,std::vector> + Geoid::density_contribution (const double &/*outer_radius*/) const + { + Assert(false, ExcNotImplemented()); + return std::make_pair(std::vector(), std::vector()); + + } + + template <> + std::pair,std::vector> + Geoid<3>::density_contribution (const double &outer_radius) const + { + const unsigned int quadrature_degree = this->introspection().polynomial_degree.temperature; + + // Need to evaluate density contribution of each volume quadrature point. + const QGauss<3> quadrature_formula(quadrature_degree); + + FEValues<3> fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_quadrature_points | + update_JxW_values | + update_gradients); + + MaterialModel::MaterialModelInputs<3> in(fe_values.n_quadrature_points, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs<3> out(fe_values.n_quadrature_points, this->n_compositional_fields()); + in.requested_properties = MaterialModel::MaterialProperties::density; + + std::vector> + composition_values(this->n_compositional_fields(), std::vector(quadrature_formula.size())); + + // Directly do the global 3d integral over each quadrature point of every cell (different from traditional way to do layer integral). + // This is necessary because of ASPECT's adaptive mesh refinement feature. + std::vector SH_density_coecos; + std::vector SH_density_coesin; + for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) + { + for (unsigned int iord = 0; iord < ideg+1; ++iord) + { + // Initialization of the density contribution integral per degree, order. + double integrated_density_cos_component = 0; + double integrated_density_sin_component = 0; + + // Loop over all of the cells. + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + // Set use_strain_rates to false since we don't need viscosity. + in.reinit(fe_values, cell, this->introspection(), this->get_solution()); + + this->get_material_model().evaluate(in, out); + + // Compute the integral of the density function + // over the cell, by looping over all quadrature points. + for (unsigned int q=0; q scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(in.position[q]); + + // Normalization after Dahlen and Tromp (1986) Appendix B.6. + const std::pair sph_harm_vals = aspect::Utilities::real_spherical_harmonic(ideg,iord,scoord[2],scoord[1]); + const double cos_component = sph_harm_vals.first; // real / cos part + const double sin_component = sph_harm_vals.second; // imaginary / sin part + + const double density = out.densities[q]; + const double r_q = in.position[q].norm(); + + integrated_density_cos_component += density * (1./r_q) * std::pow(r_q/outer_radius,ideg+1) * cos_component * fe_values.JxW(q); + integrated_density_sin_component += density * (1./r_q) * std::pow(r_q/outer_radius,ideg+1) * sin_component * fe_values.JxW(q); + } + } + SH_density_coecos.push_back(integrated_density_cos_component); + SH_density_coesin.push_back(integrated_density_sin_component); + } + } + // Sum over each processor. + dealii::Utilities::MPI::sum (SH_density_coecos,this->get_mpi_communicator(),SH_density_coecos); + dealii::Utilities::MPI::sum (SH_density_coesin,this->get_mpi_communicator(),SH_density_coesin); + + return std::make_pair(SH_density_coecos,SH_density_coesin); + } + + template + std::pair,std::vector>>, std::pair,std::vector>>> + Geoid::topography_contribution(const double &/*outer_radius*/, + const double &/*inner_radius*/) const + { + Assert(false, ExcNotImplemented()); + std::pair,std::vector>> temp; + return std::make_pair(temp, temp); + } + + template <> + std::pair,std::vector>>, std::pair,std::vector>>> + Geoid<3>::topography_contribution(const double &outer_radius, + const double &inner_radius) const + { + // Get a pointer to the boundary densities postprocessor. + const Postprocess::BoundaryDensities<3> &boundary_densities = + this->get_postprocess_manager().template get_matching_postprocessor>(); + + const double top_layer_average_density = boundary_densities.density_at_top(); + const double bottom_layer_average_density = boundary_densities.density_at_bottom(); + + const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + const types::boundary_id bottom_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); + + const unsigned int quadrature_degree = this->introspection().polynomial_degree.temperature; + const QGauss<2> quadrature_formula_face(quadrature_degree); + + FEFaceValues<3> fe_face_values (this->get_mapping(), + this->get_fe(), + quadrature_formula_face, + update_values | + update_quadrature_points | + update_JxW_values); + + // Vectors to store the location, infinitesimal area, and topography associated with each quadrature point of each surface and bottom cell respectively. + std::vector,std::pair>> surface_stored_values; + std::vector,std::pair>> CMB_stored_values; + + // Loop over all of the boundary cells and if one is at + // surface or CMB, evaluate the topography vector there. + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + { + unsigned int face_idx = numbers::invalid_unsigned_int; + bool at_upper_surface = false; + { + for (const unsigned int f : cell->face_indices()) + { + if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) + { + // If the cell is at the top boundary, assign face_idx. + face_idx = f; + at_upper_surface = true; + break; + } + else if (cell->at_boundary(f) && cell->face(f)->boundary_id() == bottom_boundary_id) + { + // If the cell is at the bottom boundary, assign face_idx. + face_idx = f; + at_upper_surface = false; + break; + } + } + // If the cell is not at the boundary, jump to the next cell. + if (face_idx == numbers::invalid_unsigned_int) + continue; + } + + // Focus on the boundary cell's upper face if on the top boundary and lower face if on the bottom boundary. + fe_face_values.reinit(cell, face_idx); + + // Topography is evaluated at each quadrature + // point on every top/bottom cell's boundary face. The + // reason to do this -- as opposed to using a single + // value per boundary face -- is that later in the + // spherical harmonic expansion, we will calculate + // sin(theta)*d_theta*d_phi by + // infinitesimal_area/radius^2. The accuracy of this + // transfer gets better as infinitesimal_area gets + // closer to zero, so using every boundary quadrature + // point's associated area (in the form of + // FEFaceValues::JxW) will lead to better accuracy in + // spherical harmonic expansion compared to using just + // one average value per face, especially in the coarse + // meshes. + + // If the cell is at the top boundary, add its contributions to the topography surface storage vector. + if (at_upper_surface) + { + if (include_surface_topo_contribution == true) + { + if (use_free_surface_topography == true) + { + for (unsigned int q=0; q current_position = fe_face_values.quadrature_point(q); + const double topography = this->get_geometry_model().height_above_reference_surface(current_position); + surface_stored_values.emplace_back (current_position, std::make_pair(fe_face_values.JxW(q), topography)); + } + } + else + { + // Get a reference to the dynamic topography postprocessor. + const Postprocess::DynamicTopography<3> &dynamic_topography = + this->get_postprocess_manager().template get_matching_postprocessor>(); + + // Get the already-computed dynamic topography solution. + const LinearAlgebra::BlockVector &topo_vector = dynamic_topography.topography_vector(); + + std::vector topo_values(quadrature_formula_face.size()); + + fe_face_values[this->introspection().extractors.temperature].get_function_values(topo_vector, topo_values); + + for (unsigned int q=0; q current_position = fe_face_values.quadrature_point(q); + const double topography = this->get_geometry_model().height_above_reference_surface(current_position) + (outer_radius - inner_radius); + CMB_stored_values.emplace_back (current_position, std::make_pair(fe_face_values.JxW(q), topography)); + } + } + else + { + // Get a reference to the dynamic topography postprocessor. + const Postprocess::DynamicTopography<3> &dynamic_topography = + this->get_postprocess_manager().template get_matching_postprocessor>(); + + // Get the already-computed dynamic topography solution. + const LinearAlgebra::BlockVector &topo_vector = dynamic_topography.topography_vector(); + + std::vector topo_values(quadrature_formula_face.size()); + + fe_face_values[this->introspection().extractors.temperature].get_function_values(topo_vector, topo_values); + + for (unsigned int q=0; q> surface_topo_spherical_function; + std::vector> CMB_topo_spherical_function; + + for (const auto &surface_stored_value : surface_stored_values) + { + const std::array scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(surface_stored_value.first); + + // Calculate spherical infinitesimal sin(theta)*d_theta*d_phi by infinitesimal_area/radius^2 + const double infinitesimal = surface_stored_value.second.first/(outer_radius*outer_radius); + + // Theta, phi, spherical infinitesimal, and surface topography + surface_topo_spherical_function.emplace_back(std::vector {scoord[2], + scoord[1], + infinitesimal, + surface_stored_value.second.second + }); + } + + for (const auto &CMB_stored_value : CMB_stored_values) + { + const std::array scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(CMB_stored_value.first); + + // Calculate spherical infinitesimal sin(theta)*d_theta*d_phi by infinitesimal_area/radius^2 + const double infinitesimal = CMB_stored_value.second.first/(inner_radius*inner_radius); + + // Theta, phi, spherical infinitesimal, and CMB dynamic topography + CMB_topo_spherical_function.emplace_back(std::vector {scoord[2], + scoord[1], + infinitesimal, + CMB_stored_value.second.second + }); + } + + std::pair,std::vector>> SH_surface_topo_coes + = std::make_pair(top_layer_average_density,to_spherical_harmonic_coefficients(surface_topo_spherical_function)); + std::pair,std::vector>> SH_CMB_topo_coes + = std::make_pair(bottom_layer_average_density,to_spherical_harmonic_coefficients(CMB_topo_spherical_function)); + return std::make_pair(SH_surface_topo_coes,SH_CMB_topo_coes); + } + + + template + std::pair + Geoid::execute (TableHandler &) + { + // Current geoid code only works for spherical shell geometry. + AssertThrow (Plugins::plugin_type_matches>(this->get_geometry_model()) + && + dim == 3, + ExcMessage("The geoid postprocessor is currently only implemented for the 3d spherical shell geometry model.")); + + const GeometryModel::SphericalShell &geometry_model = + Plugins::get_plugin_as_type> (this->get_geometry_model()); + + // Get the value of the outer radius and inner radius. + const double outer_radius = geometry_model.outer_radius(); + const double inner_radius = geometry_model.inner_radius(); + + const types::boundary_id top_boundary_id = geometry_model.translate_symbolic_boundary_name_to_id("top"); + + // Get the value of the surface gravity acceleration from the gravity model. + Point surface_point; + surface_point[0] = outer_radius; + const double surface_gravity = this->get_gravity_model().gravity_vector(surface_point).norm(); + + // Get the value of the universal gravitational constant. + const double G = aspect::constants::big_g; + + // Get the spherical harmonic coefficients of the density contribution. + std::pair,std::vector> SH_density_coes = density_contribution(outer_radius); + std::pair,std::vector>> SH_surface_topo_coes; + std::pair,std::vector>> SH_CMB_topo_coes; + + // Initialize the surface and CMB density contrasts with NaNs because they may be unused in case of no topography contribution. + double surface_delta_rho = numbers::signaling_nan(); + double CMB_delta_rho = numbers::signaling_nan(); + + // Get the spherical harmonic coefficients of the surface and CMB topography. + std::pair,std::vector>>, std::pair,std::vector>>> SH_topo_coes; + SH_topo_coes = topography_contribution(outer_radius,inner_radius); + SH_surface_topo_coes = SH_topo_coes.first; + SH_CMB_topo_coes = SH_topo_coes.second; + + // Get the density contrast at the surface and CMB to replace the initialized NaN values. + // The surface and CMB density contrasts will be used later to calculate geoid, + // and the spherical harmonic output of the surface and CMB topography contribution to geoid. + surface_delta_rho = SH_surface_topo_coes.first - density_above; + CMB_delta_rho = density_below - SH_CMB_topo_coes.first; + + // Compute the spherical harmonic coefficients of geoid anomaly. + std::vector density_anomaly_contribution_coecos; + std::vector density_anomaly_contribution_coesin; + std::vector surface_topo_contribution_coecos; + std::vector surface_topo_contribution_coesin; + std::vector CMB_topo_contribution_coecos; + std::vector CMB_topo_contribution_coesin; + geoid_coecos.clear(); + geoid_coesin.clear(); + + // First compute the spherical harmonic contributions from density anomaly, surface topography and CMB topography. + int ind = 0; // coefficients index + for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) + { + for (unsigned int iord = 0; iord < ideg+1; ++iord) + { + double coecos_density_anomaly = (4 * numbers::PI * G / (surface_gravity * (2 * ideg + 1))) * SH_density_coes.first.at(ind); + double coesin_density_anomaly = (4 * numbers::PI * G / (surface_gravity * (2 * ideg + 1))) * SH_density_coes.second.at(ind); + density_anomaly_contribution_coecos.push_back(coecos_density_anomaly); + density_anomaly_contribution_coesin.push_back(coesin_density_anomaly); + + if (include_surface_topo_contribution == true || include_CMB_topo_contribution == true) + { + const double coecos_surface_topo = (4 * numbers::PI * G / (surface_gravity * (2 * ideg + 1))) + * surface_delta_rho*SH_surface_topo_coes.second.first.at(ind)*outer_radius; + const double coesin_surface_topo = (4 * numbers::PI * G / (surface_gravity * (2 * ideg + 1))) + * surface_delta_rho*SH_surface_topo_coes.second.second.at(ind)*outer_radius; + surface_topo_contribution_coecos.push_back(coecos_surface_topo); + surface_topo_contribution_coesin.push_back(coesin_surface_topo); + + const double coecos_CMB_topo = (4 * numbers::PI * G / (surface_gravity * (2 * ideg + 1))) + * CMB_delta_rho*SH_CMB_topo_coes.second.first.at(ind)*inner_radius*std::pow(inner_radius/outer_radius,ideg+1); + const double coesin_CMB_topo = (4 * numbers::PI * G / (surface_gravity * (2 * ideg + 1))) + * CMB_delta_rho*SH_CMB_topo_coes.second.second.at(ind)*inner_radius*std::pow(inner_radius/outer_radius,ideg+1); + CMB_topo_contribution_coecos.push_back(coecos_CMB_topo); + CMB_topo_contribution_coesin.push_back(coesin_CMB_topo); + + } + + ++ind; + } + } + + // Then sum the three contributions together to get the spherical harmonic coefficients of geoid anomaly. + ind = 0; // coefficients index + for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) + { + for (unsigned int iord = 0; iord < ideg+1; ++iord) + { + if (include_surface_topo_contribution == true || include_CMB_topo_contribution == true) + { + geoid_coecos.push_back(density_anomaly_contribution_coecos.at(ind)+surface_topo_contribution_coecos.at(ind)+CMB_topo_contribution_coecos.at(ind)); + geoid_coesin.push_back(density_anomaly_contribution_coesin.at(ind)+surface_topo_contribution_coesin.at(ind)+CMB_topo_contribution_coesin.at(ind)); + } + else + { + geoid_coecos.push_back(density_anomaly_contribution_coecos.at(ind)); + geoid_coesin.push_back(density_anomaly_contribution_coesin.at(ind)); + } + + ind += 1; + } + } + + const QMidpoint quadrature_formula_face_center; + Assert(quadrature_formula_face_center.size() == 1, ExcInternalError()); + FEFaceValues fe_face_center_values (this->get_mapping(), + this->get_fe(), + quadrature_formula_face_center, + update_values | + update_quadrature_points| + update_JxW_values); + + // Define a vector to store the location of the cells along the surface. + std::vector> surface_cell_locations; + + // Loop over all the cells to get the locations of the surface cells to prepare for the geoid computation. + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + { + // If the cell is at the top boundary, store the cell's upper face midpoint location. + for (const unsigned int f : cell->face_indices()) + if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) + { + fe_face_center_values.reinit(cell,f); + const Point midpoint_at_top_face = fe_face_center_values.get_quadrature_points().at(0); + surface_cell_locations.push_back(midpoint_at_top_face); + break; + } + } + + // Transfer the geocentric coordinates of the surface cells to the surface spherical coordinates (theta,phi) + std::vector> surface_cell_spherical_coordinates; + for (unsigned int i=0; i scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(surface_cell_locations.at(i)); + const double phi = scoord[1]; + const double theta = scoord[2]; + surface_cell_spherical_coordinates.emplace_back(theta,phi); + } + + // Compute the grid geoid anomaly based on spherical harmonics. + std::vector geoid_anomaly; + for (const auto &surface_cell_spherical_coordinate : surface_cell_spherical_coordinates) + { + int ind = 0; + double geoid_value = 0; + for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) + { + for (unsigned int iord = 0; iord < ideg+1; ++iord) + { + // Normalization after Dahlen and Tromp (1986) Appendix B.6. + const std::pair sph_harm_vals = aspect::Utilities::real_spherical_harmonic(ideg,iord,surface_cell_spherical_coordinate.first,surface_cell_spherical_coordinate.second); + const double cos_component = sph_harm_vals.first; // real / cos part + const double sin_component = sph_harm_vals.second; // imaginary / sin part + + geoid_value += geoid_coecos.at(ind)*cos_component+geoid_coesin.at(ind)*sin_component; + ++ind; + } + } + geoid_anomaly.push_back(geoid_value); + } + + // The user can get the spherical harmonic coefficients of the density anomaly contribution if needed + if (output_density_anomaly_contribution_SH_coes == true) + { + // Have a stream into which we write the SH coefficients data from density anomaly contribution. + // The text stream is then later sent to processor 0. + std::ostringstream output_density_anomaly_contribution_SH_coes; + + // Prepare the output SH coefficients data from density anomaly contribution. + unsigned int SH_coes_ind = 0; + for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) + { + for (unsigned int iord = 0; iord < ideg+1; ++iord) + { + output_density_anomaly_contribution_SH_coes << ideg + << ' ' + << iord + << ' ' + << density_anomaly_contribution_coecos.at(SH_coes_ind) + << ' ' + << density_anomaly_contribution_coesin.at(SH_coes_ind) + << std::endl; + ++SH_coes_ind; + } + } + + const std::string density_anomaly_contribution_SH_coes_filename = this->get_output_directory() + + "density_anomaly_contribution_SH_coefficients." + + dealii::Utilities::int_to_string(this->get_timestep_number(), 5); + + // Because each processor already held all the SH coefficients from density anomaly contribution, we only need to stop by the processor 0 to get the data. + // On processor 0, collect all the data and put them into the output density anomaly contribution SH coefficients file. + if (dealii::Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + std::ofstream density_anomaly_contribution_SH_coes_file (density_anomaly_contribution_SH_coes_filename); + density_anomaly_contribution_SH_coes_file << "# " + << "degree order cosine_coefficient sine_coefficient" + << std::endl; + + // Write out the data on processor 0. + density_anomaly_contribution_SH_coes_file << output_density_anomaly_contribution_SH_coes.str(); + } + } + + // The user can get the spherical harmonic coefficients of the surface topography contribution if needed + if (output_surface_topo_contribution_SH_coes == true) + { + // Have a stream into which we write the SH coefficients data from surface topography contribution. + // The text stream is then later sent to processor 0. + std::ostringstream output_surface_topo_contribution_SH_coes; + + // Prepare the output SH coefficients data from surface topography contribution. + unsigned int SH_coes_ind = 0; + for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) + { + for (unsigned int iord = 0; iord < ideg+1; ++iord) + { + output_surface_topo_contribution_SH_coes << ideg + << ' ' + << iord + << ' ' + << surface_topo_contribution_coecos.at(SH_coes_ind) + << ' ' + << surface_topo_contribution_coesin.at(SH_coes_ind) + << std::endl; + ++SH_coes_ind; + } + } + + const std::string surface_topo_contribution_SH_coes_filename = this->get_output_directory() + + "surface_topography_contribution_SH_coefficients." + + dealii::Utilities::int_to_string(this->get_timestep_number(), 5); + + // Because each processor already held all the SH coefficients from surface topography contribution, + // we only need to stop by the processor 0 to get the data. On processor 0, collect all the data + // and put them into the output surface topography contribution SH coefficients file. + if (dealii::Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + std::ofstream surface_topo_contribution_SH_coes_file (surface_topo_contribution_SH_coes_filename); + surface_topo_contribution_SH_coes_file << "# " + << "degree order cosine_coefficient sine_coefficient" + << std::endl; + std::ostringstream output_surface_delta_rho; + output_surface_delta_rho << surface_delta_rho; + surface_topo_contribution_SH_coes_file << "surface density contrast(kg/m^3): " + << output_surface_delta_rho.str() + << std::endl; + // Write out the data on processor 0 + surface_topo_contribution_SH_coes_file << output_surface_topo_contribution_SH_coes.str(); + } + } + + // The user can get the spherical harmonic coefficients of the CMB topography contribution if needed. + if (output_CMB_topo_contribution_SH_coes == true) + { + // Have a stream into which we write the SH coefficients data from CMB topography contribution. + // The text stream is then later sent to processor 0. + std::ostringstream output_CMB_topo_contribution_SH_coes; + + // Prepare the output SH coefficients data from CMB topography contribution. + unsigned int SH_coes_ind = 0; + for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) + { + for (unsigned int iord = 0; iord < ideg+1; ++iord) + { + output_CMB_topo_contribution_SH_coes << ideg + << ' ' + << iord + << ' ' + << CMB_topo_contribution_coecos.at(SH_coes_ind) + << ' ' + << CMB_topo_contribution_coesin.at(SH_coes_ind) + << std::endl; + ++SH_coes_ind; + } + } + + const std::string CMB_topo_contribution_SH_coes_filename = this->get_output_directory() + + "CMB_topography_contribution_SH_coefficients." + + dealii::Utilities::int_to_string(this->get_timestep_number(), 5); + + // Because each processor already held all the SH coefficients from CMB topography contribution, we only need to stop by the processor 0 + // to get the data. On processor 0, collect all the data and put them into the output CMB topography contribution SH coefficients file. + if (dealii::Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + std::ofstream CMB_topo_contribution_SH_coes_file (CMB_topo_contribution_SH_coes_filename); + CMB_topo_contribution_SH_coes_file << "# " + << "degree order cosine_coefficient sine_coefficient" + << std::endl; + std::ostringstream output_CMB_delta_rho; + output_CMB_delta_rho << CMB_delta_rho; + CMB_topo_contribution_SH_coes_file << "CMB density contrast(kg/m^3): " + << output_CMB_delta_rho.str() + << std::endl; + // Write out the data on processor 0 + CMB_topo_contribution_SH_coes_file << output_CMB_topo_contribution_SH_coes.str(); + } + } + + // The user can get the spherical harmonic coefficients of the geoid anomaly if needed. + if (output_geoid_anomaly_SH_coes == true) + { + // Have a stream into which we write the geoid anomaly SH coefficients data. + // The text stream is then later sent to processor 0. + std::ostringstream output_geoid_anomaly_SH_coes; + + // Prepare the output geoid anomaly SH coefficients data. + unsigned int SH_coes_ind = 0; + for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) + { + for (unsigned int iord = 0; iord < ideg+1; ++iord) + { + output_geoid_anomaly_SH_coes << ideg + << ' ' + << iord + << ' ' + << geoid_coecos.at(SH_coes_ind) + << ' ' + << geoid_coesin.at(SH_coes_ind) + << std::endl; + ++SH_coes_ind; + } + } + + const std::string geoid_anomaly_SH_coes_filename = this->get_output_directory() + + "geoid_anomaly_SH_coefficients." + + dealii::Utilities::int_to_string(this->get_timestep_number(), 5); + + // Because each processor already held all the geoid anomaly SH coefficients, we only need to stop by the processor 0 to get the data. + // On processor 0, collect all the data and put them into the output geoid anomaly SH coefficients file. + if (dealii::Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + std::ofstream geoid_anomaly_SH_coes_file (geoid_anomaly_SH_coes_filename); + geoid_anomaly_SH_coes_file << "# " + << "degree order cosine_coefficient sine_coefficient" + << std::endl; + + // Write out the data on processor 0. + geoid_anomaly_SH_coes_file << output_geoid_anomaly_SH_coes.str(); + } + } + + // Have a stream into which we write the geoid height data. the text stream is then + // later sent to processor 0. + std::ostringstream output; + + // On processor 0, write the header lines + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + output << "# " + << ((output_in_lat_lon == true)? "longitude latitude" : "x y z") + << " geoid_anomaly" << std::endl; + } + + // Prepare the output data. + if (output_in_lat_lon == true) + { + double lon, lat; + for (unsigned int i=0; iget_output_directory() + + "geoid_anomaly." + + dealii::Utilities::int_to_string(this->get_timestep_number(), 5); + + Utilities::collect_and_write_file_content(filename, output.str(), this->get_mpi_communicator()); + + // Prepare the free-air gravity anomaly output. + if (output_gravity_anomaly == true) + { + // Have a stream into which we write the gravity anomaly data. the text stream is then + // later sent to processor 0. + std::ostringstream output_gravity_anomaly; + + // On processor 0, write the header lines: + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + output_gravity_anomaly << "# " + << ((output_in_lat_lon == true)? "longitude latitude" : "x y z") + << " gravity_anomaly" << std::endl; + } + + // Compute the grid gravity anomaly based on spherical harmonics. + std::vector gravity_anomaly; + gravity_anomaly.reserve(surface_cell_spherical_coordinates.size()); + + for (const auto &surface_cell_spherical_coordinate : surface_cell_spherical_coordinates) + { + int ind = 0; + double gravity_value = 0; + for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) + { + for (unsigned int iord = 0; iord < ideg+1; ++iord) + { + // Normalization after Dahlen and Tromp (1986) Appendix B.6. + const std::pair sph_harm_vals = aspect::Utilities::real_spherical_harmonic(ideg,iord,surface_cell_spherical_coordinate.first,surface_cell_spherical_coordinate.second); + const double cos_component = sph_harm_vals.first; // real / cos part + const double sin_component = sph_harm_vals.second; // imaginary / sin part + + // The conversion from geoid to gravity anomaly is given by gravity_anomaly = (l-1)*g/R_surface * geoid_anomaly + // based on Forte (2007) equation [97]. + gravity_value += (geoid_coecos.at(ind)*cos_component+geoid_coesin.at(ind)*sin_component) * (ideg - 1) * surface_gravity / outer_radius; + ++ind; + } + } + gravity_anomaly.push_back(gravity_value); + } + + // Prepare the output data. + if (output_in_lat_lon == true) + { + double lon, lat; + for (unsigned int i=0; iget_output_directory() + + "gravity_anomaly." + + dealii::Utilities::int_to_string(this->get_timestep_number(), 5); + + Utilities::collect_and_write_file_content(filename, output_gravity_anomaly.str(), this->get_mpi_communicator()); + } + + return std::pair("Writing geoid anomaly:", + filename); + } + + template + std::list + Geoid::required_other_postprocessors() const + { + std::list deps; + + if ( (include_surface_topo_contribution == true && use_free_surface_topography == false) || (include_CMB_topo_contribution == true && use_free_CMB_topography == false) ) + deps.emplace_back("dynamic topography"); + + deps.emplace_back("boundary densities"); + + return deps; + } + + template + double + Geoid::evaluate (const Point &/*p*/) const + { + Assert(false, ExcNotImplemented()); + return 0; + } + + template <> + double + Geoid<3>::evaluate (const Point<3> &p) const + { + const std::array scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(p); + const double theta = scoord[2]; + const double phi = scoord[1]; + double value = 0.; + + for (unsigned int ideg=min_degree, k=0; ideg < max_degree+1; ++ideg) + for (unsigned int iord = 0; iord < ideg+1; ++iord, ++k) + { + std::pair val = aspect::Utilities::real_spherical_harmonic( ideg, iord, theta, phi ); + + value += geoid_coecos[k] * val.first + + geoid_coesin[k] * val.second; + + } + return value; + } + + template + void + Geoid::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Geoid"); + { + prm.declare_entry("Include surface topography contribution", "true", + Patterns::Bool(), + "Option to include the contribution from surface topography on geoid. The default is true."); + prm.declare_entry("Include CMB topography contribution", "true", + Patterns::Bool(), + "Option to include the contribution from CMB topography on geoid. The default is true."); + prm.declare_entry("Maximum degree","20", + Patterns::Integer (0), + "This parameter can be a random positive integer. However, the value normally should not exceed the maximum " + "degree of the initial perturbed temperature field. For example, if the initial temperature uses S40RTS, the " + "maximum degree should not be larger than 40."); + prm.declare_entry("Minimum degree","2", + Patterns::Integer (0), + "This parameter normally is set to 2 since the perturbed gravitational potential at degree 1 always vanishes " + "in a reference frame with the planetary center of mass same as the center of figure."); + prm.declare_entry("Output data in geographical coordinates", "false", + Patterns::Bool(), + "Option to output the geoid anomaly in geographical coordinates (latitude and longitude). " + "The default is false, so the postprocessor will output the data in geocentric coordinates (x,y,z) as normally."); + prm.declare_entry("Density above","0.", + Patterns::Double (0.), + "The density value above the surface boundary."); + prm.declare_entry("Density below","9900.", + Patterns::Double (0.), + "The density value below the CMB boundary."); + prm.declare_entry("Output geoid anomaly coefficients", "false", + Patterns::Bool(), + "Option to output the spherical harmonic coefficients of the geoid anomaly up to the maximum degree. " + "The default is false, so the postprocessor will only output the geoid anomaly in grid format. "); + prm.declare_entry("Output surface topography contribution coefficients", "false", + Patterns::Bool(), + "Option to output the spherical harmonic coefficients of the surface topography contribution " + "to the maximum degree. The default is false. "); + prm.declare_entry("Output CMB topography contribution coefficients", "false", + Patterns::Bool(), + "Option to output the spherical harmonic coefficients of the CMB topography contribution " + "to the maximum degree. The default is false. "); + prm.declare_entry("Output density anomaly contribution coefficients", "false", + Patterns::Bool(), + "Option to output the spherical harmonic coefficients of the density anomaly contribution to the " + "maximum degree. The default is false. "); + prm.declare_entry("Output gravity anomaly", "false", + Patterns::Bool(), + "Option to output the free-air gravity anomaly up to the maximum degree. " + "The unit of the output is in SI, hence $m/s^2$ ($1mgal = 10^-5 m/s^2$). The default is false. "); + + prm.declare_alias("Output geoid anomaly coefficients","Also output the spherical harmonic coefficients of geoid anomaly"); + prm.declare_alias("Output surface topography contribution coefficients","Also output the spherical harmonic coefficients of surface dynamic topography contribution"); + prm.declare_alias("Output CMB topography contribution coefficients","Also output the spherical harmonic coefficients of CMB dynamic topography contribution"); + prm.declare_alias("Output density anomaly contribution coefficients","Also output the spherical harmonic coefficients of density anomaly contribution"); + prm.declare_alias("Output gravity anomaly","Also output the gravity anomaly"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + template + void + Geoid::parse_parameters (ParameterHandler &prm) + { + CitationInfo::add("geoid"); + + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Geoid"); + { + include_surface_topo_contribution = prm.get_bool ("Include surface topography contribution"); + include_CMB_topo_contribution = prm.get_bool ("Include CMB topography contribution"); + max_degree = prm.get_integer ("Maximum degree"); + min_degree = prm.get_integer ("Minimum degree"); + output_in_lat_lon = prm.get_bool ("Output data in geographical coordinates"); + density_above = prm.get_double ("Density above"); + density_below = prm.get_double ("Density below"); + output_geoid_anomaly_SH_coes = prm.get_bool ("Output geoid anomaly coefficients"); + output_surface_topo_contribution_SH_coes = prm.get_bool ("Output surface topography contribution coefficients"); + output_CMB_topo_contribution_SH_coes = prm.get_bool ("Output CMB topography contribution coefficients"); + output_density_anomaly_contribution_SH_coes = prm.get_bool ("Output density anomaly contribution coefficients"); + output_gravity_anomaly = prm.get_bool ("Output gravity anomaly"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + + template + void + Geoid::initialize () + { + // Find if the included boundaries are active free surfaces + if (include_surface_topo_contribution == true || include_CMB_topo_contribution == true) + { + if (this->get_parameters().mesh_deformation_enabled == true) + { + const types::boundary_id surface_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + const types::boundary_id bottom_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); + + const std::set mesh_deformation_boundaries = this->get_mesh_deformation_handler().get_active_mesh_deformation_boundary_indicators(); + + use_free_surface_topography = mesh_deformation_boundaries.find(surface_id) != mesh_deformation_boundaries.end(); + use_free_CMB_topography = mesh_deformation_boundaries.find(bottom_id) != mesh_deformation_boundaries.end(); + } + } + } + + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(Geoid, + "geoid", + "A postprocessor that computes a representation of " + "the geoid based on the density structure in the mantle, " + "as well as the topography at the surface and " + "core mantle boundary (CMB) if desired. The topography is based on the " + "dynamic topography postprocessor in case of no free surface, " + "and based on the real surface from the geometry model in case " + "of a free surface. The geoid is computed " + "from a spherical harmonic expansion, so the geometry " + "of the domain must be a 3d spherical shell.") + } +} diff --git a/source/postprocess/global_statistics.cc.bak b/source/postprocess/global_statistics.cc.bak new file mode 100644 index 00000000000..aae8dd2e811 --- /dev/null +++ b/source/postprocess/global_statistics.cc.bak @@ -0,0 +1,324 @@ +/* + Copyright (C) 2017 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + template + void + GlobalStatistics::initialize() + { + this->get_signals().post_stokes_solver.connect( + [&](const SimulatorAccess &/*simulator_access*/, + const unsigned int number_S_iterations, + const unsigned int number_A_iterations, + const SolverControl &solver_control_cheap, + const SolverControl &solver_control_expensive) + { + this->store_stokes_solver_history(number_S_iterations, + number_A_iterations, + solver_control_cheap, + solver_control_expensive); + }); + + this->get_signals().post_advection_solver.connect( + [&](const SimulatorAccess &/*simulator_access*/, + const bool solved_temperature_field, + const unsigned int compositional_index, + const SolverControl &solver_control) + { + this->store_advection_solver_history(solved_temperature_field, + compositional_index, + solver_control); + }); + + // delete the data after the initial refinement steps, to not mix it up + // with the first time step + if (!this->get_parameters().run_postprocessors_on_initial_refinement) + this->get_signals().post_set_initial_state.connect( + [&] (const SimulatorAccess &) + { + this->clear_data(); + }); + } + + + + template + void + GlobalStatistics::clear_data() + { + list_of_S_iterations.clear(); + list_of_A_iterations.clear(); + stokes_iterations_cheap.clear(); + stokes_iterations_expensive.clear(); + advection_iterations.clear(); + } + + + + template + void + GlobalStatistics::store_stokes_solver_history(const unsigned int number_S_iterations, + const unsigned int number_A_iterations, + const SolverControl &solver_control_cheap, + const SolverControl &solver_control_expensive) + { + list_of_S_iterations.push_back(number_S_iterations); + list_of_A_iterations.push_back(number_A_iterations); + stokes_iterations_cheap.push_back(solver_control_cheap.last_step()); + stokes_iterations_expensive.push_back(solver_control_expensive.last_step()); + } + + + + template + void + GlobalStatistics::store_advection_solver_history(const bool solved_temperature_field, + const unsigned int compositional_index, + const SolverControl &solver_control) + { + const std::string column_name = (solved_temperature_field) ? + "Iterations for temperature solver" + : + "Iterations for composition solver " + Utilities::int_to_string(compositional_index+1); + + unsigned int column_position = numbers::invalid_unsigned_int; + + for (unsigned int i=0; i(1,solver_control.last_step())); + else + advection_iterations[column_position].second.push_back(solver_control.last_step()); + } + + + + template + std::pair + GlobalStatistics::execute (TableHandler &statistics) + { + // We would like to know how many nonlinear iterations were performed since + // the last call to execute(). Unfortunately some solver schemes iterate only the + // Stokes equation, some Stokes and advection, and some do not even call the + // Stokes or advection solver. Therefore, the best estimate for the number + // of nonlinear iterations since the last call is the maximum size of the + // vectors in which we store our data. + unsigned int nonlinear_iterations = stokes_iterations_cheap.size(); + + for (const auto &advection_iteration : advection_iterations) + nonlinear_iterations = std::max(nonlinear_iterations, static_cast (advection_iteration.second.size())); + + if (one_line_per_iteration) + for (unsigned int iteration = 0; iteration < nonlinear_iterations; ++iteration) + { + generate_global_statistics(statistics); + + statistics.add_value("Nonlinear iteration number", + iteration); + + for (const auto &advection_iteration : advection_iterations) + if (iteration < advection_iteration.second.size()) + statistics.add_value(advection_iteration.first, + advection_iteration.second[iteration]); + + if (iteration < stokes_iterations_cheap.size()) + { + statistics.add_value("Iterations for Stokes solver", + stokes_iterations_cheap[iteration] + stokes_iterations_expensive[iteration]); + statistics.add_value("Velocity iterations in Stokes preconditioner", + list_of_A_iterations[iteration]); + statistics.add_value("Schur complement iterations in Stokes preconditioner", + list_of_S_iterations[iteration]); + } + + } + else + { + generate_global_statistics(statistics); + + unsigned int A_iterations = 0; + unsigned int S_iterations = 0; + unsigned int Stokes_outer_iterations = 0; + std::vector advection_outer_iterations(advection_iterations.size(),0); + + for (unsigned int iteration = 0; iteration < nonlinear_iterations; ++iteration) + { + for (unsigned int column=0; columnget_parameters().nonlinear_solver == Parameters::NonlinearSolver::single_Advection_single_Stokes + || this->get_parameters().nonlinear_solver == Parameters::NonlinearSolver::single_Advection_no_Stokes)) + statistics.add_value("Number of nonlinear iterations", + nonlinear_iterations); + + // Only output statistics columns if the solver actually signaled at least one + // successful solve. Some solver schemes might need no advection or Stokes solver + for (unsigned int column=0; column 0) + { + statistics.add_value("Iterations for Stokes solver", + Stokes_outer_iterations); + statistics.add_value("Velocity iterations in Stokes preconditioner", + A_iterations); + statistics.add_value("Schur complement iterations in Stokes preconditioner", + S_iterations); + } + } + + clear_data(); + + return std::make_pair (std::string(),std::string()); + } + + + + template + void + GlobalStatistics::generate_global_statistics(TableHandler &statistics) + { + // set global statistics about this time step + statistics.add_value("Time step number", this->get_timestep_number()); + + if (this->convert_output_to_years() == true) + { + statistics.add_value("Time (years)", this->get_time() / year_in_seconds); + statistics.set_precision("Time (years)", 12); + statistics.set_scientific("Time (years)", true); + + statistics.add_value("Time step size (years)", this->get_timestep() / year_in_seconds); + statistics.set_precision("Time step size (years)", 12); + statistics.set_scientific("Time step size (years)", true); + } + else + { + statistics.add_value("Time (seconds)", this->get_time()); + statistics.set_precision("Time (seconds)", 12); + statistics.set_scientific("Time (seconds)", true); + + statistics.add_value("Time step size (seconds)", this->get_timestep()); + statistics.set_precision("Time step size (seconds)", 12); + statistics.set_scientific("Time step size (seconds)", true); + } + + // set global statistics about the mesh and problem size + statistics.add_value("Number of mesh cells", + this->get_triangulation().n_global_active_cells()); + + types::global_dof_index n_stokes_dofs = this->introspection().system_dofs_per_block[0]; + if (this->introspection().block_indices.velocities != this->introspection().block_indices.pressure) + n_stokes_dofs += this->introspection().system_dofs_per_block[this->introspection().block_indices.pressure]; + + statistics.add_value("Number of Stokes degrees of freedom", n_stokes_dofs); + statistics.add_value("Number of temperature degrees of freedom", + this->introspection().system_dofs_per_block[this->introspection().block_indices.temperature]); + if (this->n_compositional_fields() > 0) + statistics.add_value("Number of degrees of freedom for all compositions", + static_cast(this->n_compositional_fields()) + * this->introspection().system_dofs_per_block[this->introspection().block_indices.compositional_fields[0]]); + } + + + + template + void + GlobalStatistics::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Global statistics"); + { + prm.declare_entry ("Write statistics for each nonlinear iteration", "false", + Patterns::Bool (), + "Whether to put every nonlinear iteration into a separate " + "line in the statistics file (if true), or to output only " + "one line per time step that contains the total number of " + "iterations of the Stokes and advection linear system solver."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + GlobalStatistics::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Global statistics"); + { + one_line_per_iteration = prm.get_bool("Write statistics for each nonlinear iteration"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(GlobalStatistics, + "global statistics", + "A postprocessor that outputs all the global statistics " + "information, e.g. the time of the simulation, the timestep " + "number, number of degrees of freedom and solver iterations " + "for each timestep. The postprocessor can output different " + "formats, the first printing one line in the statistics file " + "per nonlinear solver iteration (if a nonlinear solver scheme " + "is selected). The second prints one line per timestep, " + "summing the information about all nonlinear iterations in " + "this line. Note that this postprocessor is always active " + "independent on whether or not it is selected in the " + "parameter file.") + } +} diff --git a/source/postprocess/gravity_point_values.cc.bak b/source/postprocess/gravity_point_values.cc.bak new file mode 100644 index 00000000000..4371292ea51 --- /dev/null +++ b/source/postprocess/gravity_point_values.cc.bak @@ -0,0 +1,850 @@ +/* + Copyright (C) 2018 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + + template + GravityPointValues::GravityPointValues () + : + // the following value is later read from the input file + output_interval (0), + // initialize this to a nonsensical value; set it to the actual time + // the first time around we get to check it + last_output_time (std::numeric_limits::quiet_NaN()), + maximum_timesteps_between_outputs (std::numeric_limits::max()), + last_output_timestep (numbers::invalid_unsigned_int), + output_file_number (numbers::invalid_unsigned_int) + {} + + + + template + void + GravityPointValues::initialize () + { + // Get the value of the outer radius and inner radius: + if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + model_outer_radius = Plugins::get_plugin_as_type> + (this->get_geometry_model()).outer_radius(); + model_inner_radius = Plugins::get_plugin_as_type> + (this->get_geometry_model()).inner_radius(); + } + else if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + model_outer_radius = Plugins::get_plugin_as_type> + (this->get_geometry_model()).outer_radius(); + model_inner_radius = Plugins::get_plugin_as_type> + (this->get_geometry_model()).inner_radius(); + } + else if (Plugins::plugin_type_matches> (this->get_geometry_model())) + { + model_outer_radius = Plugins::get_plugin_as_type> + (this->get_geometry_model()).radius(); + model_inner_radius = 0; + } + else + { + model_outer_radius = 1; + model_inner_radius = 0; + } + + + // *** First calculate the number of satellites according to the sampling scheme: + unsigned int n_satellites; + if (sampling_scheme == fibonacci_spiral) + n_satellites = n_points_spiral * n_points_radius; + else if (sampling_scheme == map) + n_satellites = n_points_radius * n_points_longitude * n_points_latitude; + else if (sampling_scheme == list_of_points) + n_satellites = longitude_list.size(); + else n_satellites = 1; + + // *** Second assign the coordinates of all satellites: + satellite_positions_spherical.resize(n_satellites); + if (sampling_scheme == map) + { + unsigned int p = 0; + for (unsigned int h=0; h < n_points_radius; ++h) + { + for (unsigned int i=0; i < n_points_longitude; ++i) + { + for (unsigned int j=0; j < n_points_latitude; ++j) + { + if (n_points_radius > 1) + satellite_positions_spherical[p][0] = minimum_radius + ((maximum_radius - minimum_radius) / (n_points_radius - 1)) * h; + else + satellite_positions_spherical[p][0] = minimum_radius; + if (n_points_longitude > 1) + satellite_positions_spherical[p][1] = (minimum_colongitude + ((maximum_colongitude - minimum_colongitude) / + (n_points_longitude - 1)) * i) * constants::degree_to_radians; + else + satellite_positions_spherical[p][1] = minimum_colongitude * constants::degree_to_radians; + if (n_points_latitude > 1) + satellite_positions_spherical[p][2] = (minimum_colatitude + ((maximum_colatitude - minimum_colatitude) / + (n_points_latitude - 1)) * j) * constants::degree_to_radians; + else + satellite_positions_spherical[p][2] = minimum_colatitude * constants::degree_to_radians; + ++p; + } + } + } + } + if (sampling_scheme == fibonacci_spiral) + { + const double golden_ratio = (1. + std::sqrt(5.))/2.; + const double golden_angle = 2. * numbers::PI * (1. - 1./golden_ratio); + unsigned int p = 0; + for (unsigned int h=0; h < n_points_radius; ++h) + { + for (unsigned int s=0; s < n_points_spiral; ++s) + { + if (n_points_radius > 1) + satellite_positions_spherical[p][0] = minimum_radius + ((maximum_radius - minimum_radius) / (n_points_radius - 1)) * h; + else + satellite_positions_spherical[p][0] = minimum_radius; + satellite_positions_spherical[p][2] = std::acos(1. - 2. * s / (n_points_spiral - 1.)); + satellite_positions_spherical[p][1] = std::fmod((s*golden_angle), 2.*numbers::PI); + ++p; + } + } + } + if (sampling_scheme == list_of_points) + { + for (unsigned int p=0; p < n_satellites; ++p) + { + if (radius_list.size() == 1) + satellite_positions_spherical[p][0] = radius_list[0]; + else + satellite_positions_spherical[p][0] = radius_list[p]; + if (longitude_list[p] < 0) + satellite_positions_spherical[p][1] = (360 + longitude_list[p]) * constants::degree_to_radians; + else + satellite_positions_spherical[p][1] = (longitude_list[p]) * constants::degree_to_radians; + satellite_positions_spherical[p][2] = (90 - latitude_list[p]) * constants::degree_to_radians; + } + } + + // The spherical coordinates are shifted into cartesian to allow simplification + // in the mathematical equation. + satellite_positions_cartesian.resize (n_satellites); + for (unsigned int p=0; p(satellite_positions_spherical[p]); + } + + + + template + std::pair + GravityPointValues::execute (TableHandler &) + { + AssertThrow(false, ExcNotImplemented()); + return {"", ""}; + } + + + + template <> + std::pair + GravityPointValues<3>::execute (TableHandler &statistics) + { + const int dim = 3; + + // Check time to see if we output gravity + if (std::isnan(last_output_time)) + { + last_output_time = this->get_time() - output_interval; + last_output_timestep = this->get_timestep_number(); + } + if ((this->get_time() < last_output_time + output_interval) + && (this->get_timestep_number() < last_output_timestep + maximum_timesteps_between_outputs) + && (this->get_timestep_number() != 0)) + return {}; + + // Up the counter of the number of the file by one, but not in + // the very first output step. if we run postprocessors on all + // iterations, only increase file number in the first nonlinear iteration + const bool increase_file_number = (this->get_nonlinear_iteration() == 0) || + (!this->get_parameters().run_postprocessors_on_nonlinear_iterations); + if (output_file_number == numbers::invalid_unsigned_int) + output_file_number = 0; + else if (increase_file_number) + ++output_file_number; + + const std::string file_prefix = "gravity-" + Utilities::int_to_string (output_file_number, 5); + const std::string filename = (this->get_output_directory() + + "output_gravity/" + + file_prefix); + + // Get quadrature formula and increase the degree of quadrature over the velocity + // element degree. + const unsigned int degree = this->get_fe().base_element(this->introspection() + .base_elements.velocities).degree + + quadrature_degree_increase; + const QGauss quadrature_formula (degree); + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_gradients | + update_quadrature_points | + update_JxW_values); + + + // Get the value of the universal gravitational constant: + const double G = aspect::constants::big_g; + + const unsigned int n_quadrature_points_per_cell = quadrature_formula.size(); + + const unsigned int n_satellites = satellite_positions_spherical.size(); + + + // This is the main loop which computes gravity acceleration, potential and + // gradients at a point located at the spherical coordinate [r, phi, theta]. + // This loop corresponds to the 3 integrals of Newton law: + std::vector local_g_potential (n_satellites); + std::vector> local_g (n_satellites); + std::vector> local_g_anomaly (n_satellites); + std::vector> local_g_gradient (n_satellites); + + std::vector G_times_density_times_JxW (n_quadrature_points_per_cell); + std::vector G_times_density_anomaly_times_JxW (n_quadrature_points_per_cell); + + MaterialModel::MaterialModelInputs in(quadrature_formula.size(), + this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(quadrature_formula.size(), + this->n_compositional_fields()); + in.requested_properties = MaterialModel::MaterialProperties::density; + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + // Evaluate the solution at the quadrature points of this cell + fe_values.reinit (cell); + + in.reinit(fe_values, cell, this->introspection(), this->get_solution()); + this->get_material_model().evaluate(in, out); + + // Pull some computations that are independent of the + // satellite position out of the following loop. This is + // because we may have a very large number of satellites, + // so even just one multiplication that is unnecessarily + // repeated can be expensive. + for (unsigned int q = 0; q < n_quadrature_points_per_cell; ++q) + { + G_times_density_times_JxW[q] = G * out.densities[q] * + fe_values.JxW(q); + G_times_density_anomaly_times_JxW[q] = G * (out.densities[q]-reference_density) * + fe_values.JxW(q); + } + + + for (unsigned int p=0; p < n_satellites; ++p) + { + const Point satellite_position = satellite_positions_cartesian[p]; + + for (unsigned int q = 0; q < n_quadrature_points_per_cell; ++q) + { + const Tensor<1,dim> r_vector = satellite_position - fe_values.quadrature_point(q); + + const double r_squared = r_vector.norm_square(); + const double r = std::sqrt(r_squared); + const double r_cubed = r * r_squared; + const double one_over_r_cubed = 1. / r_cubed; + const double r_to_the_5 = r_squared * r_cubed; + + const double G_density_JxW = G_times_density_times_JxW[q]; + + // For gravity acceleration: + const double KK = - G_density_JxW * one_over_r_cubed; + local_g[p] += KK * r_vector; + + // For gravity anomalies: + const double KK_anomalies = - G_times_density_anomaly_times_JxW[q] * one_over_r_cubed; + local_g_anomaly[p] += KK_anomalies * r_vector; + + // For gravity potential: + local_g_potential[p] -= G_density_JxW / r; + + // For gravity gradient: + const double grad_KK = G_density_JxW / r_to_the_5; + for (unsigned int e=0; e g_potential(n_satellites); + Utilities::MPI::sum (make_const_array_view(local_g_potential), + this->get_mpi_communicator(), + make_array_view(g_potential)); + + const auto tensor_sum + = [] (const auto &v1, const auto &v2) + { + AssertDimension (v1.size(), v2.size()); + + using element_type = typename std::remove_reference::type::value_type; + + std::vector result (v1.size()); + for (unsigned int i=0; i> + g = Utilities::MPI::all_reduce + (local_g, + this->get_mpi_communicator(), + tensor_sum); + + const std::vector> + g_anomaly = Utilities::MPI::all_reduce + (local_g_anomaly, + this->get_mpi_communicator(), + tensor_sum); + + const std::vector> + g_gradient = Utilities::MPI::all_reduce + (local_g_gradient, + this->get_mpi_communicator(), + tensor_sum); + + double sum_g = 0; + double min_g = std::numeric_limits::max(); + double max_g = std::numeric_limits::lowest(); + double sum_g_potential = 0; + double min_g_potential = std::numeric_limits::max(); + double max_g_potential = std::numeric_limits::lowest(); + + for (unsigned int p=0; p < n_satellites; ++p) + { + // sum gravity components for all n_satellites: + sum_g += g[p].norm(); + sum_g_potential += g_potential[p]; + max_g = std::max(g[p].norm(), max_g); + min_g = std::min(g[p].norm(), min_g); + max_g_potential = std::max(g_potential[p], max_g_potential); + min_g_potential = std::min(g_potential[p], min_g_potential); + } + + + // Now also compute theoretical values. These are output only + // on process zero and, for now, also only computed on process zero. + std::vector g_theory(n_satellites); + std::vector g_potential_theory(n_satellites); + std::vector> g_gradient_theory(n_satellites); + + const unsigned int my_rank + = Utilities::MPI::this_mpi_process(this->get_mpi_communicator()); + const unsigned int n_ranks + = Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()); + + for (unsigned int p=0; p < n_satellites; ++p) + if (p % n_ranks == my_rank) + { + const Point satellite_position = satellite_positions_cartesian[p]; + + // analytical solution to calculate the theoretical gravity and its derivatives + // from a uniform density model. Can only be used if concentric density profile. + if (satellite_positions_spherical[p][0] <= model_inner_radius) + { + // We are inside the inner radius + g_theory[p] = 0; + g_potential_theory[p] = 2.0 * G * numbers::PI * reference_density * + ((model_inner_radius * model_inner_radius) - (model_outer_radius * model_outer_radius)); + } + else if ((satellite_positions_spherical[p][0] > model_inner_radius) + && (satellite_positions_spherical[p][0] < model_outer_radius)) + { + // We are in the spherical shell + g_theory[p] = G * numbers::PI * 4./3. * reference_density * + (satellite_positions_spherical[p][0] - + ((model_inner_radius * model_inner_radius * model_inner_radius) + / (satellite_positions_spherical[p][0] * satellite_positions_spherical[p][0]))); + g_potential_theory[p] = G * numbers::PI * 4./3. * reference_density * + (((satellite_positions_spherical[p][0] * satellite_positions_spherical[p][0])/2.0) + + ((model_inner_radius * model_inner_radius * model_inner_radius) / satellite_positions_spherical[p][0])) + - + G * numbers::PI * 2.0 * reference_density * + (model_outer_radius * model_outer_radius); + } + else + { + const double common_factor = G * numbers::PI * 4./3. * reference_density + * ((model_outer_radius * model_outer_radius * model_outer_radius) - (model_inner_radius * model_inner_radius * model_inner_radius)); + const double r = satellite_positions_spherical[p][0]; + + g_theory[p] = common_factor / (r * r); + g_potential_theory[p] = - common_factor / r; + + // For the gradient of g, start with the common part of + // the diagonal elements: + g_gradient_theory[p][0][0] = + g_gradient_theory[p][1][1] = + g_gradient_theory[p][2][2] = -1./(r * r * r); + + // Then do the off-diagonal elements: + for (unsigned int e=0; e + (g_theory, + this->get_mpi_communicator(), + tensor_sum); + + g_potential_theory = Utilities::MPI::all_reduce + (g_potential_theory, + this->get_mpi_communicator(), + tensor_sum); + + g_gradient_theory = Utilities::MPI::all_reduce + (g_gradient_theory, + this->get_mpi_communicator(), + tensor_sum); + + // open the file on rank 0 and write the headers + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + // First put all of our output into a string buffer: + std::ostringstream output; + output << "# 1: position_satellite_r" << '\n' + << "# 2: position_satellite_phi" << '\n' + << "# 3: position_satellite_theta" << '\n' + << "# 4: position_satellite_x" << '\n' + << "# 5: position_satellite_y" << '\n' + << "# 6: position_satellite_z" << '\n' + << "# 7: gravity_x" << '\n' + << "# 8: gravity_y" << '\n' + << "# 9: gravity_z" << '\n' + << "# 10: gravity_norm" << '\n' + << "# 11: gravity_theory" << '\n' + << "# 12: gravity_potential" << '\n' + << "# 13: gravity_potential_theory" << '\n' + << "# 14: gravity_anomaly_x" << '\n' + << "# 15: gravity_anomaly_y" << '\n' + << "# 16: gravity_anomaly_z" << '\n' + << "# 17: gravity_anomaly_norm" << '\n' + << "# 18: gravity_gradient_xx" << '\n' + << "# 19: gravity_gradient_yy" << '\n' + << "# 20: gravity_gradient_zz" << '\n' + << "# 21: gravity_gradient_xy" << '\n' + << "# 22: gravity_gradient_xz" << '\n' + << "# 23: gravity_gradient_yz" << '\n' + << "# 24: gravity_gradient_theory_xx" << '\n' + << "# 25: gravity_gradient_theory_yy" << '\n' + << "# 26: gravity_gradient_theory_zz" << '\n' + << "# 27: gravity_gradient_theory_xy" << '\n' + << "# 28: gravity_gradient_theory_xz" << '\n' + << "# 29: gravity_gradient_theory_yz" << '\n' + << '\n'; + + for (unsigned int p=0; p < n_satellites; ++p) + { + const Point satellite_position = satellite_positions_cartesian[p]; + + // write output. + // g_gradient is here given in eotvos E (1E = 1e-9 per square seconds): + output << satellite_positions_spherical[p][0] << ' ' + << satellite_positions_spherical[p][1] * constants::radians_to_degree << ' ' + << satellite_positions_spherical[p][2] * constants::radians_to_degree << ' ' + << satellite_position[0] << ' ' + << satellite_position[1] << ' ' + << satellite_position[2] << ' ' + << std::setprecision(precision) + << g[p] << ' ' + << g[p].norm() << ' ' + << g_theory[p] << ' ' + << g_potential[p] << ' ' + << g_potential_theory[p] << ' ' + << g_anomaly[p] << ' ' + << g_anomaly[p].norm() << ' ' + << g_gradient[p][0][0] *1e9 << ' ' + << g_gradient[p][1][1] *1e9 << ' ' + << g_gradient[p][2][2] *1e9 << ' ' + << g_gradient[p][0][1] *1e9 << ' ' + << g_gradient[p][0][2] *1e9 << ' ' + << g_gradient[p][1][2] *1e9 << ' ' + << g_gradient_theory[p][0][0] *1e9 << ' ' + << g_gradient_theory[p][1][1] *1e9 << ' ' + << g_gradient_theory[p][2][2] *1e9 << ' ' + << g_gradient_theory[p][0][1] *1e9 << ' ' + << g_gradient_theory[p][0][2] *1e9 << ' ' + << g_gradient_theory[p][1][2] *1e9 << ' ' + << '\n'; + } + + // Now push the entire buffer into the output file in one swoop fell: + std::ofstream output_file(filename); + AssertThrow(output_file, + ExcMessage("Unable to open file for writing: " + filename +".")); + output_file << output.str(); + } + + // write quantities in the statistic file + const std::string name2("Average gravity acceleration (m/s^2)"); + statistics.add_value (name2, sum_g/n_satellites); + statistics.set_precision (name2, precision); + statistics.set_scientific (name2, true); + + const std::string name3("Minimum gravity acceleration (m/s^2)"); + statistics.add_value (name3, min_g); + statistics.set_precision (name3, precision); + statistics.set_scientific (name3, true); + + const std::string name4("Maximum gravity acceleration (m/s^2)"); + statistics.add_value (name4, max_g); + statistics.set_precision (name4, precision); + statistics.set_scientific (name4, true); + + const std::string name5("Average gravity potential (m^2/s^2)"); + statistics.add_value (name5, sum_g_potential/n_satellites); + statistics.set_precision (name5, precision); + statistics.set_scientific (name5, true); + + const std::string name6("Minimum gravity potential (m^2/s^2)"); + statistics.add_value (name6, min_g_potential); + statistics.set_precision (name6, precision); + statistics.set_scientific (name6, true); + + const std::string name7("Maximum gravity potential (m^2/s^2)"); + statistics.add_value (name7, max_g_potential); + statistics.set_precision (name7, precision); + statistics.set_scientific (name7, true); + + // up the next time we need output: + set_last_output_time (this->get_time()); + last_output_timestep = this->get_timestep_number(); + return std::pair ("Writing gravity output:", filename); + } + + + + template + void + GravityPointValues::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection ("Postprocess"); + { + prm.enter_subsection ("Gravity calculation"); + { + prm.declare_entry ("Sampling scheme", "map", + Patterns::Selection ("map|list|list of points|fibonacci spiral"), + "Choose the sampling scheme. By default, the map produces a " + "grid of equally angled points between a minimum and maximum " + "radius, longitude, and latitude. A list of points contains " + "the specific coordinates of the satellites. The fibonacci " + "spiral sampling scheme produces a uniformly distributed map " + "on the surface of sphere defined by a minimum and/or " + "maximum radius."); + prm.declare_entry ("Number points fibonacci spiral", "200", + Patterns::Integer (0), + "Parameter for the fibonacci spiral sampling scheme: " + "This specifies the desired number of satellites per radius " + "layer. The default value is 200. Note that sampling " + "becomes more uniform with increasing number of satellites"); + prm.declare_entry ("Quadrature degree increase", "0", + Patterns::Integer (-1), + "Quadrature degree increase over the velocity element " + "degree may be required when gravity is calculated near " + "the surface or inside the model. An increase in the " + "quadrature element adds accuracy to the gravity " + "solution from noise due to the model grid."); + prm.declare_entry ("Number points radius", "1", + Patterns::Integer (0), + "Parameter for the map sampling scheme: " + "This specifies the number of points along " + "the radius (e.g. depth profile) between a minimum and " + "maximum radius."); + prm.declare_entry ("Number points longitude", "1", + Patterns::Integer (0), + "Parameter for the map sampling scheme: " + "This specifies the number of points along " + "the longitude (e.g. gravity map) between a minimum and " + "maximum longitude."); + prm.declare_entry ("Number points latitude", "1", + Patterns::Integer (0), + "Parameter for the map sampling scheme: " + "This specifies the number of points along " + "the latitude (e.g. gravity map) between a minimum and " + "maximum latitude."); + prm.declare_entry ("Minimum radius", "0.", + Patterns::Double (0.0), + "Parameter for the map sampling scheme: " + "Minimum radius may be defined in or outside the model. " + "Prescribe a minimum radius for a sampling coverage at a " + "specific height."); + prm.declare_entry ("Maximum radius", "0.", + Patterns::Double (0.0), + "Parameter for the map sampling scheme: " + "Maximum radius can be defined in or outside the model."); + prm.declare_entry ("Minimum longitude", "-180.", + Patterns::Double (-180.0, 180.0), + "Parameter for the uniform distribution sampling scheme: " + "Gravity may be calculated for a sets of points along " + "the longitude between a minimum and maximum longitude."); + prm.declare_entry ("Minimum latitude", "-90.", + Patterns::Double (-90.0, 90.0), + "Parameter for the uniform distribution sampling scheme: " + "Gravity may be calculated for a sets of points along " + "the latitude between a minimum and maximum latitude."); + prm.declare_entry ("Maximum longitude", "180.", + Patterns::Double (-180.0, 180.0), + "Parameter for the uniform distribution sampling scheme: " + "Gravity may be calculated for a sets of points along " + "the longitude between a minimum and maximum longitude."); + prm.declare_entry ("Maximum latitude", "90", + Patterns::Double (-90.0, 90.0), + "Parameter for the uniform distribution sampling scheme: " + "Gravity may be calculated for a sets of points along " + "the latitude between a minimum and maximum latitude."); + prm.declare_entry ("Reference density", "3300.", + Patterns::Double (0.0), + "Gravity anomalies may be computed using density " + "anomalies relative to a reference density."); + prm.declare_entry ("Precision in gravity output", "12", + Patterns::Integer (1), + "Set the precision of gravity acceleration, potential " + "and gradients in the gravity output and statistics file."); + prm.declare_entry ("List of radius", "", + Patterns::List (Patterns::Double (0.)), + "Parameter for the list of points sampling scheme: " + "List of satellite radius coordinates. Just specify one " + "radius if all points values have the same radius. If " + "not, make sure there are as many radius as longitude " + "and latitude"); + prm.declare_entry ("List of longitude", "", + Patterns::List (Patterns::Double(-180.0, 180.0)), + "Parameter for the list of points sampling scheme: " + "List of satellite longitude coordinates."); + prm.declare_entry ("List of latitude", "", + Patterns::List (Patterns::Double(-90.0, 90.0)), + "Parameter for the list of points sampling scheme: " + "List of satellite latitude coordinates."); + prm.declare_entry ("Time between gravity output", "1e8", + Patterns::Double(0.0), + "The time interval between each generation of " + "gravity output files. A value of 0 indicates " + "that output should be generated in each time step. " + "Units: years if the " + "'Use years in output instead of seconds' parameter is set; " + "seconds otherwise."); + prm.declare_entry ("Time steps between gravity output", boost::lexical_cast(std::numeric_limits::max()), + Patterns::Integer(0,std::numeric_limits::max()), + "The maximum number of time steps between each generation of " + "gravity output files."); + + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + void + GravityPointValues::parse_parameters (ParameterHandler &prm) + { + std::string gravity_subdirectory = this->get_output_directory() + "output_gravity/"; + Utilities::create_directory (gravity_subdirectory, + this->get_mpi_communicator(), + true); + + end_time = prm.get_double ("End time"); + if (this->convert_output_to_years()) + end_time *= year_in_seconds; + + prm.enter_subsection ("Postprocess"); + { + prm.enter_subsection ("Gravity calculation"); + { + if ( (prm.get ("Sampling scheme") == "uniform distribution") || (prm.get ("Sampling scheme") == "map") ) + sampling_scheme = map; + else if ( (prm.get ("Sampling scheme") == "list of points") || (prm.get ("Sampling scheme") == "list") ) + sampling_scheme = list_of_points; + else if (prm.get ("Sampling scheme") == "fibonacci spiral") + sampling_scheme = fibonacci_spiral; + else + AssertThrow (false, ExcMessage ("Not a valid sampling scheme.")); + quadrature_degree_increase = prm.get_integer ("Quadrature degree increase"); + n_points_spiral = prm.get_integer("Number points fibonacci spiral"); + n_points_radius = prm.get_integer("Number points radius"); + n_points_longitude = prm.get_integer("Number points longitude"); + n_points_latitude = prm.get_integer("Number points latitude"); + minimum_radius = prm.get_double ("Minimum radius"); + maximum_radius = prm.get_double ("Maximum radius"); + minimum_colongitude = prm.get_double ("Minimum longitude") + 180.; + maximum_colongitude = prm.get_double ("Maximum longitude") + 180.; + minimum_colatitude = prm.get_double ("Minimum latitude") + 90.; + maximum_colatitude = prm.get_double ("Maximum latitude") + 90.; + reference_density = prm.get_double ("Reference density"); + precision = prm.get_integer ("Precision in gravity output"); + radius_list = Utilities::string_to_double(Utilities::split_string_list(prm.get("List of radius"))); + longitude_list = Utilities::string_to_double(Utilities::split_string_list(prm.get("List of longitude"))); + latitude_list = Utilities::string_to_double(Utilities::split_string_list(prm.get("List of latitude"))); + AssertThrow (longitude_list.size() == latitude_list.size(), + ExcMessage ("Make sure you have the same number of point coordinates in the list sampling scheme.")); + AssertThrow (Plugins::plugin_type_matches> (this->get_geometry_model()) || + Plugins::plugin_type_matches> (this->get_geometry_model()) || + Plugins::plugin_type_matches> (this->get_geometry_model()), + ExcMessage ("This postprocessor can only be used if the geometry is a sphere, spherical shell or spherical chunk.")); + AssertThrow (! this->get_material_model().is_compressible(), + ExcMessage("This postprocessor was only tested for incompressible models so far.")); + AssertThrow (dim==3, + ExcMessage("This postprocessor was only tested for 3d models.")); + output_interval = prm.get_double ("Time between gravity output"); + if (this->convert_output_to_years()) + output_interval *= year_in_seconds; + maximum_timesteps_between_outputs = prm.get_integer("Time steps between gravity output"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + + template + template + void GravityPointValues::serialize (Archive &ar, const unsigned int) + { + // This deals with having the correct behavior during checkpoint/restart cycles: + ar &last_output_time + & last_output_timestep + & output_file_number + ; + } + + + + template + void + GravityPointValues::set_last_output_time (const double current_time) + { + // if output_interval is positive, then update the last supposed output time: + if (output_interval > 0) + { + // We need to find the last time output was supposed to be written. + // this is the last_output_time plus the largest positive multiple + // of output_intervals that passed since then. We need to handle the + // edge case where last_output_time+output_interval==current_time, + // we did an output and std::floor sadly rounds to zero. This is done + // by forcing std::floor to round 1.0-eps to 1.0. + const double magic = 1.0+2.0*std::numeric_limits::epsilon(); + last_output_time = last_output_time + std::floor((current_time-last_output_time)/output_interval*magic) * output_interval/magic; + } + } + + + + template + void + GravityPointValues::save (std::map &status_strings) const + { + std::ostringstream os; + aspect::oarchive oa (os); + oa << (*this); + + status_strings["GravityPointValues"] = os.str(); + } + + + + template + void + GravityPointValues::load (const std::map &status_strings) + { + // see if something was saved + if (status_strings.find("GravityPointValues") != status_strings.end()) + { + std::istringstream is (status_strings.find("GravityPointValues")->second); + aspect::iarchive ia (is); + ia >> (*this); + } + } + + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(GravityPointValues, + "gravity calculation", + "A postprocessor that computes gravity, gravity anomalies, gravity " + "potential and gravity gradients for a set of points (e.g. satellites) " + "in or above the model surface for either a user-defined range of " + "latitudes, longitudes and radius or a list of point coordinates." + "Spherical coordinates in the output file are radius, colatitude " + "and colongitude. Gravity is here based on the density distribution " + "from the material model (and non adiabatic). This means that the " + "density may come directly from an ascii file. This postprocessor also " + "computes theoretical gravity and its derivatives, which corresponds to " + "the analytical solution of gravity in the same geometry but filled " + "with a reference density. The reference density is also used to " + "determine density anomalies for computing gravity anomalies. Thus " + "one must carefully evaluate the meaning of the gravity anomaly output, " + "because the solution may not reflect the actual gravity anomaly (due to " + "differences in the assumed reference density). On way to guarantee correct " + "gravity anomalies is to subtract gravity of a certain point from the average " + "gravity on the map. Another way is to directly use density anomalies for this " + "postprocessor." + "The average- minimum- and maximum gravity acceleration and potential are " + "written into the statistics file.") + } +} diff --git a/source/postprocess/heat_flux_densities.cc.bak b/source/postprocess/heat_flux_densities.cc.bak new file mode 100644 index 00000000000..d4c715f8716 --- /dev/null +++ b/source/postprocess/heat_flux_densities.cc.bak @@ -0,0 +1,157 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + HeatFluxDensities::execute (TableHandler &statistics) + { + const char *unit = (dim==2)? "W/m" : "W/m^2"; + + std::vector>> heat_flux_and_area = + internal::compute_heat_flux_through_boundary_faces (*this); + + std::map local_boundary_fluxes; + std::map local_areas; + + // Compute the area and heat flux of each boundary that lives on this processor. + // Finally, sum over the processors and compute the ratio between the + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + for (const unsigned int f : cell->face_indices()) + if (cell->at_boundary(f)) + { + const types::boundary_id boundary_indicator + = cell->face(f)->boundary_id(); + local_boundary_fluxes[boundary_indicator] += heat_flux_and_area[cell->active_cell_index()][f].first; + local_areas[boundary_indicator] += heat_flux_and_area[cell->active_cell_index()][f].second; + } + + // now communicate to get the global values + std::map global_boundary_flux_densities; + { + // first collect local values in the same order in which they are listed + // in the set of boundary indicators + const std::set + boundary_indicators + = this->get_geometry_model().get_used_boundary_indicators (); + std::vector local_boundary_fluxes_vector; + std::vector local_areas_vector; + for (const auto id : boundary_indicators) + { + local_boundary_fluxes_vector.push_back (local_boundary_fluxes[id]); + local_areas_vector.push_back (local_areas[id]); + } + + // then collect contributions from all processors + std::vector global_values (local_boundary_fluxes_vector.size()); + std::vector global_areas (local_areas_vector.size()); + Utilities::MPI::sum (local_boundary_fluxes_vector, this->get_mpi_communicator(), global_values); + Utilities::MPI::sum (local_areas_vector, this->get_mpi_communicator(), global_areas); + + // and now take them apart into the global map again and compute ratios + unsigned int index = 0; + for (const auto id : boundary_indicators) + { + global_boundary_flux_densities[id] = global_values[index]/global_areas[index]; + ++index; + } + } + + // now add all of the computed heat fluxes to the statistics object + // and create a single string that can be output to the screen + std::ostringstream screen_text; + unsigned int index = 0; + for (std::map::const_iterator + p = global_boundary_flux_densities.begin(); + p != global_boundary_flux_densities.end(); ++p, ++index) + { + const std::string name = "Outward heat flux density for boundary with id " + + Utilities::int_to_string(p->first) + + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() + .translate_id_to_symbol_name (p->first)) + + " (" + unit +")"; + statistics.add_value (name, p->second); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name, 8); + statistics.set_scientific (name, true); + + // finally have something for the screen + screen_text.precision(4); + screen_text << p->second << ' ' << unit + << (index == global_boundary_flux_densities.size()-1 ? "" : ", "); + } + + return std::pair ("Heat flux densities for boundaries:", + screen_text.str()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(HeatFluxDensities, + "heat flux densities", + "A postprocessor that computes some statistics " + "about the heat flux density for each boundary id. " + "The heat flux density across each boundary " + "is computed in outward " + "direction, i.e., from the domain to the " + "outside. The heat flux is computed as sum " + "of advective heat flux and conductive heat " + "flux through Neumann boundaries, both " + "computed as integral over the boundary area, " + "and conductive heat flux through Dirichlet " + "boundaries, which is computed using the " + "consistent boundary flux method as described " + "in ``Gresho, Lee, Sani, Maslanik, Eaton (1987). " + "The consistent Galerkin FEM for computing " + "derived boundary quantities in thermal and or " + "fluids problems. International Journal for " + "Numerical Methods in Fluids, 7(4), 371-394.''" + "\n\n" + "Note that the ``heat flux statistics'' " + "postprocessor computes the same quantity as " + "the one here, but not divided by the area of " + "the surface. In other words, it computes the " + "\\textit{total} heat flux through each boundary." + ) + } +} diff --git a/source/postprocess/heat_flux_map.cc.bak b/source/postprocess/heat_flux_map.cc.bak new file mode 100644 index 00000000000..c565d3cdcad --- /dev/null +++ b/source/postprocess/heat_flux_map.cc.bak @@ -0,0 +1,565 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + namespace internal + { + template + LinearAlgebra::BlockVector + compute_dirichlet_boundary_heat_flux_solution_vector (const SimulatorAccess &simulator_access) + { + // Quadrature degree for assembling the consistent boundary flux equation, see Simulator::assemble_advection_system() + // for a justification of the chosen quadrature degree. + const unsigned int quadrature_degree = simulator_access.get_parameters().temperature_degree + + + (simulator_access.get_parameters().stokes_velocity_degree+1)/2; + + // Gauss quadrature in the interior for best accuracy. + const QGauss quadrature_formula(quadrature_degree); + // GLL quadrature on the faces to get a diagonal mass matrix. + const QGaussLobatto quadrature_formula_face(quadrature_degree); + + // The CBF method involves both boundary and volume integrals on the + // cells at the boundary. Construct FEValues objects for each of these integrations. + FEValues fe_volume_values (simulator_access.get_mapping(), + simulator_access.get_fe(), + quadrature_formula, + update_values | + update_gradients | + update_quadrature_points | + update_JxW_values); + + FEFaceValues fe_face_values (simulator_access.get_mapping(), + simulator_access.get_fe(), + quadrature_formula_face, + update_JxW_values | + update_values | + update_gradients | + update_normal_vectors | + update_quadrature_points); + + const unsigned int dofs_per_cell = simulator_access.get_fe().dofs_per_cell; + const unsigned int n_q_points = quadrature_formula.size(); + const unsigned int n_face_q_points = quadrature_formula_face.size(); + + // Vectors for solving CBF system. Since we are using GLL + // quadrature, the mass matrix will be diagonal, and we can just assemble it into a vector. + Vector local_rhs(dofs_per_cell); + Vector local_mass_matrix(dofs_per_cell); + + // The mass matrix may be stored in a vector as it is a diagonal matrix: + // it is computed based on quadrature over faces, and we use a node-location + // based quadrature formula above, so phi_i(x_q)=delta_{iq} where the + // x_q are the node points of the finite element shape functions on the face. + LinearAlgebra::BlockVector mass_matrix(simulator_access.introspection().index_sets.system_partitioning, + simulator_access.get_mpi_communicator()); + LinearAlgebra::BlockVector distributed_heat_flux_vector(simulator_access.introspection().index_sets.system_partitioning, + simulator_access.get_mpi_communicator()); + LinearAlgebra::BlockVector heat_flux_vector(simulator_access.introspection().index_sets.system_partitioning, + simulator_access.introspection().index_sets.system_relevant_partitioning, + simulator_access.get_mpi_communicator()); + LinearAlgebra::BlockVector rhs_vector(simulator_access.introspection().index_sets.system_partitioning, + simulator_access.get_mpi_communicator()); + + distributed_heat_flux_vector = 0.; + heat_flux_vector = 0.; + + typename MaterialModel::Interface::MaterialModelInputs + in(fe_volume_values.n_quadrature_points, simulator_access.n_compositional_fields()); + typename MaterialModel::Interface::MaterialModelOutputs + out(fe_volume_values.n_quadrature_points, simulator_access.n_compositional_fields()); + + HeatingModel::HeatingModelOutputs + heating_out(fe_volume_values.n_quadrature_points, simulator_access.n_compositional_fields()); + + typename MaterialModel::Interface::MaterialModelInputs + face_in(fe_face_values.n_quadrature_points, simulator_access.n_compositional_fields()); + typename MaterialModel::Interface::MaterialModelOutputs + face_out(fe_face_values.n_quadrature_points, simulator_access.n_compositional_fields()); + + std::vector old_temperatures (n_q_points); + std::vector old_old_temperatures (n_q_points); + std::vector> temperature_gradients (n_q_points); + + const double time_step = simulator_access.get_timestep(); + const double old_time_step = simulator_access.get_old_timestep(); + + const std::set &fixed_temperature_boundaries = + simulator_access.get_boundary_temperature_manager().get_fixed_temperature_boundary_indicators(); + + const std::set &fixed_heat_flux_boundaries = + simulator_access.get_parameters().fixed_heat_flux_boundary_indicators; + + Vector artificial_viscosity(simulator_access.get_triangulation().n_active_cells()); + simulator_access.get_artificial_viscosity(artificial_viscosity, true); + + // loop over all of the surface cells and evaluate the heat flux + for (const auto &cell : simulator_access.get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + { + fe_volume_values.reinit (cell); + in.reinit(fe_volume_values, cell, simulator_access.introspection(), simulator_access.get_solution()); + simulator_access.get_material_model().evaluate(in, out); + + if (simulator_access.get_parameters().formulation_temperature_equation == + Parameters::Formulation::TemperatureEquation::reference_density_profile) + { + for (unsigned int q=0; q 1) + { + Assert(time_step > 0.0 && old_time_step > 0.0, + ExcMessage("The heat flux postprocessor found a time step length of 0. " + "This is not supported, because it needs to compute the time derivative of the " + "temperature. Either use a positive timestep, or modify the postprocessor to " + "ignore the time derivative.")); + + temperature_time_derivative = (1.0/time_step) * + (in.temperature[q] * + (2*time_step + old_time_step) / (time_step + old_time_step) + - + old_temperatures[q] * + (1 + time_step/old_time_step) + + + old_old_temperatures[q] * + (time_step * time_step) / (old_time_step * (time_step + old_time_step))); + } + else if (simulator_access.get_timestep_number() == 1) + { + Assert(time_step > 0.0, + ExcMessage("The heat flux postprocessor found a time step length of 0. " + "This is not supported, because it needs to compute the time derivative of the " + "temperature. Either use a positive timestep, or modify the postprocessor to " + "ignore the time derivative.")); + + temperature_time_derivative = + (in.temperature[q] - old_temperatures[q]) / time_step; + } + else + temperature_time_derivative = 0.0; + + const double JxW = fe_volume_values.JxW(q); + + const double density_c_P = out.densities[q] * out.specific_heat[q]; + const double latent_heat_LHS = heating_out.lhs_latent_heat_terms[q]; + const double material_prefactor = density_c_P + latent_heat_LHS; + + const double artificial_viscosity_cell = static_cast(artificial_viscosity(cell->active_cell_index())); + + // The SUPG parameter tau does not have the physical dimensions of a thermal conductivity and as such should not be included in heat flux calculations + // By default, ASPECT includes the artificial viscosity in the thermal conductivity when calculating boundary heat flux. + const double diffusion_constant = (simulator_access.get_parameters().advection_stabilization_method == + Parameters::AdvectionStabilizationMethod::supg) ? + out.thermal_conductivities[q] + : + std::max(out.thermal_conductivities[q], + artificial_viscosity_cell); + + for (unsigned int i = 0; iface_indices()) + { + if (!cell->at_boundary(f)) + continue; + + fe_face_values.reinit (cell, f); + + const unsigned int boundary_id = cell->face(f)->boundary_id(); + + // Compute heat flux through Dirichlet boundary using CBF method + if (fixed_temperature_boundaries.find(boundary_id) != fixed_temperature_boundaries.end()) + { + // Assemble the mass matrix for cell face. Because the quadrature + // formula is chosen as co-located with the nodes of shape functions, + // the resulting matrix is diagonal. + for (unsigned int q=0; q::Formulation::TemperatureEquation::reference_density_profile) + { + for (unsigned int q=0; q> heat_flux(n_face_q_points); + heat_flux = simulator_access.get_boundary_heat_flux().heat_flux( + boundary_id, + face_in, + face_out, + fe_face_values.get_normal_vectors() + ); + + // For inhomogeneous Neumann boundaries we know the heat flux across the boundary at each point, + // and can thus simply integrate it for each cell. However, we still need to assemble the + // boundary terms for the CBF method, because there could be Dirichlet boundaries on the + // same cell (e.g. a different face in a corner). Therefore, do the integration into + // heat_flux_and_area, and assemble the CBF term into local_rhs. + for (unsigned int q=0; q < n_face_q_points; ++q) + { + for (unsigned int i = 0; idistribute_local_to_global(local_mass_matrix, mass_matrix); + cell->distribute_local_to_global(local_rhs, rhs_vector); + } + + mass_matrix.compress(VectorOperation::add); + rhs_vector.compress(VectorOperation::add); + + const IndexSet local_elements = mass_matrix.locally_owned_elements(); + for (unsigned int k=0; k 1.e-15) + distributed_heat_flux_vector[global_index] = rhs_vector[global_index] / mass_matrix[global_index]; + } + + distributed_heat_flux_vector.compress(VectorOperation::insert); + heat_flux_vector = distributed_heat_flux_vector; + + return heat_flux_vector; + } + + + + template + std::vector>> + compute_heat_flux_through_boundary_faces (const SimulatorAccess &simulator_access) + { + std::vector>> + heat_flux_and_area(simulator_access.get_triangulation().n_active_cells()); + + // Quadrature degree for assembling the consistent boundary flux equation, see Simulator::assemble_advection_system() + // for a justification of the chosen quadrature degree. + const unsigned int quadrature_degree = simulator_access.get_parameters().temperature_degree + + + (simulator_access.get_parameters().stokes_velocity_degree+1)/2; + + // GLL quadrature on the faces to get a diagonal mass matrix. + const QGaussLobatto quadrature_formula_face(quadrature_degree); + + FEFaceValues fe_face_values (simulator_access.get_mapping(), + simulator_access.get_fe(), + quadrature_formula_face, + update_JxW_values | + update_values | + update_gradients | + update_normal_vectors | + update_quadrature_points); + + const unsigned int n_face_q_points = quadrature_formula_face.size(); + + typename MaterialModel::Interface::MaterialModelInputs face_in(fe_face_values.n_quadrature_points, simulator_access.n_compositional_fields()); + typename MaterialModel::Interface::MaterialModelOutputs face_out(fe_face_values.n_quadrature_points, simulator_access.n_compositional_fields()); + + const std::set &fixed_temperature_boundaries = + simulator_access.get_boundary_temperature_manager().get_fixed_temperature_boundary_indicators(); + + const std::set &fixed_heat_flux_boundaries = + simulator_access.get_parameters().fixed_heat_flux_boundary_indicators; + + const std::set &tangential_velocity_boundaries = + simulator_access.get_boundary_velocity_manager().get_tangential_boundary_velocity_indicators(); + + const std::set &zero_velocity_boundaries = + simulator_access.get_boundary_velocity_manager().get_zero_boundary_velocity_indicators(); + + const LinearAlgebra::BlockVector heat_flux_vector = compute_dirichlet_boundary_heat_flux_solution_vector(simulator_access); + std::vector heat_flux_values(n_face_q_points); + + // loop over all of the surface cells and evaluate the heat flux + for (const auto &cell : simulator_access.get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned() && cell->at_boundary()) + { + for (const unsigned int f : cell->face_indices()) + if (cell->at_boundary(f)) + { + // See if this is the first face on this cell we visit, and if + // so resize the output array. + if (heat_flux_and_area[cell->active_cell_index()].size() == 0) + heat_flux_and_area[cell->active_cell_index()] + .resize (cell->n_faces(), std::pair(0.0,0.0)); + else + Assert (heat_flux_and_area[cell->active_cell_index()].size() == cell->n_faces(), + ExcInternalError()); + + // Determine the type of boundary + const unsigned int boundary_id = cell->face(f)->boundary_id(); + const bool prescribed_temperature = fixed_temperature_boundaries.find(boundary_id) != fixed_temperature_boundaries.end(); + const bool prescribed_heat_flux = fixed_heat_flux_boundaries.find(boundary_id) != fixed_heat_flux_boundaries.end(); + const bool non_tangential_velocity = + tangential_velocity_boundaries.find(boundary_id) == tangential_velocity_boundaries.end() && + zero_velocity_boundaries.find(boundary_id) == zero_velocity_boundaries.end(); + + fe_face_values.reinit (cell, f); + + // Integrate the face area + for (unsigned int q=0; qactive_cell_index()][f].second += fe_face_values.JxW(q); + + // Compute heat flux through Dirichlet boundaries by integrating the CBF solution vector + if (prescribed_temperature) + { + fe_face_values[simulator_access.introspection().extractors.temperature].get_function_values(heat_flux_vector, heat_flux_values); + + for (unsigned int q=0; qactive_cell_index()][f].first += heat_flux_values[q] * + fe_face_values.JxW(q); + } + + // if necessary, compute material properties for this face + if (prescribed_heat_flux || non_tangential_velocity) + { + face_in.reinit(fe_face_values, cell, simulator_access.introspection(), simulator_access.get_solution()); + simulator_access.get_material_model().evaluate(face_in, face_out); + + if (simulator_access.get_parameters().formulation_temperature_equation == + Parameters::Formulation::TemperatureEquation::reference_density_profile) + { + for (unsigned int q=0; q> heat_flux(n_face_q_points); + heat_flux = simulator_access.get_boundary_heat_flux().heat_flux( + boundary_id, + face_in, + face_out, + fe_face_values.get_normal_vectors() + ); + + for (unsigned int q=0; q < n_face_q_points; ++q) + { + const double normal_heat_flux = heat_flux[q] * fe_face_values.normal_vector(q); + const double JxW = fe_face_values.JxW(q); + heat_flux_and_area[cell->active_cell_index()][f].first += normal_heat_flux * JxW; + } + } + + // Compute advective heat flux + if (non_tangential_velocity) + { + for (unsigned int q=0; qactive_cell_index()][f].first += face_out.densities[q] * + face_out.specific_heat[q] * face_in.temperature[q] * + face_in.velocity[q] * fe_face_values.normal_vector(q) * + fe_face_values.JxW(q); + } + } + } + } + return heat_flux_and_area; + } + } + + + + template + std::pair + HeatFluxMap::execute (TableHandler &) + { + std::vector>> heat_flux_and_area = + internal::compute_heat_flux_through_boundary_faces (*this); + + const auto boundary_ids = this->get_geometry_model().get_used_boundary_indicators(); + for (const auto &boundary_id: boundary_ids) + if (this->get_geometry_model().translate_id_to_symbol_name(boundary_id) == "top" || + this->get_geometry_model().translate_id_to_symbol_name(boundary_id) == "bottom") + output_to_file(boundary_id, heat_flux_and_area); + + std::string placeholder_name = this->get_output_directory() + "heat_flux." + Utilities::int_to_string(this->get_timestep_number(), 5); + if (this->get_parameters().run_postprocessors_on_nonlinear_iterations) + placeholder_name.append("." + Utilities::int_to_string (this->get_nonlinear_iteration(), 4)); + + return std::pair("Writing heat flux map", + placeholder_name); + } + + + + template + void + HeatFluxMap::output_to_file(const types::boundary_id boundary_id, + const std::vector>> &heat_flux_and_area) + { + // get boundary name and avoid spaces for file output + std::string boundary_name = this->get_geometry_model().translate_id_to_symbol_name(boundary_id); + std::replace(boundary_name.begin(), boundary_name.end(), ' ', '_'); + + std::ostringstream output; + + // write the file header. note that we only do so on processor 0 + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + output << "# " + << ((dim==2)? "x y" : "x y z") + << " heat_flux_" << boundary_name << std::endl; + } + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + for (const unsigned int f: cell->face_indices()) + if (cell->at_boundary(f) && + (cell->face(f)->boundary_id() == boundary_id)) + { + // evaluate position of heat flow to write into output file + const bool respect_manifold = true; + const Point midpoint_at_surface = cell->face(f)->center(respect_manifold); + + const double flux_density = heat_flux_and_area[cell->active_cell_index()][f].first / + heat_flux_and_area[cell->active_cell_index()][f].second; + + output << std::setprecision(10) + << midpoint_at_surface + << ' ' + << std::setprecision(10) + << flux_density + << std::endl; + } + + std::string filename = this->get_output_directory() + + "heat_flux_" + boundary_name + "." + + Utilities::int_to_string(this->get_timestep_number(), 5); + if (this->get_parameters().run_postprocessors_on_nonlinear_iterations) + filename.append("." + Utilities::int_to_string (this->get_nonlinear_iteration(), 4)); + + Utilities::collect_and_write_file_content(filename, output.str(), this->get_mpi_communicator()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + namespace internal + { +#define INSTANTIATE(dim) \ + template LinearAlgebra::BlockVector compute_dirichlet_boundary_heat_flux_solution_vector (const SimulatorAccess &simulator_access); + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + + ASPECT_REGISTER_POSTPROCESSOR(HeatFluxMap, + "heat flux map", + "A postprocessor that computes the heat flux " + "density across each boundary in outward " + "direction, i.e., from the domain to the " + "outside. The heat flux is computed as sum " + "of advective heat flux and conductive heat " + "flux through Neumann boundaries, both " + "computed as integral over the boundary area, " + "and conductive heat flux through Dirichlet " + "boundaries, which is computed using the " + "consistent boundary flux method as described " + "in ``Gresho, Lee, Sani, Maslanik, Eaton (1987). " + "The consistent Galerkin FEM for computing " + "derived boundary quantities in thermal and or " + "fluids problems. International Journal for " + "Numerical Methods in Fluids, 7(4), 371-394.''") + } +} diff --git a/source/postprocess/heat_flux_statistics.cc.bak b/source/postprocess/heat_flux_statistics.cc.bak new file mode 100644 index 00000000000..e1c4110c748 --- /dev/null +++ b/source/postprocess/heat_flux_statistics.cc.bak @@ -0,0 +1,160 @@ +/* + Copyright (C) 2011 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + HeatFluxStatistics::execute (TableHandler &statistics) + { + std::vector>> heat_flux_and_area = + internal::compute_heat_flux_through_boundary_faces (*this); + + std::map local_boundary_fluxes; + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + for (const unsigned int f : cell->face_indices()) + if (cell->at_boundary(f)) + { + const types::boundary_id boundary_indicator + = cell->face(f)->boundary_id(); + local_boundary_fluxes[boundary_indicator] += heat_flux_and_area[cell->active_cell_index()][f].first; + } + + // now communicate to get the global values + std::map global_boundary_fluxes; + { + // first collect local values in the same order in which they are listed + // in the set of boundary indicators + const std::set + boundary_indicators + = this->get_geometry_model().get_used_boundary_indicators (); + std::vector local_values; + local_values.reserve(boundary_indicators.size()); + for (const auto p : boundary_indicators) + local_values.emplace_back (local_boundary_fluxes[p]); + + // then collect contributions from all processors + std::vector global_values (local_values.size()); + Utilities::MPI::sum (local_values, this->get_mpi_communicator(), global_values); + + // and now take them apart into the global map again + unsigned int index = 0; + for (std::set::const_iterator + p = boundary_indicators.begin(); + p != boundary_indicators.end(); ++p, ++index) + global_boundary_fluxes[*p] = global_values[index]; + } + + // now add all of the computed heat fluxes to the statistics object + // and create a single string that can be output to the screen + std::ostringstream screen_text; + unsigned int index = 0; + for (std::map::const_iterator + p = global_boundary_fluxes.begin(); + p != global_boundary_fluxes.end(); ++p, ++index) + { + const std::string name = "Outward heat flux through boundary with indicator " + + Utilities::int_to_string(p->first) + + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() + .translate_id_to_symbol_name (p->first)) + + " (W)"; + statistics.add_value (name, p->second); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name, 8); + statistics.set_scientific (name, true); + + // finally have something for the screen + screen_text.precision(4); + screen_text << p->second << " W" + << (index == global_boundary_fluxes.size()-1 ? "" : ", "); + } + + return std::pair ("Heat fluxes through boundary parts:", + screen_text.str()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(HeatFluxStatistics, + "heat flux statistics", + "A postprocessor that computes some " + "statistics about the heat flux " + "density across each boundary in outward " + "direction, i.e., from the domain to the " + "outside. The heat flux is computed as sum " + "of advective heat flux and conductive heat " + "flux through Neumann boundaries, both " + "computed as integral over the boundary area, " + "and conductive heat flux through Dirichlet " + "boundaries, which is computed using the " + "consistent boundary flux method as described " + "in ``Gresho, Lee, Sani, Maslanik, Eaton (1987). " + "The consistent Galerkin FEM for computing " + "derived boundary quantities in thermal and or " + "fluids problems. International Journal for " + "Numerical Methods in Fluids, 7(4), 371-394.''" + "The point-wise heat flux can be obtained from the heat flux map postprocessor, " + "which outputs the heat flux to a file, or the heat flux map " + "visualization postprocessor, which outputs the heat flux for " + "visualization. " + "\n\n" + "As stated, this postprocessor computes the \\textit{outbound} heat " + "flux. If you " + "are interested in the opposite direction, for example from " + "the core into the mantle when the domain describes the " + "mantle, then you need to multiply the result by -1." + "\n\n" + ":::{note}\n" + "In geodynamics, the term ``heat flux'' is often understood " + "to be the quantity $- k \\nabla T$, which is really a heat " + "flux \\textit{density}, i.e., a vector-valued field. In contrast " + "to this, the current postprocessor only computes the integrated " + "flux over each part of the boundary. Consequently, the units of " + "the quantity computed here are $W=\\frac{J}{s}$.\n" + ":::" + "\n\n" + "The ``heat flux densities'' postprocessor computes the same " + "quantity as the one here, but divided by the area of " + "the surface.") + } +} diff --git a/source/postprocess/heating_statistics.cc.bak b/source/postprocess/heating_statistics.cc.bak new file mode 100644 index 00000000000..92d4e91a3a5 --- /dev/null +++ b/source/postprocess/heating_statistics.cc.bak @@ -0,0 +1,166 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + HeatingStatistics::execute (TableHandler &statistics) + { + // create a quadrature formula based on the temperature element alone. + const Quadrature &quadrature_formula = this->introspection().quadratures.temperature; + const unsigned int n_q_points = quadrature_formula.size(); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_gradients | + update_quadrature_points | + update_JxW_values); + + MaterialModel::MaterialModelInputs in(fe_values.n_quadrature_points, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(fe_values.n_quadrature_points, this->n_compositional_fields()); + this->get_heating_model_manager().create_additional_material_model_inputs_and_outputs(in, out); + + std::vector> composition_values (this->n_compositional_fields(),std::vector (quadrature_formula.size())); + + const auto &heating_model_objects = this->get_heating_model_manager().get_active_heating_models(); + const std::vector &heating_model_names = this->get_heating_model_manager().get_active_heating_model_names(); + + HeatingModel::HeatingModelOutputs heating_model_outputs(n_q_points, this->n_compositional_fields()); + + std::ostringstream output; + output.precision(4); + + double average_heating_integral = 0.0; + double total_heating_integral = 0.0; + + std::vector local_heating_integrals (heating_model_objects.size()); + double local_mass = 0.0; + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + in.reinit(fe_values, cell, this->introspection(), this->get_solution()); + + this->get_material_model().fill_additional_material_model_inputs(in, this->get_solution(), fe_values, this->introspection()); + this->get_material_model().evaluate(in, out); + + if (this->get_parameters().formulation_temperature_equation + == Parameters::Formulation::TemperatureEquation::reference_density_profile) + { + // Overwrite the density by the reference density coming from the + // adiabatic conditions as required by the formulation + for (unsigned int q=0; qget_adiabatic_conditions().density(in.position[q]); + } + else if (this->get_parameters().formulation_temperature_equation + == Parameters::Formulation::TemperatureEquation::real_density) + { + // use real density + } + else + AssertThrow(false, ExcNotImplemented()); + + for (unsigned int q=0; q>>::const_iterator + heating_model = heating_model_objects.begin(); + heating_model != heating_model_objects.end(); ++heating_model, ++index) + { + (*heating_model)->evaluate(in, out, heating_model_outputs); + + for (unsigned int q=0; q global_heating_integrals (heating_model_objects.size()); + double global_mass = 0.0; + + // compute the sum over all processors + Utilities::MPI::sum (local_heating_integrals, + this->get_mpi_communicator(), + global_heating_integrals); + global_mass = Utilities::MPI::sum (local_mass, this->get_mpi_communicator()); + + unsigned int index = 0; + for (typename std::list>>::const_iterator + heating_model = heating_model_objects.begin(); + heating_model != heating_model_objects.end(); ++heating_model, ++index) + { + // finally produce something for the statistics file + const std::string name1("Average " + heating_model_names[index] + " rate (W/kg)"); + statistics.add_value (name1, global_heating_integrals[index]/global_mass); + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name1, 8); + statistics.set_scientific (name1, true); + + const std::string name2("Total " + heating_model_names[index] + " rate (W)"); + statistics.add_value (name2, global_heating_integrals[index]); + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name2, 8); + statistics.set_scientific (name2, true); + + total_heating_integral += global_heating_integrals[index]; + } + + average_heating_integral = total_heating_integral/global_mass; + + output << average_heating_integral << " W/kg, " + << total_heating_integral << " W"; + + return std::pair ("Heating rate (average/total): ", + output.str()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(HeatingStatistics, + "heating statistics", + "A postprocessor that computes some statistics about " + "heating, averaged by volume. ") + } +} diff --git a/source/postprocess/interface.cc.bak b/source/postprocess/interface.cc.bak new file mode 100644 index 00000000000..40ae8ab7c28 --- /dev/null +++ b/source/postprocess/interface.cc.bak @@ -0,0 +1,414 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include + + +namespace aspect +{ + namespace Postprocess + { +// ------------------------------ Interface ----------------------------- + + template + std::list + Interface::required_other_postprocessors() const + { + return {}; + } + + + + template + void + Interface::save (std::map &) const + {} + + + + template + void + Interface::load (const std::map &) + {} + + + +// ------------------------------ Manager ----------------------------- + + + template + std::list> + Manager::execute (TableHandler &statistics) + { + // call the execute() functions of all postprocessor objects we have + // here in turns + std::list> output_list; + for (const auto &p : this->plugin_objects) + { + try + { + // first call the update() function. + p->update(); + + // call the execute() function. if it produces any output + // then add it to the list + std::pair output + = p->execute (statistics); + + if (output.first.size() + output.second.size() > 0) + output_list.push_back (output); + } + // postprocessors that throw exceptions usually do not result in + // anything good because they result in an unwinding of the stack + // and, if only one processor triggers an exception, the + // destruction of objects often causes a deadlock. thus, if + // an exception is generated, catch it, print an error message, + // and abort the program + catch (std::exception &exc) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on MPI process <" + << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) + << "> while running postprocessor <" + << typeid(*p).name() + << ">: " << std::endl + << exc.what() << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + // terminate the program! + MPI_Abort (MPI_COMM_WORLD, 1); + } + catch (...) + { + std::cerr << std::endl << std::endl + << "----------------------------------------------------" + << std::endl; + std::cerr << "Exception on MPI process <" + << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) + << "> while running postprocessor <" + << typeid(*p).name() + << ">: " << std::endl; + std::cerr << "Unknown exception!" << std::endl + << "Aborting!" << std::endl + << "----------------------------------------------------" + << std::endl; + + // terminate the program! + MPI_Abort (MPI_COMM_WORLD, 1); + } + } + + return output_list; + } + + +// -------------------------------- Deal with registering postprocessors and automating +// -------------------------------- their setup and selection at run time + + namespace + { + std::tuple + >, + aspect::internal::Plugins::PluginList>> registered_plugins; + } + + + + template + void + Manager::declare_parameters (ParameterHandler &prm) + { + // first declare the postprocessors we know about to + // choose from + prm.enter_subsection("Postprocess"); + { + // construct a string for Patterns::MultipleSelection that + // contains the names of all registered postprocessors + const std::string pattern_of_names + = std::get(registered_plugins).get_pattern_of_names (); + prm.declare_entry("List of postprocessors", + "", + Patterns::MultipleSelection(pattern_of_names), + "A comma separated list of postprocessor objects that should be run " + "at the end of each time step. Some of these postprocessors will " + "declare their own parameters which may, for example, include that " + "they will actually do something only every so many time steps or " + "years. Alternatively, the text `all' indicates that all available " + "postprocessors should be run after each time step.\n\n" + "The following postprocessors are available:\n\n" + + + std::get(registered_plugins).get_description_string()); + } + prm.leave_subsection(); + + // now declare the parameters of each of the registered + // postprocessors in turn + std::get(registered_plugins).declare_parameters (prm); + } + + + + template + void + Manager::parse_parameters (ParameterHandler &prm) + { + Assert (std::get(registered_plugins).plugins != nullptr, + ExcMessage ("No postprocessors registered!?")); + + // first find out which postprocessors are requested + std::vector postprocessor_names; + prm.enter_subsection("Postprocess"); + { + postprocessor_names + = Utilities::split_string_list(prm.get("List of postprocessors")); + AssertThrow(Utilities::has_unique_entries(postprocessor_names), + ExcMessage("The list of strings for the parameter " + "'Postprocess/List of postprocessors' contains entries more than once. " + "This is not allowed. Please check your parameter file.")); + } + prm.leave_subsection(); + + // see if 'all' was selected (or is part of the list). if so + // simply replace the list with one that contains all names + if (std::find (postprocessor_names.begin(), + postprocessor_names.end(), + "all") != postprocessor_names.end()) + { + postprocessor_names.clear(); + for (typename std::list>::PluginInfo>::const_iterator + p = std::get(registered_plugins).plugins->begin(); + p != std::get(registered_plugins).plugins->end(); ++p) + postprocessor_names.push_back (std::get<0>(*p)); + } + + // see if the user specified "global statistics" somewhere; if so, remove + // it from the list because we will *always* want to have it and so + // whether or not it has been explicitly provided by the user makes no + // difference. + std::vector::iterator new_end + = std::remove (postprocessor_names.begin(), + postprocessor_names.end(), + "global statistics"); + if (new_end != postprocessor_names.end()) + postprocessor_names.erase (new_end, postprocessor_names.end()); + + // in any case, put the global statistics postprocessor at the front: + postprocessor_names.insert(postprocessor_names.begin(), "global statistics"); + + // then go through the list, create objects and let them parse + // their own parameters + for (unsigned int name=0; nameplugin_objects.push_back (std::unique_ptr> + (std::get(registered_plugins) + .create_plugin (postprocessor_names[name], + "Postprocessor plugins"))); + if (SimulatorAccess *sim = dynamic_cast*>(&*this->plugin_objects.back())) + sim->initialize_simulator (this->get_simulator()); + + this->plugin_objects.back()->parse_parameters (prm); + this->plugin_objects.back()->initialize (); + + // now see if the newly created postprocessor relies on others. if so, + // go through the list of the ones we already have and if the required + // ones are new, add them to the end of the list we work through + const std::list additional_postprocessors + = this->plugin_objects.back()->required_other_postprocessors (); + + for (const auto &p : additional_postprocessors) + { + AssertThrow (Patterns::Selection(std::get(registered_plugins).get_pattern_of_names ()) + .match (p) == true, + ExcMessage ("Postprocessor <" + postprocessor_names[name] + + "> states that it depends on another postprocessor, <" + + p + + ">, but the latter is not a valid name.")); + + bool already_present = false; + for (const auto &postprocessor_name : postprocessor_names) + if (postprocessor_name == p) + { + already_present = true; + break; + } + + if (already_present == false) + postprocessor_names.push_back (p); + } + } + Assert (postprocessor_names.size() == this->plugin_objects.size(), + ExcInternalError()); + + // we now have matching lists 'this->plugin_objects' and 'postprocessor_names' + // that define which postprocessors we have. we just need to bring them + // into an order so that dependencies run first, and dependents after + // them. the algorithm for creating a sorted list for this works as follows: + // + // while there are postprocessors not yet added to the sorted list: + // - go through the list + // - if we encounter a postprocessor that has not yet been added yet: + // . if all of its dependencies are in the list, add it to the end + // . if at least one of its dependencies are not yet in the list, + // skip it + // + // if we go through a loop where we do not add a postprocessor to the list + // but there are still ones that haven't been added to the list, then we + // have found a cycle in the dependencies and that is clearly a problem + std::vector already_assigned (this->plugin_objects.size(), false); + std::vector sorted_names; + std::list>> sorted_postprocessors; + while (sorted_names.size() < this->plugin_objects.size()) + { + bool at_least_one_element_added = false; + + { + typename std::list>>::iterator + pp = this->plugin_objects.begin(); + for (unsigned int i=0; i deps = (*pp)->required_other_postprocessors(); + bool unmet_dependencies = false; + for (const auto &p : deps) + if (std::find (sorted_names.begin(), + sorted_names.end(), + p) == sorted_names.end()) + { + unmet_dependencies = true; + break; + } + + // if we have unmet dependencies, there is nothing we can do + // right now for this postprocessor (but we will come back for it) + // + // if there are none, add this postprocessor. using move semantics + // removes the postprocessor from the 'this->plugin_objects' array, + // which is ok since we will swap the two arrays at the end of the + // function. + if (unmet_dependencies == false) + { + sorted_names.push_back (postprocessor_names[i]); + sorted_postprocessors.emplace_back (std::move(*pp)); + already_assigned[i] = true; + at_least_one_element_added = true; + } + } + } + + // check that we have added at least one element; if not, there is a cycle + if (at_least_one_element_added == false) + { + std::ostringstream out; + out << "While sorting postprocessors by their dependencies, " + "ASPECT encountered a cycle in dependencies. The following " + "postprocessors are involved:\n"; + typename std::list>>::const_iterator + pp = this->plugin_objects.begin(); + for (unsigned int i=0; i "; + const std::list deps = (*pp)->required_other_postprocessors(); + for (const auto &p : deps) + out << "'" << p << "' "; + out << std::endl; + } + AssertThrow (false, ExcMessage(out.str())); + } + } + Assert (postprocessor_names.size() == sorted_names.size(), + ExcInternalError()); + Assert (sorted_postprocessors.size() == sorted_names.size(), + ExcInternalError()); + Assert (std::find (already_assigned.begin(), already_assigned.end(), false) == already_assigned.end(), + ExcInternalError()); + + // finally swap the unsorted list with the sorted list and only + // keep the latter + this->plugin_objects.swap (sorted_postprocessors); + } + + + template + void + Manager::register_postprocessor (const std::string &name, + const std::string &description, + void (*declare_parameters_function) (ParameterHandler &), + std::unique_ptr> (*factory_function) ()) + { + std::get(registered_plugins).register_plugin (name, + description, + declare_parameters_function, + factory_function); + } + + + + template + void + Manager::write_plugin_graph (std::ostream &out) + { + std::get(registered_plugins).write_plugin_graph ("Postprocessor interface", + out); + } + + } +} + + +// explicit instantiations +namespace aspect +{ + namespace internal + { + namespace Plugins + { + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + template <> + std::list>::PluginInfo> * + internal::Plugins::PluginList>::plugins = nullptr; + } + } + + namespace Postprocess + { +#define INSTANTIATE(dim) \ + template class Interface; \ + template class Manager; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } +} diff --git a/source/postprocess/load_balance_statistics.cc.bak b/source/postprocess/load_balance_statistics.cc.bak new file mode 100644 index 00000000000..2749d974c50 --- /dev/null +++ b/source/postprocess/load_balance_statistics.cc.bak @@ -0,0 +1,111 @@ +/* + Copyright (C) 2016 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include + +#include + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + LoadBalanceStatistics::execute (TableHandler &statistics) + { + const unsigned int locally_owned_active_cells = this->get_triangulation().n_locally_owned_active_cells(); + const dealii::Utilities::MPI::MinMaxAvg cell_distribution + = dealii::Utilities::MPI::min_max_avg(locally_owned_active_cells, + this->get_mpi_communicator()); + + statistics.add_value ("Minimal cells per process", + static_cast(cell_distribution.min)); + statistics.add_value ("Maximal cells per process", + static_cast(cell_distribution.max)); + statistics.add_value ("Average cells per process", + cell_distribution.avg); + + if (this->n_particle_worlds() > 0) + { + const unsigned int locally_owned_particles = this->get_particle_world(0). + get_particle_handler().n_locally_owned_particles(); + const dealii::Utilities::MPI::MinMaxAvg particles_per_process = + dealii::Utilities::MPI::min_max_avg(locally_owned_particles,this->get_mpi_communicator()); + + statistics.add_value ("Minimal particles per process", + static_cast(particles_per_process.min)); + statistics.add_value ("Maximal particles per process", + static_cast(particles_per_process.max)); + statistics.add_value ("Average particles per process", + particles_per_process.avg); + + const double local_ratio = (locally_owned_active_cells != 0) + ? + static_cast(locally_owned_particles) + / static_cast(locally_owned_active_cells) + : + 0.0; + + const dealii::Utilities::MPI::MinMaxAvg particle_to_cell_ratio + = dealii::Utilities::MPI::min_max_avg(local_ratio, + this->get_mpi_communicator()); + + statistics.add_value ("Minimal local particle to cell ratio", particle_to_cell_ratio.min); + statistics.add_value ("Maximal local particle to cell ratio", particle_to_cell_ratio.max); + statistics.add_value ("Average local particle to cell ratio", particle_to_cell_ratio.avg); + } + + std::ostringstream output; + output.precision(4); + output << cell_distribution.min << '/' + << cell_distribution.max << '/' + << cell_distribution.avg; + + return std::pair ("Cells per process min/max/avg:", + output.str()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(LoadBalanceStatistics, + "load balance statistics", + "A postprocessor that computes statistics about " + "the distribution of cells, and if present particles " + "across subdomains. " + "In particular, it computes maximal, average and " + "minimal number of cells across all ranks. " + "If there are particles it also computes the " + "maximal, average, and minimum number of particles across " + "all ranks, and maximal, average, and minimal ratio " + "between local number of particles and local number " + "of cells across all processes. All of these numbers " + "can be useful to assess the load balance between " + "different MPI ranks, as the difference between the " + "minimal and maximal load should be as small as " + "possible.") + } +} diff --git a/source/postprocess/mass_flux_statistics.cc.bak b/source/postprocess/mass_flux_statistics.cc.bak new file mode 100644 index 00000000000..55f09956ba6 --- /dev/null +++ b/source/postprocess/mass_flux_statistics.cc.bak @@ -0,0 +1,188 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + MassFluxStatistics::execute (TableHandler &statistics) + { + const std::string unit = (this->convert_output_to_years()) + ? + "kg/yr" + : + "kg/s"; + const double in_years = (this->convert_output_to_years()) + ? + year_in_seconds + : + 1.0; + + // create a quadrature formula based on the temperature element alone. + const Quadrature &quadrature_formula = this->introspection().face_quadratures.velocities; + + FEFaceValues fe_face_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | update_gradients | + update_normal_vectors | + update_quadrature_points | update_JxW_values); + + std::vector> composition_values (this->n_compositional_fields(),std::vector (quadrature_formula.size())); + + std::map local_boundary_fluxes; + + MaterialModel::MaterialModelInputs in(fe_face_values.n_quadrature_points, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(fe_face_values.n_quadrature_points, this->n_compositional_fields()); + in.requested_properties = MaterialModel::MaterialProperties::density; + + // for every surface face on which it makes sense to compute a + // mass flux and that is owned by this processor, + // integrate the normal mass flux given by the formula + // j = \rho * v * n + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + for (const unsigned int f : cell->face_indices()) + if (cell->at_boundary(f)) + { + fe_face_values.reinit (cell, f); + // Set use_strain_rates to false since we don't need viscosity + in.reinit(fe_face_values, cell, this->introspection(), this->get_solution()); + + this->get_material_model().evaluate(in, out); + + + double local_normal_flux = 0; + for (unsigned int q=0; qface(f)->boundary_id(); + local_boundary_fluxes[boundary_indicator] += local_normal_flux * in_years; + } + + // now communicate to get the global values + std::map global_boundary_fluxes; + { + // first collect local values in the same order in which they are listed + // in the set of boundary indicators + const std::set + boundary_indicators + = this->get_geometry_model().get_used_boundary_indicators (); + std::vector local_values; + local_values.reserve(boundary_indicators.size()); + for (const auto p : boundary_indicators) + local_values.push_back (local_boundary_fluxes[p]); + + // then collect contributions from all processors + std::vector global_values (local_values.size()); + Utilities::MPI::sum (local_values, this->get_mpi_communicator(), global_values); + + // and now take them apart into the global map again + unsigned int index = 0; + for (std::set::const_iterator + p = boundary_indicators.begin(); + p != boundary_indicators.end(); ++p, ++index) + global_boundary_fluxes[*p] = global_values[index]; + } + + // now add all of the computed mass fluxes to the statistics object + // and create a single string that can be output to the screen + std::ostringstream screen_text; + unsigned int index = 0; + for (std::map::const_iterator + p = global_boundary_fluxes.begin(); + p != global_boundary_fluxes.end(); ++p, ++index) + { + const std::string name = "Outward mass flux through boundary with indicator " + + Utilities::int_to_string(p->first) + + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() + .translate_id_to_symbol_name (p->first)) + + " (" + unit + ")"; + statistics.add_value (name, p->second); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name, 8); + statistics.set_scientific (name, true); + + // finally have something for the screen + screen_text.precision(4); + screen_text << p->second << ' ' << unit + << (index == global_boundary_fluxes.size()-1 ? "" : ", "); + } + + return std::pair ("Mass fluxes through boundary parts:", + screen_text.str()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(MassFluxStatistics, + "mass flux statistics", + "A postprocessor that computes some statistics about " + "the mass flux across boundaries. For each boundary " + "indicator (see your geometry description for which boundary " + "indicators are used), the mass flux is computed in outward " + "direction, i.e., from the domain to the outside, using the " + "formula $\\int_{\\Gamma_i} \\rho \\mathbf v \\cdot \\mathbf n$ " + "where $\\Gamma_i$ is the part of the boundary with indicator $i$, " + "$\\rho$ is the density as reported by the material model, " + "$\\mathbf v$ is the velocity, and $\\mathbf n$ is the outward normal. " + "\n\n" + "As stated, this postprocessor computes the \\textit{outbound} mass " + "flux. If you " + "are interested in the opposite direction, for example from " + "the core into the mantle when the domain describes the " + "mantle, then you need to multiply the result by -1." + "\n\n" + ":::{note}\n" + "In geodynamics, the term ``mass flux'' is often understood " + "to be the quantity $\\rho \\mathbf v$, which is really a mass " + "flux \\textit{density}, i.e., a vector-valued field. In contrast " + "to this, the current postprocessor only computes the integrated " + "flux over each part of the boundary. Consequently, the units of " + "the quantity computed here are $\\frac{kg}{s}$.\n" + ":::") + } +} diff --git a/source/postprocess/material_statistics.cc.bak b/source/postprocess/material_statistics.cc.bak new file mode 100644 index 00000000000..9c7f6157417 --- /dev/null +++ b/source/postprocess/material_statistics.cc.bak @@ -0,0 +1,128 @@ +/* + Copyright (C) 2018 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + MaterialStatistics::execute (TableHandler &statistics) + { + // create a quadrature formula based on the temperature element alone. + const Quadrature &quadrature_formula = this->introspection().quadratures.temperature; + const unsigned int n_q_points = quadrature_formula.size(); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_gradients | + update_quadrature_points | + update_JxW_values); + + MaterialModel::MaterialModelInputs in(fe_values.n_quadrature_points, this->n_compositional_fields()); + MaterialModel::MaterialModelOutputs out(fe_values.n_quadrature_points, this->n_compositional_fields()); + in.requested_properties = MaterialModel::MaterialProperties::density | MaterialModel::MaterialProperties::viscosity; + + double local_volume = 0.0; + double local_mass = 0.0; + double local_viscosity = 0.0; + + // compute the integral quantities by quadrature + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + in.reinit(fe_values, cell, this->introspection(), this->get_solution()); + + this->get_material_model().fill_additional_material_model_inputs(in, this->get_solution(), fe_values, this->introspection()); + this->get_material_model().evaluate(in, out); + + for (unsigned int q=0; qget_mpi_communicator()); + const double global_viscosity = Utilities::MPI::sum (local_viscosity, this->get_mpi_communicator()); + const double global_volume = Utilities::MPI::sum (local_volume, this->get_mpi_communicator()); + const double average_density = global_mass / global_volume; + const double average_viscosity = global_viscosity / global_volume; + + const std::string name1("Average density (kg/m^3)"); + statistics.add_value (name1, average_density); + statistics.set_precision (name1, 8); + statistics.set_scientific (name1, true); + + const std::string name2("Average viscosity (Pa s)"); + statistics.add_value (name2, average_viscosity); + statistics.set_precision (name2, 8); + statistics.set_scientific (name2, true); + + const std::string name3("Total mass (kg)"); + statistics.add_value (name3, global_mass); + statistics.set_precision (name3, 8); + statistics.set_scientific (name3, true); + + std::ostringstream output; + output.precision(4); + + output << average_density << " kg/m^3, " + << average_viscosity << " Pa s, " + << global_mass << " kg"; + + return std::pair ("Average density / Average viscosity / Total mass: ", + output.str()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(MaterialStatistics, + "material statistics", + "A postprocessor that computes some statistics about " + "the material properties. In particular, it computes the " + "volume-averages of the density and viscosity, and the " + "total mass in the model. Specifically, it implements " + "the following formulas in each time step: " + "$\\left<\\rho\\right> = \\frac{1}{|\\Omega|} \\int_\\Omega \\rho(\\mathbf x) \\, \\text{d}x$, " + "$\\left<\\eta\\right> = \\frac{1}{|\\Omega|} \\int_\\Omega \\eta(\\mathbf x) \\, \\text{d}x$, " + "$M = \\int_\\Omega \\rho(\\mathbf x) \\, \\text{d}x$, " + "where $|\\Omega|$ is the volume of the domain.") + } +} diff --git a/source/postprocess/matrix_statistics.cc.bak b/source/postprocess/matrix_statistics.cc.bak new file mode 100644 index 00000000000..89409b70b32 --- /dev/null +++ b/source/postprocess/matrix_statistics.cc.bak @@ -0,0 +1,119 @@ +/* + Copyright (C) 2016 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include + +#include +#include + + +namespace +{ + const std::string + get_stats(const aspect::LinearAlgebra::BlockSparseMatrix &matrix, + const std::string &matrix_name, + const MPI_Comm comm) + { + std::ostringstream output; + + // convert from bytes into Mb + const double mb = 1024*1024; + // sum up local matrix memory usage + double global_matrix_memory_consumption = dealii::Utilities::MPI::sum(matrix.memory_consumption(), + comm); + output << "\nTotal " << matrix_name << " memory consumption: " + << std::fixed << std::setprecision(2) << global_matrix_memory_consumption/mb + << " MB." << std::endl; + + // output number of nonzero elements in matrix. Do so with 1000s separator + // since they are frequently large; this was previously done by using the empty + // string locale, but creating std::locale with an empty string caused problems + // on some platforms, so the functionality to catch the exception and ignore + // is kept here, even though explicitly setting a facet should always work. + try + { + // Imbue the stream with a locale that does the right thing. The + // locale is responsible for later deleting the object pointed + // to by the last argument (the "facet"), see + // https://en.cppreference.com/w/cpp/locale/locale/locale + output.imbue(std::locale(std::locale(), + new aspect::Utilities::ThousandSep)); + } + catch (const std::runtime_error &e) + { + // If the locale doesn't work, just give up + } + + + output << "Total " << matrix_name << " nnz: " + << matrix.n_nonzero_elements() << std::endl; + + // output number of nonzero elements in each matrix block + output << matrix_name << " nnz by block: " << std::endl; + for (unsigned int i=0; i + std::pair + MatrixStatistics::execute (TableHandler &) + { + std::ostringstream output; + output << get_stats(this->get_system_matrix(), + "system matrix", + this->get_mpi_communicator()); + output << get_stats(this->get_system_preconditioner_matrix(), + "system preconditioner matrix", + this->get_mpi_communicator()); + + return std::pair ("", + output.str()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(MatrixStatistics, + "matrix statistics", + "A postprocessor that computes some statistics about " + "the matrices. " + "In particular, it outputs total memory consumption, " + "total non-zero elements, and non-zero elements per " + "block, for system matrix and system preconditioner matrix.") + } +} diff --git a/source/postprocess/max_depth_field.cc.bak b/source/postprocess/max_depth_field.cc.bak new file mode 100644 index 00000000000..d0cba1d2a56 --- /dev/null +++ b/source/postprocess/max_depth_field.cc.bak @@ -0,0 +1,131 @@ +/* + Copyright (C) 2021 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file doc/COPYING. If not see + . +*/ + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + MaxDepthField::execute (TableHandler &statistics) + { + // create a quadrature formula based on the compositional element alone. + // be defensive about determining that a compositional field actually exists + AssertThrow(this->n_compositional_fields() > 0, + ExcMessage("This postprocessor cannot be used without compositional fields.")); + const Quadrature &quadrature_formula = this->introspection().quadratures.compositional_fields; + + const unsigned int n_q_points = quadrature_formula.size(); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_quadrature_points); + + std::vector compositional_values(n_q_points); + std::vector> position_values(n_q_points); + + std::vector local_max_depth(this->n_compositional_fields(), std::numeric_limits::lowest()); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + + position_values = fe_values.get_quadrature_points(); + + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + { + fe_values[this->introspection().extractors.compositional_fields[c]].get_function_values(this->get_solution(), compositional_values); + + for (unsigned int q = 0; q < n_q_points; ++q) + { + const double depth = this->get_geometry_model().depth(position_values[q]); + if (compositional_values[q] >= 0.5 && depth > local_max_depth[c]) + local_max_depth[c] = depth; + } + } + } + + // compute the max over all processors + std::vector global_max_depth(this->n_compositional_fields()); + Utilities::MPI::max (local_max_depth, + this->get_mpi_communicator(), + global_max_depth); + + // finally produce something for the statistics file + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + { + statistics.add_value("Max depth [m] for composition " + this->introspection().name_for_compositional_index(c), + global_max_depth[c]); + } + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + { + const std::string columns[] = {"Max depth [m] for composition " + this->introspection().name_for_compositional_index(c)}; + for (const auto &col: columns) + { + statistics.set_precision(col, 8); + statistics.set_scientific(col, true); + } + } + + std::ostringstream output; + output.precision(4); + for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) + { + output << global_max_depth[c]; + if (c + 1 != this->n_compositional_fields()) + output << " // "; + } + return std::pair("Compositions max depth [m]:", + output.str()); + + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(MaxDepthField, + "maximum depth of field", + "A postprocessor that for each compositional field " + "outputs the largest depth at which " + "a quadrature point is found where the field " + "has a value of 0.5 or larger. For fields that do not " + "represent materials, but for example track a certain quantity " + "like strain, this value of 0.5 does not necessarily make sense. ") + } +} diff --git a/source/postprocess/melt_statistics.cc.bak b/source/postprocess/melt_statistics.cc.bak new file mode 100644 index 00000000000..22bb2ce3829 --- /dev/null +++ b/source/postprocess/melt_statistics.cc.bak @@ -0,0 +1,152 @@ +/* + Copyright (C) 2015 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + MeltStatistics::execute (TableHandler &statistics) + { + // create a quadrature formula based on the temperature element alone. + const Quadrature &quadrature_formula = this->introspection().quadratures.temperature; + const unsigned int n_q_points = quadrature_formula.size(); + std::vector> composition_values (this->n_compositional_fields(), + std::vector (n_q_points)); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_gradients | + update_quadrature_points | + update_JxW_values); + + MaterialModel::MaterialModelInputs in(fe_values.n_quadrature_points, this->n_compositional_fields()); + + std::ostringstream output; + output.precision(4); + + double local_melt_integral = 0.0; + double local_min_melt = std::numeric_limits::max(); + double local_max_melt = std::numeric_limits::lowest(); + + // compute the integral quantities by quadrature + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + // fill material model inputs + fe_values.reinit (cell); + in.reinit(fe_values, cell, this->introspection(), this->get_solution()); + + // we can only postprocess melt fractions if the material model that is used + // in the simulation has implemented them + // otherwise, set them to zero + std::vector melt_fractions(n_q_points, 0.0); + if (MaterialModel::MeltFractionModel::is_melt_fraction_model(this->get_material_model())) + MaterialModel::MeltFractionModel::as_melt_fraction_model(this->get_material_model()) + .melt_fractions(in, melt_fractions); + + for (unsigned int q=0; qget_mpi_communicator()); + double global_min_melt = 0; + double global_max_melt = 0; + + // now do the reductions that are + // min/max operations. do them in + // one communication by multiplying + // one value by -1 + { + double local_values[2] = { -local_min_melt, local_max_melt }; + double global_values[2]; + + Utilities::MPI::max (local_values, this->get_mpi_communicator(), global_values); + + global_min_melt = -global_values[0]; + global_max_melt = global_values[1]; + } + + + // finally produce something for the statistics file + statistics.add_value ("Minimal melt fraction", + global_min_melt); + statistics.add_value ("Total melt volume", + global_melt_integral); + statistics.add_value ("Maximal melt fraction", + global_max_melt); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + { + const char *columns[] = { "Minimal melt fraction", + "Total melt volume", + "Maximal melt fraction" + }; + for (auto &column : columns) + { + statistics.set_precision (column, 8); + statistics.set_scientific (column, true); + } + } + + output << global_min_melt << ", " + << global_melt_integral << ", " + << global_max_melt; + + return std::pair ("Melt fraction min/total/max:", + output.str()); + + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(MeltStatistics, + "melt statistics", + "A postprocessor that computes some statistics about " + "the melt (volume) fraction. If the material model " + "does not implement a melt fraction function, the output is " + "set to zero.") + } +} diff --git a/source/postprocess/memory_statistics.cc.bak b/source/postprocess/memory_statistics.cc.bak new file mode 100644 index 00000000000..4bab32297b7 --- /dev/null +++ b/source/postprocess/memory_statistics.cc.bak @@ -0,0 +1,141 @@ +/* + Copyright (C) 2016 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + + +#include +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + MemoryStatistics::execute (TableHandler &statistics) + { + // memory consumption: + const double mb = 1024*1024; // convert from bytes into mb + + statistics.add_value ("System matrix memory consumption (MB) ", this->get_system_matrix().memory_consumption()/mb); + statistics.add_value ("Triangulation memory consumption (MB) ", this->get_triangulation().memory_consumption()/mb); + statistics.add_value ("p4est memory consumption (MB) ", this->get_triangulation().memory_consumption_p4est()/mb); + + double dof_handler_mem = this->get_dof_handler().memory_consumption(); + double constraints_mem = this->get_current_constraints().memory_consumption(); + if (this->is_stokes_matrix_free()) + { + dof_handler_mem += this->get_stokes_matrix_free().get_dof_handler_v().memory_consumption() + + this->get_stokes_matrix_free().get_dof_handler_p().memory_consumption(); + + dof_handler_mem += this->get_stokes_matrix_free().get_dof_handler_projection().memory_consumption(); + + constraints_mem += this->get_stokes_matrix_free().get_constraints_v().memory_consumption() + + this->get_stokes_matrix_free().get_constraints_p().memory_consumption(); + } + statistics.add_value ("DoFHandler memory consumption (MB) ", dof_handler_mem/mb); + statistics.add_value ("AffineConstraints memory consumption (MB) ", constraints_mem/mb); + + statistics.add_value ("Solution vector memory consumption (MB) ", this->get_solution().memory_consumption()/mb); + + if (this->is_stokes_matrix_free()) + { + const double mg_transfer_mem = this->get_stokes_matrix_free().get_mg_transfer_A().memory_consumption() + + this->get_stokes_matrix_free().get_mg_transfer_S().memory_consumption(); + statistics.add_value ("MGTransfer memory consumption (MB) ", mg_transfer_mem/mb); + + const double cell_data_mem = this->get_stokes_matrix_free().get_cell_data_memory_consumption(); + statistics.add_value ("Matrix-free cell data memory consumption (MB) ", cell_data_mem/mb); + } + + if (output_vmpeak) + { + // allow disabling of the output because this is not stable in automated tests: + dealii::Utilities::System::MemoryStats stats; + dealii::Utilities::System::get_memory_stats(stats); + const double max_vmpeak = dealii::Utilities::MPI::max(stats.VmPeak/1024.0, this->get_mpi_communicator()); + statistics.add_value ("Peak virtual memory usage (VmPeak) (MB) ", max_vmpeak); + } + + std::ostringstream output; + output << std::fixed << std::setprecision(2) << this->get_system_matrix().memory_consumption()/mb << " MB"; + + return std::pair ("System matrix memory consumption: ", + output.str()); + + } + + + + + template + void + MemoryStatistics::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Memory statistics"); + { + prm.declare_entry ("Output peak virtual memory (VmPeak)", "true", + Patterns::Bool(), + "If set to 'true', also output the peak virtual memory " + "usage (computed as the maximum over all processors)."); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + + + template + void + MemoryStatistics::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Memory statistics"); + { + output_vmpeak = prm.get_bool ("Output peak virtual memory (VmPeak)"); + } + prm.leave_subsection(); + } + prm.leave_subsection(); + } + } +} + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(MemoryStatistics, + "memory statistics", + "A postprocessor that computes some statistics about " + "the memory consumption. " + "In particular, it computes the memory usage of the " + "system matrix, triangulation, p4est, " + "DoFHandler, current constraints, solution vector, " + "and peak virtual memory usage, all in MB. " + "It also outputs the memory usage of the system " + "matrix to the screen.") + } +} diff --git a/source/postprocess/mobility_statistics.cc.bak b/source/postprocess/mobility_statistics.cc.bak new file mode 100644 index 00000000000..f403f11a98c --- /dev/null +++ b/source/postprocess/mobility_statistics.cc.bak @@ -0,0 +1,156 @@ +/* + Copyright (C) 2011 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + MobilityStatistics::execute (TableHandler &statistics) + { + // create a quadrature formula for the velocity for the volume of cells + const Quadrature &quadrature_formula = this->introspection().quadratures.velocities; + const unsigned int n_q_points = quadrature_formula.size(); + + FEValues fe_values (this->get_mapping(), + this->get_fe(), + quadrature_formula, + update_values | + update_quadrature_points | + update_JxW_values); + + std::vector> velocity_values(n_q_points); + + // create a quadrature formula for the velocity for the surface of cells + const Quadrature &quadrature_formula_face + = this->introspection().face_quadratures.velocities; + const unsigned int n_q_points_face = quadrature_formula_face.size(); + + FEFaceValues fe_face_values (this->get_mapping(), + this->get_fe(), + quadrature_formula_face, + update_values | + update_JxW_values | + update_quadrature_points); + + std::vector> surface_velocity_values (n_q_points_face); + + double local_velocity_square_integral = 0; + double local_velocity_square_integral_top_boundary = 0; + double local_top_boundary_area = 0; + + const std::set + boundary_indicators + = this->get_geometry_model().get_used_boundary_indicators (); + const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); + + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + fe_values.reinit (cell); + // extract velocities + fe_values[this->introspection().extractors.velocities].get_function_values (this->get_solution(), + velocity_values); + for (unsigned int q = 0; q < n_q_points; ++q) + { + local_velocity_square_integral += velocity_values[q].norm_square() * + fe_values.JxW(q); + } + + // now for the surface cells only + for (const unsigned int f : cell->face_indices()) + if (cell->face(f)->boundary_id() == top_boundary_id) + { + fe_face_values.reinit (cell, f); + // extract velocities + fe_face_values[this->introspection().extractors.velocities].get_function_values (this->get_solution(), + surface_velocity_values); + + // determine the squared velocity on the face + for (unsigned int q = 0; q < n_q_points_face; ++q) + { + const double JxW = fe_face_values.JxW(q); + local_velocity_square_integral_top_boundary += surface_velocity_values[q].norm_square() * JxW; + local_top_boundary_area += JxW; + } + } + } + + // now communicate to get the global values and convert to rms + const double global_velocity_square_integral + = Utilities::MPI::sum (local_velocity_square_integral, this->get_mpi_communicator()); + + const double global_rms_vel = std::sqrt(global_velocity_square_integral) / + std::sqrt(this->get_volume()); + + const double global_top_velocity_square_integral = Utilities::MPI::sum(local_velocity_square_integral_top_boundary, this->get_mpi_communicator()); + const double global_top_boundary_area_integral = Utilities::MPI::sum(local_top_boundary_area, this->get_mpi_communicator()); + + const double global_top_rms_vel = std::sqrt(global_top_velocity_square_integral) / + std::sqrt(global_top_boundary_area_integral); + + // now add the computed rms velocities to the statistics object + // and create a single string that can be output to the screen + const double mobility = global_top_rms_vel / global_rms_vel; + const std::string name_mobility = "Mobility"; + + statistics.add_value (name_mobility, + mobility); + + // also make sure that the other columns filled by this object + // all show up with sufficient accuracy and in scientific notation + statistics.set_precision (name_mobility, 8); + statistics.set_scientific (name_mobility, true); + + std::ostringstream output; + output.precision(3); + output << mobility; + + return std::pair ("Mobility:", + output.str()); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(MobilityStatistics, + "mobility statistics", + "A postprocessor that computes some statistics about mobility " + "following Tackley (2000) and Lourenco et al. (2020).") + } +} diff --git a/source/postprocess/particle_count_statistics.cc.bak b/source/postprocess/particle_count_statistics.cc.bak new file mode 100644 index 00000000000..8b2ca0c952b --- /dev/null +++ b/source/postprocess/particle_count_statistics.cc.bak @@ -0,0 +1,97 @@ +/* + Copyright (C) 2016 - 2021 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include + +#include +#include + + +namespace aspect +{ + namespace Postprocess + { + template + std::pair + ParticleCountStatistics::execute (TableHandler &statistics) + { + const Particle::ParticleHandler &particle_handler = + this->get_particle_world(0).get_particle_handler(); + + unsigned int local_min_particles = std::numeric_limits::max(); + unsigned int local_max_particles = 0; + const Particle::types::particle_index global_particles = this->get_particle_world(0).n_global_particles(); + + // compute local min/max + for (const auto &cell : this->get_dof_handler().active_cell_iterators()) + if (cell->is_locally_owned()) + { + const unsigned int particles_in_cell = particle_handler.n_particles_in_cell(cell); + local_min_particles = std::min(local_min_particles,particles_in_cell); + local_max_particles = std::max(local_max_particles,particles_in_cell); + } + + // now do the reductions over all processors + const unsigned int global_min_particles = Utilities::MPI::min (local_min_particles, + this->get_mpi_communicator()); + const unsigned int global_max_particles = Utilities::MPI::max (local_max_particles, + this->get_mpi_communicator()); + + // finally produce something for the statistics file + statistics.add_value ("Minimal particles per cell: ", global_min_particles); + statistics.add_value ("Average particles per cell: ", global_particles / this->get_triangulation().n_global_active_cells()); + statistics.add_value ("Maximal particles per cell: ", global_max_particles); + + std::ostringstream output; + output << global_min_particles << ", " + << global_particles / this->get_triangulation().n_global_active_cells() << ", " + << global_max_particles; + + return std::pair ("Particle count per cell min/avg/max:", + output.str()); + } + + + + template + std::list + ParticleCountStatistics::required_other_postprocessors() const + { + return {"particles"}; + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + ASPECT_REGISTER_POSTPROCESSOR(ParticleCountStatistics, + "particle count statistics", + "A postprocessor that computes some statistics about " + "the particle distribution, if present in this simulation. " + "In particular, it computes minimal, average and maximal " + "values of particles per cell in the global domain.") + } +} diff --git a/source/postprocess/particles.cc.bak b/source/postprocess/particles.cc.bak new file mode 100644 index 00000000000..126f6a1f607 --- /dev/null +++ b/source/postprocess/particles.cc.bak @@ -0,0 +1,758 @@ +/* + Copyright (C) 2011 - 2023 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace aspect +{ + namespace Postprocess + { + namespace internal + { + template + void + ParticleOutput::build_patches(const dealii::Particles::ParticleHandler &particle_handler, + const aspect::Particle::Property::ParticlePropertyInformation &property_information, + const std::vector &exclude_output_properties, + const bool only_group_3d_vectors) + { + // First store the names of the data fields that should be written + dataset_names.reserve(property_information.n_components()+1); + dataset_names.emplace_back("id"); + + // This is a map from an index for the particle property vector to an index in the output + // vector. Values equal 0 indicate a property will not be written, values bigger 0 + // indicate into which output entry the property value should be written. + std::vector property_index_to_output_index(property_information.n_components(),0); + + if (std::find(exclude_output_properties.begin(), + exclude_output_properties.end(), + "all") + == exclude_output_properties.end()) + { + // Start the output index from 1, because 0 is occupied by the "id" + unsigned int output_index = 1; + for (unsigned int field_index = 0; field_index < property_information.n_fields(); ++field_index) + { + // Determine some info about the field. + const unsigned n_components = property_information.get_components_by_field_index(field_index); + const std::string field_name = property_information.get_field_name_by_index(field_index); + const unsigned int field_position = property_information.n_fields() == 0 + ? + 0 + : + property_information.get_position_by_field_index(field_index); + + // HDF5 only supports 3d vector output, therefore only treat output fields as vector if we + // have a dimension of 3 and 3 components. + const bool field_is_vector = (only_group_3d_vectors == false + ? + n_components == dim + : + dim == 3 && n_components == 3); + + // Determine if this field should be excluded, if so, skip it + bool exclude_property = false; + for (const auto &property : exclude_output_properties) + if (field_name.find(property) != std::string::npos) + { + exclude_property = true; + break; + } + + if (exclude_property == false) + { + // For each component record its name and position in output vector + for (unsigned int component_index=0; component_index::particle_iterator particle = particle_handler.begin(); + + for (unsigned int i=0; particle != particle_handler.end(); ++particle, ++i) + { + patches[i].vertices[0] = particle->get_location(); + patches[i].patch_index = i; + + patches[i].data.reinit(dataset_names.size(),1); + + patches[i].data(0,0) = particle->get_id(); + + if (particle->has_properties()) + { + const ArrayView properties = particle->get_properties(); + + for (unsigned int property_index = 0; property_index < properties.size(); ++property_index) + { + if (property_index_to_output_index[property_index] > 0) + patches[i].data(property_index_to_output_index[property_index],0) = properties[property_index]; + } + } + } + } + + template + const std::vector> & + ParticleOutput::get_patches () const + { + return patches; + } + + template + std::vector + ParticleOutput::get_dataset_names () const + { + return dataset_names; + } + + template + std::vector< + std::tuple> + ParticleOutput::get_nonscalar_data_ranges () const + { + return vector_datasets; + } + } + + template + Particles::Particles () + : + // the following value is later read from the input file + output_interval (0), + // initialize this to a nonsensical value; set it to the actual time + // the first time around we get to check it + last_output_time (std::numeric_limits::quiet_NaN()) + ,output_file_number (numbers::invalid_unsigned_int), + group_files(0), + write_in_background_thread(false) + {} + + + + template + Particles::~Particles () + { + // make sure a thread that may still be running in the background, + // writing data, finishes + if (background_thread.joinable()) + background_thread.join (); + } + + + + template + // We need to pass the arguments by value, as this function can be called on a separate thread: + void Particles::writer (const std::string &filename, //NOLINT(performance-unnecessary-value-param) + const std::string &temporary_output_location, //NOLINT(performance-unnecessary-value-param) + const std::string &file_contents) + { + std::string tmp_filename = filename; + if (temporary_output_location != "") + { + tmp_filename = temporary_output_location + "/aspect.tmp.XXXXXX"; + + // Create the temporary file; get at the actual filename + // by using a C-style string that mkstemp will then overwrite + std::vector tmp_filename_x (tmp_filename.size()+1); + std::strcpy(tmp_filename_x.data(), tmp_filename.c_str()); + const int tmp_file_desc = mkstemp(tmp_filename_x.data()); + tmp_filename = tmp_filename_x.data(); + + // If we failed to create the temp file, just write directly to the target file. + // We also provide a warning about this fact. There are places where + // this fails *on every node*, so we will get a lot of warning messages + // into the output; in these cases, just writing multiple pieces to + // std::cerr will produce an unreadable mass of text; rather, first + // assemble the error message completely, and then output it atomically + if (tmp_file_desc == -1) + { + const std::string x = ("***** WARNING: could not create temporary file <" + + + tmp_filename + + + ">, will output directly to final location. This may negatively " + "affect performance. (On processor " + + Utilities::int_to_string(Utilities::MPI::this_mpi_process (MPI_COMM_WORLD)) + + ".)\n"); + + std::cerr << x << std::flush; + + tmp_filename = filename; + } + else + close(tmp_file_desc); + } + + std::ofstream out(tmp_filename); + + AssertThrow (out, ExcMessage(std::string("Trying to write to file <") + + filename + + ">, but the file can't be opened!")); + + // now write and then move the tmp file to its final destination + // if necessary + out << file_contents; + out.close (); + + if (tmp_filename != filename) + { + std::string command = std::string("mv ") + tmp_filename + " " + filename; + int error = system(command.c_str()); + + AssertThrow(error == 0, + ExcMessage("Could not move " + tmp_filename + " to " + + filename + ". On processor " + + Utilities::int_to_string(Utilities::MPI::this_mpi_process (MPI_COMM_WORLD)) + ".")); + } + } + + template + void + Particles::write_description_files (const internal::ParticleOutput &data_out, + const std::string &solution_file_prefix, + const std::vector &filenames) + { + const double time_in_years_or_seconds = (this->convert_output_to_years() ? + this->get_time() / year_in_seconds : + this->get_time()); + const std::string pvtu_filename = (solution_file_prefix + + ".pvtu"); + std::ofstream pvtu_file (this->get_output_directory() + "particles/" + + pvtu_filename); + data_out.write_pvtu_record (pvtu_file, filenames); + + // now also generate a .pvd file that matches simulation + // time and corresponding .pvtu record + times_and_pvtu_file_names.emplace_back(time_in_years_or_seconds, "particles/"+pvtu_filename); + + const std::string pvd_filename = (this->get_output_directory() + "particles.pvd"); + std::ofstream pvd_file (pvd_filename); + + DataOutBase::write_pvd_record (pvd_file, times_and_pvtu_file_names); + + // finally, do the same for VisIt via the .visit file for this + // time step, as well as for all time steps together + const std::string visit_filename = (this->get_output_directory() + + "particles/" + + solution_file_prefix + + ".visit"); + std::ofstream visit_file (visit_filename); + + DataOutBase::write_visit_record (visit_file, filenames); + + { + // the global .visit file needs the relative path because it sits a + // directory above + std::vector filenames_with_path; + filenames_with_path.reserve(filenames.size()); + for (const auto &filename : filenames) + { + filenames_with_path.push_back("particles/" + filename); + } + + output_file_names_by_timestep.push_back (filenames_with_path); + } + + std::ofstream global_visit_file (this->get_output_directory() + + "particles.visit"); + + std::vector>> times_and_output_file_names; + for (unsigned int timestep=0; timestep + std::pair + Particles::execute (TableHandler &statistics) + { + // if this is the first time we get here, set the last output time + // to the current time - output_interval. this makes sure we + // always produce data during the first time step + if (std::isnan(last_output_time)) + last_output_time = this->get_time() - output_interval; + + const Particle::World &world = this->get_particle_world(0); + + statistics.add_value("Number of advected particles",world.n_global_particles()); + + // If it's not time to generate an output file + // return early with the number of particles that were advected + if (this->get_time() < last_output_time + output_interval) + return std::make_pair("Number of advected particles:", + Utilities::int_to_string(world.n_global_particles())); + + // If we do not write output + // return early with the number of particles that were advected + if (output_formats.size() == 0 || output_formats[0] == "none") + { + // Up the next time we need output. This is relevant to correctly + // write output after a restart if the format is changed. + set_last_output_time (this->get_time()); + + return std::make_pair("Number of advected particles:", + Utilities::int_to_string(world.n_global_particles())); + } + + if (output_file_number == numbers::invalid_unsigned_int) + output_file_number = 0; + else + ++output_file_number; + + // Create the particle output + const bool output_hdf5 = std::find(output_formats.begin(), output_formats.end(),"hdf5") != output_formats.end(); + internal::ParticleOutput data_out; + data_out.build_patches(world.get_particle_handler(), + world.get_property_manager().get_data_info(), + exclude_output_properties, + output_hdf5); + + // Now prepare everything for writing the output and choose output format + std::string particle_file_prefix = "particles-" + Utilities::int_to_string (output_file_number, 5); + + const double time_in_years_or_seconds = (this->convert_output_to_years() ? + this->get_time() / year_in_seconds : + this->get_time()); + + for (const auto &output_format : output_formats) + { + // this case was handled above + Assert(output_format != "none", ExcInternalError()); + + if (output_format == "hdf5") + { + const std::string particle_file_name = "particles/" + particle_file_prefix + ".h5"; + const std::string xdmf_filename = "particles.xdmf"; + + // Do not filter redundant values, there are no duplicate particles + DataOutBase::DataOutFilter data_filter(DataOutBase::DataOutFilterFlags(false, true)); + + data_out.write_filtered_data(data_filter); + data_out.write_hdf5_parallel(data_filter, + this->get_output_directory()+particle_file_name, + this->get_mpi_communicator()); + + const XDMFEntry new_xdmf_entry = data_out.create_xdmf_entry(data_filter, + particle_file_name, + time_in_years_or_seconds, + this->get_mpi_communicator()); + xdmf_entries.push_back(new_xdmf_entry); + data_out.write_xdmf_file(xdmf_entries, this->get_output_directory() + xdmf_filename, + this->get_mpi_communicator()); + } + else if (output_format == "vtu") + { + // Write descriptive files (.pvtu,.pvd,.visit) on the root process + const int my_id = Utilities::MPI::this_mpi_process(this->get_mpi_communicator()); + + if (my_id == 0) + { + std::vector filenames; + const unsigned int n_processes = Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()); + const unsigned int n_files = (group_files == 0) ? n_processes : std::min(group_files,n_processes); + for (unsigned int i=0; iget_mpi_communicator()); + + const unsigned int my_file_id = (group_files == 0 + ? + my_id + : + my_id % group_files); + const std::string filename = this->get_output_directory() + + "particles/" + + particle_file_prefix + + "." + + Utilities::int_to_string (my_file_id, 4) + + ".vtu"; + + // pass time step number and time as metadata into the output file + DataOutBase::VtkFlags vtk_flags; + vtk_flags.cycle = this->get_timestep_number(); + vtk_flags.time = time_in_years_or_seconds; + + data_out.set_flags (vtk_flags); + + // Write as many files as processes. For this case we support writing in a + // background thread and to a temporary location, so we first write everything + // into a string that is written to disk in a writer function + if ((group_files == 0) || (group_files >= n_processes)) + { + // Put the content we want to write into a string object that + // we can then write in the background + std::unique_ptr file_contents; + { + std::ostringstream tmp; + + data_out.write (tmp, DataOutBase::parse_output_format(output_format)); + file_contents = std::make_unique(tmp.str()); + } + + if (write_in_background_thread) + { + // Wait for all previous write operations to finish, should + // any be still active, ... + if (background_thread.joinable()) + background_thread.join (); + + // ...then continue with writing our own data. + background_thread + = std::thread([ my_filename = filename, // filename is const, so we can not move from it + my_temporary_output_location = temporary_output_location, + my_file_contents = std::move(file_contents)]() + { + writer (my_filename, my_temporary_output_location, *my_file_contents); + }); + } + else + writer(filename,temporary_output_location,*file_contents); + } + // Just write one data file in parallel + else if (group_files == 1) + { + data_out.write_vtu_in_parallel(filename, + this->get_mpi_communicator()); + } + // Write as many output files as 'group_files' groups + else + { + int color = my_id % group_files; + + MPI_Comm comm; + int ierr = MPI_Comm_split(this->get_mpi_communicator(), color, my_id, &comm); + AssertThrowMPI(ierr); + + data_out.write_vtu_in_parallel(filename, comm); + ierr = MPI_Comm_free(&comm); + AssertThrowMPI(ierr); + } + } + // Write in a different format than hdf5 or vtu. This case is supported, but is not + // optimized for parallel output in that every process will write one file directly + // into the output directory. This may or may not affect performance depending on + // the model setup and the network file system type. + else + { + const unsigned int myid = Utilities::MPI::this_mpi_process(this->get_mpi_communicator()); + + const std::string filename = this->get_output_directory() + + "particles/" + + particle_file_prefix + + "." + + Utilities::int_to_string (myid, 4) + + DataOutBase::default_suffix + (DataOutBase::parse_output_format(output_format)); + + std::ofstream out (filename); + + AssertThrow(out, + ExcMessage("Unable to open file for writing: " + filename +".")); + + data_out.write (out, DataOutBase::parse_output_format(output_format)); + } + } + + + // up the next time we need output + set_last_output_time (this->get_time()); + + const std::string particle_output = this->get_output_directory() + "particles/" + particle_file_prefix; + + // record the file base file name in the output file + statistics.add_value ("Particle file name", + particle_output); + return std::make_pair("Writing particle output:", particle_output); + } + + + + template + void + Particles::set_last_output_time (const double current_time) + { + // if output_interval is positive, then update the last supposed output + // time + if (output_interval > 0) + { + // We need to find the last time output was supposed to be written. + // this is the last_output_time plus the largest positive multiple + // of output_intervals that passed since then. We need to handle the + // edge case where last_output_time+output_interval==current_time, + // we did an output and std::floor sadly rounds to zero. This is done + // by forcing std::floor to round 1.0-eps to 1.0. + const double magic = 1.0+2.0*std::numeric_limits::epsilon(); + last_output_time = last_output_time + std::floor((current_time-last_output_time)/output_interval*magic) * output_interval/magic; + } + } + + + template + template + void Particles::serialize (Archive &ar, const unsigned int) + { + ar &last_output_time + & output_file_number + & times_and_pvtu_file_names + & output_file_names_by_timestep + & xdmf_entries + ; + } + + + template + void + Particles::save (std::map &status_strings) const + { + std::ostringstream os; + aspect::oarchive oa (os); + + this->get_particle_world(0).save(os); + oa << (*this); + + status_strings["Particles"] = os.str(); + } + + + template + void + Particles::load (const std::map &status_strings) + { + // see if something was saved + if (status_strings.find("Particles") != status_strings.end()) + { + std::istringstream is (status_strings.find("Particles")->second); + aspect::iarchive ia (is); + + // Load the particle world + this->get_particle_world(0).load(is); + + ia >> (*this); + } + } + + + template + void + Particles::declare_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Particles"); + { + prm.declare_entry ("Time between data output", "1e8", + Patterns::Double (0.), + "The time interval between each generation of " + "output files. A value of zero indicates that " + "output should be generated every time step.\n\n" + "Units: years if the " + "'Use years in output instead of seconds' parameter is set; " + "seconds otherwise."); + + // now also see about the file format we're supposed to write in + // Note: "ascii" is a legacy format used by ASPECT before particle output + // in deal.II was implemented. It is nearly identical to the gnuplot format, thus + // we now simply replace "ascii" by "gnuplot" should it be selected. + prm.declare_entry ("Data output format", "vtu", + Patterns::MultipleSelection (DataOutBase::get_output_format_names ()+"|ascii"), + "A comma separated list of file formats to be used for graphical " + "output. The list of possible output formats that can be given " + "here is documented in the appendix of the manual where the current " + "parameter is described."); + + prm.declare_entry ("Number of grouped files", "16", + Patterns::Integer(0), + "VTU file output supports grouping files from several CPUs " + "into a given number of files using MPI I/O when writing on a parallel " + "filesystem. Select 0 for no grouping. This will disable " + "parallel file output and instead write one file per processor. " + "A value of 1 will generate one big file containing the whole " + "solution, while a larger value will create that many files " + "(at most as many as there are MPI ranks)."); + + prm.declare_entry ("Write in background thread", "false", + Patterns::Bool(), + "File operations can potentially take a long time, blocking the " + "progress of the rest of the model run. Setting this variable to " + "`true' moves this process into a background thread, while the " + "rest of the model continues."); + + prm.declare_entry ("Temporary output location", "", + Patterns::Anything(), + "On large clusters it can be advantageous to first write the " + "output to a temporary file on a local file system and later " + "move this file to a network file system. If this variable is " + "set to a non-empty string it will be interpreted as a " + "temporary storage location."); + + prm.declare_entry ("Exclude output properties", "", + Patterns::Anything(), + "A comma separated list of particle properties that should " + "\\textit{not} be output. If this list contains the " + "entry `all', only the id of particles will be provided in " + "graphical output files."); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + + Particle::World::declare_parameters(prm); + } + + + template + void + Particles::parse_parameters (ParameterHandler &prm) + { + prm.enter_subsection("Postprocess"); + { + prm.enter_subsection("Particles"); + { + output_interval = prm.get_double ("Time between data output"); + if (this->convert_output_to_years()) + output_interval *= year_in_seconds; + + AssertThrow(this->get_parameters().run_postprocessors_on_nonlinear_iterations == false, + ExcMessage("Postprocessing nonlinear iterations in models with " + "particles is currently not supported.")); + + output_formats = Utilities::split_string_list(prm.get ("Data output format")); + AssertThrow(Utilities::has_unique_entries(output_formats), + ExcMessage("The list of strings for the parameter " + "'Postprocess/Particles/Data output format' contains entries more than once. " + "This is not allowed. Please check your parameter file.")); + + AssertThrow ((std::find (output_formats.begin(), + output_formats.end(), + "none") == output_formats.end()) + || + (output_formats.size() == 1), + ExcMessage ("If you specify 'none' for the parameter \"Data output format\", " + "then this needs to be the only value given.")); + + if (std::find (output_formats.begin(), + output_formats.end(), + "none") == output_formats.end()) + aspect::Utilities::create_directory (this->get_output_directory() + "particles/", + this->get_mpi_communicator(), + true); + + // Note: "ascii" is a legacy format used by ASPECT before particle output + // in deal.II was implemented. It is nearly identical to the gnuplot format, thus + // we simply replace "ascii" by "gnuplot" should it be selected. + std::vector::iterator output_format = std::find (output_formats.begin(), + output_formats.end(), + "ascii"); + if (output_format != output_formats.end()) + *output_format = "gnuplot"; + + group_files = prm.get_integer("Number of grouped files"); + write_in_background_thread = prm.get_bool("Write in background thread"); + temporary_output_location = prm.get("Temporary output location"); + + if (temporary_output_location != "") + { + // Check if a command-processor is available by calling system() with a + // null pointer. System is guaranteed to return non-zero if it finds + // a terminal and zero if there is none (like on the compute nodes of + // some cluster architectures, e.g. IBM BlueGene/Q) + AssertThrow(system((char *)nullptr) != 0, + ExcMessage("Usage of a temporary storage location is only supported if " + "there is a terminal available to move the files to their final location " + "after writing. The system() command did not succeed in finding such a terminal.")); + } + + exclude_output_properties = Utilities::split_string_list(prm.get("Exclude output properties")); + + // Never output the integrator properties that are for internal use only + exclude_output_properties.emplace_back("internal: integrator properties"); + } + prm.leave_subsection (); + } + prm.leave_subsection (); + } + } +} + + +// explicit instantiations +namespace aspect +{ + namespace Postprocess + { + namespace internal + { +#define INSTANTIATE(dim) \ + template class ParticleOutput; + + ASPECT_INSTANTIATE(INSTANTIATE) + +#undef INSTANTIATE + } + + ASPECT_REGISTER_POSTPROCESSOR(Particles, + "particles", + "A Postprocessor that creates particles that follow the " + "velocity field of the simulation. The particles can be generated " + "and propagated in various ways and they can carry a number of " + "constant or time-varying properties. The postprocessor can write " + "output positions and properties of all particles at chosen intervals, " + "although this is not mandatory. It also allows other parts of the " + "code to query the particles for information.") + } +} diff --git a/source/postprocess/point_values.cc.bak b/source/postprocess/point_values.cc.bak new file mode 100644 index 00000000000..9b3d7401b72 --- /dev/null +++ b/source/postprocess/point_values.cc.bak @@ -0,0 +1,369 @@ +/* + Copyright (C) 2016 - 2022 by the authors of the ASPECT code. + + This file is part of ASPECT. + + ASPECT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + ASPECT 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ASPECT; see the file LICENSE. If not see + . +*/ + + +#include +#include +#include +#include +#include +#include + +#include + +namespace aspect +{ + namespace Postprocess + { + template + PointValues::PointValues () + : + // the following value is later read from the input file + output_interval (0), + // initialize this to a nonsensical value; set it to the actual time + // the first time around we get to check it + last_output_time (std::numeric_limits::quiet_NaN()), + evaluation_points_cartesian (std::vector>() ), + point_values (std::vector>>>() ), + use_natural_coordinates (false) + {} + + template + std::pair + PointValues::execute (TableHandler &) + { + // if this is the first time we get here, set the next output time + // to the current time. this makes sure we always produce data during + // the first time step + if (std::isnan(last_output_time)) + last_output_time = this->get_time() - output_interval; + + // see if output is requested at this time + if (this->get_time() < last_output_time + output_interval) + return {"", ""}; + + // evaluate the solution at all of our evaluation points + std::vector> + current_point_values (evaluation_points_cartesian.size(), + Vector (this->introspection().n_components)); + + for (unsigned int p=0; pget_mapping(), + this->get_dof_handler(), + this->get_solution(), + evaluation_points_cartesian[p], + current_point_values[p]); + point_found = true; + } + catch (const VectorTools::ExcPointNotAvailableHere &) + { + // ignore + } + + // ensure that at least one processor found things + const int n_procs = Utilities::MPI::sum (point_found ? 1 : 0, this->get_mpi_communicator()); + AssertThrow (n_procs > 0, + ExcMessage ("While trying to evaluate the solution at point " + + Utilities::to_string(evaluation_points_cartesian[p][0]) + ", " + + Utilities::to_string(evaluation_points_cartesian[p][1]) + + (dim == 3 + ? + ", " + Utilities::to_string(evaluation_points_cartesian[p][2]) + : + "") + "), " + + "no processors reported that the point lies inside the " + + "set of cells they own. Are you trying to evaluate the " + + "solution at a point that lies outside of the domain?" + )); + + // Reduce all collected values into local Vector + Utilities::MPI::sum (current_point_values[p], this->get_mpi_communicator(), + current_point_values[p]); + + // Normalize in cases where points are claimed by multiple processors + if (n_procs > 1) + current_point_values[p] /= n_procs; + } + + // finally push these point values all onto the list we keep + point_values.emplace_back (this->get_time(), current_point_values); + + // now write all of the data to the file of choice. start with a pre-amble that + // explains the meaning of the various fields + const std::string filename = (this->get_output_directory() + + "point_values.txt"); + + if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) + { + + std::ofstream f (filename); + f << ("#
- // - // (usually T(K) or P(bar)) - // - // - // - // (usually T(K) or P(bar)) - // - // - // - // Number of property columns in the table - // Column names - - // First line is the Perplex version number - std::getline(in, temp); // get next line, table file name - - std::getline(in, temp); // get next line, dimension of table - unsigned int n_variables; - in >> n_variables; - AssertThrow (n_variables==2, ExcMessage("The PerpleX file " + filename + " must be two dimensional (P(bar)-T(K)).")); - - std::getline(in, temp); // get next line, either T(K) or P(bar) - - for (unsigned int i=0; i<2; ++i) - { - std::string natural_variable; - in >> natural_variable; - - if (natural_variable == "T(K)") - { - std::getline(in, temp); - in >> min_temp; - std::getline(in, temp); - in >> delta_temp; - std::getline(in, temp); - in >> n_temperature; - std::getline(in, temp); // get next line, either T(K), P(bar) or number of columns - } - else if (natural_variable == "P(bar)") - { - std::getline(in, temp); - in >> min_press; - min_press *= 1e5; // conversion from [bar] to [Pa] - std::getline(in, temp); - in >> delta_press; - delta_press *= 1e5; // conversion from [bar] to [Pa] - std::getline(in, temp); - in >> n_pressure; - std::getline(in, temp); // get next line, either T(K), P(bar) or number of columns - } - else - { - AssertThrow (false, ExcMessage("The start of the PerpleX file " + filename + " does not have the expected format.")); - } - } - - in >> n_columns; - std::getline(in, temp); // get next line, column labels - - // here we string match to assign properties to columns - // column i in text file -> column j in properties - // Properties are stored in the order rho, alpha, cp, vp, vs, h - std::vector prp_indices(6, -1); - std::vector phase_column_indices; - unsigned int dominant_phase_column_index = numbers::invalid_unsigned_int; - - // First two columns should be P(bar) and T(K). - // Here we find the order. - std::string column_name; - in >> column_name; - - std::string first_natural_variable; - if (column_name == "P(bar)") - { - first_natural_variable = column_name; - in >> column_name; - AssertThrow(column_name == "T(K)", ExcMessage("The second column name in PerpleX lookup file " + filename + " should be T(K).")); - } - else if (column_name == "T(K)") - { - first_natural_variable = column_name; - in >> column_name; - AssertThrow(column_name == "P(bar)", ExcMessage("The second column name in PerpleX lookup file " + filename + " should be P(bar).")); - } - else - { - AssertThrow(false, ExcMessage("The first column name in the PerpleX lookup file " + filename + " should be P(bar) or T(K).")); - } - - for (unsigned int n=2; n> column_name; - if (column_name == "rho,kg/m3") - prp_indices[0] = n; - else if (column_name == "alpha,1/K") - prp_indices[1] = n; - else if (column_name == "cp,J/K/kg") - prp_indices[2] = n; - else if (column_name == "vp,km/s") - prp_indices[3] = n; - else if (column_name == "vs,km/s") - prp_indices[4] = n; - else if (column_name == "h,J/kg") - prp_indices[5] = n; - else if (column_name == "phase") - { - has_dominant_phase_column = true; - dominant_phase_column_index = n; - } - else if (column_name.length() > 3) - { - if (column_name.substr(0,13).compare("vol_fraction_") == 0) - { - if (std::find(phase_column_names.begin(), - phase_column_names.end(), - column_name) != phase_column_names.end()) - { - AssertThrow(false, - ExcMessage("The PerpleX lookup file " + filename + " must have unique column names. " - "Sometimes, the same phase is stable with >1 composition at the same " - "pressure and temperature, so you may see several columns with the same name. " - "Either combine columns with the same name, or change the names.")); - } - // Populate phase_column_names with the column name - // and phase_column_indices with the column index in the current lookup file. - phase_column_indices.push_back(n); - phase_column_names.push_back(column_name); - } - } - } - AssertThrow(std::all_of(prp_indices.begin(), prp_indices.end(), [](int i) - { - return i>=0; - }), - ExcMessage("The PerpleX lookup file " + filename + " must contain columns with names " - "rho,kg/m3, alpha,1/K, cp,J/K/kg, vp,km/s, vs,km/s and h,J/kg.")); - - std::getline(in, temp); // first data line - - AssertThrow(min_temp >= 0.0, ExcMessage("Read in of Material header failed (mintemp).")); - AssertThrow(delta_temp > 0, ExcMessage("Read in of Material header failed (delta_temp).")); - AssertThrow(n_temperature > 0, ExcMessage("Read in of Material header failed (numtemp).")); - AssertThrow(min_press >= 0, ExcMessage("Read in of Material header failed (min_press).")); - AssertThrow(delta_press > 0, ExcMessage("Read in of Material header failed (delta_press).")); - AssertThrow(n_pressure > 0, ExcMessage("Read in of Material header failed (numpress).")); - - - max_temp = min_temp + (n_temperature-1) * delta_temp; - max_press = min_press + (n_pressure-1) * delta_press; - - density_values.reinit(n_temperature,n_pressure); - thermal_expansivity_values.reinit(n_temperature,n_pressure); - specific_heat_values.reinit(n_temperature,n_pressure); - vp_values.reinit(n_temperature,n_pressure); - vs_values.reinit(n_temperature,n_pressure); - enthalpy_values.reinit(n_temperature,n_pressure); - - if (has_dominant_phase_column) - dominant_phase_indices.reinit(n_temperature,n_pressure); - - phase_volume_fractions.resize(phase_column_names.size()); - for (auto &phase_volume_fraction : phase_volume_fractions) - phase_volume_fraction.reinit(n_temperature,n_pressure); - - unsigned int i = 0; - std::vector previous_row_values(n_columns, 0.); - - while (!in.eof()) - { - std::vector row_values(n_columns); - std::string phase; - - for (unsigned int n=0; n> phase; - else - in >> row_values[n]; // assigned as 0 if in.fail() == True - - // P-T grids created with PerpleX-werami sometimes contain rows - // filled with NaNs at extreme P-T conditions where the thermodynamic - // models break down. These P-T regions are typically not relevant to - // geodynamic modeling (they most commonly appear above - // mantle liquidus temperatures at low pressures). - // More frustratingly, PerpleX-vertex occasionally fails to find a - // valid mineral assemblage in small, isolated regions within the domain, - // and so PerpleX-werami also returns NaNs for pixels within these regions. - // It is recommended that the user preprocesses their input - // files to replace these NaNs before plugging them into ASPECT. - // If this lookup encounters invalid doubles it replaces them - // with the most recent valid double. - if (in.fail()) - { - in.clear(); - row_values[n] = previous_row_values[n]; - } - } - previous_row_values = row_values; - - std::getline(in, temp); // read next line - if (in.eof()) - break; - - if (std::find(dominant_phase_names.begin(), dominant_phase_names.end(), phase) == dominant_phase_names.end()) - dominant_phase_names.push_back(phase); - - // The ordering of the first two columns in the PerpleX table files - // dictates whether the inner loop is over temperature or pressure. - // The first column is always the inner loop. - // The following lines populate the material property tables - // according to that implicit loop structure. - if (first_natural_variable == "T(K)") - { - density_values[i%n_temperature][i/n_temperature]=row_values[prp_indices[0]]; - thermal_expansivity_values[i%n_temperature][i/n_temperature]=row_values[prp_indices[1]]; - specific_heat_values[i%n_temperature][i/n_temperature]=row_values[prp_indices[2]]; - vp_values[i%n_temperature][i/n_temperature]=row_values[prp_indices[3]]; - vs_values[i%n_temperature][i/n_temperature]=row_values[prp_indices[4]]; - enthalpy_values[i%n_temperature][i/n_temperature]=row_values[prp_indices[5]]; - - if (has_dominant_phase_column) - { - std::vector::iterator it = std::find(dominant_phase_names.begin(), dominant_phase_names.end(), phase); - dominant_phase_indices[i%n_temperature][i/n_temperature] = std::distance(dominant_phase_names.begin(), it); - } - - for (unsigned int n=0; n::iterator it = std::find(dominant_phase_names.begin(), dominant_phase_names.end(), phase); - dominant_phase_indices[i/n_pressure][i%n_pressure] = std::distance(dominant_phase_names.begin(), it); - } - - for (unsigned int n=0; n>(7,1.0); - material_lookup->load_file(data_directory+material_file_name, - comm); - } - - - - double - EntropyReader::specific_heat(const double entropy, - const double pressure) const - { - const double specific_heat = material_lookup->get_data({entropy,pressure}, 3); - return specific_heat; - } - - - - double - EntropyReader::density(const double entropy, - const double pressure) const - { - const double density = material_lookup->get_data({entropy,pressure}, 1); - return density; - } - - - - double - EntropyReader::thermal_expansivity(const double entropy, - const double pressure) const - { - const double thermal_expansivity = material_lookup->get_data({entropy,pressure}, 2); - return thermal_expansivity; - } - - - - double - EntropyReader::temperature(const double entropy, - const double pressure) const - { - const double temperature = material_lookup->get_data({entropy,pressure}, 0); - return temperature; - } - - - - double - EntropyReader::seismic_vp(const double entropy, - const double pressure) const - { - const double seismic_vp = material_lookup->get_data({entropy,pressure}, 4); - return seismic_vp; - } - - - - double - EntropyReader::seismic_vs(const double entropy, - const double pressure) const - { - const double seismic_vs = material_lookup->get_data({entropy,pressure}, 5); - return seismic_vs; - } - - - - Tensor<1, 2> - EntropyReader::density_gradient(const double entropy, - const double pressure) const - { - const Tensor<1, 2> density_gradient= material_lookup->get_gradients({entropy,pressure}, 1); - return density_gradient; - } - - - } - - - - std::vector - compute_only_composition_fractions(const std::vector &compositional_fields, - const std::vector &indices_to_use) - { - std::vector composition_fractions(indices_to_use.size()+1); - - // Clip the compositional fields so they are between zero and one, - // and sum the compositional fields for normalization purposes. - double sum_composition = 0.0; - std::vector x_comp (indices_to_use.size()); - - for (unsigned int i=0; i < x_comp.size(); ++i) - { - x_comp[i] = std::min(std::max(compositional_fields[indices_to_use[i]], 0.0), 1.0); - sum_composition += x_comp[i]; - } - - // Compute background field fraction - if (sum_composition >= 1.0) - composition_fractions[0] = 0.0; - else - composition_fractions[0] = 1.0 - sum_composition; - - // Compute and possibly normalize field fractions - for (unsigned int i=0; i < x_comp.size(); ++i) - { - if (sum_composition >= 1.0) - composition_fractions[i+1] = x_comp[i]/sum_composition; - else - composition_fractions[i+1] = x_comp[i]; - } - - return composition_fractions; - } - - - - std::vector - compute_composition_fractions(const std::vector &compositional_fields, - const ComponentMask &field_mask) - { - std::vector composition_fractions(compositional_fields.size()+1); - - // Clip the compositional fields so they are between zero and one, - // and sum the compositional fields for normalization purposes. - double sum_composition = 0.0; - std::vector x_comp = compositional_fields; - for (unsigned int i=0; i < x_comp.size(); ++i) - if (field_mask[i] == true) - { - x_comp[i] = std::min(std::max(x_comp[i], 0.0), 1.0); - sum_composition += x_comp[i]; - } - - // Compute background field fraction - if (sum_composition >= 1.0) - composition_fractions[0] = 0.0; - else - composition_fractions[0] = 1.0 - sum_composition; - - // Compute and possibly normalize field fractions - for (unsigned int i=0; i < x_comp.size(); ++i) - if (field_mask[i] == true) - { - if (sum_composition >= 1.0) - composition_fractions[i+1] = x_comp[i]/sum_composition; - else - composition_fractions[i+1] = x_comp[i]; - } - - return composition_fractions; - } - - - - std::vector - compute_volume_fractions(const std::vector &compositional_fields, - const ComponentMask &field_mask) - { - return compute_composition_fractions(compositional_fields, field_mask); - } - - - - std::vector - compute_volumes_from_masses(const std::vector &masses, - const std::vector &densities, - const bool return_as_fraction) - { - Assert(masses.size() == densities.size(), - ExcMessage ("The mass fractions and densities vectors used for computing " - "volumes from masses have to have the same length! " - "You have provided " - + Utilities::int_to_string(masses.size()) + - " mass fractions and " - + Utilities::int_to_string(densities.size()) + - " densities.")); - - const unsigned int n_fields = masses.size(); - std::vector volumes(n_fields); - - if (n_fields == 1 && return_as_fraction) - { - volumes[0] = 1.0; - return volumes; - } - - double sum_volumes = 0.0; - for (unsigned int j=0; j < n_fields; ++j) - { - volumes[j] = masses[j] / densities[j]; - sum_volumes += volumes[j]; - } - - if (return_as_fraction) - { - for (unsigned int j=0; j < n_fields; ++j) - volumes[j] /= sum_volumes; - } - return volumes; - } - - - - CompositionalAveragingOperation - parse_compositional_averaging_operation (const std::string ¶meter_name, - const ParameterHandler &prm) - { - CompositionalAveragingOperation averaging_operation; - if (prm.get (parameter_name) == "harmonic") - averaging_operation = MaterialUtilities::harmonic; - else if (prm.get (parameter_name) == "arithmetic") - averaging_operation = MaterialUtilities::arithmetic; - else if (prm.get (parameter_name) == "geometric") - averaging_operation = MaterialUtilities::geometric; - else if (prm.get (parameter_name) == "maximum composition") - averaging_operation = MaterialUtilities::maximum_composition; - else - { - AssertThrow(false, ExcMessage("Not a valid viscosity averaging scheme")); - - //We will never get here, but we have to return something so the compiler does not complain - return MaterialUtilities::harmonic; - } - - return averaging_operation; - } - - - - double - average_value (const std::vector &volume_fractions, - const std::vector ¶meter_values, - const enum CompositionalAveragingOperation &average_type) - { - Assert(volume_fractions.size() == parameter_values.size(), - ExcMessage ("The volume fractions and parameter values vectors used for averaging " - "have to have the same length! You have provided " - + Utilities::int_to_string(volume_fractions.size()) + - " volume fractions and " - + Utilities::int_to_string(parameter_values.size()) + - " parameter values.")); - - double averaged_parameter = 0.0; - - switch (average_type) - { - case arithmetic: - { - for (unsigned int i=0; i 0, - ExcMessage ("All parameter values must be greater than 0 for harmonic averaging!")); - averaged_parameter += volume_fractions[i]/(parameter_values[i]); - } - averaged_parameter = 1.0/averaged_parameter; - break; - } - case geometric: - { - for (unsigned int i=0; i 0, - ExcMessage ("All parameter values must be greater than 0 for geometric averaging!")); - averaged_parameter += volume_fractions[i] * std::log(parameter_values[i]); - } - averaged_parameter = std::exp(averaged_parameter); - break; - } - case maximum_composition: - { - const unsigned int idx = static_cast(std::max_element( volume_fractions.begin(), - volume_fractions.end() ) - - volume_fractions.begin()); - averaged_parameter = parameter_values[idx]; - break; - } - default: - { - AssertThrow(false, ExcNotImplemented()); - break; - } - } - return averaged_parameter; - } - - - - template - void - fill_averaged_equation_of_state_outputs(const EquationOfStateOutputs &eos_outputs, - const std::vector &mass_fractions, - const std::vector &volume_fractions, - const unsigned int i, - MaterialModelOutputs &out) - { - // The density, isothermal compressibility and thermal expansivity are volume-averaged - // The specific entropy derivatives and heat capacity are mass-averaged - out.densities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.densities, MaterialUtilities::arithmetic); - out.compressibilities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.compressibilities, MaterialUtilities::arithmetic); - out.thermal_expansion_coefficients[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.thermal_expansion_coefficients, MaterialUtilities::arithmetic); - out.entropy_derivative_pressure[i] = MaterialUtilities::average_value (mass_fractions, eos_outputs.entropy_derivative_pressure, MaterialUtilities::arithmetic); - out.entropy_derivative_temperature[i] = MaterialUtilities::average_value (mass_fractions, eos_outputs.entropy_derivative_temperature, MaterialUtilities::arithmetic); - out.specific_heat[i] = MaterialUtilities::average_value (mass_fractions, eos_outputs.specific_heat_capacities, MaterialUtilities::arithmetic); - } - - - - double phase_average_value (const std::vector &phase_function_values, - const std::vector &n_phase_transitions_per_composition, - const std::vector ¶meter_values, - const unsigned int composition_index, - const PhaseUtilities::PhaseAveragingOperation operation) - { - // Calculate base index and assign base value - unsigned int start_phase_index = 0; - for (unsigned int i=0; i 0) - { - // Do averaging when there are multiple phases - if (operation == PhaseUtilities::logarithmic) - averaged_parameter = log(averaged_parameter); - - for (unsigned int i=0; i - PhaseFunctionInputs::PhaseFunctionInputs(const double temperature_, - const double pressure_, - const double depth_, - const double pressure_depth_derivative_, - const unsigned int phase_index_) - - : - temperature(temperature_), - pressure(pressure_), - depth(depth_), - pressure_depth_derivative(pressure_depth_derivative_), - phase_index(phase_index_) - {} - - - - template - double - PhaseFunction::compute_value (const PhaseFunctionInputs &in) const - { - AssertIndexRange (in.phase_index, transition_temperature_lower_limits.size()); - AssertIndexRange (in.phase_index, transition_temperature_upper_limits.size()); - - // the percentage of material that has undergone the transition - double function_value; - if (in.temperature < transition_temperature_lower_limits[in.phase_index] || - in.temperature >= transition_temperature_upper_limits[in.phase_index]) - { - // assign 0.0 if temperature is out of range - function_value = 0.0; - } - else - { - if (use_depth_instead_of_pressure) - { - AssertIndexRange (in.phase_index, transition_depths.size()); - - // calculate the deviation from the transition point (convert temperature to depth) - double depth_deviation = in.depth - transition_depths[in.phase_index]; - - if (in.pressure_depth_derivative != 0.0) - { - AssertIndexRange (in.phase_index, transition_slopes.size()); - AssertIndexRange (in.phase_index, transition_temperatures.size()); - - depth_deviation -= transition_slopes[in.phase_index] / in.pressure_depth_derivative - * (in.temperature - transition_temperatures[in.phase_index]); - } - - // use delta function for width = 0 - AssertIndexRange (in.phase_index, transition_widths.size()); - if (transition_widths[in.phase_index] == 0) - function_value = (depth_deviation > 0) ? 1. : 0.; - else - function_value = 0.5*(1.0 + std::tanh(depth_deviation / transition_widths[in.phase_index])); - } - else - { - // calculate the deviation from the transition point (convert temperature to pressure) - AssertIndexRange (in.phase_index, transition_pressures.size()); - const double pressure_deviation = in.pressure - transition_pressures[in.phase_index] - - transition_slopes[in.phase_index] * (in.temperature - transition_temperatures[in.phase_index]); - - // use delta function for width = 0 - AssertIndexRange (in.phase_index, transition_pressure_widths.size()); - if (transition_pressure_widths[in.phase_index] == 0) - function_value = (pressure_deviation > 0) ? 1. : 0.; - else - function_value = 0.5*(1.0 + std::tanh(pressure_deviation / transition_pressure_widths[in.phase_index])); - } - } - - return function_value; - } - - - - template - double - PhaseFunction::compute_derivative (const PhaseFunctionInputs &in) const - { - double transition_pressure; - double pressure_width; - double width_temp; - - // we already should have the adiabatic conditions here - Assert (this->get_adiabatic_conditions().is_initialized(), - ExcMessage("The adiabatic conditions need to be already initialized " - "to calculate the derivative of phase functions. Either call this " - "function after the reference conditions have been computed, or implement " - "a workaround for the case without reference profile.")); - - // phase transition based on depth - if (use_depth_instead_of_pressure) - { - const Point transition_point = this->get_geometry_model().representative_point(transition_depths[in.phase_index]); - const Point transition_plus_width = this->get_geometry_model().representative_point(transition_depths[in.phase_index] + transition_widths[in.phase_index]); - const Point transition_minus_width = this->get_geometry_model().representative_point(transition_depths[in.phase_index] - transition_widths[in.phase_index]); - transition_pressure = this->get_adiabatic_conditions().pressure(transition_point); - pressure_width = 0.5 * (this->get_adiabatic_conditions().pressure(transition_plus_width) - - this->get_adiabatic_conditions().pressure(transition_minus_width)); - width_temp = transition_widths[in.phase_index]; - } - // using pressure instead of depth to define the phase transition - else - { - transition_pressure = transition_pressures[in.phase_index]; - pressure_width = transition_pressure_widths[in.phase_index]; - width_temp = transition_pressure_widths[in.phase_index]; - } - - // calculate the deviation from the transition point - const double pressure_deviation = in.pressure - transition_pressure - - transition_slopes[in.phase_index] * (in.temperature - transition_temperatures[in.phase_index]); - - // calculate the analytical derivative of the phase function - if ( - (in.temperature < transition_temperature_lower_limits[in.phase_index]) || - (in.temperature >= transition_temperature_upper_limits[in.phase_index]) - ) - { - // return 0 if temperature is out of range - return 0; - } - else if (width_temp == 0) - return 0; - else - return 0.5 / pressure_width * (1.0 - std::tanh(pressure_deviation / pressure_width) - * std::tanh(pressure_deviation / pressure_width)); - } - - - - template - unsigned int - PhaseFunction:: - n_phase_transitions () const - { - if (use_depth_instead_of_pressure) - return transition_depths.size(); - else - return transition_pressures.size(); - } - - template - unsigned int - PhaseFunction:: - n_phases () const - { - return n_phases_total; - } - - template - const std::vector & - PhaseFunction::n_phase_transitions_for_each_composition () const - { - return *n_phase_transitions_per_composition; - } - - template - const std::vector & - PhaseFunction::n_phases_for_each_composition () const - { - return n_phases_per_composition; - } - - - - template - double - PhaseFunction:: - get_transition_slope (const unsigned int phase_index) const - { - return transition_slopes[phase_index]; - } - - - - template - double - PhaseFunction:: - get_transition_depth (const unsigned int phase_index) const - { - return transition_depths[phase_index]; - } - - - - template - void - PhaseFunction::declare_parameters (ParameterHandler &prm) - { - prm.declare_entry ("Phase transition depths", "", - Patterns::Anything(), - "A list of depths where phase transitions occur. Values must " - "monotonically increase. " - "Units: \\si{\\meter}."); - prm.declare_entry ("Phase transition widths", "", - Patterns::Anything(), - "A list of widths for each phase transition, in terms of depth. The phase functions " - "are scaled with these values, leading to a jump between phases " - "for a value of zero and a gradual transition for larger values. " - "List must have the same number of entries as Phase transition depths. " - "Units: \\si{\\meter}."); - prm.declare_entry ("Phase transition pressures", "", - Patterns::Anything(), - "A list of pressures where phase transitions occur. Values must " - "monotonically increase. Define transition by depth instead of " - "pressure must be set to false to use this parameter. " - "Units: \\si{\\pascal}."); - prm.declare_entry ("Phase transition pressure widths", "", - Patterns::Anything(), - "A list of widths for each phase transition, in terms of pressure. The phase functions " - "are scaled with these values, leading to a jump between phases " - "for a value of zero and a gradual transition for larger values. " - "List must have the same number of entries as Phase transition pressures. " - "Define transition by depth instead of pressure must be set to false " - "to use this parameter. " - "Units: \\si{\\pascal}."); - prm.declare_entry ("Define transition by depth instead of pressure", "true", - Patterns::Bool (), - "Whether to list phase transitions by depth or pressure. If this parameter is true, " - "then the input file will use Phase transitions depths and Phase transition widths " - "to define the phase transition. If it is false, the parameter file will read in " - "phase transition data from Phase transition pressures and " - "Phase transition pressure widths."); - prm.declare_entry ("Phase transition temperatures", "", - Patterns::Anything(), - "A list of temperatures where phase transitions occur. Higher or lower " - "temperatures lead to phase transition occurring in smaller or greater " - "depths than given in Phase transition depths, depending on the " - "Clapeyron slope given in Phase transition Clapeyron slopes. " - "List must have the same number of entries as Phase transition depths. " - "Units: \\si{\\kelvin}."); - prm.declare_entry ("Phase transition temperature upper limits", - boost::lexical_cast(std::numeric_limits::max()), - Patterns::Anything(), - "A list of upper temperature limits for each phase transition. Above " - "this temperature the respective phase transition is deactivated. The default " - "value means there is no upper limit for any phase transitions. " - "List must have the same number of entries as Phase transition depths. " - "When the optional temperature limits are applied, the user has to be " - "careful about the consistency between adjacent phases. Phase transitions " - "should be continuous in pressure-temperature space. " - "We recommend producing a phase diagram with " - "simple model setups to check the implementation as a starting point." - "Units: \\si{\\kelvin}."); - prm.declare_entry ("Phase transition temperature lower limits", - boost::lexical_cast(std::numeric_limits::lowest()), - Patterns::Anything(), - "A list of lower temperature limits for each phase transition. Below " - "this temperature the respective phase transition is deactivated. The default " - "value means there is no lower limit for any phase transition. " - "List must have the same number of entries as Phase transition depths. " - "When the optional temperature limits are applied, the user has to be " - "careful about the consistency between adjacent phases. Phase transitions " - "should be continuous in pressure-temperature space. " - "We recommend producing a phase diagram with " - "simple model setups to check the implementation as a starting point." - "Units: \\si{\\kelvin}."); - prm.declare_entry ("Phase transition Clapeyron slopes", "", - Patterns::Anything(), - "A list of Clapeyron slopes for each phase transition. A positive " - "Clapeyron slope indicates that the phase transition will occur in " - "a greater depth, if the temperature is higher than the one given in " - "Phase transition temperatures and in a smaller depth, if the " - "temperature is smaller than the one given in Phase transition temperatures. " - "For negative slopes the other way round. " - "List must have the same number of entries as Phase transition depths. " - "Units: \\si{\\pascal\\per\\kelvin}."); - } - - - - template - void - PhaseFunction::parse_parameters (ParameterHandler &prm) - { - // Establish that a background field is required here - const bool has_background_field = true; - - // Retrieve the list of composition names - const std::vector list_of_composition_names = this->introspection().get_composition_names(); - - n_phase_transitions_per_composition = std::make_unique>(); - - use_depth_instead_of_pressure = prm.get_bool ("Define transition by depth instead of pressure"); - - if (use_depth_instead_of_pressure) - { - transition_depths = Utilities::parse_map_to_double_array (prm.get("Phase transition depths"), - list_of_composition_names, - has_background_field, - "Phase transition depths", - true, - n_phase_transitions_per_composition, - true); - - transition_widths = Utilities::parse_map_to_double_array (prm.get("Phase transition widths"), - list_of_composition_names, - has_background_field, - "Phase transition widths", - true, - n_phase_transitions_per_composition, - true); - } - else - { - transition_pressures = Utilities::parse_map_to_double_array (prm.get("Phase transition pressures"), - list_of_composition_names, - has_background_field, - "Phase transition pressures", - true, - n_phase_transitions_per_composition, - true); - - transition_pressure_widths = Utilities::parse_map_to_double_array (prm.get("Phase transition pressure widths"), - list_of_composition_names, - has_background_field, - "Phase transition pressure widths", - true, - n_phase_transitions_per_composition, - true); - } - - transition_temperatures = Utilities::parse_map_to_double_array (prm.get("Phase transition temperatures"), - list_of_composition_names, - has_background_field, - "Phase transition temperatures", - true, - n_phase_transitions_per_composition, - true); - - transition_temperature_upper_limits = Utilities::parse_map_to_double_array (prm.get("Phase transition temperature upper limits"), - list_of_composition_names, - has_background_field, - "Phase transition temperature upper limits", - true, - n_phase_transitions_per_composition, - true); - - transition_temperature_lower_limits = Utilities::parse_map_to_double_array (prm.get("Phase transition temperature lower limits"), - list_of_composition_names, - has_background_field, - "Phase transition temperature lower limits", - true, - n_phase_transitions_per_composition, - true); - - transition_slopes = Utilities::parse_map_to_double_array (prm.get("Phase transition Clapeyron slopes"), - list_of_composition_names, - has_background_field, - "Phase transition Clapeyron slopes", - true, - n_phase_transitions_per_composition, - true); - - n_phases_total = 0; - n_phases_per_composition.clear(); - for (unsigned int n : *n_phase_transitions_per_composition) - { - n_phases_per_composition.push_back(n+1); - n_phases_total += n+1; - } - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace MaterialModel - { - namespace MaterialUtilities - { -#define INSTANTIATE(dim) \ - template void fill_averaged_equation_of_state_outputs (const EquationOfStateOutputs &, \ - const std::vector &, \ - const std::vector &, \ - const unsigned int, \ - MaterialModelOutputs &); \ - template struct PhaseFunctionInputs; \ - template class PhaseFunction; - - ASPECT_INSTANTIATE(INSTANTIATE) - -#undef INSTANTIATE - } - } -} diff --git a/source/material_model/visco_plastic.cc.bak b/source/material_model/visco_plastic.cc.bak deleted file mode 100644 index cef81e360e1..00000000000 --- a/source/material_model/visco_plastic.cc.bak +++ /dev/null @@ -1,678 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - -#include -#include -#include -#include -#include -#include -#include - -namespace aspect -{ - namespace MaterialModel - { - - template - bool - ViscoPlastic:: - is_yielding (const double pressure, - const double temperature, - const std::vector &composition, - const SymmetricTensor<2,dim> &strain_rate) const - { - /* The following returns whether or not the material is plastically yielding - * as documented in evaluate. - */ - bool plastic_yielding = false; - - MaterialModel::MaterialModelInputs in (/*n_evaluation_points=*/1, - this->n_compositional_fields()); - unsigned int i = 0; - - in.pressure[i] = pressure; - in.temperature[i] = temperature; - in.composition[i] = composition; - in.strain_rate[i] = strain_rate; - - const std::vector volume_fractions = MaterialUtilities::compute_only_composition_fractions(composition, - this->introspection().chemical_composition_field_indices()); - - const IsostrainViscosities isostrain_viscosities - = rheology->calculate_isostrain_viscosities(in, i, volume_fractions); - - std::vector::const_iterator max_composition - = std::max_element(volume_fractions.begin(),volume_fractions.end()); - - plastic_yielding = isostrain_viscosities.composition_yielding[std::distance(volume_fractions.begin(), - max_composition)]; - - return plastic_yielding; - } - - - - template - bool - ViscoPlastic:: - is_yielding(const MaterialModelInputs &in) const - { - Assert(in.n_evaluation_points() == 1, ExcInternalError()); - - const std::vector volume_fractions = MaterialUtilities::compute_only_composition_fractions(in.composition[0], - this->introspection().chemical_composition_field_indices()); - - /* The following handles phases in a similar way as in the 'evaluate' function. - * Results then enter the calculation of plastic yielding. - */ - std::vector phase_function_values(phase_function.n_phase_transitions(), 0.0); - - if (phase_function.n_phase_transitions() > 0) - { - const double gravity_norm = this->get_gravity_model().gravity_vector(in.position[0]).norm(); - - double reference_density; - if (this->get_adiabatic_conditions().is_initialized()) - { - reference_density = this->get_adiabatic_conditions().density(in.position[0]); - } - else - { - EquationOfStateOutputs eos_outputs_all_phases (n_phases); - equation_of_state.evaluate(in, 0, eos_outputs_all_phases); - reference_density = eos_outputs_all_phases.densities[0]; - } - - MaterialUtilities::PhaseFunctionInputs phase_inputs(in.temperature[0], - in.pressure[0], - this->get_geometry_model().depth(in.position[0]), - gravity_norm*reference_density, - numbers::invalid_unsigned_int); - - for (unsigned int j=0; j < phase_function.n_phase_transitions(); ++j) - { - phase_inputs.phase_index = j; - phase_function_values[j] = phase_function.compute_value(phase_inputs); - } - } - - /* The following returns whether or not the material is plastically yielding - * as documented in evaluate. - */ - const IsostrainViscosities isostrain_viscosities = rheology->calculate_isostrain_viscosities(in, 0, volume_fractions, phase_function_values, phase_function.n_phase_transitions_for_each_composition()); - - std::vector::const_iterator max_composition = std::max_element(volume_fractions.begin(), volume_fractions.end()); - const bool plastic_yielding = isostrain_viscosities.composition_yielding[std::distance(volume_fractions.begin(), max_composition)]; - - return plastic_yielding; - } - - - - template - void - ViscoPlastic:: - evaluate(const MaterialModel::MaterialModelInputs &in, - MaterialModel::MaterialModelOutputs &out) const - { - EquationOfStateOutputs eos_outputs (this->introspection().get_number_of_fields_of_type(CompositionalFieldDescription::chemical_composition)+1); - EquationOfStateOutputs eos_outputs_all_phases (n_phases); - - std::vector average_elastic_shear_moduli (in.n_evaluation_points()); - - // Store value of phase function for each phase and composition - // While the number of phases is fixed, the value of the phase function is updated for every point - std::vector phase_function_values(phase_function.n_phase_transitions(), 0.0); - - // Loop through all requested points - for (unsigned int i=0; i < in.n_evaluation_points(); ++i) - { - // First compute the equation of state variables and thermodynamic properties - equation_of_state.evaluate(in, i, eos_outputs_all_phases); - - const double gravity_norm = this->get_gravity_model().gravity_vector(in.position[i]).norm(); - const double reference_density = (this->get_adiabatic_conditions().is_initialized()) - ? - this->get_adiabatic_conditions().density(in.position[i]) - : - eos_outputs_all_phases.densities[0]; - - // The phase index is set to invalid_unsigned_int, because it is only used internally - // in phase_average_equation_of_state_outputs to loop over all existing phases - MaterialUtilities::PhaseFunctionInputs phase_inputs(in.temperature[i], - in.pressure[i], - this->get_geometry_model().depth(in.position[i]), - gravity_norm*reference_density, - numbers::invalid_unsigned_int); - - // Compute value of phase functions - for (unsigned int j=0; j < phase_function.n_phase_transitions(); ++j) - { - phase_inputs.phase_index = j; - phase_function_values[j] = phase_function.compute_value(phase_inputs); - } - - // Average by value of gamma function to get value of compositions - phase_average_equation_of_state_outputs(eos_outputs_all_phases, - phase_function_values, - n_phase_transitions_for_each_chemical_composition, - eos_outputs); - - const std::vector volume_fractions = MaterialUtilities::compute_only_composition_fractions(in.composition[i], - this->introspection().chemical_composition_field_indices()); - - // not strictly correct if thermal expansivities are different, since we are interpreting - // these compositions as volume fractions, but the error introduced should not be too bad. - out.densities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.densities, MaterialUtilities::arithmetic); - out.thermal_expansion_coefficients[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.thermal_expansion_coefficients, MaterialUtilities::arithmetic); - out.specific_heat[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.specific_heat_capacities, MaterialUtilities::arithmetic); - - if (define_conductivities == false) - { - double thermal_diffusivity = 0.0; - - for (unsigned int j=0; j < volume_fractions.size(); ++j) - thermal_diffusivity += volume_fractions[j] * thermal_diffusivities[j]; - - // Thermal conductivity at the given positions. If the temperature equation uses - // the reference density profile formulation, use the reference density to - // calculate thermal conductivity. Otherwise, use the real density. If the adiabatic - // conditions are not yet initialized, the real density will still be used. - if (this->get_parameters().formulation_temperature_equation == - Parameters::Formulation::TemperatureEquation::reference_density_profile && - this->get_adiabatic_conditions().is_initialized()) - out.thermal_conductivities[i] = thermal_diffusivity * out.specific_heat[i] * - this->get_adiabatic_conditions().density(in.position[i]); - else - out.thermal_conductivities[i] = thermal_diffusivity * out.specific_heat[i] * out.densities[i]; - } - else - { - // Use thermal conductivity values specified in the parameter file, if this - // option was selected. - out.thermal_conductivities[i] = MaterialUtilities::average_value (volume_fractions, thermal_conductivities, MaterialUtilities::arithmetic); - } - - out.compressibilities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.compressibilities, MaterialUtilities::arithmetic); - out.entropy_derivative_pressure[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.entropy_derivative_pressure, MaterialUtilities::arithmetic); - out.entropy_derivative_temperature[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.entropy_derivative_temperature, MaterialUtilities::arithmetic); - - // Compute the effective viscosity if requested and retrieve whether the material is plastically yielding. - // Also always compute the viscosity if additional outputs are requested, because the viscosity is needed - // to compute the elastic force term. - bool plastic_yielding = false; - IsostrainViscosities isostrain_viscosities; - if (in.requests_property(MaterialProperties::viscosity) || in.requests_property(MaterialProperties::additional_outputs)) - { - // Currently, the viscosities for each of the compositional fields are calculated assuming - // isostrain amongst all compositions, allowing calculation of the viscosity ratio. - // TODO: This is only consistent with viscosity averaging if the arithmetic averaging - // scheme is chosen. It would be useful to have a function to calculate isostress viscosities. - isostrain_viscosities = - rheology->calculate_isostrain_viscosities(in, i, volume_fractions, phase_function_values, n_phase_transitions_for_each_chemical_composition); - - // The isostrain condition implies that the viscosity averaging should be arithmetic (see above). - // We have given the user freedom to apply alternative bounds, because in diffusion-dominated - // creep (where n_diff=1) viscosities are stress and strain-rate independent, so the calculation - // of compositional field viscosities is consistent with any averaging scheme. - out.viscosities[i] = MaterialUtilities::average_value(volume_fractions, isostrain_viscosities.composition_viscosities, rheology->viscosity_averaging); - - // Decide based on the maximum composition if material is yielding. - // This avoids for example division by zero for harmonic averaging (as plastic_yielding - // holds values that are either 0 or 1), but might not be consistent with the viscosity - // averaging chosen. - std::vector::const_iterator max_composition = std::max_element(volume_fractions.begin(), volume_fractions.end()); - plastic_yielding = isostrain_viscosities.composition_yielding[std::distance(volume_fractions.begin(), max_composition)]; - - // Compute viscosity derivatives if they are requested - if (MaterialModel::MaterialModelDerivatives *derivatives = - out.template get_additional_output>()) - - rheology->compute_viscosity_derivatives(i, volume_fractions, - isostrain_viscosities.composition_viscosities, - in, out, phase_function_values, - n_phase_transitions_for_each_chemical_composition); - } - else - { - // The viscosity was not requested. Poison its value, along with the other - // quantities we set above and that would otherwise remain uninitialized - isostrain_viscosities.composition_yielding.clear(); - isostrain_viscosities.composition_viscosities.clear(); - isostrain_viscosities.current_friction_angles.clear(); - isostrain_viscosities.current_cohesions.clear(); - - out.viscosities[i] = numbers::signaling_nan(); - - if (MaterialModel::MaterialModelDerivatives *derivatives = - out.template get_additional_output>()) - { - derivatives->viscosity_derivative_wrt_strain_rate[i] = numbers::signaling_nan>(); - derivatives->viscosity_derivative_wrt_pressure[i] = numbers::signaling_nan(); - } - } - - // Now compute changes in the compositional fields (i.e. the accumulated strain). - for (unsigned int c=0; cstrain_rheology.fill_reaction_outputs(in, i, rheology->min_strain_rate, plastic_yielding, out); - - // Fill plastic outputs if they exist. - // The values in isostrain_viscosities only make sense when the calculate_isostrain_viscosities function - // has been called. - // TODO do we even need a separate function? We could compute the PlasticAdditionalOutputs here like - // the ElasticAdditionalOutputs. - rheology->fill_plastic_outputs(i, volume_fractions, plastic_yielding, in, out, isostrain_viscosities); - - if (this->get_parameters().enable_elasticity) - { - // Compute average elastic shear modulus - average_elastic_shear_moduli[i] = MaterialUtilities::average_value(volume_fractions, - rheology->elastic_rheology.get_elastic_shear_moduli(), - rheology->viscosity_averaging); - - // Fill the material properties that are part of the elastic additional outputs - if (ElasticAdditionalOutputs *elastic_out = out.template get_additional_output>()) - { - elastic_out->elastic_shear_moduli[i] = average_elastic_shear_moduli[i]; - } - } - } - - // If we use the full strain tensor, compute the change in the individual tensor components. - rheology->strain_rheology.compute_finite_strain_reaction_terms(in, out); - - if (this->get_parameters().enable_elasticity) - { - rheology->elastic_rheology.fill_elastic_outputs(in, average_elastic_shear_moduli, out); - rheology->elastic_rheology.fill_reaction_outputs(in, average_elastic_shear_moduli, out); - } - } - - - - template - bool - ViscoPlastic:: - is_compressible () const - { - return equation_of_state.is_compressible(); - } - - - - template - double ViscoPlastic:: - get_min_strain_rate () const - { - return rheology->min_strain_rate; - } - - - - template - void - ViscoPlastic::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Material model"); - { - prm.enter_subsection ("Visco Plastic"); - { - MaterialUtilities::PhaseFunction::declare_parameters(prm); - - EquationOfState::MulticomponentIncompressible::declare_parameters (prm); - - Rheology::ViscoPlastic::declare_parameters(prm); - - // Equation of state parameters - prm.declare_entry ("Thermal diffusivities", "0.8e-6", - Patterns::List(Patterns::Double (0.)), - "List of thermal diffusivities, for background material and compositional fields, " - "for a total of N+1 values, where N is the number of all compositional fields or only " - "those corresponding to chemical compositions. " - "If only one value is given, then all use the same value. " - "Units: \\si{\\meter\\squared\\per\\second}."); - prm.declare_entry ("Define thermal conductivities","false", - Patterns::Bool (), - "Whether to directly define thermal conductivities for each compositional field " - "instead of calculating the values through the specified thermal diffusivities, " - "densities, and heat capacities. "); - prm.declare_entry ("Thermal conductivities", "3.0", - Patterns::List(Patterns::Double(0)), - "List of thermal conductivities, for background material and compositional fields, " - "for a total of N+1 values, where N is the number of all compositional fields or only " - "those corresponding to chemical compositions. " - "If only one value is given, then all use the same value. " - "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - - template - void - ViscoPlastic::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Material model"); - { - prm.enter_subsection ("Visco Plastic"); - { - // Phase transition parameters - phase_function.initialize_simulator (this->get_simulator()); - phase_function.parse_parameters (prm); - - std::vector n_phases_for_each_composition = phase_function.n_phases_for_each_composition(); - - // Currently, phase_function.n_phases_for_each_composition() returns a list of length - // equal to the total number of compositions, whether or not they are chemical compositions. - // The equation_of_state (multicomponent incompressible) requires a list only for - // chemical compositions. - std::vector n_phases_for_each_chemical_composition = {n_phases_for_each_composition[0]}; - n_phase_transitions_for_each_chemical_composition = {n_phases_for_each_composition[0] - 1}; - n_phases = n_phases_for_each_composition[0]; - for (auto i : this->introspection().chemical_composition_field_indices()) - { - n_phases_for_each_chemical_composition.push_back(n_phases_for_each_composition[i+1]); - n_phase_transitions_for_each_chemical_composition.push_back(n_phases_for_each_composition[i+1] - 1); - n_phases += n_phases_for_each_composition[i+1]; - } - - // Equation of state parameters - equation_of_state.initialize_simulator (this->get_simulator()); - equation_of_state.parse_parameters (prm, - std::make_unique>(n_phases_for_each_chemical_composition)); - - // Make options file for parsing maps to double arrays - std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); - chemical_field_names.insert(chemical_field_names.begin(),"background"); - - std::vector compositional_field_names = this->introspection().get_composition_names(); - compositional_field_names.insert(compositional_field_names.begin(),"background"); - - Utilities::MapParsing::Options options(chemical_field_names, "Thermal diffusivities"); - options.list_of_allowed_keys = compositional_field_names; - options.allow_multiple_values_per_key = true; - options.n_values_per_key = n_phases_for_each_chemical_composition; - options.check_values_per_key = (options.n_values_per_key.size() != 0); - options.store_values_per_key = (options.n_values_per_key.size() == 0); - - thermal_diffusivities = Utilities::MapParsing::parse_map_to_double_array(prm.get("Thermal diffusivities"), options); - define_conductivities = prm.get_bool ("Define thermal conductivities"); - - options.property_name = "Thermal conductivities"; - thermal_conductivities = Utilities::MapParsing::parse_map_to_double_array (prm.get("Thermal conductivities"), options); - - rheology = std::make_unique>(); - rheology->initialize_simulator (this->get_simulator()); - rheology->parse_parameters(prm, std::make_unique>(n_phases_for_each_chemical_composition)); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - - // Declare dependencies on solution variables - this->model_dependence.viscosity = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::strain_rate | NonlinearDependence::compositional_fields; - this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; - this->model_dependence.compressibility = NonlinearDependence::none; - this->model_dependence.specific_heat = NonlinearDependence::none; - this->model_dependence.thermal_conductivity = NonlinearDependence::temperature | NonlinearDependence::pressure | NonlinearDependence::compositional_fields; - } - - - - template - void - ViscoPlastic::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const - { - rheology->create_plastic_outputs(out); - - if (this->get_parameters().enable_elasticity) - rheology->elastic_rheology.create_elastic_outputs(out); - } - - } -} - -// explicit instantiations -namespace aspect -{ - namespace MaterialModel - { - ASPECT_REGISTER_MATERIAL_MODEL(ViscoPlastic, - "visco plastic", - "An implementation of an incompressible visco(elastic)-plastic rheology " - "with options for selecting dislocation creep, diffusion creep or " - "composite viscous flow laws. Prior to yielding, one may select to " - "modify the viscosity to account for viscoelastic effects by setting the " - "parameter 'Enable elasticity' in subsection Formulation to true. Plasticity " - "limits viscous stresses through a Drucker Prager yield criterion. " - "The implementation of this material model is based heavily on the " - "`DiffusionDislocation' (Bob Myhill), `DruckerPrager' " - "(Anne Glerum), and `Viscoelastic' (John Naliboff) material models. " - "\n\n " - "The viscosity for dislocation or diffusion creep is defined as " - "$ \\eta = \\frac 12 A^{-\\frac{1}{n}} d^{\\frac{m}{n}} " - "\\dot{\\varepsilon}_{ii}^{\\frac{1-n}{n}} " - "\\exp\\left(\\frac{E + PV}{nRT}\\right)$ " - "where $A$ is the prefactor, $n$ is the stress exponent, " - "$\\dot{\\varepsilon}_{ii}$ is the square root of the deviatoric " - "strain rate tensor second invariant, $d$ is grain size, " - "$m$ is the grain size exponent, $E$ is activation energy, " - "$V$ is activation volume, $P$ is pressure, $R$ is the gas " - "exponent and $T$ is temperature. " - "This form of the viscosity equation is commonly used in " - "geodynamic simulations. See, for example, Billen and Hirth " - "(2007), G3, 8, Q08012. Significantly, other studies may use " - "slightly different forms of the viscosity equation leading to " - "variations in how specific terms are defined or combined. For " - "example, the grain size exponent should always be positive in " - "the diffusion viscosity equation used here, while other studies " - "place the grain size term in the denominator and invert the sign " - "of the grain size exponent. When examining previous work, one " - "should carefully check how the viscous prefactor and grain size " - "terms are defined. " - "\n\n " - "One may select to use the diffusion ($\\eta_{\\text{diff}}$; $n=1$, $m\\neq 0$), " - "dislocation ($\\eta_{\\text{disl}}$, $n>1$, $m=0$) or composite " - "$\\frac{\\eta_{\\text{diff}} \\eta_{\\text{disl}}}{\\eta_{\\text{diff}}+\\eta_{\\text{disl}}}$ equation form. " - "\n\n " - "The diffusion and dislocation prefactors can be weakened with a factor " - "between 0 and 1 according to the total or the viscous strain only. " - "\n\n " - "Viscosity is limited through one of two different `yielding' mechanisms. " - "\n\n" - "The first plasticity mechanism limits viscous stress through a " - "Drucker Prager yield criterion, where the yield stress in 3d is " - "$\\sigma_y = \\frac{6C\\cos(\\phi) + 2P\\sin(\\phi)} " - "{\\sqrt{3}(3+\\sin(\\phi))}$ " - "and " - "$\\sigma_y = C\\cos(\\phi) + P\\sin(\\phi)$ " - "in 2d. Above, $C$ is cohesion and $\\phi$ is the angle of " - "internal friction. Note that the 2d form is equivalent to the " - "Mohr Coulomb yield surface. If $\\phi$ is 0, the yield stress " - "is fixed and equal to the cohesion (Von Mises yield criterion). " - "When the viscous stress ($2\\eta {\\varepsilon}_{ii}$) exceeds " - "the yield stress, the viscosity is rescaled back to the yield " - "surface: $\\eta_{y}=\\sigma_{y}/(2{\\varepsilon}_{ii})$. " - "This form of plasticity is commonly used in geodynamic models. " - "See, for example, Thieulot, C. (2011), PEPI 188, pp. 47-68. " - "\n\n" - "The user has the option to linearly reduce the cohesion and " - "internal friction angle as a function of the finite strain magnitude. " - "The finite strain invariant or full strain tensor is calculated through " - "compositional fields within the material model. This implementation is " - "identical to the compositional field finite strain plugin and cookbook " - "described in the manual (author: Gassmoeller, Dannberg). If the user selects to track " - "the finite strain invariant ($e_{ii}$), a single compositional field tracks " - "the value derived from $e_{ii}^t = (e_{ii})^{(t-1)} + \\dot{e}_{ii}\\; dt$, where $t$ and $t-1$ " - "are the current and prior time steps, $\\dot{e}_{ii}$ is the second invariant of the " - "strain rate tensor and $dt$ is the time step size. In the case of the " - "full strain tensor $F$, the finite strain magnitude is derived from the " - "second invariant of the symmetric stretching tensor $L$, where " - "$L = F [F]^T$. The user must specify a single compositional " - "field for the finite strain invariant or multiple fields (4 in 2d, 9 in 3d) " - "for the finite strain tensor. These field(s) must be the first listed " - "compositional fields in the parameter file. Note that one or more of the finite strain " - "tensor components must be assigned a non-zero value initially. This value can be " - "be quite small (e.g., 1.e-8), but still non-zero. While the option to track and use " - "the full finite strain tensor exists, tracking the associated compositional fields " - "is computationally expensive in 3d. Similarly, the finite strain magnitudes " - "may in fact decrease if the orientation of the deformation field switches " - "through time. Consequently, the ideal solution is track the finite strain " - "invariant (single compositional) field within the material and track " - "the full finite strain tensor through particles." - "When only the second invariant of the strain is tracked, one has the option to " - "track the full strain or only the plastic strain. In the latter case, strain is only tracked " - "in case the material is plastically yielding, i.e. the viscous stress > yield stress. " - "\n\n" - "Viscous stress may also be limited by a non-linear stress limiter " - "that has a form similar to the Peierls creep mechanism. " - "This stress limiter assigns an effective viscosity " - "$\\sigma_{\\text{eff}} = \\frac{\\tau_y}{2\\varepsilon_y} " - "{\\frac{\\varepsilon_{ii}}{\\varepsilon_y}}^{\\frac{1}{n_y}-1}$ " - "Above $\\tau_y$ is a yield stress, $\\varepsilon_y$ is the " - "reference strain rate, $\\varepsilon_{ii}$ is the strain rate " - "and $n_y$ is the stress limiter exponent. The yield stress, " - "$\\tau_y$, is defined through the Drucker Prager yield criterion " - "formulation. This method of limiting viscous stress has been used " - "in various forms within the geodynamic literature \\cite{chri92,vavv02,cibi13,cibi15}." - "When $n_y$ is 1, it essentially becomes a linear viscosity model, " - "and in the limit $n_y\\rightarrow \\infty$ it converges to the " - "standard viscosity rescaling method (concretely, values $n_y>20$ " - "are large enough)." - "\n\n " - "The visco-plastic rheology described above may also be modified to include " - "viscoelastic deformation, thus producing a viscoelastic plastic constitutive " - "relationship. " - "\n\n " - "The viscoelastic rheology behavior takes into account the elastic shear " - "strength (e.g., shear modulus), while the tensile and volumetric " - "strength (e.g., Young's and bulk modulus) are not considered. The " - "model is incompressible and allows specifying an arbitrary number " - "of compositional fields, where each field represents a different " - "rock type or component of the viscoelastic stress tensor. The stress " - "tensor in 2d and 3d, respectively, contains 3 or 6 components. The " - "compositional fields representing these components must be named " - "and listed in a very specific format, which is designed to minimize " - "mislabeling stress tensor components as distinct 'compositional " - "rock types' (or vice versa). For 2d models, the first three " - "compositional fields must be labeled 'stress\\_xx', 'stress\\_yy' and 'stress\\_xy'. " - "In 3d, the first six compositional fields must be labeled 'stress\\_xx', " - "'stress\\_yy', 'stress\\_zz', 'stress\\_xy', 'stress\\_xz', 'stress\\_yz'. " - "\n\n " - "Combining this viscoelasticity implementation with non-linear viscous flow " - "and plasticity produces a constitutive relationship commonly referred to " - "as partial elastoviscoplastic (e.g., pEVP) in the geodynamics community. " - "While extensively discussed and applied within the geodynamics " - "literature, notable references include: " - "Moresi et al. (2003), J. Comp. Phys., v. 184, p. 476-497. " - "Gerya and Yuen (2007), Phys. Earth. Planet. Inter., v. 163, p. 83-105. " - "Gerya (2010), Introduction to Numerical Geodynamic Modeling. " - "Kaus (2010), Tectonophysics, v. 484, p. 36-47. " - "Choi et al. (2013), J. Geophys. Res., v. 118, p. 2429-2444. " - "Keller et al. (2013), Geophys. J. Int., v. 195, p. 1406-1442. " - "\n\n " - "The overview below directly follows Moresi et al. (2003) eqns. 23-38. " - "However, an important distinction between this material model and " - "the studies above is the use of compositional fields, rather than " - "particles, to track individual components of the viscoelastic stress " - "tensor. The material model will be updated when an option to track " - "and calculate viscoelastic stresses with particles is implemented. " - "\n\n " - "Moresi et al. (2003) begins (eqn. 23) by writing the deviatoric " - "rate of deformation ($\\hat{D}$) as the sum of elastic " - "($\\hat{D_{e}}$) and viscous ($\\hat{D_{v}}$) components: " - "$\\hat{D} = \\hat{D_{e}} + \\hat{D_{v}}$. " - "These terms further decompose into " - "$\\hat{D_{v}} = \\frac{\\tau}{2\\eta}$ and " - "$\\hat{D_{e}} = \\frac{\\overset{\\nabla}{\\tau}}{2\\mu}$, where " - "$\\tau$ is the viscous deviatoric stress, $\\eta$ is the shear viscosity, " - "$\\mu$ is the shear modulus and $\\overset{\\nabla}{\\tau}$ is the " - "Jaumann corotational stress rate. This later term (eqn. 24) contains the " - "time derivative of the deviatoric stress ($\\dot{\\tau}$) and terms that " - "account for material spin (e.g., rotation) due to advection: " - "$\\overset{\\nabla}{\\tau} = \\dot{\\tau} + {\\tau}W -W\\tau$. " - "Above, $W$ is the material spin tensor (eqn. 25): " - "$W_{ij} = \\frac{1}{2} \\left (\\frac{\\partial V_{i}}{\\partial x_{j}} - " - "\\frac{\\partial V_{j}}{\\partial x_{i}} \\right )$. " - "\n\n " - "If plasticity is included, the deviatoric rate of deformation may be written as: " - "$\\hat{D} = \\hat{D_{e}} + \\hat{D_{v}} + \\hat{D_{p}}$, where $\\hat{D_{p}}$ " - "is the plastic component. $\\hat{D_{p}}$ decomposes to $\\frac{\\tau_{y}}{2\\eta_{y}}$, " - "where $\\tau_{y}$ is the yield stress and $\\eta_{y}$ is the viscosity rescaled " - "to the yield surface. " - "The Jaumann stress-rate can also be approximated using terms from the " - "previous time step ($t$) and current time step ($t + \\Delta t^{e}$): " - "$\\smash[t]{\\overset{\\nabla}{\\tau}}^{t + \\Delta t^{e}} \\approx " - "\\frac{\\tau^{t + \\Delta t^{e} - \\tau^{t}}}{\\Delta t^{e}} - " - "W^{t}\\tau^{t} + \\tau^{t}W^{t}$. " - "In this material model, the size of the time step above ($\\Delta t^{e}$) " - "can be specified as the numerical time step size or an independent fixed time " - "step. If the latter case is selected, the user has an option to apply a " - "stress averaging scheme to account for the differences between the numerical " - "and fixed elastic time step (eqn. 32). If one selects to use a fixed elastic time " - "step throughout the model run, this can still be achieved by using CFL and " - "maximum time step values that restrict the numerical time step to a specific time." - "\n\n " - "The formulation above allows rewriting the total rate of deformation (eqn. 29) as\n " - "$\\tau^{t + \\Delta t^{e}} = \\eta_{eff} \\left ( " - "2\\hat{D}^{t + \\triangle t^{e}} + \\frac{\\tau^{t}}{\\mu \\Delta t^{e}} + " - "\\frac{W^{t}\\tau^{t} - \\tau^{t}W^{t}}{\\mu} \\right )$. " - "\n\n " - "The effective viscosity (eqn. 28) is a function of the viscosity ($\\eta$), " - "elastic time step size ($\\Delta t^{e}$) and shear relaxation time " - "($ \\alpha = \\frac{\\eta}{\\mu} $): " - "$\\eta_{eff} = \\eta \\frac{\\Delta t^{e}}{\\Delta t^{e} + \\alpha}$ " - "The magnitude of the shear modulus thus controls how much the effective " - "viscosity is reduced relative to the initial viscosity. " - "\n\n " - "Elastic effects are introduced into the governing Stokes equations through " - "an elastic force term (eqn. 30) using stresses from the previous time step: " - "$F^{e,t} = -\\frac{\\eta_{eff}}{\\mu \\Delta t^{e}} \\tau^{t}$. " - "This force term is added onto the right-hand side force vector in the " - "system of equations. " - "\n\n " - "When plastic yielding occurs, the effective viscosity in equation 29 and 30 is the " - "plastic viscosity (equation 36). If the current stress is below the plastic " - "yield stress, the effective viscosity is still as defined in equation 28. " - "During non-linear iterations, we define the current stress prior to yielding " - "(e.g., value compared to yield stress) as " - "$\\tau^{t + \\Delta t^{e}} = \\eta_{eff} \\left ( 2\\hat{D}^{t + \\triangle t^{e}} + " - "\\frac{\\tau^{t}}{\\mu \\Delta t^{e}} \\right ) $" - "\n\n " - "Compositional fields can each be assigned individual values of " - "thermal diffusivity, heat capacity, density, thermal " - "expansivity and rheological parameters. " - "\n\n " - "If more than one compositional field is present at a given " - "point, viscosities are averaged with an arithmetic, geometric " - "harmonic (default) or maximum composition scheme. " - "\n\n " - "The value for the components of this formula and additional " - "parameters are read from the parameter file in subsection " - " 'Material model/Visco Plastic'.") - } -} diff --git a/source/material_model/viscoelastic.cc.bak b/source/material_model/viscoelastic.cc.bak deleted file mode 100644 index f25c6375a4a..00000000000 --- a/source/material_model/viscoelastic.cc.bak +++ /dev/null @@ -1,313 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file doc/COPYING. If not see - . -*/ - - -#include -#include -#include -#include - -namespace aspect -{ - namespace MaterialModel - { - template - void - Viscoelastic:: - evaluate(const MaterialModel::MaterialModelInputs &in, - MaterialModel::MaterialModelOutputs &out) const - { - EquationOfStateOutputs eos_outputs (this->introspection().get_number_of_fields_of_type(CompositionalFieldDescription::chemical_composition)+1); - - // Store which components to exclude during volume fraction computation. - ComponentMask composition_mask(this->n_compositional_fields(), true); - // assign compositional fields associated with viscoelastic stress a value of 0 - // assume these fields are listed first - for (unsigned int i=0; i < SymmetricTensor<2,dim>::n_independent_components; ++i) - composition_mask.set(i,false); - - std::vector average_elastic_shear_moduli (in.n_evaluation_points()); - std::vector elastic_shear_moduli(elastic_rheology.get_elastic_shear_moduli()); - - for (unsigned int i=0; i < in.n_evaluation_points(); ++i) - { - const std::vector composition = in.composition[i]; - - const std::vector volume_fractions = MaterialUtilities::compute_only_composition_fractions(composition, - this->introspection().chemical_composition_field_indices()); - - equation_of_state.evaluate(in, i, eos_outputs); - - // Arithmetic averaging of thermal conductivities - // This may not be strictly the most reasonable thing, but for most Earth materials we hope - // that they do not vary so much that it is a big problem. - out.thermal_conductivities[i] = MaterialUtilities::average_value(volume_fractions, thermal_conductivities, MaterialUtilities::arithmetic); - - // not strictly correct if thermal expansivities are different, since we are interpreting - // these compositions as volume fractions, but the error introduced should not be too bad. - out.densities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.densities, MaterialUtilities::arithmetic); - out.thermal_expansion_coefficients[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.thermal_expansion_coefficients, MaterialUtilities::arithmetic); - out.specific_heat[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.specific_heat_capacities, MaterialUtilities::arithmetic); - - out.compressibilities[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.compressibilities, MaterialUtilities::arithmetic); - out.entropy_derivative_pressure[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.entropy_derivative_pressure, MaterialUtilities::arithmetic); - out.entropy_derivative_temperature[i] = MaterialUtilities::average_value (volume_fractions, eos_outputs.entropy_derivative_temperature, MaterialUtilities::arithmetic); - - for (unsigned int c=0; c *elastic_out = out.template get_additional_output>()) - { - elastic_out->elastic_shear_moduli[i] = average_elastic_shear_moduli[i]; - } - } - - elastic_rheology.fill_elastic_outputs(in, average_elastic_shear_moduli, out); - elastic_rheology.fill_reaction_outputs(in, average_elastic_shear_moduli, out); - - } - - template - bool - Viscoelastic:: - is_compressible () const - { - return equation_of_state.is_compressible(); - } - - template - void - Viscoelastic::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Material model"); - { - prm.enter_subsection("Viscoelastic"); - { - EquationOfState::MulticomponentIncompressible::declare_parameters (prm); - Rheology::Elasticity::declare_parameters (prm); - - prm.declare_entry ("Viscosities", "1.e21", - Patterns::List(Patterns::Double (0.)), - "List of viscosities for background mantle and compositional fields, " - "for a total of N+1 values, where N is the number of all compositional fields or only " - "those corresponding to chemical compositions. " - "If only one value is given, then all use the same value. " - "Units: \\si{\\pascal\\second}."); - prm.declare_entry ("Thermal conductivities", "4.7", - Patterns::List(Patterns::Double (0.)), - "List of thermal conductivities for background mantle and compositional fields, " - "for a total of N+1 values, where N is the number of all compositional fields or only " - "those corresponding to chemical compositions. " - "If only one value is given, then all use the same value. " - "Units: \\si{\\watt\\per\\meter\\per\\kelvin}."); - prm.declare_entry ("Viscosity averaging scheme", "harmonic", - Patterns::Selection("arithmetic|harmonic|geometric|maximum composition "), - "When more than one compositional field is present at a point " - "with different viscosities, we need to come up with an average " - "viscosity at that point. Select a weighted harmonic, arithmetic, " - "geometric, or maximum composition."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - Viscoelastic::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Material model"); - { - prm.enter_subsection("Viscoelastic"); - { - // Equation of state parameters - equation_of_state.initialize_simulator (this->get_simulator()); - equation_of_state.parse_parameters (prm); - - elastic_rheology.initialize_simulator (this->get_simulator()); - elastic_rheology.parse_parameters(prm); - - viscosity_averaging = MaterialUtilities::parse_compositional_averaging_operation ("Viscosity averaging scheme", - prm); - - // Make options file for parsing maps to double arrays - std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); - chemical_field_names.insert(chemical_field_names.begin(),"background"); - - std::vector compositional_field_names = this->introspection().get_composition_names(); - compositional_field_names.insert(compositional_field_names.begin(),"background"); - - Utilities::MapParsing::Options options(chemical_field_names, "Viscosities"); - options.list_of_allowed_keys = compositional_field_names; - - viscosities = Utilities::MapParsing::parse_map_to_double_array (prm.get("Viscosities"), options); - options.property_name = "Thermal conductivities"; - thermal_conductivities = Utilities::MapParsing::parse_map_to_double_array (prm.get("Thermal conductivities"), options); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - - - - // Declare dependencies on solution variables - this->model_dependence.viscosity = NonlinearDependence::compositional_fields; - this->model_dependence.density = NonlinearDependence::temperature | NonlinearDependence::compositional_fields; - this->model_dependence.compressibility = NonlinearDependence::none; - this->model_dependence.specific_heat = NonlinearDependence::compositional_fields; - this->model_dependence.thermal_conductivity = NonlinearDependence::compositional_fields; - } - - - - template - void - Viscoelastic::create_additional_named_outputs (MaterialModel::MaterialModelOutputs &out) const - { - elastic_rheology.create_elastic_outputs(out); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MaterialModel - { - ASPECT_REGISTER_MATERIAL_MODEL(Viscoelastic, - "viscoelastic", - "An implementation of a simple linear viscoelastic rheology that " - "only includes the deviatoric components of elasticity. Specifically, " - "the viscoelastic rheology only takes into account the elastic shear " - "strength (e.g., shear modulus), while the tensile and volumetric " - "strength (e.g., Young's and bulk modulus) are not considered. The " - "model is incompressible and allows specifying an arbitrary number " - "of compositional fields, where each field represents a different " - "rock type or component of the viscoelastic stress tensor. The stress " - "tensor in 2d and 3d, respectively, contains 3 or 6 components. The " - "compositional fields representing these components must be named " - "and listed in a very specific format, which is designed to minimize " - "mislabeling stress tensor components as distinct 'compositional " - "rock types' (or vice versa). For 2d models, the first three " - "compositional fields must be labeled 'stress\\_xx', 'stress\\_yy' and 'stress\\_xy'. " - "In 3d, the first six compositional fields must be labeled 'stress\\_xx', " - "'stress\\_yy', 'stress\\_zz', 'stress\\_xy', 'stress\\_xz', 'stress\\_yz'. " - "\n\n " - "Expanding the model to include non-linear viscous flow (e.g., " - "diffusion/dislocation creep) and plasticity would produce a " - "constitutive relationship commonly referred to as partial " - "elastoviscoplastic (e.g., pEVP) in the geodynamics community. " - "While extensively discussed and applied within the geodynamics " - "literature, notable references include: " - "Moresi et al. (2003), J. Comp. Phys., v. 184, p. 476-497. " - "Gerya and Yuen (2007), Phys. Earth. Planet. Inter., v. 163, p. 83-105. " - "Gerya (2010), Introduction to Numerical Geodynamic Modeling. " - "Kaus (2010), Tectonophysics, v. 484, p. 36-47. " - "Choi et al. (2013), J. Geophys. Res., v. 118, p. 2429-2444. " - "Keller et al. (2013), Geophys. J. Int., v. 195, p. 1406-1442. " - "\n\n " - "The overview below directly follows Moresi et al. (2003) eqns. 23-32. " - "However, an important distinction between this material model and " - "the studies above is the use of compositional fields, rather than " - "particles, to track individual components of the viscoelastic stress " - "tensor. The material model will be updated when an option to track " - "and calculate viscoelastic stresses with particles is implemented. " - "\n\n " - "Moresi et al. (2003) begins (eqn. 23) by writing the deviatoric " - "rate of deformation ($\\hat{D}$) as the sum of elastic " - "($\\hat{D_{e}}$) and viscous ($\\hat{D_{v}}$) components: " - "$\\hat{D} = \\hat{D_{e}} + \\hat{D_{v}}$. " - "These terms further decompose into " - "$\\hat{D_{v}} = \\frac{\\tau}{2\\eta}$ and " - "$\\hat{D_{e}} = \\frac{\\overset{\\nabla}{\\tau}}{2\\mu}$, where " - "$\\tau$ is the viscous deviatoric stress, $\\eta$ is the shear viscosity, " - "$\\mu$ is the shear modulus and $\\overset{\\nabla}{\\tau}$ is the " - "Jaumann corotational stress rate. This later term (eqn. 24) contains the " - "time derivative of the deviatoric stress ($\\dot{\\tau}$) and terms that " - "account for material spin (e.g., rotation) due to advection: " - "$\\overset{\\nabla}{\\tau} = \\dot{\\tau} + {\\tau}W -W\\tau$. " - "Above, $W$ is the material spin tensor (eqn. 25): " - "$W_{ij} = \\frac{1}{2} \\left (\\frac{\\partial V_{i}}{\\partial x_{j}} - " - "\\frac{\\partial V_{j}}{\\partial x_{i}} \\right )$. " - "\n\n " - "The Jaumann stress-rate can also be approximated using terms from the " - "previous time step ($t$) and current time step ($t + \\Delta t^{e}$): " - "$\\smash[t]{\\overset{\\nabla}{\\tau}}^{t + \\Delta t^{e}} \\approx " - "\\frac{\\tau^{t + \\Delta t^{e} - \\tau^{t}}}{\\Delta t^{e}} - " - "W^{t}\\tau^{t} + \\tau^{t}W^{t}$. " - "In this material model, the size of the time step above ($\\Delta t^{e}$) " - "can be specified as the numerical time step size or an independent fixed time " - "step. If the latter case is selected, the user has an option to apply a " - "stress averaging scheme to account for the differences between the numerical " - "and fixed elastic time step (eqn. 32). If one selects to use a fixed elastic time " - "step throughout the model run, this can still be achieved by using CFL and " - "maximum time step values that restrict the numerical time step to a specific time." - "\n\n " - "The formulation above allows rewriting the total deviatoric stress (eqn. 29) as\n " - "$\\tau^{t + \\Delta t^{e}} = \\eta_\\text{eff} \\left ( " - "2\\hat{D}^{t + \\triangle t^{e}} + \\frac{\\tau^{t}}{\\mu \\Delta t^{e}} + " - "\\frac{W^{t}\\tau^{t} - \\tau^{t}W^{t}}{\\mu} \\right )$. " - "\n\n " - "The effective viscosity (eqn. 28) is a function of the viscosity ($\\eta$), " - "elastic time step size ($\\Delta t^{e}$) and shear relaxation time " - "($ \\alpha = \\frac{\\eta}{\\mu} $): " - "$\\eta_\\text{eff} = \\eta \\frac{\\Delta t^{e}}{\\Delta t^{e} + \\alpha}$ " - "The magnitude of the shear modulus thus controls how much the effective " - "viscosity is reduced relative to the initial viscosity. " - "\n\n " - "Elastic effects are introduced into the governing Stokes equations through " - "an elastic force term (eqn. 30) using stresses from the previous time step: " - "$F^{e,t} = -\\frac{\\eta_\\text{eff}}{\\mu \\Delta t^{e}} \\tau^{t}$. " - "This force term is added onto the right-hand side force vector in the " - "system of equations. " - "\n\n " - "The value of each compositional field representing distinct rock types at a " - "point is interpreted to be a volume fraction of that rock type. If the sum of " - "the compositional field volume fractions is less than one, then the remainder " - "of the volume is assumed to be 'background material'." - "\n\n " - "Several model parameters (densities, elastic shear moduli, thermal expansivities, " - "thermal conductivies, specific heats) can be defined per-compositional field. " - "For each material parameter the user supplies a comma delimited list of length " - "N+1, where N is the number of compositional fields. The additional field corresponds " - "to the value for background material. They should be ordered ''background, " - "composition1, composition2...''. However, the first 3 (2d) or 6 (3d) composition " - "fields correspond to components of the elastic stress tensor and their material " - "values will not contribute to the volume fractions. If a single value is given, then " - "all the compositional fields are given that value. Other lengths of lists are not " - "allowed. For a given compositional field the material parameters are treated as " - "constant, except density, which varies linearly with temperature according to the " - "thermal expansivity. " - "\n\n " - "When more than one compositional field is present at a point, they are averaged " - "arithmetically. An exception is viscosity, which may be averaged arithmetically, " - "harmonically, geometrically, or by selecting the viscosity of the composition field " - "with the greatest volume fraction.") - } -} diff --git a/source/mesh_deformation/ascii_data.cc.bak b/source/mesh_deformation/ascii_data.cc.bak deleted file mode 100644 index 4c8a6b6f3c3..00000000000 --- a/source/mesh_deformation/ascii_data.cc.bak +++ /dev/null @@ -1,151 +0,0 @@ -/* - Copyright (C) 2016 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - - -#include -#include -#include -#include - -#include -#include - - -namespace aspect -{ - namespace MeshDeformation - { - template - AsciiData::AsciiData () - : - surface_boundary_id(1) - {} - - - - template - void - AsciiData::initialize () - { - surface_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); - - Utilities::AsciiDataBoundary::initialize({surface_boundary_id}, - 1); - } - - - - template - Tensor<1,dim> - AsciiData::compute_initial_deformation_on_boundary(const types::boundary_id boundary_indicator, - const Point &position) const - { - const double topo = Utilities::AsciiDataBoundary::get_data_component(boundary_indicator, - position, - 0); - - const Tensor<1,dim> gravity = this->get_gravity_model().gravity_vector(position); - - Tensor<1,dim> topography_direction; - if (gravity.norm() > 0.0) - topography_direction = -gravity / gravity.norm(); - - return topo * topography_direction; - } - - - - template - bool - AsciiData:: - needs_surface_stabilization () const - { - return false; - } - - - - template - void - AsciiData::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh deformation"); - { - Utilities::AsciiDataBase::declare_parameters(prm, - "$ASPECT_SOURCE_DIR/data/geometry-model/initial-topography-model/ascii-data/test/", - "box_3d_%s.0.txt"); - } - prm.leave_subsection(); - } - - - - template - void - AsciiData::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh deformation"); - { - Utilities::AsciiDataBase::parse_parameters(prm); - } - prm.leave_subsection(); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace MeshDeformation - { - ASPECT_REGISTER_MESH_DEFORMATION_MODEL(AsciiData, - "ascii data", - "Implementation of a model in which the initial mesh " - "deformation (initial topography) is " - "derived from a file containing data " - "in ascii format. The following geometry models " - "are currently supported: box, chunk, spherical. " - "Note the required format of the " - "input data: The first lines may contain any number of comments " - "if they begin with `#', but one of these lines needs to " - "contain the number of grid points in each dimension as " - "for example `# POINTS: 3 3'. " - "The order of the data columns " - "has to be `x', `Topography [m]' in a 2d model and " - " `x', `y', `Topography [m]' in a 3d model, which means that " - "there has to be a single column " - "containing the topography. " - "Note that the data in the input " - "file needs to be sorted in a specific order: " - "the first coordinate needs to ascend first, " - "followed by the second in order to " - "assign the correct data to the prescribed coordinates. " - "If you use a spherical model, " - "then the assumed grid changes. " - "`x' will be replaced by the azimuth angle in radians " - " and `y' by the polar angle in radians measured " - "positive from the north pole. The grid will be assumed to be " - "a longitude-colatitude grid. Note that the order " - "of spherical coordinates is `phi', `theta' " - "and not `theta', `phi', since this allows " - "for dimension independent expressions.") - } -} diff --git a/source/mesh_deformation/diffusion.cc.bak b/source/mesh_deformation/diffusion.cc.bak deleted file mode 100644 index abe769a856c..00000000000 --- a/source/mesh_deformation/diffusion.cc.bak +++ /dev/null @@ -1,582 +0,0 @@ -/* - Copyright (C) 2020 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace aspect -{ - - namespace MeshDeformation - { - template - Diffusion::Diffusion() - : - diffusivity(0.), - timesteps_between_diffusion (1), - apply_diffusion(false) - {} - - - - template - void - Diffusion::initialize () - { - AssertThrow(Plugins::plugin_type_matches>(this->get_geometry_model()) || - Plugins::plugin_type_matches>(this->get_geometry_model()), - ExcMessage("The surface diffusion mesh deformation plugin only works for Box geometries.")); - } - - - - template - void - Diffusion::update () - { - // Set the current timestep number - const unsigned int current_timestep_number = this->get_timestep_number(); - - // Determine whether we need to apply diffusion based - // on the timestep interval between applications. - // Because mesh deformation is computed at the beginning - // of each timestep, we do not apply diffusion in the first timestep. - if (current_timestep_number != 0) - { - if (current_timestep_number % timesteps_between_diffusion == 0) - apply_diffusion = true; - else - apply_diffusion = false; - } - } - - - - template - void Diffusion::diffuse_boundary(const DoFHandler &mesh_deformation_dof_handler, - const IndexSet &mesh_locally_owned, - const IndexSet &mesh_locally_relevant, - LinearAlgebra::Vector &output, - const std::set &boundary_ids) const - { - // Check that the current timestep does not exceed the diffusion timestep - check_diffusion_time_step(mesh_deformation_dof_handler, boundary_ids); - - // Set up constraints - AffineConstraints matrix_constraints(mesh_locally_relevant); - DoFTools::make_hanging_node_constraints(mesh_deformation_dof_handler, matrix_constraints); - - std::set periodic_boundary_indicators; - using periodic_boundary_pairs = std::set, unsigned int>>; - const periodic_boundary_pairs pbp = this->get_geometry_model().get_periodic_boundary_pairs(); - for (const auto &p : pbp) - { - DoFTools::make_periodicity_constraints(mesh_deformation_dof_handler, - p.first.first, p.first.second, p.second, matrix_constraints); - periodic_boundary_indicators.insert(p.first.first); - periodic_boundary_indicators.insert(p.first.second); - } - - // A boundary can be: - // 1) A mesh deformation boundary with its deformation computed by this plugin. - // 2) A zero mesh displacement boundary: - // a) boundaries with zero Stokes velocity that are not an Additional tangential mesh boundary or mesh deformation boundary, - // b) boundaries with prescribed Stokes velocity that are not an Additional tangential mesh boundary or mesh deformation boundary. - // 3) A tangential mesh displacement boundary (no normal flux): - // a) tangential Stokes boundaries that are not a mesh deformation boundary, - // b) additional tangential mesh boundaries other than those in a) and c), - // c) periodic boundaries that are not a mesh deformation boundary. - // We obtain the zero mesh displacement boundaries by subtracting the mesh deformation ones (1+3) from all used boundary indicators. In this - // case, when no Stokes velocity boundary conditions are set (e.g. when using the single Advection, - // no Stokes solver scheme, we do end up with mesh displacement boundary conditions. - - // All boundary indicators used by the current geometry. - const std::set all_boundaries = this->get_geometry_model().get_used_boundary_indicators(); - - // Get the tangential Stokes velocity boundary indicators. - const std::set tangential_velocity_boundary_indicators = - this->get_boundary_velocity_manager().get_tangential_boundary_velocity_indicators(); - - // The list of all tangential mesh deformation boundary indicators. - std::set tmp_tangential_boundaries, tmp2_tangential_boundaries, all_tangential_boundaries; - std::set_union(tangential_velocity_boundary_indicators.begin(),tangential_velocity_boundary_indicators.end(), - additional_tangential_mesh_boundary_indicators.begin(),additional_tangential_mesh_boundary_indicators.end(), - std::inserter(tmp_tangential_boundaries, tmp_tangential_boundaries.end())); - std::set_union(tmp_tangential_boundaries.begin(),tmp_tangential_boundaries.end(), - periodic_boundary_indicators.begin(),periodic_boundary_indicators.end(), - std::inserter(tmp2_tangential_boundaries, tmp2_tangential_boundaries.end())); - // Tangential Stokes velocity boundaries can also be mesh deformation boundaries, - // so correct for that. - std::set_difference(tmp2_tangential_boundaries.begin(),tmp2_tangential_boundaries.end(), - boundary_ids.begin(),boundary_ids.end(), - std::inserter(all_tangential_boundaries, all_tangential_boundaries.end())); - - // The list of mesh deformation boundary indicators of boundaries that are allowed to move either - // tangentially or in all directions. - std::set all_deformable_boundaries; - std::set_union(all_tangential_boundaries.begin(),all_tangential_boundaries.end(), - boundary_ids.begin(),boundary_ids.end(), - std::inserter(all_deformable_boundaries, all_deformable_boundaries.end())); - - // The list of mesh deformation boundary indicators of boundaries that are not allowed to move. - std::set all_fixed_boundaries; - std::set_difference(all_boundaries.begin(),all_boundaries.end(), - all_deformable_boundaries.begin(),all_deformable_boundaries.end(), - std::inserter(all_fixed_boundaries, all_fixed_boundaries.end())); - - // Make the no flux boundary constraints - for (const types::boundary_id &boundary_id : all_fixed_boundaries) - { - VectorTools::interpolate_boundary_values (this->get_mapping(), - mesh_deformation_dof_handler, - boundary_id, - dealii::Functions::ZeroFunction(dim), - matrix_constraints); - } - - // Make the no normal flux boundary constraints - VectorTools::compute_no_normal_flux_constraints (mesh_deformation_dof_handler, - /* first_vector_component= */ - 0, - all_tangential_boundaries, - matrix_constraints, this->get_mapping()); - - matrix_constraints.close(); - - // Set up the system to solve - LinearAlgebra::SparseMatrix matrix; - - // Sparsity of the matrix - TrilinosWrappers::SparsityPattern sp (mesh_locally_owned, - mesh_locally_owned, - mesh_locally_relevant, - this->get_mpi_communicator()); - DoFTools::make_sparsity_pattern (mesh_deformation_dof_handler, sp, matrix_constraints, false, - Utilities::MPI::this_mpi_process(this->get_mpi_communicator())); - - sp.compress(); - matrix.reinit (sp); - - LinearAlgebra::Vector system_rhs, solution; - system_rhs.reinit(mesh_locally_owned, this->get_mpi_communicator()); - solution.reinit(mesh_locally_owned, this->get_mpi_communicator()); - - // Initialize Gauss-Legendre quadrature for degree+1 quadrature points of the surface faces - const QGauss face_quadrature(mesh_deformation_dof_handler.get_fe().degree+1); - // Update shape function values and gradients, the quadrature points and the Jacobian x quadrature weights. - const UpdateFlags update_flags = UpdateFlags(update_values | update_gradients | update_quadrature_points | update_normal_vectors | update_JxW_values); - // We want to extract the displacement at the free surface faces of the mesh deformation element. - FEFaceValues fs_fe_face_values (this->get_mapping(), mesh_deformation_dof_handler.get_fe(), face_quadrature, update_flags); - // and to solve on the whole mesh deformation mesh - // The number of quadrature points on a mesh deformation surface face - const unsigned int n_fs_face_q_points = fs_fe_face_values.n_quadrature_points; - - // What we need to build our system on the mesh deformation element - - // The nr of shape functions per mesh deformation element - const unsigned int dofs_per_cell = mesh_deformation_dof_handler.get_fe().dofs_per_cell; - - // Map of local to global cell dof indices - std::vector cell_dof_indices (dofs_per_cell); - - // The local rhs vector - Vector cell_vector (dofs_per_cell); - // The local matrix - FullMatrix cell_matrix (dofs_per_cell, dofs_per_cell); - - // Vector for getting the local dim displacement values - std::vector> displacement_values(n_fs_face_q_points); - - // Vector for getting the local dim initial topography values - std::vector> initial_topography_values(n_fs_face_q_points); - - // The global displacements on the MeshDeformation FE - LinearAlgebra::Vector displacements = this->get_mesh_deformation_handler().get_mesh_displacements(); - - // The global initial topography on the MeshDeformation FE - // TODO Once the initial mesh deformation is ready, this - // can be removed. - LinearAlgebra::Vector initial_topography = this->get_mesh_deformation_handler().get_initial_topography(); - - // Do nothing at time zero - if (this->get_timestep_number() < 1) - return; - - // An extractor for the dim-valued displacement vectors - // Later on we will compute the gravity-parallel displacement - FEValuesExtractors::Vector extract_vertical_displacements(0); - - // An extractor for the dim-valued initial topography vectors - // Later on we will compute the gravity-parallel displacement - FEValuesExtractors::Vector extract_initial_topography(0); - - // Cell iterator over the MeshDeformation FE - typename DoFHandler::active_cell_iterator - fscell = mesh_deformation_dof_handler.begin_active(), - fsendc = mesh_deformation_dof_handler.end(); - - // Iterate over all cells to find those at the mesh deformation boundary - for (; fscell!=fsendc; ++fscell) - if (fscell->at_boundary() && fscell->is_locally_owned()) - for (const unsigned int face_no : fscell->face_indices()) - if (fscell->face(face_no)->at_boundary()) - { - // Boundary indicator of current cell face - const types::boundary_id boundary_indicator - = fscell->face(face_no)->boundary_id(); - - // Only apply diffusion to the requested boundaries - if (boundary_ids.find(boundary_indicator) == boundary_ids.end()) - continue; - - // Recompute values, gradients, etc on the faces - fs_fe_face_values.reinit (fscell, face_no); - - // Get the global numbers of the local DoFs of the mesh deformation cell - fscell->get_dof_indices (cell_dof_indices); - - // Extract the displacement values - fs_fe_face_values[extract_vertical_displacements].get_function_values (displacements, displacement_values); - - // Extract the initial topography values - fs_fe_face_values[extract_initial_topography].get_function_values (initial_topography, initial_topography_values); - - // Reset local rhs and matrix - cell_vector = 0; - cell_matrix = 0; - - // Loop over the quadrature points of the current face - for (unsigned int point=0; point direction = -(this->get_gravity_model().gravity_vector(fs_fe_face_values.quadrature_point(point))); - // Normalize direction vector - if (direction.norm() > 0.0) - direction *= 1./direction.norm(); - // TODO this is only correct for box geometries - else - { - AssertThrow(Plugins::plugin_type_matches>(this->get_geometry_model()) || - Plugins::plugin_type_matches>(this->get_geometry_model()), - ExcMessage("The surface diffusion mesh deformation plugin only works for Box geometries.")); - direction[dim-1] = 1.; - } - - // Compute the total displacement in the gravity direction, - // i.e. the initial topography + any additional mesh displacement. - const double displacement = direction * (displacement_values[point] + initial_topography_values[point]); - - // To project onto the tangent space of the surface, - // we define the projection P:= I- n x n, - // with I the unit tensor and n the unit normal to the surface. - // The surface gradient then is P times the usual gradient of the shape functions. - const Tensor<2, dim, double> projection = unit_symmetric_tensor() - - outer_product(fs_fe_face_values.normal_vector(point), fs_fe_face_values.normal_vector(point)); - - - // The shape values for the i-loop - std::vector phi(dofs_per_cell); - - // The projected gradients of the shape values for the i-loop - std::vector> projected_grad_phi(dofs_per_cell); - - // Loop over the shape functions - for (unsigned int i=0; i>(this->get_geometry_model()) || - Plugins::plugin_type_matches>(this->get_geometry_model()), - ExcMessage("The surface diffusion mesh deformation plugin only works for Box geometries.")); - if (mesh_deformation_dof_handler.get_fe().system_to_component_index(i).first == dim-1) - { - // Precompute shape values and projected shape value gradients - phi[i] = fs_fe_face_values.shape_value (i, point); - projected_grad_phi[i] = projection * fs_fe_face_values.shape_grad(i, point); - - // Assemble the RHS - // RHS = M*H_old - cell_vector(i) += phi[i] * displacement * fs_fe_face_values.JxW(point); - - for (unsigned int j=0; jget_timestep() * diffusivity * - projected_grad_phi[i] * - (projection * fs_fe_face_values.shape_grad(j, point)) - ) - * fs_fe_face_values.JxW(point); - } - } - } - } - } - - matrix_constraints.distribute_local_to_global (cell_matrix, cell_vector, - cell_dof_indices, matrix, system_rhs, false); - } - - system_rhs.compress (VectorOperation::add); - matrix.compress(VectorOperation::add); - - // Jacobi seems to be fine here. Other preconditioners (ILU, IC) run into trouble - // because the matrix is mostly empty, since we don't touch internal vertices. - LinearAlgebra::PreconditionJacobi preconditioner_mass; - LinearAlgebra::PreconditionJacobi::AdditionalData preconditioner_control(1,1e-16,1); - preconditioner_mass.initialize(matrix, preconditioner_control); - - this->get_pcout() << " Solving mesh surface diffusion" << std::endl; - SolverControl solver_control(5*system_rhs.size(), this->get_parameters().linear_stokes_solver_tolerance*system_rhs.l2_norm()); - SolverCG cg(solver_control); - cg.solve (matrix, solution, system_rhs, preconditioner_mass); - - // Distribute constraints on mass matrix - matrix_constraints.distribute (solution); - - // The solution contains the new displacements, but we need to return a velocity. - // Therefore, we compute v=d_displacement/d_t. - // d_displacement are the new mesh node locations - // minus the old locations, which are initial_topography + displacements. - LinearAlgebra::Vector velocity(mesh_locally_owned, mesh_locally_relevant, this->get_mpi_communicator()); - velocity = solution; - velocity -= initial_topography; - velocity -= displacements; - - // The velocity - if (this->get_timestep() > 0.) - velocity /= this->get_timestep(); - else - AssertThrow(false, ExcZero()); - - output = velocity; - } - - - - template - void Diffusion::check_diffusion_time_step (const DoFHandler &mesh_deformation_dof_handler, - const std::set &boundary_ids) const - { - double min_local_conduction_timestep = std::numeric_limits::max(); - - for (const auto &fscell : mesh_deformation_dof_handler.active_cell_iterators()) - if (fscell->at_boundary() && fscell->is_locally_owned()) - for (const unsigned int face_no : fscell->face_indices()) - if (fscell->face(face_no)->at_boundary()) - { - // Get the boundary indicator of current cell face - const types::boundary_id boundary_indicator - = fscell->face(face_no)->boundary_id(); - - // Only consider the requested boundaries - if (boundary_ids.find(boundary_indicator) == boundary_ids.end()) - continue; - - // Calculate the corresponding conduction timestep - min_local_conduction_timestep = std::min(min_local_conduction_timestep, - this->get_parameters().CFL_number*std::pow(fscell->face(face_no)->minimum_vertex_distance(),2.) - / diffusivity); - } - - // Get the global minimum timestep - const double min_conduction_timestep = Utilities::MPI::min (min_local_conduction_timestep, this->get_mpi_communicator()); - - double conduction_timestep = min_conduction_timestep; - if (this->convert_output_to_years()) - conduction_timestep /= year_in_seconds; - - AssertThrow (this->get_timestep() <= min_conduction_timestep, - ExcMessage("The numerical timestep is too large for diffusion of the surface. Although the " - "diffusion scheme is stable, note that the error increases linearly with the timestep. " - "The diffusion timestep is: " + std::to_string(conduction_timestep) + ", while " - "the advection timestep is: " + std::to_string (this->get_timestep ()))); - } - - - - template - void - Diffusion::compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, - AffineConstraints &mesh_velocity_constraints, - const std::set &boundary_id) const - { - if (!apply_diffusion) - return; - - LinearAlgebra::Vector boundary_velocity; - - const IndexSet &mesh_locally_owned = mesh_deformation_dof_handler.locally_owned_dofs(); - IndexSet mesh_locally_relevant; - DoFTools::extract_locally_relevant_dofs (mesh_deformation_dof_handler, - mesh_locally_relevant); - boundary_velocity.reinit(mesh_locally_owned, mesh_locally_relevant, - this->get_mpi_communicator()); - - // Determine the mesh velocity at the surface based on diffusion of - // the topography - diffuse_boundary(mesh_deformation_dof_handler, mesh_locally_owned, - mesh_locally_relevant, boundary_velocity, boundary_id); - - // now insert the relevant part of the solution into the mesh constraints - const IndexSet constrained_dofs = - DoFTools::extract_boundary_dofs(mesh_deformation_dof_handler, - ComponentMask(dim, true), - boundary_id); - - for (unsigned int i = 0; i < constrained_dofs.n_elements(); ++i) - { - types::global_dof_index index = constrained_dofs.nth_index_in_set(i); - if (mesh_velocity_constraints.can_store_line(index)) - if (mesh_velocity_constraints.is_constrained(index)==false) - { - mesh_velocity_constraints.add_line(index); - mesh_velocity_constraints.set_inhomogeneity(index, boundary_velocity[index]); - } - } - } - - - - template - bool - Diffusion:: - needs_surface_stabilization () const - { - return false; - } - - - - template - void Diffusion::declare_parameters(ParameterHandler &prm) - { - prm.enter_subsection("Mesh deformation"); - { - prm.enter_subsection("Diffusion"); - { - prm.declare_entry("Hillslope transport coefficient", "1e-6", - Patterns::Double(0), - "The hillslope transport coefficient $\\kappa$ used to " - "diffuse the free surface, either as a " - "stabilization step or to mimic erosional " - "and depositional processes. Units: $\\si{m^2/s}$. "); - prm.declare_entry("Time steps between diffusion", "1", - Patterns::Integer(0,std::numeric_limits::max()), - "The number of time steps between each application of " - "diffusion."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - - template - void Diffusion::parse_parameters(ParameterHandler &prm) - { - prm.enter_subsection ("Mesh deformation"); - { - // Create the list of tangential mesh movement boundary indicators. - try - { - const std::vector x_additional_tangential_mesh_boundary_indicators - = this->get_geometry_model().translate_symbolic_boundary_names_to_ids(Utilities::split_string_list - (prm.get ("Additional tangential mesh velocity boundary indicators"))); - - additional_tangential_mesh_boundary_indicators.insert(x_additional_tangential_mesh_boundary_indicators.begin(), - x_additional_tangential_mesh_boundary_indicators.end()); - } - catch (const std::string &error) - { - AssertThrow (false, ExcMessage ("While parsing the entry , there was an error. Specifically, " - "the conversion function complained as follows:\n\n" - + error)); - } - - prm.enter_subsection ("Diffusion"); - { - diffusivity = prm.get_double("Hillslope transport coefficient"); - timesteps_between_diffusion = prm.get_integer("Time steps between diffusion"); - } - prm.leave_subsection (); - } - prm.leave_subsection (); - } - } -} - - -// explicit instantiation of the functions we implement in this file -namespace aspect -{ - namespace MeshDeformation - { - ASPECT_REGISTER_MESH_DEFORMATION_MODEL(Diffusion, - "diffusion", - "A plugin that computes the deformation of surface " - "vertices according to the solution of the hillslope diffusion problem. " - "Specifically, at the end of each timestep, or after a specific number " - "of timesteps, this plugin solves the following equation: " - "\\begin{align*}" - " \\frac{\\partial h}{\\partial t} = \\kappa \\left( \\frac{\\partial^{2} h}{\\partial x^{2}} " - "+ \\frac{\\partial^{2} h}{\\partial y^{2}} \\right), " - "\\end{align*} " - "where $\\kappa$ is the hillslope diffusion coefficient (diffusivity), and $h(x,y)$ the " - "height of a point along the top boundary with respect to the surface of the unperturbed domain. " - "\n\n" - "Using this definition, the plugin then solves for one time step, i.e., " - "using as initial condition $h(t_{n-1})$ the current surface elevation, " - "and computing $h(t_n)$ from it by solving the equation above over " - "the time interval $t_n-t_{n-1}$. From this, one can then compute " - "a surface velocity $v = \\frac{h(t_n)-h(t_{n-1})}{t_n-t_{n-1}}$. " - "\n\n" - "This surface velocity is used to deform the surface and as a boundary condition " - "for solving the Laplace equation to determine the mesh velocity in the " - "domain interior. " - "Diffusion can be applied every timestep, mimicking surface processes of erosion " - "and deposition, or at a user-defined timestep interval to purely smooth the surface " - "topography to avoid too great a distortion of mesh elements when a free " - "surface is also used.") - } -} diff --git a/source/mesh_deformation/fastscape.cc.bak b/source/mesh_deformation/fastscape.cc.bak deleted file mode 100644 index e0adde32c31..00000000000 --- a/source/mesh_deformation/fastscape.cc.bak +++ /dev/null @@ -1,1997 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ -#include - -#ifdef ASPECT_WITH_FASTSCAPE - -#include -#include -#include -#include -#include -#include - -namespace aspect -{ - namespace MeshDeformation - { - /** - * Define FastScape functions as C functions. Must use the exact same function/variable name - * and type as used in FastScape. All function names must be made lowercase, and an - * underscore added at the end. Types must be defined as pointers, and sent to - * FastScape as a reference. Additional functions are available within FastScape, - * see https://fastscape.org/fastscapelib-fortran/ for a list of all functions and - * their input parameters. These functions must be defined at the top here before - * they are used. - */ - extern"C" - { - /** - * Function to initialize FastScape. - */ - void fastscape_init_(); - - /** - * Set the x and y extent of the FastScape model. - */ - void fastscape_set_xl_yl_(const double *xxl, - const double *yyl); - - /** - * Set number of grid points in x (nx) and y (ny) - */ - void fastscape_set_nx_ny_(const unsigned int *nnx, - const unsigned int *nny); - - /** - * Allocate memory, must be called after set nx/ny. - */ - void fastscape_setup_(); - - /** - * Set FastScape boundary conditions. - */ - void fastscape_set_bc_(const unsigned int *jbc); - - /** - * Set FastScape timestep. This will vary based on the ASPECT timestep. - */ - void fastscape_set_dt_(const double *dtt); - - /** - * Initialize FastScape topography. - */ - void fastscape_init_h_(double *hp); - - /** - * Initialize FastScape silt fraction during a restart. - */ - void fastscape_init_f_(double *sf); - - /** - * Set FastScape erosional parameters on land. These parameters will apply to the stream power law (SPL) - * and hillslope diffusion for basement and sediment. This can be set between timesteps. - */ - void fastscape_set_erosional_parameters_(double *kkf, - const double *kkfsed, - const double *mm, - const double *nnn, - double *kkd, - const double *kkdsed, - const double *gg1, - const double *gg2, - const double *pp); - - /** - * Set FastScape marine erosional parameters. This can be set between timesteps. - */ - void fastscape_set_marine_parameters_(const double *sl, - const double *p1, - const double *p2, - const double *z1, - const double *z2, - const double *r, - const double *l, - const double *kds1, - const double *kds2); - - /** - * Set advection velocities for FastScape. This can be set between timesteps. - */ - void fastscape_set_v_(double *ux, - double *uy); - - /** - * Set FastScape uplift rate. This can be set between timesteps. - */ - void fastscape_set_u_(double *up); - - /** - * Set FastScape topography. This can be set between timesteps. - */ - void fastscape_set_h_(double *hp); - - /** - * Set FastScape basement. This can be set between timesteps. Sediment within FastScape - * is considered as the difference between the topography and basement, though this may differ - * from sediment as seen in ASPECT because the FastScape basement only takes the surface - * velocities into consideration. - */ - void fastscape_set_basement_(double *b); - - /** - * Run FastScape for a single FastScape timestep. - */ - void fastscape_execute_step_(); - - /** - * Create a .VTK file for the FastScape surface within the FastScape folder of the - * ASPECT output folder. - */ - void fastscape_named_vtk_(double *fp, - const double *vexp, - unsigned int *astep, - const char *c, - const unsigned int *length); - - /** - * Copy the current FastScape topography. - */ - void fastscape_copy_h_(double *hp); - - /** - * Copy the current FastScape basement. - */ - void fastscape_copy_basement_(double *b); - - /** - * Copy the current FastScape silt fraction. - */ - void fastscape_copy_f_(double *sf); - - /** - * Copy the current FastScape slopes. - */ - void fastscape_copy_slope_(double *slopep); - - /** - * Destroy FastScape. - */ - void fastscape_destroy_(); - } - - - template - FastScape::~FastScape () - { - // It doesn't seem to matter if this is done on all processors or only on the one that runs - // FastScape as the destroy function checks if the memory is allocated. - if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - fastscape_destroy_(); - } - - template - void - FastScape::initialize () - { - AssertThrow(Plugins::plugin_type_matches>(this->get_geometry_model()), - ExcMessage("FastScape can only be run with a box geometry model.")); - - const GeometryModel::Box *geometry - = dynamic_cast*> (&this->get_geometry_model()); - - // Find the id associated with the top boundary and boundaries that call mesh deformation. - const types::boundary_id top_boundary = this->get_geometry_model().translate_symbolic_boundary_name_to_id ("top"); - const std::set mesh_deformation_boundary_ids - = this->get_mesh_deformation_handler().get_active_mesh_deformation_boundary_indicators(); - - // Get the deformation type names called for each boundary. - std::map> mesh_deformation_boundary_indicators_map - = this->get_mesh_deformation_handler().get_active_mesh_deformation_names(); - - // Loop over each mesh deformation boundary, and make sure FastScape is only called on the surface. - for (const types::boundary_id id : mesh_deformation_boundary_ids) - { - const std::vector &names = mesh_deformation_boundary_indicators_map[id]; - for (const auto &name : names) - { - if (name == "fastscape") - AssertThrow(id == top_boundary, - ExcMessage("FastScape can only be called on the surface boundary.")); - } - } - - // Several compositional fields are commonly used in conjunction with the FastScape plugin, i.e. - // "sediment_age" to track the age of the sediment deposited and "deposition_depth" to track the depth - // with respect to the unperturbed surface of the model domain. Their values are controlled by setting - // boundary conditions on the top boundary that is deformed by FastScape. While it is useful to track these - // fields, they are not needed for any function in the FastScape plugin. If they exist however, we need - // to make sure that these fields do not have the type "chemical composition" and are therefore not taken - // into account when computing material properties. - const std::vector chemical_field_names = this->introspection().chemical_composition_field_names(); - if (this->introspection().compositional_name_exists("sediment_age")) - { - const std::vector::const_iterator - it = std::find(chemical_field_names.begin(), chemical_field_names.end(), "sediment_age"); - AssertThrow (it == chemical_field_names.end(), - ExcMessage("There is a field sediment_age that is of type chemical composition. " - "Please change it to type generic so that it does not affect material properties.")); - } - if (this->introspection().compositional_name_exists("deposition_depth")) - { - const std::vector::const_iterator - it = std::find(chemical_field_names.begin(), chemical_field_names.end(), "deposition_depth"); - AssertThrow (it == chemical_field_names.end(), - ExcMessage("There is a field deposition_depth that is of type chemical composition. " - "Please change it to type generic so that it does not affect material properties.")); - } - - // Initialize parameters for restarting FastScape - restart = this->get_parameters().resume_computation; - - // Since we don't open these until we're on one process, we need to check if the - // restart files exist beforehand. - if (restart) - { - if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - AssertThrow(Utilities::fexists(this->get_output_directory() + "fastscape_elevation_restart.txt"), - ExcMessage("Cannot open topography file to restart FastScape.")); - AssertThrow(Utilities::fexists(this->get_output_directory() + "fastscape_basement_restart.txt"), - ExcMessage("Cannot open basement file to restart FastScape.")); - AssertThrow(Utilities::fexists(this->get_output_directory() + "fastscape_silt_fraction_restart.txt"), - ExcMessage("Cannot open silt fraction file to restart FastScape.")); - } - } - - // The first entry represents the minimum coordinates of the model domain, the second the model extent. - for (unsigned int d=0; dget_origin()[d]; - grid_extent[d].second = geometry->get_extents()[d]; - } - - // Get the x and y repetitions used in the parameter file so - // the FastScape cell size can be properly set. - const std::array repetitions = geometry->get_repetitions(); - - // Set number of x points, which is generally 1+(FastScape refinement level)^2. - // The FastScape refinement level is a combination of the maximum ASPECT refinement level - // at the surface and any additional refinement we want in FastScape. If - // repetitions are specified we need to adjust the number of points to match what ASPECT has, - // which can be determined by multiplying the points by the repetitions before adding 1. - // Finally, if ghost nodes are used we add two additional points on each side. - const unsigned int ghost_nodes = 2*use_ghost_nodes; - const unsigned int fastscape_refinement_level = maximum_surface_refinement_level + additional_refinement_levels; - const unsigned int fastscape_nodes = std::pow(2,fastscape_refinement_level); - fastscape_nx = fastscape_nodes * repetitions[0] + ghost_nodes + 1; - - // Size of FastScape cell. - fastscape_dx = (grid_extent[0].second)/(fastscape_nodes * repetitions[0]); - - // FastScape X extent, which is generally ASPECT's extent unless the ghost nodes are used, - // in which case 2 cells are added on either side. - fastscape_x_extent = (grid_extent[0].second) + fastscape_dx * ghost_nodes; - - // Sub intervals are 3 less than points, if including the ghost nodes. Otherwise 1 less. - table_intervals[0] = fastscape_nodes * repetitions[0]; - table_intervals[dim-1] = 1; - - if (dim == 2) - { - fastscape_dy = fastscape_dx; - fastscape_y_extent = round(fastscape_y_extent_2d/fastscape_dy)*fastscape_dy + fastscape_dy * ghost_nodes; - fastscape_ny = 1+fastscape_y_extent/fastscape_dy; - } - else - { - fastscape_ny = fastscape_nodes * repetitions[1] + ghost_nodes + 1; - fastscape_dy = (grid_extent[1].second)/(fastscape_nodes * repetitions[1]); - table_intervals[1] = fastscape_nodes * repetitions[1]; - fastscape_y_extent = (grid_extent[1].second) + fastscape_dy * ghost_nodes; - } - - // Create a folder for the FastScape visualization files. - Utilities::create_directory (this->get_output_directory() + "fastscape/", - this->get_mpi_communicator(), - false); - - last_output_time = 0; - } - - - template - void - FastScape::compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, - AffineConstraints &mesh_velocity_constraints, - const std::set &boundary_ids) const - { - - // Because there is no increase in time during timestep 0, we return and only - // initialize and run FastScape from timestep 1 and on. - if (this->get_timestep_number() == 0) - return; - - TimerOutput::Scope timer_section(this->get_computing_timer(), "FastScape plugin"); - - const unsigned int current_timestep = this->get_timestep_number (); - const double aspect_timestep_in_years = this->get_timestep() / year_in_seconds; - - // Find a FastScape timestep that is below our maximum timestep. - unsigned int fastscape_iterations = fastscape_steps_per_aspect_step; - double fastscape_timestep_in_years = aspect_timestep_in_years/fastscape_iterations; - while (fastscape_timestep_in_years>maximum_fastscape_timestep) - { - fastscape_iterations *= 2; - fastscape_timestep_in_years *= 0.5; - } - - // Vector to hold the velocities that represent the change to the surface. - const unsigned int fastscape_array_size = fastscape_nx*fastscape_ny; - std::vector mesh_velocity_z(fastscape_array_size); - - // FastScape requires multiple specially defined and ordered variables sent to its functions. To make - // the transfer of these down to one process easier, we first fill out a vector of local_aspect_values, - // then when we get down to one process we use these local_aspect_values to fill the double arrays - // in the order needed for FastScape. - std::vector> local_aspect_values = get_aspect_values(); - - // Run FastScape on single process. - if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - // Initialize the variables that will be sent to FastScape. - // Elevation is initialized at a very high number so that we can later check that all points - // received data from ASPECT, and if not throw an assert. - std::vector elevation(fastscape_array_size, std::numeric_limits::max()); - std::vector velocity_x(fastscape_array_size); - std::vector velocity_y(fastscape_array_size); - std::vector velocity_z(fastscape_array_size); - std::vector bedrock_river_incision_rate_array(fastscape_array_size); - std::vector bedrock_transport_coefficient_array(fastscape_array_size); - std::vector basement(fastscape_array_size); - std::vector silt_fraction(fastscape_array_size); - std::vector elevation_old(fastscape_array_size); - - fill_fastscape_arrays(elevation, - bedrock_transport_coefficient_array, - bedrock_river_incision_rate_array, - velocity_x, - velocity_y, - velocity_z, - local_aspect_values); - - if (current_timestep == 1 || restart) - { - this->get_pcout() << " Initializing FastScape... " << (1+maximum_surface_refinement_level+additional_refinement_levels) << - " levels, cell size: " << fastscape_dx << " m." << std::endl; - - // Set ghost nodes before initializing. - if (use_ghost_nodes && !restart) - set_ghost_nodes(elevation, - velocity_x, - velocity_y, - velocity_z, - fastscape_timestep_in_years, - true); - - // If we are restarting from a checkpoint, load h values for FastScape instead of using the ASPECT values. - if (restart) - { - read_restart_files(elevation, - basement, - silt_fraction); - - restart = false; - } - - initialize_fastscape(elevation, - basement, - bedrock_transport_coefficient_array, - bedrock_river_incision_rate_array, - silt_fraction); - } - else - { - // If it isn't the first timestep we ignore initialization and instead copy all height values from FastScape. - // Generally, we overwrite the topography data from ASPECT as FastScape may be at a higher resolution. However, - // if we are not using FastScape to advect then we do not want to do this and instead use the ASPECT values. - if (fastscape_advection_uplift) - fastscape_copy_h_(elevation.data()); - } - - // Find the appropriate sediment rain based off the time interval. - const double time_in_years = this->get_time() / year_in_seconds; - auto it = std::lower_bound(sediment_rain_times.begin(), sediment_rain_times.end(), time_in_years); - const unsigned int inds = std::distance(sediment_rain_times.begin(), it); - const double sediment_rain = sediment_rain_rates[inds]; - - // Keep initial h values so we can calculate velocity later. - // In the first timestep, h will be given from other processes. - // In later timesteps, we copy h directly from FastScape. - std::mt19937 random_number_generator(fastscape_seed); - std::uniform_real_distribution random_distribution(-noise_elevation,noise_elevation); - for (unsigned int i=0; i 0 && use_marine_component) - { - // Only apply sediment rain to areas below sea level. - if (elevation[i] < sea_level) - { - // If the rain would put us above sea level, set height to sea level. - if (elevation[i] + sediment_rain*aspect_timestep_in_years > sea_level) - elevation[i] = sea_level; - else - elevation[i] = std::min(sea_level,elevation[i] + sediment_rain*aspect_timestep_in_years); - } - } - } - } - - // The ghost nodes are added as a single layer of points surrounding the entire model. - // For example, if ASPECT's surface mesh is a 2D surface that is 3x3 (nx x ny) points, - // FastScape will be set as a 2D 5x5 point surface. On return to ASPECT, the outer ghost nodes - // will be ignored, and ASPECT will see only the inner 3x3 surface of FastScape. - if (use_ghost_nodes) - set_ghost_nodes(elevation, - velocity_x, - velocity_y, - velocity_z, - fastscape_timestep_in_years, - false); - - // If specified, apply the orographic controls to the FastScape model. - if (use_orographic_controls) - apply_orographic_controls(elevation, - bedrock_transport_coefficient_array, - bedrock_river_incision_rate_array); - - // Set velocity components. - if (fastscape_advection_uplift) - { - fastscape_set_u_(velocity_z.data()); - fastscape_set_v_(velocity_x.data(), - velocity_y.data()); - } - - // Set h to new values, and erosional parameters if there have been changes. - fastscape_set_h_(elevation.data()); - - fastscape_set_erosional_parameters_(bedrock_river_incision_rate_array.data(), - &sediment_river_incision_rate, - &drainage_area_exponent_m, - &slope_exponent_n, - bedrock_transport_coefficient_array.data(), - &sediment_transport_coefficient, - &bedrock_deposition_g, - &sediment_deposition_g, - &slope_exponent_p); - - // Find timestep size, run FastScape, and make visualizations. - execute_fastscape(elevation, - bedrock_transport_coefficient_array, - velocity_x, - velocity_y, - velocity_z, - fastscape_timestep_in_years, - fastscape_iterations); - - // Write a file to store h, b & step for restarting. - // TODO: It would be good to roll this into the general ASPECT checkpointing, - // and when we do this needs to be changed. - if (((this->get_parameters().checkpoint_time_secs == 0) && - (this->get_parameters().checkpoint_steps > 0) && - ((current_timestep + 1) % this->get_parameters().checkpoint_steps == 0)) || - (this->get_time() == this->get_end_time() && this->get_timestepping_manager().need_checkpoint_on_terminate())) - { - save_restart_files(elevation, - basement, - silt_fraction); - } - - // Find out our velocities from the change in height. - // Where mesh_velocity_z is a vector of array size that exists on all processes. - for (unsigned int i=0; iget_mpi_communicator(), mesh_velocity_z, 0); - } - else - { - for (unsigned int i=0; iget_mpi_communicator()); - - // Check whether the FastScape mesh was filled with data. - const bool fastscape_mesh_filled = Utilities::MPI::broadcast (this->get_mpi_communicator(), true, 0); - if (fastscape_mesh_filled != true) - throw aspect::QuietException(); - - // This is called solely so we can set the timer and will return immediately. - execute_fastscape(mesh_velocity_z, - mesh_velocity_z, - mesh_velocity_z, - mesh_velocity_z, - mesh_velocity_z, - aspect_timestep_in_years, - fastscape_steps_per_aspect_step); - - mesh_velocity_z = Utilities::MPI::broadcast(this->get_mpi_communicator(), mesh_velocity_z, 0); - } - - // Get the sizes needed for a data table of the mesh velocities. - TableIndices size_idx; - for (unsigned int d=0; d velocity_table = fill_data_table(mesh_velocity_z, size_idx, fastscape_nx, fastscape_ny); - - // As our grid_extent variable end points do not account for the change related to an origin - // not at 0, we adjust this here into an interpolation extent. - std::array,dim> interpolation_extent; - for (unsigned int d=0; d *velocities; - Functions::InterpolatedUniformGridData velocities (interpolation_extent, - table_intervals, - velocity_table); - - VectorFunctionFromScalarFunctionObject vector_function_object( - [&](const Point &p) -> double - { - return velocities.value(p); - }, - dim-1, - dim); - - VectorTools::interpolate_boundary_values (mesh_deformation_dof_handler, - *boundary_ids.begin(), - vector_function_object, - mesh_velocity_constraints); - } - - - template - std::vector> - FastScape::get_aspect_values() const - { - - const types::boundary_id relevant_boundary = this->get_geometry_model().translate_symbolic_boundary_name_to_id ("top"); - std::vector> local_aspect_values(dim+2, std::vector()); - - // Get a quadrature rule that exists only on the corners, and increase the refinement if specified. - const QIterated face_corners (QTrapezoid<1>(), - std::pow(2,additional_refinement_levels+surface_refinement_difference)); - - FEFaceValues fe_face_values (this->get_mapping(), - this->get_fe(), - face_corners, - update_values | - update_quadrature_points); - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned() && cell->at_boundary()) - for (unsigned int face_no = 0; face_no < GeometryInfo::faces_per_cell; ++face_no) - if (cell->face(face_no)->at_boundary()) - { - if ( cell->face(face_no)->boundary_id() != relevant_boundary) - continue; - - std::vector> vel(face_corners.size()); - fe_face_values.reinit(cell, face_no); - fe_face_values[this->introspection().extractors.velocities].get_function_values(this->get_solution(), vel); - - for (unsigned int corner = 0; corner < face_corners.size(); ++corner) - { - const Point vertex = fe_face_values.quadrature_point(corner); - - // Find what x point we're at. Add 1 or 2 depending on if ghost nodes are used. - // Subtract the origin point so that it corresponds to an origin of 0,0 in FastScape. - const double indx = 1+use_ghost_nodes+(vertex(0) - grid_extent[0].first)/fastscape_dx; - - // The quadrature rule is created so that there are enough interpolation points in the - // lowest resolved ASPECT surface cell to fill out the FastScape mesh. However, as the - // same rule is used for all cell sizes, higher resolution areas will have interpolation - // points that do not correspond to a FastScape node. In which case, indx will not be a - // whole number and we can ignore the point. - if (std::abs(indx - round(indx)) >= node_tolerance) - continue; - - - // If we're in 2D, we want to take the values and apply them to every row of X points. - if (dim == 2) - { - for (unsigned int ys=0; ys= node_tolerance) - continue; - - const double index = round((indy-1))*fastscape_nx+round(indx); - - local_aspect_values[0].push_back(vertex(dim-1) - grid_extent[dim-1].second); //z component - local_aspect_values[1].push_back(index-1); - - for (unsigned int d=0; d - void FastScape::fill_fastscape_arrays(std::vector &elevation, - std::vector &bedrock_transport_coefficient_array, - std::vector &bedrock_river_incision_rate_array, - std::vector &velocity_x, - std::vector &velocity_y, - std::vector &velocity_z, - std::vector> &local_aspect_values) const - { - for (unsigned int i=0; iget_mpi_communicator()); ++p) - { - // First, find out the size of the array a process wants to send. - MPI_Status status; - MPI_Probe(p, 42, this->get_mpi_communicator(), &status); - int incoming_size = 0; - MPI_Get_count(&status, MPI_DOUBLE, &incoming_size); - - // Resize the array so it fits whatever the process sends. - for (unsigned int i=0; iget_mpi_communicator(), &status); - - // Now, place the numbers into the correct place based off the index. - for (unsigned int i=0; i::max() && !is_ghost_node(i,false)) - fastscape_mesh_filled = false; - } - - Utilities::MPI::broadcast(this->get_mpi_communicator(), fastscape_mesh_filled, 0); - AssertThrow (fastscape_mesh_filled == true, - ExcMessage("The FastScape mesh is missing data. A likely cause for this is that the " - "maximum surface refinement or surface refinement difference are improperly set.")); - } - - - template - void FastScape::initialize_fastscape(std::vector &elevation, - std::vector &basement, - std::vector &bedrock_transport_coefficient_array, - std::vector &bedrock_river_incision_rate_array, - std::vector &silt_fraction) const - { - Assert (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0, ExcInternalError()); - - const unsigned int current_timestep = this->get_timestep_number (); - - // Initialize FastScape with grid and extent. - fastscape_init_(); - fastscape_set_nx_ny_(&fastscape_nx, - &fastscape_ny); - fastscape_setup_(); - fastscape_set_xl_yl_(&fastscape_x_extent, - &fastscape_y_extent); - - // Set boundary conditions - fastscape_set_bc_(&fastscape_boundary_conditions); - - // Initialize topography - fastscape_init_h_(elevation.data()); - - // Set erosional parameters. - fastscape_set_erosional_parameters_(bedrock_river_incision_rate_array.data(), - &sediment_river_incision_rate, - &drainage_area_exponent_m, - &slope_exponent_n, - bedrock_transport_coefficient_array.data(), - &sediment_transport_coefficient, - &bedrock_deposition_g, - &sediment_deposition_g, - &slope_exponent_p); - - if (use_marine_component) - fastscape_set_marine_parameters_(&sea_level, - &sand_surface_porosity, - &silt_surface_porosity, - &sand_efold_depth, - &silt_efold_depth, - &sand_silt_ratio, - &sand_silt_averaging_depth, - &sand_transport_coefficient, - &silt_transport_coefficient); - - // Only set the basement and silt_fraction if it's a restart - if (current_timestep != 1) - { - fastscape_set_basement_(basement.data()); - if (use_marine_component) - fastscape_init_f_(silt_fraction.data()); - } - - } - - - template - void FastScape::execute_fastscape(std::vector &elevation, - std::vector &extra_vtk_field, - std::vector &velocity_x, - std::vector &velocity_y, - std::vector &velocity_z, - const double &fastscape_timestep_in_years, - const unsigned int &fastscape_iterations) const - { - TimerOutput::Scope timer_section(this->get_computing_timer(), "Execute FastScape"); - if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) != 0) - return; - - // Because on the first timestep we will create an initial VTK file before running FastScape - // and a second after, we first set the visualization step to zero. - unsigned int visualization_step = 0; - const unsigned int current_timestep = this->get_timestep_number (); - std::string dirname = (this->get_output_directory() + "fastscape/"); - const char *dirname_char=dirname.c_str(); - const unsigned int dirname_length = dirname.length(); - - // Set time step - fastscape_set_dt_(&fastscape_timestep_in_years); - this->get_pcout() << " Executing FastScape... " << (fastscape_iterations) << " timesteps of " << fastscape_timestep_in_years << " years." << std::endl; - { - // If it is the first timestep, write an initial VTK file. - if (current_timestep == 1) - { - this->get_pcout() << " Writing initial VTK..." << std::endl; - // FastScape by default visualizes a field called HHHHH, - // and the parameter this shows will be whatever is given as the first - // position. At the moment it visualizes the bedrock diffusivity. - fastscape_named_vtk_(extra_vtk_field.data(), - &vexp, - &visualization_step, - dirname_char, - &dirname_length); - } - - for (unsigned int fastscape_iteration = 0; fastscape_iteration < fastscape_iterations; ++fastscape_iteration) - { - fastscape_execute_step_(); - - // If we are using the ghost nodes we want to reset them every FastScape timestep. - if (use_ghost_nodes) - { - fastscape_copy_h_(elevation.data()); - - set_ghost_nodes(elevation, - velocity_x, - velocity_y, - velocity_z, - fastscape_timestep_in_years, - false); - - // Set velocity components. - if (fastscape_advection_uplift) - { - fastscape_set_u_(velocity_z.data()); - fastscape_set_v_(velocity_x.data(), - velocity_y.data()); - } - - // Set h to new values, and erosional parameters if there have been changes. - fastscape_set_h_(elevation.data()); - } - } - - // Copy h values. - fastscape_copy_h_(elevation.data()); - - - // Determine whether to create a VTK file this timestep. - bool write_vtk = false; - - if (this->get_time() >= last_output_time + output_interval || this->get_time() == this->get_end_time()) - { - write_vtk = true; - - if (output_interval > 0) - { - // We need to find the last time output was supposed to be written. - // this is the last_output_time plus the largest positive multiple - // of output_intervals that passed since then. We need to handle the - // edge case where last_output_time+output_interval==current_time, - // we did an output and std::floor sadly rounds to zero. This is done - // by forcing std::floor to round 1.0-eps to 1.0. - const double magic = 1.0+2.0*std::numeric_limits::epsilon(); - last_output_time = last_output_time + std::floor((this->get_time()-last_output_time)/output_interval*magic) * output_interval/magic; - } - } - - if (write_vtk) - { - this->get_pcout() << " Writing FastScape VTK..." << std::endl; - visualization_step = current_timestep; - fastscape_named_vtk_(extra_vtk_field.data(), - &vexp, - &visualization_step, - dirname_char, - &dirname_length); - } - } - } - - - template - void FastScape::apply_orographic_controls(const std::vector &elevation, - std::vector &bedrock_transport_coefficient_array, - std::vector &bedrock_river_incision_rate_array) const - { - // First for the wind barrier, we find the maximum height and index - // along each line in the x and y direction. - // If wind is east or west, we find maximum point for each ny row along x. - const unsigned int fastscape_array_size = fastscape_nx*fastscape_ny; - std::vector> max_elevation_along_x(2, std::vector(fastscape_ny, 0.0)); - if (wind_direction == 0 || wind_direction == 1) - { - for (unsigned int i=0; i max_elevation_along_x[0][i]) - { - // Maximum elevation value along the ny row. - max_elevation_along_x[0][i] = elevation[fastscape_nx*i+j]; - // Location of maximum elevation. - max_elevation_along_x[1][i] = j; - } - } - } - } - - // If wind is north or south, we find maximum point for each nx row along y. - std::vector> max_elevation_along_y(2, std::vector(fastscape_nx, 0.0)); - if (wind_direction == 2 || wind_direction == 3) - { - for (unsigned int i=0; i max_elevation_along_y[0][i]) - { - max_elevation_along_y[0][i] = elevation[fastscape_nx*j+i]; - max_elevation_along_y[1][i] = j; - } - } - } - } - - // Now we loop through all the points again and apply the factors. - std::vector control_applied(fastscape_array_size, 0); - for (unsigned int i=0; i wind_barrier_elevation) && (j < max_elevation_along_x[1][i]) ) - { - bedrock_river_incision_rate_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; - bedrock_transport_coefficient_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; - control_applied[fastscape_nx*i+j] = 1; - } - break; - } - case 1 : - { - if ( (max_elevation_along_x[0][i] > wind_barrier_elevation) && (j > max_elevation_along_x[1][i]) ) - { - bedrock_river_incision_rate_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; - bedrock_transport_coefficient_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; - control_applied[fastscape_nx*i+j] = 1; - } - break; - } - case 2 : - { - if ( (max_elevation_along_y[0][j] > wind_barrier_elevation) && (i > max_elevation_along_y[1][j]) ) - { - bedrock_river_incision_rate_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; - bedrock_transport_coefficient_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; - control_applied[fastscape_nx*i+j] = 1; - } - break; - } - case 3 : - { - if ( (max_elevation_along_y[0][j] > wind_barrier_elevation) && (i < max_elevation_along_y[1][j]) ) - { - bedrock_river_incision_rate_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; - bedrock_transport_coefficient_array[fastscape_nx*i+j] *= wind_barrier_erosional_factor; - control_applied[fastscape_nx*i+j] = 1; - } - break; - } - default : - AssertThrow(false, ExcMessage("This does not correspond with a wind direction.")); - break; - } - - // If we are above the flat elevation and stack controls, apply the flat elevation factor. If we are not - // stacking controls, apply the factor if the wind barrier was not applied to this point. - if (elevation[fastscape_nx*i+j] > flat_elevation) - { - if ( stack_controls==true || !stack_controls && (control_applied[fastscape_nx*i+j]==0) ) - { - bedrock_river_incision_rate_array[fastscape_nx*i+j] *= flat_erosional_factor; - bedrock_transport_coefficient_array[fastscape_nx*i+j] *= flat_erosional_factor; - } - // If we are not stacking controls and the wind barrier was applied to this point, only - // switch to this control if the factor is greater. - else if ( stack_controls==false && (control_applied[fastscape_nx*i+j]==1) && (flat_erosional_factor > wind_barrier_erosional_factor) ) - { - if ( wind_barrier_erosional_factor != 0) - { - bedrock_river_incision_rate_array[fastscape_nx*i+j] = (bedrock_river_incision_rate_array[fastscape_nx*i+j]/wind_barrier_erosional_factor)*flat_erosional_factor; - bedrock_transport_coefficient_array[fastscape_nx*i+j] = (bedrock_transport_coefficient_array[fastscape_nx*i+j]/wind_barrier_erosional_factor)*flat_erosional_factor; - } - // If a wind barrier factor of zero was applied for some reason, we set it back to the default - // and apply the flat_erosional_factor. - else - { - bedrock_river_incision_rate_array[fastscape_nx*i+j] = bedrock_river_incision_rate*flat_erosional_factor; - bedrock_transport_coefficient_array[fastscape_nx*i+j] = bedrock_transport_coefficient*flat_erosional_factor; - } - } - } - } - } - } - - - template - void FastScape::set_ghost_nodes(std::vector &elevation, - std::vector &velocity_x, - std::vector &velocity_y, - std::vector &velocity_z, - const double &fastscape_timestep_in_years, - const bool init) const - { - // Copy the slopes at each point, this will be used to set an H - // at the ghost nodes if a boundary mass flux is given. - const unsigned int fastscape_array_size = fastscape_nx*fastscape_ny; - std::vector slopep(fastscape_array_size); - - if (!init) - fastscape_copy_slope_(slopep.data()); - - // Here we set the ghost nodes at the left and right boundaries. In most cases, - // this involves setting the node to the same values of v and h as the inward node. - // With the inward node being above or below for the bottom and top rows of ghost nodes, - // or to the left and right for the right and left columns of ghost nodes. - for (unsigned int j=0; j 0) - { - slope = 0; - if (j == 0) - slope = left_flux / bedrock_transport_coefficient - std::tan(slopep[index_left + fastscape_nx + 1] * numbers::PI / 180.); - else if (j == (fastscape_ny - 1)) - slope = left_flux / bedrock_transport_coefficient - std::tan(slopep[index_left - fastscape_nx + 1] * numbers::PI / 180.); - else - slope = left_flux / bedrock_transport_coefficient - std::tan(slopep[index_left + 1] * numbers::PI / 180.); - - elevation[index_left] = elevation[index_left] + slope * 2 * fastscape_dx; - } - else - elevation[index_left] = elevation[index_left + 1]; - } - - if (right == 0 && !init) - { - - if (right_flux > 0) - { - slope = 0; - if (j == 0) - slope = right_flux / bedrock_transport_coefficient - std::tan(slopep[index_right + fastscape_nx - 1] * numbers::PI / 180.); - else if (j == (fastscape_ny - 1)) - slope = right_flux / bedrock_transport_coefficient - std::tan(slopep[index_right - fastscape_nx - 1] * numbers::PI / 180.); - else - slope = right_flux / bedrock_transport_coefficient - std::tan(slopep[index_right - 1] * numbers::PI / 180.); - - elevation[index_right] = elevation[index_right] + slope * 2 * fastscape_dx; - } - else - elevation[index_right] = elevation[index_right - 1]; - - - } - - // If the boundaries are periodic, then we look at the velocities on both sides of the - // model, and set the ghost node according to the direction of flow. As FastScape will - // receive all velocities it will have a direction, and we only need to look at the (non-ghost) - // nodes directly to the left and right. - if (left == 0 && right == 0 || leftright_ghost_nodes_periodic == true) - { - // First we assume that flow is going to the left. - unsigned int side = index_left; - unsigned int op_side = index_right; - - // Indexing depending on which side the ghost node is being set to. - int jj = 1; - - // If nodes on both sides are going the same direction, then set the respective - // ghost nodes to equal these sides. By doing this, the ghost nodes at the opposite - // side of flow will work as a mirror mimicking what is happening on the other side. - if (velocity_x[index_right-1] > 0 && velocity_x[index_left+1] >= 0) - { - side = index_right; - op_side = index_left; - jj = -1; - } - else if (velocity_x[index_right-1] <= 0 && velocity_x[index_left+1] < 0) - { - side = index_left; - op_side = index_right; - jj = 1; - } - else - continue; - - // Now set the nodes for periodic boundaries. As an example, assume we have 9 FastScape nodes in x: - // - // 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - // - // Of these 9 nodes, 0 and 8 are ghost nodes and 1 and 7 are the periodic ASPECT boundaries. - // If we assume that the horizontal ASPECT direction of travel is towards node 7, then we would - // set the ghost node 8 velocities and heights to that of node 2, ghost node 0 to node 6, and - // ASPECT boundary node 1 to ASPECT boundary node 7. E.g., based on the FastScape values for - // vx, vy, vz, and elevation, the nodes could be rewritten as: - // - // 6 - 7 - 2 - 3 - 4 - 5 - 6 - 7 - 2 - // - // This makes it so that effectively both periodic ASPECT boundaries see the same - // topography on either side of them to try and make sure they experience the same - // amount of diffusion and SPL. - velocity_x[index_right] = velocity_x[index_left+2]; - velocity_y[index_right] = velocity_y[index_left+2]; - velocity_z[index_right] = velocity_z[index_left+2] + (elevation[index_left+2] - elevation[index_right])/fastscape_timestep_in_years; - - velocity_x[index_left] = velocity_x[index_right-2]; - velocity_y[index_left] = velocity_y[index_right-2]; - velocity_z[index_left] = velocity_z[index_right-2] + (elevation[index_right-2] - elevation[index_left])/fastscape_timestep_in_years; - - // Set opposing ASPECT boundary so it's periodic. - elevation[op_side-jj] = elevation[side+jj]; - velocity_x[op_side-jj] = velocity_x[side+jj]; - velocity_y[op_side-jj] = velocity_y[side+jj]; - velocity_z[op_side-jj] = velocity_z[side+jj]; - - } - } - - // Now do the same for the top and bottom ghost nodes. - for (unsigned int j=0; j 0) - { - slope = 0; - if (j == 0) - slope = top_flux / bedrock_transport_coefficient - std::tan(slopep[index_top - fastscape_nx + 1] * numbers::PI / 180.); - else if (j == (fastscape_nx - 1)) - slope = top_flux / bedrock_transport_coefficient - std::tan(slopep[index_top - fastscape_nx - 1] * numbers::PI / 180.); - else - slope = top_flux / bedrock_transport_coefficient - std::tan(slopep[index_top - fastscape_nx] * numbers::PI / 180.); - - elevation[index_top] = elevation[index_top] + slope * 2 * fastscape_dx; - } - else - elevation[index_top] = elevation[index_top - fastscape_nx]; - } - - if (bottom == 0 && !init) - { - if (left_flux > 0) - { - slope = 0; - if (j == 0) - slope = bottom_flux / bedrock_transport_coefficient - std::tan(slopep[index_bot + fastscape_nx + 1] * numbers::PI / 180.); - else if (j == (fastscape_nx - 1)) - slope = bottom_flux / bedrock_transport_coefficient - std::tan(slopep[index_bot + fastscape_nx - 1] * numbers::PI / 180.); - else - slope = bottom_flux / bedrock_transport_coefficient - std::tan(slopep[index_bot + fastscape_nx] * numbers::PI / 180.); - - elevation[index_bot] = elevation[index_bot] + slope * 2 * fastscape_dx; - } - else - elevation[index_bot] = elevation[index_bot + fastscape_nx]; - } - - if (bottom == 0 && top == 0 || topbottom_ghost_nodes_periodic == true) - { - unsigned int side = index_bot; - unsigned int op_side = index_top; - int jj = fastscape_nx; - - if (velocity_y[index_bot+fastscape_nx-1] > 0 && velocity_y[index_top-fastscape_nx-1] >= 0) - { - side = index_top; - op_side = index_bot; - jj = -fastscape_nx; - } - else if (velocity_y[index_bot+fastscape_nx-1] <= 0 && velocity_y[index_top-fastscape_nx-1] < 0) - { - side = index_bot; - op_side = index_top; - jj = fastscape_nx; - } - else - continue; - - // Set top ghost node - velocity_x[index_top] = velocity_x[index_bot + 2*fastscape_nx]; - velocity_y[index_top] = velocity_y[index_bot + 2*fastscape_nx]; - velocity_z[index_top] = velocity_z[index_bot + 2*fastscape_nx] + (elevation[index_bot + 2*fastscape_nx] - elevation[index_top])/fastscape_timestep_in_years; - - // Set bottom ghost node - velocity_x[index_bot] = velocity_x[index_top - 2*fastscape_nx]; - velocity_y[index_bot] = velocity_y[index_top - 2*fastscape_nx]; - velocity_z[index_bot] = velocity_z[index_top - 2*fastscape_nx] + (elevation[index_top - 2*fastscape_nx] - elevation[index_bot])/fastscape_timestep_in_years; - - // Set opposing ASPECT boundary so it's periodic. - elevation[op_side-jj] = elevation[side+jj]; - velocity_x[op_side-jj] = velocity_x[side+jj]; - velocity_y[op_side-jj] = velocity_y[side+jj]; - velocity_z[op_side-jj] = velocity_z[side+jj]; - } - } - } - - template - bool FastScape::is_ghost_node(const unsigned int &index, - const bool &exclude_boundaries) const - { - if (use_ghost_nodes == false && exclude_boundaries == false) - return false; - - const unsigned int row = index / fastscape_nx; // Calculate the row index - const unsigned int col = index % fastscape_nx; // Calculate the column index - - // If we are at a boundary node and ghost nodes are enabled - // or we are excluding the boundaries then return true. - if (row == 0 || row == fastscape_ny-1 || col == 0 || col == fastscape_nx-1) - return true; - else - return false; - } - - - template - Table - FastScape::fill_data_table(std::vector &values, - TableIndices &size_idx, - const unsigned int &fastscape_nx, - const unsigned int &fastscape_ny) const - { - // Create data table based off of the given size. - Table data_table; - data_table.TableBase::reinit(size_idx); - TableIndices idx; - - // Loop through the data table and fill it with the velocities from FastScape. - if (dim == 2) - { - std::vector values_2d(fastscape_nx); - - for (unsigned int x=use_ghost_nodes; x<(fastscape_nx-use_ghost_nodes); ++x) - { - // If we do not average the values, then use a slice near the center. - if (!average_out_of_plane_surface_topography) - { - const unsigned int index = x+fastscape_nx*(round((fastscape_ny-use_ghost_nodes)/2)); - - // If we are using the ghost nodes, then the x value locations need to be shifted back 1 - // e.g., given a 4x4 mesh an index of 5 would correspond to an x of 1 and y of 1 in the loop, - // but should correspond to 0,0 for ASPECT. - values_2d[x-use_ghost_nodes] = values[index]; - } - // Here we use average velocities across the y nodes, excluding the ghost nodes (top and bottom row). - // Note: If ghost nodes are turned off, boundary effects may influence this. - else - { - for (unsigned int y=use_ghost_nodes; y<(fastscape_ny-use_ghost_nodes); ++y) - { - const unsigned int index = x+fastscape_nx*y; - values_2d[x-use_ghost_nodes] += values[index]; - } - values_2d[x-use_ghost_nodes] = values_2d[x-use_ghost_nodes]/(fastscape_ny-2*use_ghost_nodes); - } - } - - for (unsigned int x=0; x - void FastScape::read_restart_files(std::vector &elevation, - std::vector &basement, - std::vector &silt_fraction) const - { - this->get_pcout() << " Loading FastScape restart file... " << std::endl; - - // Create variables for output directory and restart file - const unsigned int fastscape_array_size = fastscape_nx*fastscape_ny; - std::string dirname = this->get_output_directory(); - const std::string restart_filename_elevation = dirname + "fastscape_elevation_restart.txt"; - const std::string restart_filename_basement = dirname + "fastscape_basement_restart.txt"; - const std::string restart_filename_silt_fraction = dirname + "fastscape_silt_fraction_restart.txt"; - const std::string restart_filename_time = dirname + "fastscape_last_output_time.txt"; - - // Load in h values. - std::ifstream in_elevation(restart_filename_elevation); - AssertThrow (in_elevation, ExcIO()); - { - unsigned int line = 0; - while (line < fastscape_array_size) - { - in_elevation >> elevation[line]; - line++; - } - } - - // Load in b values. - std::ifstream in_basement(restart_filename_basement); - AssertThrow (in_basement, ExcIO()); - { - unsigned int line = 0; - while (line < fastscape_array_size) - { - in_basement >> basement[line]; - line++; - } - } - - // Load in silt_fraction values if - // marine sediment transport and deposition is active. - if (use_marine_component) - { - std::ifstream in_silt_fraction(restart_filename_silt_fraction); - AssertThrow (in_silt_fraction, ExcIO()); - - if (sand_surface_porosity > 0. || silt_surface_porosity > 0.) - this->get_pcout() << " Restarting runs with nonzero porosity can lead to a different system after restart. " << std::endl; - unsigned int line = 0; - while (line < fastscape_array_size) - { - in_silt_fraction >> silt_fraction[line]; - line++; - } - } - - // Now load the last output at time of restart. - // this allows us to correctly track when to call - // FastScape to make new VTK files. - std::ifstream in_last_output_time(restart_filename_time); - AssertThrow (in_last_output_time, ExcIO()); - { - in_last_output_time >> last_output_time; - } - } - - template - void FastScape::save_restart_files(const std::vector &elevation, - std::vector &basement, - std::vector &silt_fraction) const - { - this->get_pcout() << " Writing FastScape restart file... " << std::endl; - - // Create variables for output directory and restart file - const unsigned int fastscape_array_size = fastscape_nx*fastscape_ny; - std::string dirname = this->get_output_directory(); - const std::string restart_filename_elevation = dirname + "fastscape_elevation_restart.txt"; - const std::string restart_filename_basement = dirname + "fastscape_basement_restart.txt"; - const std::string restart_filename_silt_fraction = dirname + "fastscape_silt_fraction_restart.txt"; - const std::string restart_filename_time = dirname + "fastscape_last_output_time.txt"; - - std::ofstream out_elevation(restart_filename_elevation); - std::ofstream out_basement(restart_filename_basement); - std::ofstream out_silt_fraction(restart_filename_silt_fraction); - std::ofstream out_last_output_time(restart_filename_time); - std::stringstream buffer_basement; - std::stringstream buffer_elevation; - std::stringstream buffer_silt_fraction; - std::stringstream buffer_time; - - fastscape_copy_basement_(basement.data()); - - // If marine sediment transport and deposition is active, - // we also need to store the silt fraction. - if (use_marine_component) - fastscape_copy_f_(silt_fraction.data()); - - out_last_output_time << last_output_time << "\n"; - - for (unsigned int i = 0; i < fastscape_array_size; ++i) - { - buffer_elevation << elevation[i] << "\n"; - buffer_basement << basement[i] << "\n"; - if (use_marine_component) - buffer_silt_fraction << silt_fraction[i] << "\n"; - } - - out_elevation << buffer_elevation.str(); - out_basement << buffer_basement.str(); - if (use_marine_component) - out_silt_fraction << buffer_silt_fraction.str(); - } - - - - template - bool - FastScape:: - needs_surface_stabilization () const - { - return true; - } - - - - template - void FastScape::declare_parameters(ParameterHandler &prm) - { - prm.enter_subsection ("Mesh deformation"); - { - prm.enter_subsection ("Fastscape"); - { - prm.declare_entry("Number of fastscape timesteps per aspect timestep", "5", - Patterns::Integer(), - "Initial number of fastscape time steps per ASPECT timestep, this value will double if" - "the FastScape timestep is above the maximum FastScape timestep."); - prm.declare_entry("Maximum timestep length", "10e3", - Patterns::Double(0), - "Maximum timestep for FastScape. Units: $\\{yrs}$"); - prm.declare_entry("Vertical exaggeration", "-1", - Patterns::Double(), - "Vertical exaggeration for FastScape's VTK file. -1 outputs topography, basement, and sealevel."); - prm.declare_entry("Additional fastscape refinement", "0", - Patterns::Integer(), - "How many levels above ASPECT FastScape should be refined."); - prm.declare_entry ("Average out of plane surface topography in 2d", "true", - Patterns::Bool (), - "If this is set to false, then a 2D model will only consider the " - "center slice FastScape gives. If set to true, then ASPECT will" - "average the mesh along Y excluding the ghost nodes."); - prm.declare_entry("Fastscape seed", "1000", - Patterns::Integer(), - "Seed used for adding an initial noise to FastScape topography based on the initial noise magnitude."); - prm.declare_entry("Maximum surface refinement level", "1", - Patterns::Integer(), - "This should be set to the highest ASPECT refinement level expected at the surface."); - prm.declare_entry("Surface refinement difference", "0", - Patterns::Integer(), - "The difference between the lowest and highest refinement level at the surface. E.g., if three resolution " - "levels are expected, this would be set to 2."); - prm.declare_entry ("Use marine component", "false", - Patterns::Bool (), - "Flag to use the marine component of FastScape."); - prm.declare_entry("Y extent in 2d", "100000", - Patterns::Double(), - "FastScape Y extent when using a 2D ASPECT model. Units: $\\{m}$"); - prm.declare_entry ("Use ghost nodes", "true", - Patterns::Bool (), - "Flag to use ghost nodes"); - prm.declare_entry ("Uplift and advect with fastscape", "true", - Patterns::Bool (), - "Flag to use FastScape advection and uplift."); - prm.declare_entry("Node tolerance", "0.001", - Patterns::Double(), - "Node tolerance for how close an ASPECT node must be to the FastScape node for the value to be transferred."); - prm.declare_entry ("Sediment rain rates", "0,0", - Patterns::List (Patterns::Double(0)), - "Sediment rain rates given as a list 1 greater than the number of sediment rain time intervals. E.g, " - " If the time interval is given at 5 Myr, there will be one value for 0-5 Myr model time and a second value " - " for 5+ Myr. Units: $\\{m/yr}$"); - prm.declare_entry ("Sediment rain time intervals", "0", - Patterns::List (Patterns::Double(0)), - "A list of times to change the sediment rain rate. Units: $\\{yrs}$"); - prm.declare_entry("Initial noise magnitude", "5", - Patterns::Double(), - "Maximum topography change from the initial noise. Units: $\\{m}$"); - - prm.enter_subsection ("Boundary conditions"); - { - prm.declare_entry ("Front", "1", - Patterns::Integer (0, 1), - "Front (bottom) boundary condition, where 1 is fixed and 0 is reflective."); - prm.declare_entry ("Right", "1", - Patterns::Integer (0, 1), - "Right boundary condition, where 1 is fixed and 0 is reflective."); - prm.declare_entry ("Back", "1", - Patterns::Integer (0, 1), - "Back (top) boundary condition, where 1 is fixed and 0 is reflective."); - prm.declare_entry ("Left", "1", - Patterns::Integer (0, 1), - "Left boundary condition, where 1 is fixed and 0 is reflective."); - prm.declare_entry("Left mass flux", "0", - Patterns::Double(), - "Flux per unit length through left boundary. Units: $\\{m^2/yr}$ "); - prm.declare_entry("Right mass flux", "0", - Patterns::Double(), - "Flux per unit length through right boundary. Units: $\\{m^2/yr}$ "); - prm.declare_entry("Back mass flux", "0", - Patterns::Double(), - "Flux per unit length through back boundary. Units: $\\{m^2/yr}$ "); - prm.declare_entry("Front mass flux", "0", - Patterns::Double(), - "Flux per unit length through front boundary. Units: $\\{m^2/yr}$ "); - prm.declare_entry ("Back front ghost nodes periodic", "false", - Patterns::Bool (), - "Whether to set the ghost nodes at the FastScape back and front boundary " - "to periodic even if 'Back' and 'Front' are set to fixed boundary."); - prm.declare_entry ("Left right ghost nodes periodic", "false", - Patterns::Bool (), - "Whether to set the ghost nodes at the FastScape left and right boundary " - "to periodic even if 'Left' and 'Right' are set to fixed boundary."); - } - prm.leave_subsection(); - - prm.enter_subsection ("Erosional parameters"); - { - prm.declare_entry("Drainage area exponent", "0.4", - Patterns::Double(), - "Exponent for drainage area."); - prm.declare_entry("Slope exponent", "1", - Patterns::Double(), - "The slope exponent for SPL (n). Generally m/n should equal approximately 0.4"); - prm.declare_entry("Multi-direction slope exponent", "1", - Patterns::Double(), - "Exponent to determine the distribution from the SPL to neighbor nodes, with" - "10 being steepest decent and 1 being more varied."); - prm.declare_entry("Bedrock deposition coefficient", "1", - Patterns::Double(), - "Deposition coefficient for bedrock."); - prm.declare_entry("Sediment deposition coefficient", "-1", - Patterns::Double(), - "Deposition coefficient for sediment, -1 sets this to the same as the bedrock deposition coefficient."); - prm.declare_entry("Bedrock river incision rate", "1e-5", - Patterns::Double(), - "River incision rate for bedrock in the Stream Power Law. Units: $\\{m^(1-2*drainage_area_exponent)/yr}$"); - prm.declare_entry("Sediment river incision rate", "-1", - Patterns::Double(), - "River incision rate for sediment in the Stream Power Law. -1 sets this to the bedrock river incision rate. Units: $\\{m^(1-2*drainage_area_exponent)/yr}$ "); - prm.declare_entry("Bedrock diffusivity", "1e-2", - Patterns::Double(), - "Transport coefficient (diffusivity) for bedrock. Units: $\\{m^2/yr}$ "); - prm.declare_entry("Sediment diffusivity", "-1", - Patterns::Double(), - "Transport coefficient (diffusivity) for sediment. -1 sets this to the bedrock diffusivity. Units: $\\{m^2/yr}$"); - prm.declare_entry("Orographic elevation control", "2000", - Patterns::Integer(), - "Above this height, the elevation factor is applied. Units: $\\{m}$"); - prm.declare_entry("Orographic wind barrier height", "500", - Patterns::Integer(), - "When terrain reaches this height the wind barrier factor is applied. Units: $\\{m}$"); - prm.declare_entry("Elevation factor", "1", - Patterns::Double(), - "Amount to multiply the bedrock river incision rate nad transport coefficient by past the given orographic elevation control."); - prm.declare_entry("Wind barrier factor", "1", - Patterns::Double(), - "Amount to multiply the bedrock river incision rate nad transport coefficient by past given wind barrier height."); - prm.declare_entry ("Stack orographic controls", "true", - Patterns::Bool (), - "Whether or not to apply both controls to a point, or only a maximum of one set as the wind barrier."); - prm.declare_entry ("Flag to use orographic controls", "false", - Patterns::Bool (), - "Whether or not to apply orographic controls."); - prm.declare_entry ("Wind direction", "west", - Patterns::Selection("east|west|south|north"), - "This parameter assumes a wind direction, deciding which side is reduced from the wind barrier."); - prm.declare_entry ("Use a fixed erosional base level", "false", - Patterns::Bool (), - "Whether or not to use an erosional base level that differs from sea level. Setting this parameter to " - "true will set all ghost nodes of fixed FastScape boundaries to the height you specify in " - "'set Erosional base level'. \nThis can make " - "sense for a continental model where the model surrounding topography is assumed above sea level, " - "e.g. highlands. If the sea level would be used as an erosional base level in this case, all topography " - "erodes away with lots of 'sediment volume' lost through the sides of the model. This is mostly " - "important, when there are mountains in the middle of the model, while it is less important when there " - "is lower relief in the middle of the model. \n" - "In the FastScape visualization files, setting the extra base level may show up as a strong " - "slope at the fixed boundaries of the model. However, in the ASPECT visualization files it will not " - "show up, as the ghost nodes only exist in FastScape."); - prm.declare_entry("Erosional base level", "0", - Patterns::Double(), - "When 'Use a fixed erosional base level' is set to true, all ghost nodes of fixed " - "FastScape boundaries where no mass flux is specified by the user (FastScape boundary condition set to 1 " - "and 'Left/Right/Bottom/Top mass flux' set to 0) will be fixed to this elevation. The " - "reflecting boundaries (FastScape boundary condition set to 0) will not be affected, nor are the " - "boundaries where a mass flux is specified. \n" - "Units: m"); - } - prm.leave_subsection(); - - prm.enter_subsection ("Marine parameters"); - { - prm.declare_entry("Sea level", "0", - Patterns::Double(), - "Sea level relative to the ASPECT surface, where the maximum Z or Y extent in ASPECT is a sea level of zero. Units: $\\{m}$ "); - prm.declare_entry("Sand porosity", "0.0", - Patterns::Double(), - "Porosity of sand. "); - prm.declare_entry("Silt porosity", "0.0", - Patterns::Double(), - "Porosity of silt. "); - prm.declare_entry("Sand e-folding depth", "1e3", - Patterns::Double(), - "E-folding depth for the exponential of the sand porosity law. Units: $\\{m}$"); - prm.declare_entry("Silt e-folding depth", "1e3", - Patterns::Double(), - "E-folding depth for the exponential of the silt porosity law. Units: $\\{m}$"); - prm.declare_entry("Sand-silt ratio", "0.5", - Patterns::Double(), - "Ratio of sand to silt for material leaving continent."); - prm.declare_entry("Depth averaging thickness", "1e2", - Patterns::Double(), - "Depth averaging for the sand-silt equation. Units: $\\{m}$"); - prm.declare_entry("Sand transport coefficient", "5e2", - Patterns::Double(), - "Transport coefficient (diffusivity) for sand. Units: $\\{m^2/yr}$"); - prm.declare_entry("Silt transport coefficient", "2.5e2", - Patterns::Double(), - "Transport coefficient (diffusivity) for silt. Units: $\\{m^2/yr}$ "); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - prm.leave_subsection (); - } - - - template - void FastScape::parse_parameters(ParameterHandler &prm) - { - prm.enter_subsection ("Mesh deformation"); - { - prm.enter_subsection("Fastscape"); - { - fastscape_steps_per_aspect_step = prm.get_integer("Number of fastscape timesteps per aspect timestep"); - maximum_fastscape_timestep = prm.get_double("Maximum timestep length"); - vexp = prm.get_double("Vertical exaggeration"); - additional_refinement_levels = prm.get_integer("Additional fastscape refinement"); - average_out_of_plane_surface_topography = prm.get_bool("Average out of plane surface topography in 2d"); - fastscape_seed = prm.get_integer("Fastscape seed"); - maximum_surface_refinement_level = prm.get_integer("Maximum surface refinement level"); - surface_refinement_difference = prm.get_integer("Surface refinement difference"); - use_marine_component = prm.get_bool("Use marine component"); - fastscape_y_extent_2d = prm.get_double("Y extent in 2d"); - use_ghost_nodes = prm.get_bool("Use ghost nodes"); - fastscape_advection_uplift = prm.get_bool("Uplift and advect with fastscape"); - node_tolerance = prm.get_double("Node tolerance"); - noise_elevation = prm.get_double("Initial noise magnitude"); - sediment_rain_rates = Utilities::string_to_double - (Utilities::split_string_list(prm.get ("Sediment rain rates"))); - sediment_rain_times = Utilities::string_to_double - (Utilities::split_string_list(prm.get ("Sediment rain time intervals"))); - - if (!this->convert_output_to_years()) - { - maximum_fastscape_timestep /= year_in_seconds; - for (unsigned int j=0; j sediment_rain_times[i-1], ExcMessage("Sediment rain time intervals must be an increasing array.")); - - prm.enter_subsection("Boundary conditions"); - { - bottom = prm.get_integer("Front"); - right = prm.get_integer("Right"); - top = prm.get_integer("Back"); - left = prm.get_integer("Left"); - left_flux = prm.get_double("Left mass flux"); - right_flux = prm.get_double("Right mass flux"); - top_flux = prm.get_double("Back mass flux"); - bottom_flux = prm.get_double("Front mass flux"); - - if (!this->convert_output_to_years()) - { - left_flux *= year_in_seconds; - right_flux *= year_in_seconds; - top_flux *= year_in_seconds; - bottom_flux *= year_in_seconds; - } - - // Put the boundary condition values into a four digit value to send to FastScape. - fastscape_boundary_conditions = bottom*1000+right*100+top*10+left; - - if ((left_flux != 0 && top_flux != 0) || (left_flux != 0 && bottom_flux != 0) || - (right_flux != 0 && bottom_flux != 0) || (right_flux != 0 && top_flux != 0)) - AssertThrow(false,ExcMessage("Currently the plugin does not support mass flux through adjacent boundaries.")); - - topbottom_ghost_nodes_periodic = prm.get_bool("Back front ghost nodes periodic"); - leftright_ghost_nodes_periodic = prm.get_bool("Left right ghost nodes periodic"); - } - prm.leave_subsection(); - - prm.enter_subsection("Erosional parameters"); - { - drainage_area_exponent_m = prm.get_double("Drainage area exponent"); - slope_exponent_n = prm.get_double("Slope exponent"); - sediment_river_incision_rate = prm.get_double("Sediment river incision rate"); - bedrock_river_incision_rate = prm.get_double("Bedrock river incision rate"); - sediment_transport_coefficient = prm.get_double("Sediment diffusivity"); - bedrock_transport_coefficient = prm.get_double("Bedrock diffusivity"); - bedrock_deposition_g = prm.get_double("Bedrock deposition coefficient"); - sediment_deposition_g = prm.get_double("Sediment deposition coefficient"); - slope_exponent_p = prm.get_double("Multi-direction slope exponent"); - flat_elevation = prm.get_integer("Orographic elevation control"); - wind_barrier_elevation = prm.get_integer("Orographic wind barrier height"); - flat_erosional_factor = prm.get_double("Elevation factor"); - wind_barrier_erosional_factor = prm.get_double("Wind barrier factor"); - stack_controls = prm.get_bool("Stack orographic controls"); - use_orographic_controls = prm.get_bool("Flag to use orographic controls"); - - if (!this->convert_output_to_years()) - { - bedrock_river_incision_rate *= year_in_seconds; - bedrock_transport_coefficient *= year_in_seconds; - sediment_river_incision_rate *= year_in_seconds; - bedrock_transport_coefficient *= year_in_seconds; - } - - // Wind direction - if (prm.get ("Wind direction") == "west") - wind_direction = 0; - else if (prm.get ("Wind direction") == "east") - wind_direction = 1; - else if (prm.get ("Wind direction") == "north") - wind_direction = 2; - else if (prm.get ("Wind direction") == "south") - wind_direction = 3; - else - AssertThrow(false, ExcMessage("Not a valid wind direction.")); - - // set fixed ghost nodes to a base level for erosion that differs from sea level - use_fixed_erosional_base = prm.get_bool("Use a fixed erosional base level"); - if (use_fixed_erosional_base) - AssertThrow(use_fixed_erosional_base && use_ghost_nodes, ExcMessage( - "If you want to use an erosional base level differing from sea level, " - "you need to use ghost nodes.")); - h_erosional_base = prm.get_double("Erosional base level"); - } - prm.leave_subsection(); - - prm.enter_subsection("Marine parameters"); - { - sea_level = prm.get_double("Sea level"); - sand_surface_porosity = prm.get_double("Sand porosity"); - silt_surface_porosity = prm.get_double("Silt porosity"); - sand_efold_depth = prm.get_double("Sand e-folding depth"); - silt_efold_depth = prm.get_double("Silt e-folding depth"); - sand_silt_ratio = prm.get_double("Sand-silt ratio"); - sand_silt_averaging_depth = prm.get_double("Depth averaging thickness"); - sand_transport_coefficient = prm.get_double("Sand transport coefficient"); - silt_transport_coefficient = prm.get_double("Silt transport coefficient"); - - if (!this->convert_output_to_years()) - { - sand_transport_coefficient *= year_in_seconds; - silt_transport_coefficient *= year_in_seconds; - } - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - prm.leave_subsection (); - - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Visualization"); - { - output_interval = prm.get_double ("Time between graphical output"); - if (this->convert_output_to_years()) - output_interval *= year_in_seconds; - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - - -// explicit instantiation of the functions we implement in this file -namespace aspect -{ - namespace MeshDeformation - { - ASPECT_REGISTER_MESH_DEFORMATION_MODEL(FastScape, - "fastscape", - "A plugin that uses the program FastScape to compute the deformation of the mesh surface. " - "FastScape is a surface processes code that computes the erosion, transport and " - "deposition of sediments both on land and in the marine domain. These surface processes " - "include river incision (through the stream power law), hillslope diffusion and " - "marine diffusion, as described in Braun and Willett 2013; Yuan et al. 2019; " - "Yuan et al. 2019b. " - "\n" - "Upon initialization, FastScape requires the initial topography of the surface boundary " - "of ASPECT's model domain and several user-specified erosional and depositional parameters. " - "In each ASPECT timestep, FastScape is then fed ASPECT's material velocity at the surface " - "boundary. The z-component of this velocity is used to uplift the FastScape surface, " - "while the horizontal components are used to advect the topography in the x-y plane. " - "\n" - "After solving its governing equations (this can be done in several timesteps " - "that are smaller than the ASPECT timestep), FastScape returns a new topography of the surface. " - "The difference in topography before and after the call to FastScape divided by the ASPECT " - "timestep provides the mesh velocity at the domain's surface that is used to displace the surface " - "and internal mesh nodes. " - "\n" - "FastScape can be used in both 2D and 3D ASPECT simulations. In 2D, one can think of the coupled " - "model as a T-model.The ASPECT domain spans the x - z plane, while FastScape acts on the horizontal " - "x-y plane. This means that to communicate ASPECT's material velocities to FastScape, " - "FastScape mesh nodes with the same x-coordinate (so lying along the y-direction) get the same velocities. " - "In turn, the FastScape topography is collapsed back onto the line of the ASPECT surface boundary " - "by averaging the topography over the y-direction. In 3D no such actions are necessary. " - "\n" - "The FastScape manual (https://fastscape.org/fastscapelib-fortran/) provides more information " - "on the input parameters. ") - - } -} -#endif diff --git a/source/mesh_deformation/free_surface.cc.bak b/source/mesh_deformation/free_surface.cc.bak deleted file mode 100644 index 83d083d7b07..00000000000 --- a/source/mesh_deformation/free_surface.cc.bak +++ /dev/null @@ -1,336 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include - - -namespace aspect -{ - namespace MeshDeformation - { - template - void - FreeSurface::initialize () - { - // Pressure normalization doesn't really make sense with a free surface, and if we do - // use it, we can run into problems with geometry_model->depth(). - AssertThrow ( this->get_parameters().pressure_normalization == "no", - ExcMessage("The free surface scheme can only be used with no pressure normalization") ); - - // Check that we do not use the free surface on a boundary that has zero slip, - // free slip or prescribed velocity boundary conditions on it. - - // Get the zero velocity boundary indicators - std::set velocity_boundary_indicators = this->get_boundary_velocity_manager().get_zero_boundary_velocity_indicators(); - - // Get the tangential velocity boundary indicators - const std::set tmp_tangential_vel_boundary_indicators = this->get_boundary_velocity_manager().get_tangential_boundary_velocity_indicators(); - velocity_boundary_indicators.insert(tmp_tangential_vel_boundary_indicators.begin(), - tmp_tangential_vel_boundary_indicators.end()); - - // Get the active velocity boundary indicators - const std::map>> - tmp_active_vel_boundary_indicators = this->get_boundary_velocity_manager().get_active_boundary_velocity_names(); - - for (const auto &p : tmp_active_vel_boundary_indicators) - velocity_boundary_indicators.insert(p.first); - - // Get the mesh deformation boundary indicators - const std::set tmp_mesh_deformation_boundary_indicators = this->get_mesh_deformation_boundary_indicators(); - for (const auto &p : tmp_mesh_deformation_boundary_indicators) - AssertThrow(velocity_boundary_indicators.find(p) == velocity_boundary_indicators.end(), - ExcMessage("The free surface mesh deformation plugin cannot be used with the current velocity boundary conditions")); - } - - - template - void FreeSurface::project_velocity_onto_boundary(const DoFHandler &mesh_deformation_dof_handler, - const IndexSet &mesh_locally_owned, - const IndexSet &mesh_locally_relevant, - LinearAlgebra::Vector &output) const - { - // TODO: should we use the extrapolated solution? - - // stuff for iterating over the mesh - const QGauss face_quadrature(mesh_deformation_dof_handler.get_fe().degree+1); - UpdateFlags update_flags = UpdateFlags(update_values | update_quadrature_points - | update_normal_vectors | update_JxW_values); - FEFaceValues fs_fe_face_values (this->get_mapping(), mesh_deformation_dof_handler.get_fe(), face_quadrature, update_flags); - FEFaceValues fe_face_values (this->get_mapping(), this->get_fe(), face_quadrature, update_flags); - const unsigned int n_face_q_points = fe_face_values.n_quadrature_points, - dofs_per_cell = fs_fe_face_values.dofs_per_cell; - - // stuff for assembling system - std::vector cell_dof_indices (dofs_per_cell); - Vector cell_vector (dofs_per_cell); - FullMatrix cell_matrix (dofs_per_cell, dofs_per_cell); - - // stuff for getting the velocity values - std::vector> velocity_values(n_face_q_points); - - // set up constraints - AffineConstraints mass_matrix_constraints( -#if DEAL_II_VERSION_GTE(9,6,0) - mesh_deformation_dof_handler.locally_owned_dofs(), -#endif - mesh_locally_relevant); - DoFTools::make_hanging_node_constraints(mesh_deformation_dof_handler, mass_matrix_constraints); - - using periodic_boundary_pairs = std::set, unsigned int>>; - periodic_boundary_pairs pbp = this->get_geometry_model().get_periodic_boundary_pairs(); - for (const auto &p : pbp) - DoFTools::make_periodicity_constraints(mesh_deformation_dof_handler, - p.first.first, p.first.second, p.second, mass_matrix_constraints); - - mass_matrix_constraints.close(); - - // set up the matrix - LinearAlgebra::SparseMatrix mass_matrix; - TrilinosWrappers::SparsityPattern sp (mesh_locally_owned, - mesh_locally_owned, - mesh_locally_relevant, - this->get_mpi_communicator()); - DoFTools::make_sparsity_pattern (mesh_deformation_dof_handler, sp, mass_matrix_constraints, false, - Utilities::MPI::this_mpi_process(this->get_mpi_communicator())); - sp.compress(); - mass_matrix.reinit (sp); - - FEValuesExtractors::Vector extract_vel(0); - - // make distributed vectors. - LinearAlgebra::Vector rhs, dist_solution; - rhs.reinit(mesh_locally_owned, this->get_mpi_communicator()); - dist_solution.reinit(mesh_locally_owned, this->get_mpi_communicator()); - - typename DoFHandler::active_cell_iterator - cell = this->get_dof_handler().begin_active(), endc= this->get_dof_handler().end(); - typename DoFHandler::active_cell_iterator - fscell = mesh_deformation_dof_handler.begin_active(); - - // Get the boundary indicators of those boundaries with - // a free surface. - const std::set tmp_free_surface_boundary_indicators = this->get_mesh_deformation_handler().get_free_surface_boundary_indicators(); - - for (; cell!=endc; ++cell, ++fscell) - if (cell->at_boundary() && cell->is_locally_owned()) - for (const unsigned int face_no : cell->face_indices()) - if (cell->face(face_no)->at_boundary()) - { - const types::boundary_id boundary_indicator - = cell->face(face_no)->boundary_id(); - - // Only project onto the free surface boundary/boundaries. - if (tmp_free_surface_boundary_indicators.find(boundary_indicator) == tmp_free_surface_boundary_indicators.end()) - continue; - - fscell->get_dof_indices (cell_dof_indices); - fs_fe_face_values.reinit (fscell, face_no); - fe_face_values.reinit (cell, face_no); - fe_face_values[this->introspection().extractors.velocities].get_function_values(this->get_solution(), velocity_values); - - cell_vector = 0; - cell_matrix = 0; - for (unsigned int point=0; point direction; - if ( advection_direction == SurfaceAdvection::normal ) // project onto normal vector - direction = fs_fe_face_values.normal_vector(point); - else if ( advection_direction == SurfaceAdvection::vertical ) // project onto local gravity - direction = this->get_gravity_model().gravity_vector(fs_fe_face_values.quadrature_point(point)); - else - AssertThrow(false, ExcInternalError()); - - direction *= ( direction.norm() > 0.0 ? 1./direction.norm() : 0.0 ); - - for (unsigned int i=0; iget_parameters().linear_stokes_solver_tolerance*rhs.l2_norm()); - SolverCG cg(solver_control); - cg.solve (mass_matrix, dist_solution, rhs, preconditioner_mass); - - mass_matrix_constraints.distribute (dist_solution); - output = dist_solution; - } - - - - /** - * A function that creates constraints for the velocity of certain mesh - * vertices (e.g. the surface vertices) for a specific boundary. - * The calling class will respect - * these constraints when computing the new vertex positions. - */ - template - void - FreeSurface::compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, - AffineConstraints &mesh_velocity_constraints, - const std::set &boundary_id) const - { - // For the free surface indicators we constrain the displacement to be v.n - LinearAlgebra::Vector boundary_velocity; - - const IndexSet &mesh_locally_owned = mesh_deformation_dof_handler.locally_owned_dofs(); - IndexSet mesh_locally_relevant; - DoFTools::extract_locally_relevant_dofs (mesh_deformation_dof_handler, - mesh_locally_relevant); - boundary_velocity.reinit(mesh_locally_owned, mesh_locally_relevant, - this->get_mpi_communicator()); - project_velocity_onto_boundary(mesh_deformation_dof_handler, mesh_locally_owned, - mesh_locally_relevant, boundary_velocity); - - // now insert the relevant part of the solution into the mesh constraints - const IndexSet constrained_dofs = - DoFTools::extract_boundary_dofs(mesh_deformation_dof_handler, - ComponentMask(dim, true), - boundary_id); - - for (unsigned int i = 0; i < constrained_dofs.n_elements(); ++i) - { - types::global_dof_index index = constrained_dofs.nth_index_in_set(i); - if (mesh_velocity_constraints.can_store_line(index)) - if (mesh_velocity_constraints.is_constrained(index)==false) - { -#if DEAL_II_VERSION_GTE(9,6,0) - mesh_velocity_constraints.add_constraint(index, - {}, - boundary_velocity[index]); -#else - mesh_velocity_constraints.add_line(index); - mesh_velocity_constraints.set_inhomogeneity(index, boundary_velocity[index]); -#endif - } - } - } - - - - template - bool - FreeSurface:: - needs_surface_stabilization () const - { - return true; - } - - - - template - void FreeSurface::declare_parameters(ParameterHandler &prm) - { - prm.enter_subsection ("Mesh deformation"); - { - prm.enter_subsection ("Free surface"); - { - prm.declare_entry("Surface velocity projection", "normal", - Patterns::Selection("normal|vertical"), - "After each time step the free surface must be " - "advected in the direction of the velocity field. " - "Mass conservation requires that the mesh velocity " - "is in the normal direction of the surface. However, " - "for steep topography or large curvature, advection " - "in the normal direction can become ill-conditioned, " - "and instabilities in the mesh can form. Projection " - "of the mesh velocity onto the local vertical direction " - "can preserve the mesh quality better, but at the " - "cost of slightly poorer mass conservation of the " - "domain."); - } - prm.leave_subsection (); - } - prm.leave_subsection (); - } - - - - template - void FreeSurface::parse_parameters(ParameterHandler &prm) - { - prm.enter_subsection ("Mesh deformation"); - { - prm.enter_subsection ("Free surface"); - { - std::string advection_dir = prm.get("Surface velocity projection"); - - if ( advection_dir == "normal") - advection_direction = SurfaceAdvection::normal; - else if ( advection_dir == "vertical") - advection_direction = SurfaceAdvection::vertical; - else - AssertThrow(false, ExcMessage("The surface velocity projection must be ``normal'' or ``vertical''.")); - } - prm.leave_subsection (); - } - prm.leave_subsection (); - } - } -} - - -// explicit instantiation of the functions we implement in this file -namespace aspect -{ - namespace MeshDeformation - { - ASPECT_REGISTER_MESH_DEFORMATION_MODEL(FreeSurface, - "free surface", - "A plugin that computes the deformation of surface " - "vertices according to the solution of the flow problem. " - "In particular this means if the surface of the domain is " - "left open to flow, this flow will carry the mesh with it. " - "The implementation was described in \\cite{rose_freesurface}, " - "with the stabilization of the free surface originally described " - "in \\cite{kaus:etal:2010}.") - } -} diff --git a/source/mesh_deformation/function.cc.bak b/source/mesh_deformation/function.cc.bak deleted file mode 100644 index 32027eafd2e..00000000000 --- a/source/mesh_deformation/function.cc.bak +++ /dev/null @@ -1,149 +0,0 @@ -/* - Copyright (C) 2018 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - - -#include - -#include - -namespace aspect -{ - namespace MeshDeformation - { - template - BoundaryFunction::BoundaryFunction() - : - function(dim) - {} - - - - template - void - BoundaryFunction::update () - { - // we get time passed as seconds (always) but may want - // to reinterpret it in years - if (this->convert_output_to_years()) - function.set_time (this->get_time() / year_in_seconds); - else - function.set_time (this->get_time()); - } - - - - /** - * A function that creates constraints for the velocity of certain mesh - * vertices (e.g. the surface vertices) for a specific boundary. - * The calling class will respect - * these constraints when computing the new vertex positions. - */ - template - void - BoundaryFunction::compute_velocity_constraints_on_boundary(const DoFHandler &mesh_deformation_dof_handler, - AffineConstraints &mesh_velocity_constraints, - const std::set &boundary_ids) const - { - // Loop over all boundary indicators to set the velocity constraints - for (const auto boundary_id : boundary_ids) - VectorTools::interpolate_boundary_values (this->get_mapping(), - mesh_deformation_dof_handler, - boundary_id, - function, - mesh_velocity_constraints); - } - - - - template - bool - BoundaryFunction:: - needs_surface_stabilization () const - { - return false; - } - - - - template - void BoundaryFunction::declare_parameters(ParameterHandler &prm) - { - prm.enter_subsection ("Mesh deformation"); - { - prm.enter_subsection ("Boundary function"); - { - Functions::ParsedFunction::declare_parameters (prm, dim); - } - prm.leave_subsection(); - } - prm.leave_subsection (); - } - - template - void BoundaryFunction::parse_parameters(ParameterHandler &prm) - { - prm.enter_subsection ("Mesh deformation"); - { - prm.enter_subsection("Boundary function"); - { - try - { - function.parse_parameters (prm); - } - catch (...) - { - std::cerr << "ERROR: FunctionParser failed to parse\n" - << "\t'Mesh deformation.BoundaryFunction'\n" - << "with expression\n" - << "\t'" << prm.get("Function expression") << "'" - << "More information about the cause of the parse error \n" - << "is shown below.\n"; - throw; - } - } - prm.leave_subsection(); - } - prm.leave_subsection (); - } - } -} - - -// explicit instantiation of the functions we implement in this file -namespace aspect -{ - namespace MeshDeformation - { - ASPECT_REGISTER_MESH_DEFORMATION_MODEL(BoundaryFunction, - "boundary function", - "A plugin, which prescribes the surface mesh to " - "deform according to an analytically prescribed " - "function. Note that the function prescribes a " - "deformation velocity, i.e. the return value of " - "this plugin is later multiplied by the time step length " - "to compute the displacement increment in this time step. " - "Although the function's time variable is interpreted as " - "years when Use years in output instead of seconds is set to true, " - "the boundary deformation velocity should still be given " - "in m/s. The format of the " - "functions follows the syntax understood by the " - "muparser library, see {ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") - } -} diff --git a/source/mesh_deformation/interface.cc.bak b/source/mesh_deformation/interface.cc.bak deleted file mode 100644 index 50d4f2307e8..00000000000 --- a/source/mesh_deformation/interface.cc.bak +++ /dev/null @@ -1,1605 +0,0 @@ -/* - Copyright (C) 2014 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include - -#include - -namespace aspect -{ - namespace Assemblers - { - template - ApplyStabilization::ApplyStabilization(const double stabilization_theta) - : - free_surface_theta(stabilization_theta) - {} - - template - void - ApplyStabilization:: - execute (internal::Assembly::Scratch::ScratchBase &scratch_base, - internal::Assembly::CopyData::CopyDataBase &data_base) const - { - internal::Assembly::Scratch::StokesSystem &scratch = dynamic_cast& > (scratch_base); - internal::Assembly::CopyData::StokesSystem &data = dynamic_cast& > (data_base); - - AssertThrow(!this->get_mesh_deformation_handler().get_boundary_indicators_requiring_stabilization().empty(), - ExcMessage("Applying surface stabilization, even though no boundary requires it.")); - - - if (this->get_parameters().include_melt_transport) - { - this->get_melt_handler().apply_free_surface_stabilization_with_melt (free_surface_theta, - scratch.cell, - scratch, - data); - return; - } - - const Introspection &introspection = this->introspection(); - const FiniteElement &fe = this->get_fe(); - - const typename DoFHandler::active_cell_iterator cell (&this->get_triangulation(), - scratch.finite_element_values.get_cell()->level(), - scratch.finite_element_values.get_cell()->index(), - &this->get_dof_handler()); - - const unsigned int n_face_q_points = scratch.face_finite_element_values.n_quadrature_points; - const unsigned int stokes_dofs_per_cell = data.local_dof_indices.size(); - - // Get the boundary indicators of those boundaries that require stabilization - const std::set tmp_boundary_indicators_requiring_stabilization = this->get_mesh_deformation_handler().get_boundary_indicators_requiring_stabilization(); - - // only apply on mesh deformation faces that require stabilization - if (cell->at_boundary() && cell->is_locally_owned()) - for (const unsigned int face_no : cell->face_indices()) - if (cell->face(face_no)->at_boundary()) - { - const types::boundary_id boundary_indicator - = cell->face(face_no)->boundary_id(); - - if (tmp_boundary_indicators_requiring_stabilization.find(boundary_indicator) - == tmp_boundary_indicators_requiring_stabilization.end()) - continue; - - scratch.face_finite_element_values.reinit(cell, face_no); - - scratch.face_material_model_inputs.reinit (scratch.face_finite_element_values, - cell, - this->introspection(), - this->get_solution()); - scratch.face_material_model_inputs.requested_properties = MaterialModel::MaterialProperties::density; - - this->get_material_model().evaluate(scratch.face_material_model_inputs, scratch.face_material_model_outputs); - - for (unsigned int q_point = 0; q_point < n_face_q_points; ++q_point) - { - for (unsigned int i = 0, i_stokes = 0; i_stokes < stokes_dofs_per_cell; /*increment at end of loop*/) - { - if (introspection.is_stokes_component(fe.system_to_component_index(i).first)) - { - scratch.phi_u[i_stokes] = scratch.face_finite_element_values[introspection.extractors.velocities].value(i, q_point); - ++i_stokes; - } - ++i; - } - - const Tensor<1,dim> - gravity = this->get_gravity_model().gravity_vector(scratch.face_finite_element_values.quadrature_point(q_point)); - const double g_norm = gravity.norm(); - - // construct the relevant vectors - const Tensor<1,dim> n_hat = scratch.face_finite_element_values.normal_vector(q_point); - const Tensor<1,dim> g_hat = (g_norm == 0.0 ? Tensor<1,dim>() : gravity/g_norm); - - const double pressure_perturbation = scratch.face_material_model_outputs.densities[q_point] * - this->get_timestep() * - free_surface_theta * - g_norm; - - // see Kaus et al 2010 for details of the stabilization term - for (unsigned int i=0; i< stokes_dofs_per_cell; ++i) - for (unsigned int j=0; j< stokes_dofs_per_cell; ++j) - { - // The fictive stabilization stress is (phi_u[i].g)*(phi_u[j].n) - const double stress_value = -pressure_perturbation* - (scratch.phi_u[i]*g_hat) * (scratch.phi_u[j]*n_hat) - *scratch.face_finite_element_values.JxW(q_point); - - data.local_matrix(i,j) += stress_value; - } - } - } - } - } - - - - namespace MeshDeformation - { - template - bool - Interface::needs_surface_stabilization () const - { - return false; - } - - - - template - Tensor<1,dim> - Interface:: - compute_initial_deformation_on_boundary(const types::boundary_id /*boundary_indicator*/, - const Point &/*position*/) const - { - return Tensor<1,dim>(); - } - - - - template - void - Interface:: - compute_velocity_constraints_on_boundary(const DoFHandler &/*mesh_deformation_dof_handler*/, - AffineConstraints &/*mesh_velocity_constraints*/, - const std::set &/*boundary_id*/) const - {} - - - - template - MeshDeformationHandler::MeshDeformationHandler (Simulator &simulator) - : sim(simulator), // reference to the simulator that owns the MeshDeformationHandler - mesh_deformation_fe (FE_Q(1),dim), // Q1 elements which describe the mesh geometry - mesh_deformation_dof_handler (sim.triangulation), - include_initial_topography(false) - { - // Now reset the mapping of the simulator to be something that captures mesh deformation in time. - sim.mapping = std::make_unique> (mesh_deformation_dof_handler, - mesh_displacements); - } - - - - template - MeshDeformationHandler::~MeshDeformationHandler () - { - // Free the Simulator's mapping object, otherwise - // when the MeshDeformationHandler gets destroyed, - // the mapping's reference to the mesh displacement - // vector will be invalid. - sim.mapping.reset(); - } - - - - namespace - { - std::tuple - >, - aspect::internal::Plugins::PluginList>> registered_plugins; - } - - - - template - void - MeshDeformationHandler::initialize () - { - // In case we prescribed initial topography, we should take this into - // account. However, it is not included in the mesh displacements, - // so we need to fetch it separately. - if (!Plugins::plugin_type_matches>(this->get_initial_topography_model())) - include_initial_topography = true; - - // If a surface needs to be stabilized, set up the assemblers. - if (!this->get_mesh_deformation_handler().get_boundary_indicators_requiring_stabilization().empty()) - { - this->get_signals().set_assemblers.connect( - [&](const SimulatorAccess &sim_access, - aspect::Assemblers::Manager &assemblers) - { - this->set_assemblers(sim_access, assemblers); - }); - } - } - - - - template - void MeshDeformationHandler::set_assemblers(const SimulatorAccess &, - aspect::Assemblers::Manager &assemblers) const - { - assemblers.stokes_system.push_back( - std::make_unique> (surface_theta)); - - // Note that we do not want face_material_model_data, because we do not - // connect to a face assembler. We instead connect to a normal assembler, - // and compute our own material_model_inputs in apply_stabilization - // (because we want to use the solution instead of the current_linearization_point - // to compute the material properties). - assemblers.stokes_system_assembler_on_boundary_face_properties.needed_update_flags |= (update_values | - update_gradients | - update_quadrature_points | - update_normal_vectors | - update_JxW_values); - } - - - - template - void - MeshDeformationHandler::register_mesh_deformation (const std::string &name, - const std::string &description, - void (*declare_parameters_function) (ParameterHandler &), - std::unique_ptr> (*factory_function) ()) - { - std::get(registered_plugins).register_plugin (name, - description, - declare_parameters_function, - factory_function); - } - - - - template - void - MeshDeformationHandler::update () - { - AssertThrow(sim.parameters.mesh_deformation_enabled, ExcInternalError()); - - for (const auto &boundary_and_deformation_objects : mesh_deformation_objects) - { - for (const auto &model : boundary_and_deformation_objects.second) - model->update(); - } - } - - - - template - void MeshDeformationHandler::declare_parameters(ParameterHandler &prm) - { - prm.enter_subsection ("Mesh deformation"); - { - const std::string pattern_of_names - = std::get(registered_plugins).get_pattern_of_names (); - - prm.declare_entry ("Additional tangential mesh velocity boundary indicators", "", - Patterns::List (Patterns::Anything()), - "A comma separated list of names denoting those boundaries " - "where there the mesh is allowed to move tangential to the " - "boundary. All tangential mesh movements along " - "those boundaries that have tangential material velocity " - "boundary conditions are allowed by default, this parameters " - "allows to generate mesh movements along other boundaries that are " - "open, or have prescribed material velocities or tractions." - "\n\n" - "The names of the boundaries listed here can either be " - "numbers (in which case they correspond to the numerical " - "boundary indicators assigned by the geometry object), or they " - "can correspond to any of the symbolic names the geometry object " - "may have provided for each part of the boundary. You may want " - "to compare this with the documentation of the geometry model you " - "use in your model."); - prm.declare_entry ("Mesh deformation boundary indicators", "", - Patterns::List (Patterns::Anything()), - "A comma separated list of names denoting those boundaries " - "where there the mesh is allowed to move according to the " - "specified mesh deformation objects. " - "\n\n" - "The names of the boundaries listed here can either be " - "numbers (in which case they correspond to the numerical " - "boundary indicators assigned by the geometry object), or they " - "can correspond to any of the symbolic names the geometry object " - "may have provided for each part of the boundary. You may want " - "to compare this with the documentation of the geometry model you " - "use in your model. " - "\n\n" - "The format is id1: object1 \\& object2, id2: object3 \\& object2, where " - "objects are one of " + std::get(registered_plugins).get_description_string()); - - prm.enter_subsection ("Free surface"); - { - prm.declare_entry("Free surface stabilization theta", "0.5", - Patterns::Double(0., 1.), - "Theta parameter described in \\cite{kaus:etal:2010}. " - "An unstabilized free surface can overshoot its " - "equilibrium position quite easily and generate " - "unphysical results. One solution is to use a " - "quasi-implicit correction term to the forces near the " - "free surface. This parameter describes how much " - "the free surface is stabilized with this term, " - "where zero is no stabilization, and one is fully " - "implicit."); - } - prm.leave_subsection (); - } - prm.leave_subsection (); - - std::get(registered_plugins).declare_parameters (prm); - } - - - - template - void MeshDeformationHandler::parse_parameters(ParameterHandler &prm) - { - prm.enter_subsection ("Mesh deformation"); - { - // Create the map of prescribed mesh movement boundary indicators - // Each boundary indicator can carry a number of mesh deformation plugin names. - const std::vector x_mesh_deformation_boundary_indicators - = Utilities::split_string_list(prm.get("Mesh deformation boundary indicators"),","); - - for (const auto &entry : x_mesh_deformation_boundary_indicators) - { - // each entry has the format (white space is optional): - // : - const std::vector split_parts = Utilities::split_string_list (entry, ':'); - AssertThrow (split_parts.size() == 2, - ExcMessage ("The format for mesh deformation indicators " - "requires that each entry has the form `" - " : ', but there does not " - "appear to be a colon in the entry <" - + entry - + ">.")); - - // Get the values, i.e. the mesh deformation plugin names - const std::vector object_names = Utilities::split_string_list(split_parts[1],"&"); - - // Try to translate the id into a boundary_id. - types::boundary_id boundary_id; - try - { - boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id(split_parts[0]); - } - catch (const std::string &error) - { - AssertThrow (false, ExcMessage ("While parsing the entry , there was an error. Specifically, " - "the conversion function complained as follows:\n\n" - + error)); - } - - // Store the boundary indicator. If the entry exists this does nothing. - prescribed_mesh_deformation_boundary_indicators.insert(boundary_id); - - for (const auto &object_name : object_names) - { - // Make sure there are no duplicated entries. If this boundary is not - // already in the map the first call to map[key] will create an empty entry. - AssertThrow(std::find(mesh_deformation_object_names[boundary_id].begin(), - mesh_deformation_object_names[boundary_id].end(), object_name) - == mesh_deformation_object_names[boundary_id].end(), - ExcMessage("The current mesh deformation object is listed twice for boundary indicator " - + dealii::Utilities::int_to_string(boundary_id))); - - mesh_deformation_object_names[boundary_id].push_back(object_name); - - if (object_name == "free surface") - free_surface_boundary_indicators.insert(boundary_id); - } - } - - // Create the list of tangential mesh movement boundary indicators - try - { - const std::vector x_additional_tangential_mesh_boundary_indicators - = this->get_geometry_model().translate_symbolic_boundary_names_to_ids(Utilities::split_string_list - (prm.get ("Additional tangential mesh velocity boundary indicators"))); - - tangential_mesh_deformation_boundary_indicators.insert(x_additional_tangential_mesh_boundary_indicators.begin(), - x_additional_tangential_mesh_boundary_indicators.end()); - } - catch (const std::string &error) - { - AssertThrow (false, ExcMessage ("While parsing the entry , there was an error. Specifically, " - "the conversion function complained as follows:\n\n" - + error)); - } - - // Boundaries with tangential Stokes velocity boundary conditions are implicitly - // treated as tangential mesh boundaries, but only if they do not have - // assigned mesh deformation objects. - for (const auto &boundary_id : this->get_boundary_velocity_manager().get_tangential_boundary_velocity_indicators()) - tangential_mesh_deformation_boundary_indicators.insert(boundary_id); - - // The tangential mesh boundaries can accidentally contain prescribed mesh - // boundaries if they were in the list of tangential Stokes boundaries. - // If so remove them. - for (const auto &boundary_id : prescribed_mesh_deformation_boundary_indicators) - tangential_mesh_deformation_boundary_indicators.erase(boundary_id); - - // All periodic boundaries are implicitly treated as tangential mesh deformation boundaries. - using periodic_boundary_pair = std::pair, unsigned int>; - for (const periodic_boundary_pair &p : this->get_geometry_model().get_periodic_boundary_pairs()) - { - tangential_mesh_deformation_boundary_indicators.insert(p.first.first); - tangential_mesh_deformation_boundary_indicators.insert(p.first.second); - } - - // Create the list of zero mesh movement (fixed) boundary indicators, these are - // all boundaries, which are not prescribed or tangential. - zero_mesh_deformation_boundary_indicators = this->get_geometry_model().get_used_boundary_indicators(); - - for (const auto &boundary_id : prescribed_mesh_deformation_boundary_indicators) - zero_mesh_deformation_boundary_indicators.erase(boundary_id); - - for (const auto &boundary_id : tangential_mesh_deformation_boundary_indicators) - zero_mesh_deformation_boundary_indicators.erase(boundary_id); - - prm.enter_subsection ("Free surface"); - { - surface_theta = prm.get_double("Free surface stabilization theta"); - } - prm.leave_subsection (); - - } - prm.leave_subsection (); - - // go through the list of object names, create objects and let them parse - // their own parameters - for (const auto &boundary_and_object_names : mesh_deformation_object_names) - { - for (const auto &object_name : boundary_and_object_names.second) - { - mesh_deformation_objects[boundary_and_object_names.first].push_back( - std::unique_ptr> (std::get(registered_plugins) - .create_plugin (object_name, - "Mesh deformation::Model names"))); - - if (SimulatorAccess *sim = dynamic_cast*>(mesh_deformation_objects[boundary_and_object_names.first].back().get())) - sim->initialize_simulator (this->get_simulator()); - - mesh_deformation_objects[boundary_and_object_names.first].back()->parse_parameters (prm); - mesh_deformation_objects[boundary_and_object_names.first].back()->initialize (); - } - } - - // Go through the objects, and get the indicators for boundaries that need to be stabilized. - for (const auto &boundary_and_deformation_objects : mesh_deformation_objects) - { - for (const auto &model : boundary_and_deformation_objects.second) - if (model->needs_surface_stabilization() == true) - boundary_indicators_requiring_stabilization.insert(boundary_and_deformation_objects.first); - } - } - - - - template - void MeshDeformationHandler::execute() - { - AssertThrow(sim.parameters.mesh_deformation_enabled, ExcInternalError()); - - TimerOutput::Scope timer (sim.computing_timer, "Mesh deformation"); - - old_mesh_displacements = mesh_displacements; - - // Make the constraints for the elliptic problem. - make_constraints(); - - // Assemble and solve the vector Laplace problem which determines - // the mesh displacements in the interior of the domain - if (this->is_stokes_matrix_free()) - compute_mesh_displacements_gmg(); - else - compute_mesh_displacements(); - - // Interpolate the mesh velocity into the same - // finite element space as used in the Stokes solve, which - // is needed for the ALE corrections. - interpolate_mesh_velocity(); - - // After changing the mesh we need to rebuild things - sim.rebuild_stokes_matrix = sim.rebuild_stokes_preconditioner = true; - } - - - - template - const Mapping & - MeshDeformationHandler::get_level_mapping(const unsigned int level) const - { - return *level_mappings[level].get(); - } - - - - template - void MeshDeformationHandler::make_constraints() - { - AssertThrow(sim.parameters.mesh_deformation_enabled, ExcInternalError()); - - // Now construct the mesh displacement constraints - mesh_velocity_constraints.clear(); -#if DEAL_II_VERSION_GTE(9,6,0) - mesh_velocity_constraints.reinit(mesh_deformation_dof_handler.locally_owned_dofs(), - mesh_locally_relevant); -#else - mesh_velocity_constraints.reinit(mesh_locally_relevant); -#endif - // mesh_velocity_constraints can use the same hanging node - // information that was used for mesh_vertex constraints. - mesh_velocity_constraints.merge(mesh_vertex_constraints); - - // Add the vanilla periodic boundary constraints - using periodic_boundary_pairs = std::set, unsigned int>>; - const periodic_boundary_pairs pbp = this->get_geometry_model().get_periodic_boundary_pairs(); - for (const auto &p : pbp) - DoFTools::make_periodicity_constraints(mesh_deformation_dof_handler, - p.first.first, - p.first.second, - p.second, - mesh_velocity_constraints); - - // Zero out the displacement for the zero-velocity boundaries - // if the boundary is not in the set of tangential mesh boundaries and not in the set of mesh deformation boundary indicators - for (const auto &boundary_id : zero_mesh_deformation_boundary_indicators) - { - VectorTools::interpolate_boundary_values (this->get_mapping(), - mesh_deformation_dof_handler, - boundary_id, - Functions::ZeroFunction(dim), - mesh_velocity_constraints); - } - - this->get_signals().pre_compute_no_normal_flux_constraints(sim.triangulation); - // Make the no flux boundary constraints - VectorTools::compute_no_normal_flux_constraints (mesh_deformation_dof_handler, - /* first_vector_component= */ - 0, - tangential_mesh_deformation_boundary_indicators, - mesh_velocity_constraints, - this->get_mapping()); - - this->get_signals().post_compute_no_normal_flux_constraints(sim.triangulation); - - // Ask all plugins to add their constraints. - // For the moment add constraints from all plugins into one matrix, then - // merge that matrix with the existing constraints (respecting the existing - // constraints as more important) - AffineConstraints plugin_constraints(mesh_vertex_constraints.get_local_lines()); - - for (const auto &boundary_id : mesh_deformation_objects) - { - std::set boundary_id_set; - boundary_id_set.insert(boundary_id.first); - - for (const auto &model : boundary_id.second) - { - AffineConstraints current_plugin_constraints(mesh_vertex_constraints.get_local_lines()); - - model->compute_velocity_constraints_on_boundary(mesh_deformation_dof_handler, - current_plugin_constraints, - boundary_id_set); - if ((this->is_stokes_matrix_free())) - { - mg_constrained_dofs.make_zero_boundary_constraints(mesh_deformation_dof_handler, - boundary_id_set); - } - - const IndexSet local_lines = current_plugin_constraints.get_local_lines(); - for (dealii::IndexSet::size_type local_line : local_lines) - { - if (current_plugin_constraints.is_constrained(local_line)) - { - if (plugin_constraints.is_constrained(local_line) == false) - { -#if DEAL_II_VERSION_GTE(9,6,0) - plugin_constraints.add_constraint(local_line, - {}, - current_plugin_constraints.get_inhomogeneity(local_line)); -#else - plugin_constraints.add_line(local_line); - plugin_constraints.set_inhomogeneity(local_line, - current_plugin_constraints.get_inhomogeneity(local_line)); -#endif - } - else - { - // Add the inhomogeneity of the current plugin to the existing constraints - const double inhomogeneity = plugin_constraints.get_inhomogeneity(local_line); - plugin_constraints.set_inhomogeneity(local_line, current_plugin_constraints.get_inhomogeneity(local_line) + inhomogeneity); - } - } - } - } - } - - mesh_velocity_constraints.merge(plugin_constraints,AffineConstraints::left_object_wins); - mesh_velocity_constraints.close(); - } - - - - template - void MeshDeformationHandler::make_initial_constraints() - { - AssertThrow(this->get_parameters().mesh_deformation_enabled, ExcInternalError()); - - // This might look incorrect at first glance, but it is okay to - // overwrite the velocity constraints with our displacements - // because this object is used for updating the displacement in - // compute_mesh_displacements(). - mesh_velocity_constraints.clear(); -#if DEAL_II_VERSION_GTE(9,6,0) - mesh_velocity_constraints.reinit(mesh_deformation_dof_handler.locally_owned_dofs(), - mesh_locally_relevant); -#else - mesh_velocity_constraints.reinit(mesh_locally_relevant); -#endif - // mesh_velocity_constraints can use the same hanging node - // information that was used for mesh_vertex constraints. - mesh_velocity_constraints.merge(mesh_vertex_constraints); - - // Add the vanilla periodic boundary constraints - std::set periodic_boundaries; - using periodic_boundary_pairs = std::set, unsigned int>>; - const periodic_boundary_pairs pbp = this->get_geometry_model().get_periodic_boundary_pairs(); - for (const auto &p : pbp) - { - periodic_boundaries.insert(p.first.first); - periodic_boundaries.insert(p.first.second); - - DoFTools::make_periodicity_constraints(mesh_deformation_dof_handler, - p.first.first, - p.first.second, - p.second, - mesh_velocity_constraints); - } - - // Zero out the displacement for the fixed boundaries - for (const types::boundary_id &boundary_id : zero_mesh_deformation_boundary_indicators) - { - VectorTools::interpolate_boundary_values (this->get_mapping(), - mesh_deformation_dof_handler, - boundary_id, - Functions::ZeroFunction(dim), - mesh_velocity_constraints); - } - - // Make tangential deformation constraints for tangential boundaries - this->get_signals().pre_compute_no_normal_flux_constraints(sim.triangulation); - VectorTools::compute_no_normal_flux_constraints (mesh_deformation_dof_handler, - /* first_vector_component= */ - 0, - tangential_mesh_deformation_boundary_indicators, - mesh_velocity_constraints, - this->get_mapping()); - this->get_signals().post_compute_no_normal_flux_constraints(sim.triangulation); - - // Ask all plugins to add their constraints. - // For the moment add constraints from all plugins into one matrix, then - // merge that matrix with the existing constraints (respecting the existing - // constraints as more important) - AffineConstraints plugin_constraints(mesh_vertex_constraints.get_local_lines()); - - std::set boundary_id_set; - - for (const auto &boundary_id_and_deformation_objects: mesh_deformation_objects) - { - for (const auto &deformation_object : boundary_id_and_deformation_objects.second) - { - AffineConstraints current_plugin_constraints(mesh_vertex_constraints.get_local_lines()); - - Utilities::VectorFunctionFromVelocityFunctionObject vel - (dim, - [&] (const Point &x) -> Tensor<1,dim> - { - return deformation_object->compute_initial_deformation_on_boundary(boundary_id_and_deformation_objects.first, x); - }); - - VectorTools::interpolate_boundary_values (this->get_mapping(), - mesh_deformation_dof_handler, - boundary_id_and_deformation_objects.first, - vel, - current_plugin_constraints); - - boundary_id_set.insert(boundary_id_and_deformation_objects.first); - - - const IndexSet local_lines = current_plugin_constraints.get_local_lines(); - for (dealii::IndexSet::size_type local_line : local_lines) - { - if (current_plugin_constraints.is_constrained(local_line)) - { - if (plugin_constraints.is_constrained(local_line) == false) - { -#if DEAL_II_VERSION_GTE(9,6,0) - plugin_constraints.add_constraint(local_line, - {}, - current_plugin_constraints.get_inhomogeneity(local_line)); -#else - plugin_constraints.add_line(local_line); - plugin_constraints.set_inhomogeneity(local_line, - current_plugin_constraints.get_inhomogeneity(local_line)); -#endif - } - else - { - // Add the current plugin constraints to the existing inhomogeneity - const double inhomogeneity = plugin_constraints.get_inhomogeneity(local_line); - plugin_constraints.set_inhomogeneity(local_line, current_plugin_constraints.get_inhomogeneity(local_line) + inhomogeneity); - } - } - } - } - } - if ((this->is_stokes_matrix_free())) - { - mg_constrained_dofs.make_zero_boundary_constraints(mesh_deformation_dof_handler, - boundary_id_set); - } - mesh_velocity_constraints.merge(plugin_constraints, - AffineConstraints::left_object_wins); - mesh_velocity_constraints.close(); - } - - - - template - void MeshDeformationHandler::compute_mesh_displacements() - { - // This functions updates the mesh displacement of the whole - // domain (stored in the vector mesh_displacements) based on - // information on the boundary. - // - // Each step, we get the velocity specified on the free surface - // boundary (stored in mesh_velocity_constraints) and solve for - // the velocity in the interior by solving a vector Laplace - // problem. This velocity is then used to update the - // displacement vector. - // - // This is different in timestep 0. Here, the information on the - // boundary is actually a displacement (given initial - // topography), which is used to set the initial - // displacement. The process in this function is otherwise - // identical. - - const QGauss quadrature(mesh_deformation_fe.degree + 1); - UpdateFlags update_flags = UpdateFlags(update_values | update_JxW_values | update_gradients); - FEValues fe_values (*sim.mapping, mesh_deformation_fe, quadrature, update_flags); - - const unsigned int dofs_per_cell = fe_values.dofs_per_cell, - dofs_per_face = sim.finite_element.dofs_per_face, - n_q_points = fe_values.n_quadrature_points; - - std::vector cell_dof_indices (dofs_per_cell); - std::vector face_dof_indices (dofs_per_face); - Vector cell_vector (dofs_per_cell); - FullMatrix cell_matrix (dofs_per_cell, dofs_per_cell); - - // We are just solving a Laplacian in each spatial direction, so - // the degrees of freedom for different dimensions do not couple. - Table<2,DoFTools::Coupling> coupling (dim, dim); - coupling.fill(DoFTools::none); - - for (unsigned int c=0; cis_locally_owned()) - { - cell->get_dof_indices (cell_dof_indices); - fe_values.reinit (cell); - - cell_vector = 0; - cell_matrix = 0; - for (unsigned int point=0; point> constant_modes; - DoFTools::extract_constant_modes (mesh_deformation_dof_handler, - ComponentMask(dim, true), - constant_modes); - // TODO: think about keeping object between time steps - LinearAlgebra::PreconditionAMG preconditioner_stiffness; - LinearAlgebra::PreconditionAMG::AdditionalData Amg_data; - Amg_data.constant_modes = constant_modes; - Amg_data.elliptic = true; - Amg_data.higher_order_elements = false; - Amg_data.smoother_sweeps = 2; - Amg_data.aggregation_threshold = 0.02; - preconditioner_stiffness.initialize(mesh_matrix); - - // we solve with higher accuracy in the initial timestep: - const double tolerance - = sim.parameters.linear_stokes_solver_tolerance - * ((this->simulator_is_past_initialization()) ? 1.0 : 1e-5); - - SolverControl solver_control(5*rhs.size(), tolerance * rhs.l2_norm()); - SolverCG cg(solver_control); - - cg.solve (mesh_matrix, solution, rhs, preconditioner_stiffness); - this->get_pcout() << " Solving mesh displacement system... " << solver_control.last_step() <<" iterations."<< std::endl; - - mesh_velocity_constraints.distribute (solution); - - // Update the mesh velocity vector - fs_mesh_velocity = solution; - - // Update the mesh displacement vector - if (this->simulator_is_past_initialization()) - { - // during the simulation, we add dt*solution - LinearAlgebra::Vector distributed_mesh_displacements(mesh_locally_owned, sim.mpi_communicator); - distributed_mesh_displacements = mesh_displacements; - distributed_mesh_displacements.add(this->get_timestep(), solution); - mesh_displacements = distributed_mesh_displacements; - } - else - { - // In the initial step we apply 100% of the initial displacement - mesh_displacements = solution; - } - - if (this->is_stokes_matrix_free()) - update_multilevel_deformation(); - } - - - - template - void MeshDeformationHandler::compute_mesh_displacements_gmg() - { - // Same as compute_mesh_displacements, but using matrix-free GMG - // instead of matrix-based AMG. - - // We use this gmg solver only when the gmg stokes solver is used - // for the following reasons (TODO): - // 1. this gmg solver does not support periodic boundary conditions - // 2. To use this solver even when gmg stokes solver is not used, we need to - // initialize the triangulation with Triangulation::limit_level_difference_at_vertices - // and parallel::distributed::Triangulation::construct_multigrid_hierarchy - // 3. Although this gmg solver is much faster than the amg solver, it's only tested for - // limited free surface cases. - - Assert(mesh_deformation_fe.degree == 1, ExcNotImplemented()); - // To be efficient, the operations performed in the matrix-free implementation require - // knowledge of loop lengths at compile time, which are given by the degree of the finite element. - const unsigned int mesh_deformation_fe_degree = 1; - - using SystemOperatorType = dealii::MatrixFreeOperators:: - LaplaceOperator; - - SystemOperatorType laplace_operator; - - MGLevelObject mg_matrices; - - typename MatrixFree::AdditionalData additional_data; - additional_data.tasks_parallel_scheme = - MatrixFree::AdditionalData::none; - const UpdateFlags update_flags(update_values | update_JxW_values | update_gradients); - additional_data.mapping_update_flags = update_flags; - std::shared_ptr> system_mf_storage - = std::make_shared>(); - system_mf_storage->reinit(*sim.mapping, - mesh_deformation_dof_handler, - mesh_velocity_constraints, - QGauss<1>(mesh_deformation_fe_degree + 1), - additional_data); - laplace_operator.initialize(system_mf_storage); - - // correct rhs: - // In a matrix-free method, since the LaplaceOperator class represents - // the matrix-vector product of a homogeneous operator (the left-hand - // side of the last formula). It does not matter whether the AffineConstraints - // object passed to the MatrixFree::reinit() contains inhomogeneous constraints or not, - // the MatrixFree::cell_loop() call will only resolve the homogeneous - // part of the constraints as long as it represents a linear operator. - - // What this function does is to move the inhomogeneous constraints to the - // right-hand side of the system by computing the residual of the system - // and subtracting it from the right-hand side: r = b - A*u0, - // where u0 is the initial guess and stored the degrees of freedom constrained by - // Inhomogeneous Dirichlet boundary conditions, and r is rhs. - // Then we have a new system Ax = r, and the solution is u = u0 + x. - // More details can be found in deal.II tutorial step-37 Section Possibilities for extensions. - dealii::LinearAlgebra::distributed::Vector u0, rhs, solution; - laplace_operator.initialize_dof_vector(u0); - laplace_operator.initialize_dof_vector(rhs); - laplace_operator.initialize_dof_vector(solution); - u0 = 0.; - mesh_velocity_constraints.distribute(u0); - u0.update_ghost_values(); - - rhs = 0.; - - FEEvaluation mesh_deformation(*laplace_operator.get_matrix_free()); - for (unsigned int cell = 0; - cell < laplace_operator.get_matrix_free()->n_cell_batches(); - ++cell) - { - mesh_deformation.reinit(cell); - mesh_deformation.read_dof_values_plain(u0); - mesh_deformation.evaluate(EvaluationFlags::gradients); - for (unsigned int q = 0; q < mesh_deformation.n_q_points; ++q) - { - mesh_deformation.submit_gradient(-1.0 * mesh_deformation.get_gradient(q), q); - } - mesh_deformation.integrate(EvaluationFlags::gradients); - mesh_deformation.distribute_local_to_global(rhs); - } - rhs.compress(VectorOperation::add); - - // clear the level constraints of the previous time step - mg_constrained_dofs.clear_user_constraints(); - - // setup GMG, following deal.II step-37: - const unsigned int n_levels = sim.triangulation.n_global_levels(); - - // Currently does not support periodic boundary constraints - { - using periodic_boundary_pairs = std::set, unsigned int>>; - const periodic_boundary_pairs pbp = this->get_geometry_model().get_periodic_boundary_pairs(); - AssertThrow(pbp.size() == 0, - ExcMessage("Periodic boundary constraints are not supported in computing mesh displacements using GMG.")); - } - - mg_constrained_dofs.make_zero_boundary_constraints(mesh_deformation_dof_handler, - zero_mesh_deformation_boundary_indicators); - - mg_matrices.clear_elements(); - mg_matrices.resize(0, n_levels-1); - - for (unsigned int level = 0; level < n_levels; ++level) - { - IndexSet relevant_dofs; - DoFTools::extract_locally_relevant_level_dofs(mesh_deformation_dof_handler, - level, - relevant_dofs); - AffineConstraints level_constraints; -#if DEAL_II_VERSION_GTE(9,6,0) - level_constraints.reinit(mesh_deformation_dof_handler.locally_owned_mg_dofs(level), - relevant_dofs); - for (const auto index : mg_constrained_dofs.get_boundary_indices(level)) - level_constraints.constrain_dof_to_zero(index); -#else - level_constraints.reinit(relevant_dofs); - level_constraints.add_lines(mg_constrained_dofs.get_boundary_indices(level)); -#endif - level_constraints.close(); - - const Mapping &mapping = get_level_mapping(level); - - std::set no_flux_boundary - = sim.boundary_velocity_manager.get_tangential_boundary_velocity_indicators(); - if (!no_flux_boundary.empty()) - { - AffineConstraints user_level_constraints; -#if DEAL_II_VERSION_GTE(9,6,0) - user_level_constraints.reinit(mesh_deformation_dof_handler.locally_owned_mg_dofs(level), - relevant_dofs); -#else - user_level_constraints.reinit(relevant_dofs); -#endif - const IndexSet &refinement_edge_indices = - mg_constrained_dofs.get_refinement_edge_indices(level); - dealii::VectorTools::compute_no_normal_flux_constraints_on_level( - mesh_deformation_dof_handler, - 0, - no_flux_boundary, - user_level_constraints, - mapping, - refinement_edge_indices, - level); - - user_level_constraints.close(); - mg_constrained_dofs.add_user_constraints(level, user_level_constraints); - - // let Dirichlet values win over no normal flux: - level_constraints.merge(user_level_constraints, AffineConstraints::left_object_wins); - level_constraints.close(); - } - - typename MatrixFree::AdditionalData additional_data; - additional_data.tasks_parallel_scheme = - MatrixFree::AdditionalData::none; - additional_data.mapping_update_flags = update_flags; - additional_data.mg_level = level; - std::shared_ptr> mg_mf_storage_level - = std::make_shared>(); - - mg_mf_storage_level->reinit(mapping, - mesh_deformation_dof_handler, - level_constraints, - QGauss<1>(mesh_deformation_fe_degree + 1), - additional_data); - mg_matrices[level].clear(); - mg_matrices[level].initialize(mg_mf_storage_level, - mg_constrained_dofs, - level); - } - - MGTransferMF mg_transfer(mg_constrained_dofs); - mg_transfer.build(mesh_deformation_dof_handler); - - using SmootherType = - PreconditionChebyshev>; - - mg::SmootherRelaxation> mg_smoother; - - MGLevelObject smoother_data; - smoother_data.resize(0, n_levels - 1); - - // Smoother: Chebyshev, degree 5. We use a relatively high degree here (5), - // since matrix-vector products are comparably cheap. We choose to smooth out - // a range of [1.2lambda_max/15,1.2lambda_max] in the smoother where lambda_max - // is an estimate of the largest eigenvalue (the factor 1.2 is applied inside - // PreconditionChebyshev). In order to compute that eigenvalue, - // the Chebyshev initialization performs a few steps of a CG algorithm without preconditioner. - // Since the highest eigenvalue is usually the easiest one to find - // and a rough estimate is enough, we choose 10 iterations. - for (unsigned int level = 0; level < n_levels; - ++level) - { - if (level > 0) - { - smoother_data[level].smoothing_range = 15.; - smoother_data[level].degree = 5; - smoother_data[level].eig_cg_n_iterations = 10; - } - else - { - // On level zero, we initialize the smoother differently - // because we want to use the Chebyshev iteration as a solver. - smoother_data[0].smoothing_range = 1e-3; - smoother_data[0].degree = numbers::invalid_unsigned_int; - smoother_data[0].eig_cg_n_iterations = mg_matrices[0].m(); - } - mg_matrices[level].compute_diagonal(); - smoother_data[level].preconditioner = - mg_matrices[level].get_matrix_diagonal_inverse(); - } - mg_smoother.initialize(mg_matrices, smoother_data); - MGCoarseGridApplySmoother> mg_coarse; - mg_coarse.initialize(mg_smoother); - - // set up the interface matrices - mg::Matrix> mg_matrix(mg_matrices); - MGLevelObject> mg_interface_matrices; - mg_interface_matrices.resize(0, n_levels - 1); - for (unsigned int level = 0; level < n_levels; - ++level) - mg_interface_matrices[level].initialize(mg_matrices[level]); - mg::Matrix> mg_interface(mg_interface_matrices); - Multigrid> mg(mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother); - mg.set_edge_matrices(mg_interface, mg_interface); - PreconditionMG, - MGTransferMF> - preconditioner(mesh_deformation_dof_handler, mg, mg_transfer); - - - // solve - const double tolerance - = sim.parameters.linear_stokes_solver_tolerance - * ((this->simulator_is_past_initialization()) ? 1.0 : 1e-5); - - SolverControl solver_control_mf(5 * rhs.size(), - tolerance * rhs.l2_norm()); - SolverCG> cg(solver_control_mf); - - mesh_velocity_constraints.set_zero(solution); - cg.solve(laplace_operator, solution, rhs, preconditioner); - this->get_pcout() << " Solving mesh displacement system... " << solver_control_mf.last_step() <<" iterations."<< std::endl; - - mesh_velocity_constraints.distribute(solution); - solution.update_ghost_values(); - - // copy solution: - LinearAlgebra::Vector solution_tmp; - solution_tmp.reinit(mesh_locally_owned, sim.mpi_communicator); - internal::ChangeVectorTypes::copy(solution_tmp, solution); - - // Update the mesh velocity vector - fs_mesh_velocity = solution_tmp; - - // Update the mesh displacement vector - if (this->simulator_is_past_initialization()) - { - // during the simulation, we add dt*solution - LinearAlgebra::Vector distributed_mesh_displacements(mesh_locally_owned, sim.mpi_communicator); - distributed_mesh_displacements = mesh_displacements; - distributed_mesh_displacements.add(this->get_timestep(), solution_tmp); - mesh_displacements = distributed_mesh_displacements; - } - else - { - // In the initial step we apply 100% of the initial displacement - mesh_displacements = solution_tmp; - } - - update_multilevel_deformation(); - } - - - - template - void MeshDeformationHandler::set_initial_topography() - { - LinearAlgebra::Vector distributed_initial_topography; - distributed_initial_topography.reinit(mesh_locally_owned, sim.mpi_communicator); - - if (!include_initial_topography) - distributed_initial_topography = 0.; - else - { - const std::vector> support_points - = mesh_deformation_fe.base_element(0).get_unit_support_points(); - - const Quadrature quad(support_points); - const UpdateFlags update_flags = UpdateFlags(update_quadrature_points); - FEValues fs_fe_values (*sim.mapping, mesh_deformation_fe, quad, update_flags); - - const unsigned int n_q_points = fs_fe_values.n_quadrature_points, - dofs_per_cell = fs_fe_values.dofs_per_cell; - - std::vector cell_dof_indices (dofs_per_cell); - - for (const auto &cell : mesh_deformation_dof_handler.active_cell_iterators()) - if (cell->is_locally_owned()) - { - cell->get_dof_indices (cell_dof_indices); - - fs_fe_values.reinit (cell); - for (unsigned int j=0; j surface_point; - std::array natural_coord = this->get_geometry_model().cartesian_to_natural_coordinates(fs_fe_values.quadrature_point(j)); - if (Plugins::plugin_type_matches> (this->get_geometry_model())) - { - for (unsigned int d=0; dget_initial_topography_model().value(surface_point); - - - // TODO adapt to radial topography - const unsigned int support_point_index - = mesh_deformation_fe.component_to_system_index(dim-1,/*dof index within component=*/ j); - distributed_initial_topography[cell_dof_indices[support_point_index]] = topo; - } - } - } - - distributed_initial_topography.compress(VectorOperation::insert); - initial_topography = distributed_initial_topography; - } - - - template - void MeshDeformationHandler::interpolate_mesh_velocity() - { - // Interpolate the mesh vertex velocity onto the Stokes velocity system for use in ALE corrections - LinearAlgebra::BlockVector distributed_mesh_velocity; - distributed_mesh_velocity.reinit(sim.introspection.index_sets.system_partitioning, sim.mpi_communicator); - - const std::vector> support_points - = sim.finite_element.base_element(sim.introspection.component_indices.velocities[0]).get_unit_support_points(); - - const Quadrature quad(support_points); - const UpdateFlags update_flags = UpdateFlags(update_values | update_JxW_values); - FEValues fs_fe_values (*sim.mapping, mesh_deformation_fe, quad, update_flags); - FEValues fe_values (*sim.mapping, sim.finite_element, quad, update_flags); - const unsigned int n_q_points = fe_values.n_quadrature_points, - dofs_per_cell = fe_values.dofs_per_cell; - - std::vector cell_dof_indices (dofs_per_cell); - FEValuesExtractors::Vector extract_vel(0); - std::vector> velocity_values(n_q_points); - - typename DoFHandler::active_cell_iterator - fscell = mesh_deformation_dof_handler.begin_active(); - - for (const auto &cell : sim.dof_handler.active_cell_iterators()) - { - if (cell->is_locally_owned()) - { - cell->get_dof_indices (cell_dof_indices); - - fe_values.reinit (cell); - fs_fe_values.reinit (fscell); - fs_fe_values[extract_vel].get_function_values(fs_mesh_velocity, velocity_values); - for (unsigned int j=0; j - void MeshDeformationHandler::setup_dofs() - { - AssertThrow(sim.parameters.mesh_deformation_enabled, ExcInternalError()); - - // these live in the same FE as the velocity variable: - mesh_velocity.reinit(sim.introspection.index_sets.system_partitioning, - sim.introspection.index_sets.system_relevant_partitioning, - sim.mpi_communicator); - - mesh_deformation_dof_handler.distribute_dofs(mesh_deformation_fe); - - // Renumber the DoFs hierarchical so that we get the - // same numbering if we resume the computation. This - // is because the numbering depends on the order the - // cells are created. - DoFRenumbering::hierarchical (mesh_deformation_dof_handler); - - if (this->is_stokes_matrix_free()) - { - mesh_deformation_dof_handler.distribute_mg_dofs(); - - mg_constrained_dofs.initialize(mesh_deformation_dof_handler); - - const unsigned int n_levels = this->get_triangulation().n_global_levels(); - - level_displacements.resize(0, n_levels-1); - // Important! Preallocate level vectors with all needed ghost - // entries. While interpolate_to_mg can create these vectors - // automatically, they will not contain all ghost values that we - // need to evaluate the mapping later. - for (unsigned int level = 0; level < n_levels; ++level) - { - IndexSet relevant_mg_dofs; - DoFTools::extract_locally_relevant_level_dofs(mesh_deformation_dof_handler, - level, - relevant_mg_dofs); - level_displacements[level].reinit(mesh_deformation_dof_handler.locally_owned_mg_dofs(level), - relevant_mg_dofs, - sim.mpi_communicator); - level_displacements[level].update_ghost_values(); - } - - // create the mappings on each level: - level_mappings.resize(0, n_levels-1); - level_mappings.apply([&](const unsigned int level, std::unique_ptr> &object) - { - object = std::make_unique>>( - /* degree = */ 1, - mesh_deformation_dof_handler, - level_displacements[level], - level); - }); - - mg_transfer.build(mesh_deformation_dof_handler); - - } - - { - std::locale s = this->get_pcout().get_stream().getloc(); - // Creating std::locale with an empty string previously caused problems - // on some platforms, so the functionality to catch the exception and ignore - // is kept here, even though explicitly setting a facet should always work. - try - { - // Imbue the stream with a locale that does the right thing. The - // locale is responsible for later deleting the object pointed - // to by the last argument (the "facet"), see - // https://en.cppreference.com/w/cpp/locale/locale/locale - this->get_pcout().get_stream().imbue(std::locale(std::locale(), - new aspect::Utilities::ThousandSep)); - } - catch (const std::runtime_error &e) - { - // If the locale doesn't work, just give up - } - - this->get_pcout() << "Number of mesh deformation degrees of freedom: " - << mesh_deformation_dof_handler.n_dofs() - << std::endl; - - this->get_pcout().get_stream().imbue(s); - } - - mesh_locally_owned = mesh_deformation_dof_handler.locally_owned_dofs(); - DoFTools::extract_locally_relevant_dofs (mesh_deformation_dof_handler, - mesh_locally_relevant); - - // This will initialize the mesh displacement and free surface - // mesh velocity vectors with zero-valued entries. - mesh_displacements.reinit(mesh_locally_owned, mesh_locally_relevant, sim.mpi_communicator); - old_mesh_displacements.reinit(mesh_locally_owned, mesh_locally_relevant, sim.mpi_communicator); - initial_topography.reinit(mesh_locally_owned, mesh_locally_relevant, sim.mpi_communicator); - fs_mesh_velocity.reinit(mesh_locally_owned, mesh_locally_relevant, sim.mpi_communicator); - - // if we are just starting, we need to set the initial topography. - if (this->simulator_is_past_initialization() == false || - this->get_timestep_number() == 0) - set_initial_topography(); - - // We would like to make sure that the mesh stays conforming upon - // redistribution, so we construct mesh_vertex_constraints, which - // keeps track of hanging node constraints. - // Note: this would be a more natural fit in make_constraints(), - // but we would like to be able to apply vertex constraints directly - // after setup_dofs(), as is done, for instance, during mesh - // refinement. - mesh_vertex_constraints.clear(); -#if DEAL_II_VERSION_GTE(9,6,0) - mesh_vertex_constraints.reinit(mesh_deformation_dof_handler.locally_owned_dofs(), - mesh_locally_relevant); -#else - mesh_vertex_constraints.reinit(mesh_locally_relevant); -#endif - DoFTools::make_hanging_node_constraints(mesh_deformation_dof_handler, mesh_vertex_constraints); - - // We can safely close this now - mesh_vertex_constraints.close(); - - // if we are just starting, we need to prescribe the initial deformation - if (this->simulator_is_past_initialization() == false || - this->get_timestep_number() == 0) - { - TimerOutput::Scope timer (sim.computing_timer, "Mesh deformation initialize"); - - make_initial_constraints(); - if (this->is_stokes_matrix_free()) - compute_mesh_displacements_gmg(); - else - compute_mesh_displacements(); - } - - if (this->is_stokes_matrix_free()) - update_multilevel_deformation(); - } - - - - template - void MeshDeformationHandler::update_multilevel_deformation () - { - Assert(this->is_stokes_matrix_free(), ExcInternalError()); - - // Convert the mesh_displacements to a d:Vector that we can use - // to transfer to the MG levels below. The conversion is done by - // going through a ReadWriteVector. - dealii::LinearAlgebra::distributed::Vector displacements(mesh_deformation_dof_handler.locally_owned_dofs(), - this->get_triangulation().get_communicator()); - dealii::LinearAlgebra::ReadWriteVector rwv; - rwv.reinit(mesh_displacements); - displacements.import(rwv, VectorOperation::insert); - - const unsigned int n_levels = sim.triangulation.n_global_levels(); - for (unsigned int level = 0; level < n_levels; ++level) - { - level_displacements[level].zero_out_ghost_values(); - } - - mg_transfer.interpolate_to_mg(mesh_deformation_dof_handler, - level_displacements, - displacements); - - for (unsigned int level = 0; level < n_levels; ++level) - { - level_displacements[level].update_ghost_values(); - } - - } - - - - template - const std::map> & - MeshDeformationHandler::get_active_mesh_deformation_names () const - { - return mesh_deformation_object_names; - } - - - - template - const std::map>>> & - MeshDeformationHandler::get_active_mesh_deformation_models () const - { - return mesh_deformation_objects; - } - - - - template - const std::set & - MeshDeformationHandler::get_active_mesh_deformation_boundary_indicators () const - { - return prescribed_mesh_deformation_boundary_indicators; - } - - - - template - const std::set & - MeshDeformationHandler::get_boundary_indicators_requiring_stabilization () const - { - return boundary_indicators_requiring_stabilization; - } - - - - template - const std::set & - MeshDeformationHandler::get_free_surface_boundary_indicators () const - { - return free_surface_boundary_indicators; - } - - - - template - double MeshDeformationHandler::get_free_surface_theta()const - { - return surface_theta; - } - - - - template - const LinearAlgebra::Vector & - MeshDeformationHandler::get_mesh_displacements () const - { - return mesh_displacements; - } - - - - template - const DoFHandler & - MeshDeformationHandler::get_mesh_deformation_dof_handler () const - { - return mesh_deformation_dof_handler; - } - - - - template - const LinearAlgebra::Vector & - MeshDeformationHandler::get_initial_topography () const - { - return initial_topography; - } - - - - template - std::string - get_valid_model_names_pattern () - { - return std::get(registered_plugins).get_pattern_of_names (); - } - - - - template - void - MeshDeformationHandler::write_plugin_graph (std::ostream &out) - { - std::get(registered_plugins).write_plugin_graph ("Mesh deformation interface", - out); - } - } -} - - -// explicit instantiation of the functions we implement in this file -namespace aspect -{ - namespace internal - { - namespace Plugins - { - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - } - } - - namespace MeshDeformation - { -#define INSTANTIATE(dim) \ - template class Interface; \ - template class MeshDeformationHandler; \ - \ - template \ - std::string \ - get_valid_model_names_pattern (); - - ASPECT_INSTANTIATE(INSTANTIATE) - -#undef INSTANTIATE - } -} diff --git a/source/mesh_refinement/artificial_viscosity.cc.bak b/source/mesh_refinement/artificial_viscosity.cc.bak deleted file mode 100644 index 55573204606..00000000000 --- a/source/mesh_refinement/artificial_viscosity.cc.bak +++ /dev/null @@ -1,132 +0,0 @@ -/* - Copyright (C) 2015 - 2020 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - ArtificialViscosity::execute(Vector &indicators) const - { - indicators = 0; - Vector this_indicator(indicators.size()); - if (temperature_scaling_factor > 0.0) - { - this->get_artificial_viscosity(indicators); - indicators *= temperature_scaling_factor; - } - - for (unsigned int c=0; cn_compositional_fields(); ++c) - { - this_indicator = 0; - this->get_artificial_viscosity_composition(this_indicator, c); - - // compute indicators += c*this_indicator: - indicators.add(composition_scaling_factors[c], this_indicator); - } - } - - template - void - ArtificialViscosity:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Artificial viscosity"); - { - prm.declare_entry("Temperature scaling factor", - "0.0", - Patterns::Double (0.), - "A scaling factor for the artificial viscosity " - " of the temperature equation. Use 0.0 to disable."); - prm.declare_entry("Compositional field scaling factors", - "", - Patterns::List (Patterns::Double (0.)), - "A list of scaling factors by which every individual compositional " - "field will be multiplied. These " - "factors are used to weigh the various indicators relative to " - "each other and to the temperature. " - "\n\n" - "If the list of scaling factors given in this parameter is empty, then this " - "indicates that they should all be chosen equal to 0. If the list " - "is not empty then it needs to have as many entries as there are " - "compositional fields."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - ArtificialViscosity::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Artificial viscosity"); - { - temperature_scaling_factor = prm.get_double("Temperature scaling factor"); - - composition_scaling_factors - = Utilities::string_to_double( - Utilities::split_string_list(prm.get("Compositional field scaling factors"))); - - AssertThrow (composition_scaling_factors.size() == this->n_compositional_fields() - || - composition_scaling_factors.size() == 0, - ExcMessage ("The number of scaling factors given here must either be " - "zero or equal to the number of chosen refinement criteria.")); - - if (composition_scaling_factors.size() == 0) - composition_scaling_factors.resize (this->n_compositional_fields(), 0.0); - - const double sum_composition_factors = - std::accumulate (composition_scaling_factors.begin(), - composition_scaling_factors.end(), 0.0); - - AssertThrow(sum_composition_factors + temperature_scaling_factor > 0.0, - ExcMessage("You need to have a positive scaling factor " - "for at least one variable.")); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(ArtificialViscosity, - "artificial viscosity", - "A mesh refinement criterion that computes " - "refinement indicators from the artificial viscosity " - "of the temperature or compositional fields " - "based on user specified weights.") - } -} diff --git a/source/mesh_refinement/boundary.cc.bak b/source/mesh_refinement/boundary.cc.bak deleted file mode 100644 index e51173946f2..00000000000 --- a/source/mesh_refinement/boundary.cc.bak +++ /dev/null @@ -1,122 +0,0 @@ -/* - Copyright (C) 2011 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - Boundary::execute(Vector &indicators) const - { - indicators = 0; - - // iterate over all of the cells and choose the ones at the indicated - // boundaries for refinement (assign the largest error to them) - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned() && cell->at_boundary()) - for (const unsigned int face_no : cell->face_indices()) - if (cell->face(face_no)->at_boundary()) - { - const types::boundary_id boundary_indicator - = cell->face(face_no)->boundary_id(); - if ( boundary_refinement_indicators.find(boundary_indicator) != - boundary_refinement_indicators.end() ) - { - indicators(cell->active_cell_index()) = 1.0; - break; // no need to loop over the rest of the faces - } - } - - } - - template - void - Boundary:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Boundary"); - { - prm.declare_entry ("Boundary refinement indicators", "", - Patterns::List (Patterns::Anything()), - "A comma separated list of names denoting those boundaries " - "where there should be mesh refinement." - "\n\n" - "The names of the boundaries listed here can either be " - "numbers (in which case they correspond to the numerical " - "boundary indicators assigned by the geometry object), or they " - "can correspond to any of the symbolic names the geometry object " - "may have provided for each part of the boundary. You may want " - "to compare this with the documentation of the geometry model you " - "use in your model."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - Boundary::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Boundary"); - { - const std::vector x_boundary_refinement_indicators - = this->get_geometry_model().translate_symbolic_boundary_names_to_ids(Utilities::split_string_list - (prm.get ("Boundary refinement indicators"))); - boundary_refinement_indicators - = std::set (x_boundary_refinement_indicators.begin(), - x_boundary_refinement_indicators.end()); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Boundary, - "boundary", - "A class that implements a mesh refinement criterion which " - "always flags all cells on specified boundaries for refinement. " - "This is useful to provide high accuracy for processes at or " - "close to the edge of the model domain." - "\n\n" - "To use this refinement criterion, you may want to combine " - "it with other refinement criteria, setting the 'Normalize " - "individual refinement criteria' flag and using the `max' " - "setting for 'Refinement criteria merge operation'.") - } -} diff --git a/source/mesh_refinement/compaction_length.cc.bak b/source/mesh_refinement/compaction_length.cc.bak deleted file mode 100644 index 13d0ac9f614..00000000000 --- a/source/mesh_refinement/compaction_length.cc.bak +++ /dev/null @@ -1,158 +0,0 @@ -/* - Copyright (C) 2015 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include -#include - -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - CompactionLength::tag_additional_cells () const - { - // tag_additional_cells is executed before the equations are solved - // for the very first time. If we do not have the finite element, we - // do not have any material properties and just do nothing in this plugin. - if (this->get_dof_handler().n_locally_owned_dofs() == 0) - return; - - // Use a quadrature in the support points of the porosity to compute the - // compaction length at: - const typename Simulator::AdvectionField porosity = Simulator::AdvectionField::composition( - this->introspection().compositional_index_for_name("porosity")); - - const unsigned int base_element_index = porosity.base_element(this->introspection()); - const Quadrature quadrature(this->get_fe().base_element(base_element_index).get_unit_support_points()); - - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature, - update_quadrature_points | update_values | update_gradients); - - MaterialModel::MaterialModelInputs in(quadrature.size(), this->n_compositional_fields()); - MaterialModel::MaterialModelOutputs out(quadrature.size(), this->n_compositional_fields()); - MeltHandler::create_material_model_outputs(out); - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - bool refine = false; - bool clear_coarsen = false; - - fe_values.reinit(cell); - in.reinit(fe_values, cell, this->introspection(), this->get_solution()); - this->get_material_model().evaluate(in, out); - - MaterialModel::MeltOutputs *melt_out = out.template get_additional_output>(); - AssertThrow(melt_out != nullptr, - ExcMessage("Need MeltOutputs from the material model for computing the melt properties.")); - - // for each composition dof, check if the compaction length exceeds the cell size - for (unsigned int i=0; icompaction_viscosities[i]) - * melt_out->permeabilities[i] / melt_out->fluid_viscosities[i]); - - // If the compaction length exceeds the cell diameter anywhere in the cell, cell is marked for refinement. - // Do not apply any refinement if the porosity is so small that melt can not migrate. - if (compaction_length < 2.0 * cells_per_compaction_length * cell->minimum_vertex_distance() - && this->get_melt_handler().is_melt_cell(cell)) - clear_coarsen = true; - - if (compaction_length < cells_per_compaction_length * cell->minimum_vertex_distance() - && this->get_melt_handler().is_melt_cell(cell)) - { - refine = true; - break; - } - } - - if (clear_coarsen) - cell->clear_coarsen_flag (); - if (refine) - cell->set_refine_flag (); - } - } - - template - void - CompactionLength:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Compaction length"); - { - prm.declare_entry("Mesh cells per compaction length", "1.0", - Patterns::Double (0.), - "The desired ratio between compaction length and size of the " - "mesh cells, or, in other words, how many cells the mesh should " - "(at least) have per compaction length. Every cell where this " - "ratio is smaller than the value specified by this parameter " - "(in places with fewer mesh cells per compaction length) is " - "marked for refinement."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - CompactionLength::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Compaction length"); - { - cells_per_compaction_length = prm.get_double ("Mesh cells per compaction length"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(CompactionLength, - "compaction length", - "A mesh refinement criterion for models with melt transport " - "that computes refinement indicators based on the compaction " - "length, defined as " - "$\\delta = \\sqrt{\\frac{(\\xi + 4 \\eta/3) k}{\\eta_f}}$. " - "$\\xi$ is the bulk viscosity, $\\eta$ is the shear viscosity, " - "$k$ is the permeability and $\\eta_f$ is the melt viscosity. " - "If the cell width or height exceeds a multiple (which is " - "specified as an input parameter) of this compaction length, " - "the cell is marked for refinement.") - } -} diff --git a/source/mesh_refinement/composition.cc.bak b/source/mesh_refinement/composition.cc.bak deleted file mode 100644 index 69a9c76d6a0..00000000000 --- a/source/mesh_refinement/composition.cc.bak +++ /dev/null @@ -1,152 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - Composition::execute(Vector &indicators) const - { - AssertThrow (this->n_compositional_fields() >= 1, - ExcMessage ("This refinement criterion cannot be used when no " - "compositional fields are active!")); - indicators = 0; - Vector this_indicator (indicators.size()); - - const Quadrature &quadrature = this->introspection().face_quadratures.compositional_fields; - - for (unsigned int c=0; cn_compositional_fields(); ++c) - { - this_indicator = 0; - KellyErrorEstimator::estimate (this->get_mapping(), - this->get_dof_handler(), - quadrature, - std::map*>(), - this->get_solution(), - this_indicator, - this->introspection().component_masks.compositional_fields[c], - nullptr, - 0, - this->get_triangulation().locally_owned_subdomain()); - // compute indicators += c*this_indicator: - indicators.add(composition_scaling_factors[c], this_indicator); - } - } - - template - void - Composition:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Composition"); - { - prm.declare_entry("Compositional field scaling factors", - "", - Patterns::List (Patterns::Double (0.)), - "A list of scaling factors by which every individual compositional " - "field will be multiplied. If only a single compositional " - "field exists, then this parameter has no particular meaning. " - "On the other hand, if multiple criteria are chosen, then these " - "factors are used to weigh the various indicators relative to " - "each other. " - "\n\n" - "If the list of scaling factors given in this parameter is empty, then this " - "indicates that they should all be chosen equal to one. If the list " - "is not empty then it needs to have as many entries as there are " - "compositional fields."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - Composition::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Composition"); - { - composition_scaling_factors - = Utilities::string_to_double( - Utilities::split_string_list(prm.get("Compositional field scaling factors"))); - - AssertThrow (composition_scaling_factors.size() == this->n_compositional_fields() - || - composition_scaling_factors.size() == 0, - ExcMessage ("The number of scaling factors given here must either be " - "zero or equal to the number of chosen refinement criteria.")); - - if (composition_scaling_factors.size() == 0) - composition_scaling_factors.resize (this->n_compositional_fields(), 1.0); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Composition, - "composition", - "A mesh refinement criterion that computes " - "refinement indicators from the compositional fields. " - "If there is more than one compositional field, then " - "it simply takes the sum of the indicators computed " - "from each of the compositional field." - "\n\n" - "The way these indicators are computed is by " - "evaluating the `Kelly error indicator' on each " - "compositional field. This error indicator takes the " - "finite element approximation of the compositional " - "field and uses it to compute an approximation " - "of the second derivatives of the composition for " - "each cell. This approximation is then multiplied " - "by an appropriate power of the cell's diameter " - "to yield an indicator for how large the error " - "is likely going to be on this cell. This " - "construction rests on the observation that for " - "many partial differential equations, the error " - "on each cell is proportional to some power of " - "the cell's diameter times the second derivatives " - "of the solution on that cell." - "\n\n" - "For complex equations such as those we solve " - "here, this observation may not be strictly " - "true in the mathematical sense, but it often " - "yields meshes that are surprisingly good.") - } -} diff --git a/source/mesh_refinement/composition_approximate_gradient.cc.bak b/source/mesh_refinement/composition_approximate_gradient.cc.bak deleted file mode 100644 index 0397704160a..00000000000 --- a/source/mesh_refinement/composition_approximate_gradient.cc.bak +++ /dev/null @@ -1,153 +0,0 @@ -/* - Copyright (C) 2015 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - CompositionApproximateGradient::execute(Vector &indicators) const - { - AssertThrow (this->n_compositional_fields() >= 1, - ExcMessage ("This refinement criterion can not be used when no " - "compositional fields are active!")); - indicators = 0; - // create a vector with the requisite ghost elements - // and use it for estimating the gradients of compositional field - LinearAlgebra::BlockVector vec(this->introspection().index_sets.system_partitioning, - this->introspection().index_sets.system_relevant_partitioning, - this->get_mpi_communicator()); - Vector indicators_tmp(this->get_triangulation().n_active_cells()); - for (unsigned int c=0; cn_compositional_fields(); ++c) - { - const unsigned int block_idx = this->introspection().block_indices.compositional_fields[c]; - vec.block(block_idx) = this->get_solution().block(block_idx); - vec.compress(VectorOperation::insert); - indicators_tmp = 0; - DerivativeApproximation::approximate_gradient(this->get_mapping(), - this->get_dof_handler(), - vec, - indicators_tmp, - this->introspection().component_indices.compositional_fields[c]); - - indicators_tmp *= composition_scaling_factors[c]; - - // Scale approximated gradient in each cell with the correct power of h. Otherwise, - // error indicators do not reduce when refined if there is a density - // jump. We need at least order 1 for the error not to grow when - // refining, so anything >1 should work. (note that the gradient - // itself scales like 1/h, so multiplying it with any factor h^s, s>1 - // will yield convergence of the error indicators to zero as h->0) - const double power = 1.0 + dim / 2.0; - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - indicators_tmp(cell->active_cell_index()) *= std::pow(cell->diameter(), power); - - indicators += indicators_tmp; - } - } - - - template - void - CompositionApproximateGradient:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Composition approximate gradient"); - { - prm.declare_entry("Compositional field scaling factors", - "", - Patterns::List (Patterns::Double (0.)), - "A list of scaling factors by which every individual compositional " - "field gradient will be multiplied. If only a single compositional " - "field exists, then this parameter has no particular meaning. " - "On the other hand, if multiple criteria are chosen, then these " - "factors are used to weigh the various indicators relative to " - "each other. " - "\n\n" - "If the list of scaling factors given in this parameter is empty, then this " - "indicates that they should all be chosen equal to one. If the list " - "is not empty then it needs to have as many entries as there are " - "compositional fields."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - CompositionApproximateGradient::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Composition approximate gradient"); - { - composition_scaling_factors - = Utilities::string_to_double( - Utilities::split_string_list(prm.get("Compositional field scaling factors"))); - - AssertThrow (composition_scaling_factors.size() == this->n_compositional_fields() - || - composition_scaling_factors.size() == 0, - ExcMessage ("The number of scaling factors given here must either be " - "zero or equal to the number of chosen refinement criteria.")); - - if (composition_scaling_factors.size() == 0) - composition_scaling_factors.resize (this->n_compositional_fields(), 1.0); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(CompositionApproximateGradient, - "composition approximate gradient", - "A mesh refinement criterion that computes refinement " - "indicators from the gradients of compositional fields. " - "If there is more than one compositional field, then " - "it simply takes the sum of the indicators times " - "a user-specified weight for each field." - "\n\n" - "In contrast to the `composition gradient' refinement " - "criterion, the current criterion does not " - "compute the gradient at quadrature points on each cell, " - "but by a finite difference approximation between the " - "centers of cells. Consequently, it also works if " - "the compositional fields are computed using discontinuous " - "finite elements.") - } -} diff --git a/source/mesh_refinement/composition_gradient.cc.bak b/source/mesh_refinement/composition_gradient.cc.bak deleted file mode 100644 index 47eace30bb8..00000000000 --- a/source/mesh_refinement/composition_gradient.cc.bak +++ /dev/null @@ -1,185 +0,0 @@ -/* - Copyright (C) 2015 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - CompositionGradient::execute(Vector &indicators) const - { - AssertThrow (this->n_compositional_fields() >= 1, - ExcMessage ("This refinement criterion can not be used when no " - "compositional fields are active!")); - - indicators = 0; - const double power = 1.0 + dim/2.0; - - for (const unsigned int base_element_index : this->introspection().get_composition_base_element_indices()) - { - const Quadrature quadrature (this->get_fe().base_element(base_element_index).get_unit_support_points()); - const unsigned int dofs_per_cell = quadrature.size(); - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature, - update_quadrature_points | update_gradients); - - // the values of the compositional fields are stored as block vectors for each field - // we have to extract them in this structure - std::vector> composition_gradients (quadrature.size()); - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - const unsigned int idx = cell->active_cell_index(); - fe_values.reinit(cell); - - for (const unsigned int c : this->introspection().get_compositional_field_indices_with_base_element(base_element_index)) - { - const typename Simulator::AdvectionField composition = Simulator::AdvectionField::composition(c); - fe_values[composition.scalar_extractor(this->introspection())].get_function_gradients (this->get_solution(), - composition_gradients); - - // Some up the indicators for this composition on this cell. Note that quadrature points and dofs - // are enumerated in the same order. - double this_indicator = 0.0; - for (unsigned int j=0; j1 should work. (note that the gradient - // itself scales like 1/h, so multiplying it with any factor h^s, s>1 - // will yield convergence of the error indicators to zero as h->0) - this_indicator *= std::pow(cell->diameter(), power); - - indicators[idx] += composition_scaling_factors[c] * this_indicator; - } - } - } - } - - template - void - CompositionGradient:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Composition gradient"); - { - prm.declare_entry("Compositional field scaling factors", - "", - Patterns::List (Patterns::Double (0.)), - "A list of scaling factors by which every individual compositional " - "field gradient will be multiplied. If only a single compositional " - "field exists, then this parameter has no particular meaning. " - "On the other hand, if multiple criteria are chosen, then these " - "factors are used to weigh the various indicators relative to " - "each other. " - "\n\n" - "If the list of scaling factors given in this parameter is empty, then this " - "indicates that they should all be chosen equal to one. If the list " - "is not empty then it needs to have as many entries as there are " - "compositional fields."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - CompositionGradient::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Composition gradient"); - { - composition_scaling_factors - = Utilities::string_to_double( - Utilities::split_string_list(prm.get("Compositional field scaling factors"))); - - AssertThrow (composition_scaling_factors.size() == this->n_compositional_fields() - || - composition_scaling_factors.size() == 0, - ExcMessage ("The number of scaling factors given here must either be " - "zero or equal to the number of chosen refinement criteria.")); - - if (composition_scaling_factors.size() == 0) - composition_scaling_factors.resize (this->n_compositional_fields(), 1.0); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(CompositionGradient, - "composition gradient", - "A mesh refinement criterion that computes refinement " - "indicators from the gradients of compositional fields. " - "If there is more than one compositional field, then " - "it simply takes the sum of the indicators times " - "a user-specified weight for each field." - "\n\n" - "This refinement criterion computes the gradient of " - "the compositional field at quadrature points on each " - "cell, and then averages them in some way to obtain a " - "refinement indicator for each cell. This will give a " - "reasonable approximation of the true gradient of the " - "compositional field if you are using a continuous " - "finite element." - "\n\n" - "On the other hand, for discontinuous " - "finite elements (see the `Use discontinuous composition " - "discretization' parameter in the `Discretization' " - "section), the gradient at quadrature points does not " - "include the contribution of jumps in the compositional " - "field between cells, and consequently will not be an " - "accurate approximation of the true gradient. As an " - "extreme example, consider the case of using piecewise " - "constant finite elements for compositional fields; in " - "that case, the gradient of the solution at quadrature " - "points inside each cell will always be exactly zero, " - "even if the finite element solution is different " - "from each cell to the next. Consequently, the " - "current refinement criterion will likely not be " - "useful in this situation. That said, " - "the `composition approximate " - "gradient' refinement criterion exists for exactly " - "this purpose.") - } -} diff --git a/source/mesh_refinement/composition_threshold.cc.bak b/source/mesh_refinement/composition_threshold.cc.bak deleted file mode 100644 index d2ad3cbf622..00000000000 --- a/source/mesh_refinement/composition_threshold.cc.bak +++ /dev/null @@ -1,137 +0,0 @@ -/* - Copyright (C) 2015 - 2019 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - CompositionThreshold::tag_additional_cells () const - { - AssertThrow (this->n_compositional_fields() >= 1, - ExcMessage ("This refinement criterion can not be used when no " - "compositional fields are active!")); - - // tag_additional_cells is executed before the equations are solved - // for the very first time. If we do not have the finite element, we - // do not have the compositional fields and just do nothing in this plugin. - if (this->get_dof_handler().n_locally_owned_dofs() == 0) - return; - - const unsigned int dofs_per_cell = this->get_fe().dofs_per_cell; - std::vector local_dof_indices(dofs_per_cell); - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - cell->get_dof_indices (local_dof_indices); - bool refine = false; - - for (unsigned int c=0; cn_compositional_fields(); ++c) - { - const unsigned int component_idx = this->introspection().component_indices.compositional_fields[c]; - for (unsigned int i=0; iget_fe().system_to_component_index(i).first == component_idx) - { - const double composition_value = this->get_solution()[local_dof_indices[i]]; - // if the composition exceeds the threshold, cell is marked for refinement - if (composition_value > composition_thresholds[c]) - { - refine = true; - break; - } - } - } - if (refine) - break; - } - - if (refine) - { - cell->clear_coarsen_flag (); - cell->set_refine_flag (); - } - } - } - - template - void - CompositionThreshold:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Composition threshold"); - { - prm.declare_entry("Compositional field thresholds", - "", - Patterns::List (Patterns::Double()), - "A list of thresholds that every individual compositional " - "field will be evaluated against."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - CompositionThreshold::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Composition threshold"); - { - composition_thresholds - = Utilities::string_to_double( - Utilities::split_string_list(prm.get("Compositional field thresholds"))); - - AssertThrow (composition_thresholds.size() == this->n_compositional_fields(), - ExcMessage ("The number of thresholds given here must be " - "equal to the number of chosen refinement criteria.")); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(CompositionThreshold, - "composition threshold", - "A mesh refinement criterion that computes refinement " - "indicators from the compositional fields. If any field " - "exceeds the threshold given in the input file, the cell " - "is marked for refinement.") - } -} diff --git a/source/mesh_refinement/density.cc.bak b/source/mesh_refinement/density.cc.bak deleted file mode 100644 index 9f97b335d85..00000000000 --- a/source/mesh_refinement/density.cc.bak +++ /dev/null @@ -1,143 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include -#include -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - Density::execute(Vector &indicators) const - { - indicators = 0; - -//TODO: if the density doesn't actually depend on the solution - // then we can get away with simply interpolating it spatially - - - // create a vector in which we set the temperature block to - // be a finite element interpolation of the density. - // we do so by setting up a quadrature formula with the - // temperature unit support points, then looping over these - // points, compute the output quantity at them, and writing - // the result into the output vector in the same order - // (because quadrature points and temperature dofs are, - // by design of the quadrature formula, numbered in the - // same way) - LinearAlgebra::BlockVector vec_distributed (this->introspection().index_sets.system_partitioning, - this->get_mpi_communicator()); - - const Quadrature quadrature(this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_support_points()); - std::vector local_dof_indices (this->get_fe().dofs_per_cell); - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature, - update_quadrature_points | update_values | update_gradients); - - MaterialModel::MaterialModelInputs in(quadrature.size(), - this->n_compositional_fields()); - MaterialModel::MaterialModelOutputs out(quadrature.size(), - this->n_compositional_fields()); - in.requested_properties = MaterialModel::MaterialProperties::density; - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit(cell); - // Set use_strain_rates to false since we don't need viscosity - in.reinit(fe_values, cell, this->introspection(), this->get_solution()); - - this->get_material_model().evaluate(in, out); - - cell->get_dof_indices (local_dof_indices); - - // for each temperature dof, write into the output - // vector the density. note that quadrature points and - // dofs are enumerated in the same order - for (unsigned int i=0; iget_fe().base_element(this->introspection().base_elements.temperature).dofs_per_cell; ++i) - { - const unsigned int system_local_dof - = this->get_fe().component_to_system_index(this->introspection().component_indices.temperature, - /*dof index within component=*/i); - - vec_distributed(local_dof_indices[system_local_dof]) - = out.densities[i]; - } - } - - vec_distributed.compress(VectorOperation::insert); - - // now create a vector with the requisite ghost elements - // and use it for estimating the gradients - LinearAlgebra::BlockVector vec (this->introspection().index_sets.system_partitioning, - this->introspection().index_sets.system_relevant_partitioning, - this->get_mpi_communicator()); - vec = vec_distributed; - - DerivativeApproximation::approximate_gradient (this->get_mapping(), - this->get_dof_handler(), - vec, - indicators, - this->introspection().component_indices.temperature); - - // Scale gradient in each cell with the correct power of h. Otherwise, - // error indicators do not reduce when refined if there is a density - // jump. We need at least order 1 for the error not to grow when - // refining, so anything >1 should work. (note that the gradient - // itself scales like 1/h, so multiplying it with any factor h^s, s>1 - // will yield convergence of the error indicators to zero as h->0) - const double power = 1.0 + dim/2.0; - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - indicators(cell->active_cell_index()) *= std::pow(cell->diameter(), power); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Density, - "density", - "A mesh refinement criterion that computes " - "refinement indicators from a field that describes " - "the spatial variability of the density, $\\rho$. " - "Because this quantity may not be a continuous function ($\\rho$ " - "and $C_p$ may be discontinuous functions along discontinuities in the " - "medium, for example due to phase changes), we approximate the " - "gradient of this quantity to refine the mesh. The error indicator " - "defined here takes the magnitude of the approximate gradient " - "and scales it by $h_K^{1+d/2}$ where $h_K$ is the diameter of each cell " - "and $d$ is the dimension. " - "This scaling ensures that the error indicators converge to zero as " - "$h_K\\rightarrow 0$ even if the energy density is discontinuous, since " - "the gradient of a discontinuous function grows like $1/h_K$.") - } -} diff --git a/source/mesh_refinement/interface.cc.bak b/source/mesh_refinement/interface.cc.bak deleted file mode 100644 index 8e16815ddd4..00000000000 --- a/source/mesh_refinement/interface.cc.bak +++ /dev/null @@ -1,519 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include - - -namespace aspect -{ - namespace MeshRefinement - { -// ------------------------------ Interface ----------------------------- - - template - void - Interface::execute (Vector &error_indicators) const - { - for (float &error_indicator : error_indicators) - error_indicator = 0; - } - - - template - void - Interface::tag_additional_cells () const - {} - - - -// ------------------------------ Manager ----------------------------- - - template - Manager::~Manager() - = default; - - - - template - void - Manager::update () - { - Assert (this->plugin_objects.size() > 0, ExcInternalError()); - - // call the update() functions of all refinement plugins. - for (const auto &p : this->plugin_objects) - { - try - { - p->update (); - } - - // plugins that throw exceptions usually do not result in - // anything good because they result in an unwinding of the stack - // and, if only one processor triggers an exception, the - // destruction of objects often causes a deadlock. thus, if - // an exception is generated, catch it, print an error message, - // and abort the program - catch (std::exception &exc) - { - std::cerr << std::endl << std::endl - << "----------------------------------------------------" - << std::endl; - std::cerr << "Exception on MPI process <" - << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) - << "> while running mesh refinement plugin <" - << typeid(*p).name() - << ">: " << std::endl - << exc.what() << std::endl - << "Aborting!" << std::endl - << "----------------------------------------------------" - << std::endl; - - // terminate the program! - MPI_Abort (MPI_COMM_WORLD, 1); - } - catch (...) - { - std::cerr << std::endl << std::endl - << "----------------------------------------------------" - << std::endl; - std::cerr << "Exception on MPI process <" - << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) - << "> while running mesh refinement plugin <" - << typeid(*p).name() - << ">: " << std::endl; - std::cerr << "Unknown exception!" << std::endl - << "Aborting!" << std::endl - << "----------------------------------------------------" - << std::endl; - - // terminate the program! - MPI_Abort (MPI_COMM_WORLD, 1); - } - } - } - - - - template - void - Manager::execute (Vector &error_indicators) const - { - Assert (this->plugin_objects.size() > 0, ExcInternalError()); - - // call the execute() functions of all plugins we have - // here in turns. then normalize the output vector and - // verify that its values are non-negative numbers - std::vector> all_error_indicators (this->plugin_objects.size(), - Vector(error_indicators.size())); - unsigned int index = 0; - for (typename std::list>>::const_iterator - p = this->plugin_objects.begin(); - p != this->plugin_objects.end(); ++p, ++index) - { - try - { - (*p)->execute (all_error_indicators[index]); - - for (unsigned int i=0; i= 0, - ExcMessage ("Error indicators must be non-negative numbers!")); - - // see if we want to normalize the criteria - if (normalize_criteria == true) - { - const double global_max = Utilities::MPI::max (all_error_indicators[index].linfty_norm(), - this->get_mpi_communicator()); - if (global_max != 0) - all_error_indicators[index] /= global_max; - } - - // then also scale them - all_error_indicators[index] *= scaling_factors[index]; - } - // plugins that throw exceptions usually do not result in - // anything good because they result in an unwinding of the stack - // and, if only one processor triggers an exception, the - // destruction of objects often causes a deadlock. thus, if - // an exception is generated, catch it, print an error message, - // and abort the program - catch (std::exception &exc) - { - std::cerr << std::endl << std::endl - << "----------------------------------------------------" - << std::endl; - std::cerr << "Exception on MPI process <" - << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) - << "> while running mesh refinement plugin <" - << typeid(**p).name() - << ">: " << std::endl - << exc.what() << std::endl - << "Aborting!" << std::endl - << "----------------------------------------------------" - << std::endl; - - // terminate the program! - MPI_Abort (MPI_COMM_WORLD, 1); - } - catch (...) - { - std::cerr << std::endl << std::endl - << "----------------------------------------------------" - << std::endl; - std::cerr << "Exception on MPI process <" - << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) - << "> while running mesh refinement plugin <" - << typeid(**p).name() - << ">: " << std::endl; - std::cerr << "Unknown exception!" << std::endl - << "Aborting!" << std::endl - << "----------------------------------------------------" - << std::endl; - - // terminate the program! - MPI_Abort (MPI_COMM_WORLD, 1); - } - } - - // now merge the results - switch (merge_operation) - { - case plus: - { - for (unsigned int i=0; iplugin_objects.size(); ++i) - error_indicators += all_error_indicators[i]; - break; - } - - case max: - { - error_indicators = all_error_indicators[0]; - for (unsigned int i=1; iplugin_objects.size(); ++i) - { - Assert (error_indicators.size() == all_error_indicators[i].size(), - ExcInternalError()); - for (unsigned int j=0; j - void - Manager::tag_additional_cells () const - { - Assert (this->plugin_objects.size() > 0, ExcInternalError()); - - // call the tag_additional_cells() functions of all - // plugins we have here in turns. - for (const auto &p : this->plugin_objects) - { - try - { - p->tag_additional_cells (); - } - - // plugins that throw exceptions usually do not result in - // anything good because they result in an unwinding of the stack - // and, if only one processor triggers an exception, the - // destruction of objects often causes a deadlock. thus, if - // an exception is generated, catch it, print an error message, - // and abort the program - catch (std::exception &exc) - { - std::cerr << std::endl << std::endl - << "----------------------------------------------------" - << std::endl; - std::cerr << "Exception on MPI process <" - << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) - << "> while running mesh refinement plugin <" - << typeid(*p).name() - << ">: " << std::endl - << exc.what() << std::endl - << "Aborting!" << std::endl - << "----------------------------------------------------" - << std::endl; - - // terminate the program! - MPI_Abort (MPI_COMM_WORLD, 1); - } - catch (...) - { - std::cerr << std::endl << std::endl - << "----------------------------------------------------" - << std::endl; - std::cerr << "Exception on MPI process <" - << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) - << "> while running mesh refinement plugin <" - << typeid(*p).name() - << ">: " << std::endl; - std::cerr << "Unknown exception!" << std::endl - << "Aborting!" << std::endl - << "----------------------------------------------------" - << std::endl; - - // terminate the program! - MPI_Abort (MPI_COMM_WORLD, 1); - } - } - } - - - - - -// -------------------------------- Deal with registering plugins and automating -// -------------------------------- their setup and selection at run time - - namespace - { - std::tuple - >, - aspect::internal::Plugins::PluginList>> registered_plugins; - } - - - - template - void - Manager::declare_parameters (ParameterHandler &prm) - { - // first declare the postprocessors we know about to - // choose from - prm.enter_subsection("Mesh refinement"); - { - // construct a string for Patterns::MultipleSelection that - // contains the names of all registered plugins - const std::string pattern_of_names - = std::get(registered_plugins).get_pattern_of_names (); - prm.declare_entry("Strategy", - "thermal energy density", - Patterns::MultipleSelection(pattern_of_names), - "A comma separated list of mesh refinement criteria that " - "will be run whenever mesh refinement is required. The " - "results of each of these criteria, i.e., the refinement " - "indicators they produce for all the cells of the mesh " - "will then be normalized to a range between zero and one " - "and the results of different criteria will then be " - "merged through the operation selected in this section.\n\n" - "The following criteria are available:\n\n" - + - std::get(registered_plugins).get_description_string()); - - prm.declare_entry("Normalize individual refinement criteria", - "true", - Patterns::Bool(), - "If multiple refinement criteria are specified in the " - "``Strategy'' parameter, then they need to be combined " - "somehow to form the final refinement indicators. This " - "is done using the method described by the ``Refinement " - "criteria merge operation'' parameter which can either " - "operate on the raw refinement indicators returned by " - "each strategy (i.e., dimensional quantities) or using " - "normalized values where the indicators of each strategy " - "are first normalized to the interval $[0,1]$ (which also " - "makes them non-dimensional). This parameter determines " - "whether this normalization will happen."); - prm.declare_entry("Refinement criteria scaling factors", - "", - Patterns::List (Patterns::Double (0.)), - "A list of scaling factors by which every individual refinement " - "criterion will be multiplied by. If only a single refinement " - "criterion is selected (using the ``Strategy'' parameter, then " - "this parameter has no particular meaning. On the other hand, if " - "multiple criteria are chosen, then these factors are used to " - "weigh the various indicators relative to each other. " - "\n\n" - "If ``Normalize individual refinement criteria'' is set to true, " - "then the criteria will first be normalized to the interval $[0,1]$ " - "and then multiplied by the factors specified here. You will likely " - "want to choose the factors to be not too far from 1 in that case, say " - "between 1 and 10, to avoid essentially disabling those criteria " - "with small weights. On the other hand, if the criteria are not " - "normalized to $[0,1]$ using the parameter mentioned above, then " - "the factors you specify here need to take into account the relative " - "numerical size of refinement indicators (which in that case carry " - "physical units)." - "\n\n" - "You can experimentally play with these scaling factors by choosing " - "to output the refinement indicators into the graphical output of " - "a run." - "\n\n" - "If the list of indicators given in this parameter is empty, then this " - "indicates that they should all be chosen equal to one. If the list " - "is not empty then it needs to have as many entries as there are " - "indicators chosen in the ``Strategy'' parameter."); - prm.declare_entry("Refinement criteria merge operation", - "max", - Patterns::Selection("plus|max"), - "If multiple mesh refinement criteria are computed for each cell " - "(by passing a list of more than element to the \\texttt{Strategy} " - "parameter in this section of the input file) " - "then one will have to decide which criteria should win when deciding " - "which cells to refine. The operation that determines how to combine these competing " - "criteria is the one that is selected here. The options are:\n\n" - "\\begin{itemize}\n" - "\\item \\texttt{plus}: Add the various error indicators together and " - "refine those cells on which the sum of indicators is largest.\n" - "\\item \\texttt{max}: Take the maximum of the various error indicators and " - "refine those cells on which the maximal indicators is largest.\n" - "\\end{itemize}" - "The refinement indicators computed by each strategy are modified by " - "the ``Normalize individual refinement criteria'' and ``Refinement " - "criteria scale factors'' parameters."); - } - prm.leave_subsection(); - - // now declare the parameters of each of the registered - // plugins in turn - std::get(registered_plugins).declare_parameters (prm); - } - - - - template - void - Manager::parse_parameters (ParameterHandler &prm) - { - Assert (std::get(registered_plugins).plugins != nullptr, - ExcMessage ("No mesh refinement plugins registered!?")); - - // find out which plugins are requested and the various other - // parameters we declare here - std::vector plugin_names; - prm.enter_subsection("Mesh refinement"); - { - plugin_names - = Utilities::split_string_list(prm.get("Strategy")); - - AssertThrow(Utilities::has_unique_entries(plugin_names), - ExcMessage("The list of strings for the parameter " - "'Mesh refinement/Strategy' contains entries more than once. " - "This is not allowed. Please check your parameter file.")); - - normalize_criteria = prm.get_bool ("Normalize individual refinement criteria"); - - scaling_factors - = Utilities::string_to_double( - Utilities::split_string_list(prm.get("Refinement criteria scaling factors"))); - AssertThrow (scaling_factors.size() == plugin_names.size() - || - scaling_factors.size() == 0, - ExcMessage ("The number of scaling factors given here must either be " - "zero or equal to the number of chosen refinement criteria.")); - if (scaling_factors.size() == 0) - scaling_factors = std::vector (plugin_names.size(), 1.0); - - if (prm.get("Refinement criteria merge operation") == "plus") - merge_operation = plus; - else if (prm.get("Refinement criteria merge operation") == "max") - merge_operation = max; - else - AssertThrow (false, ExcNotImplemented()); - } - prm.leave_subsection(); - - // go through the list, create objects and let them parse - // their own parameters - AssertThrow (plugin_names.size() >= 1, - ExcMessage ("You need to provide at least one mesh refinement criterion in the input file!")); - for (auto &plugin_name : plugin_names) - { - this->plugin_objects.push_back (std::unique_ptr> - (std::get(registered_plugins) - .create_plugin (plugin_name, - "Mesh refinement::Refinement criteria merge operation"))); - - if (SimulatorAccess *sim = dynamic_cast*>(&*this->plugin_objects.back())) - sim->initialize_simulator (this->get_simulator()); - - this->plugin_objects.back()->parse_parameters (prm); - this->plugin_objects.back()->initialize (); - } - } - - - template - void - Manager::register_mesh_refinement_criterion (const std::string &name, - const std::string &description, - void (*declare_parameters_function) (ParameterHandler &), - std::unique_ptr> (*factory_function) ()) - { - std::get(registered_plugins).register_plugin (name, - description, - declare_parameters_function, - factory_function); - } - - - - template - void - Manager::write_plugin_graph (std::ostream &out) - { - std::get(registered_plugins).write_plugin_graph ("Mesh refinement criteria interface", - out); - } - - } -} - - -// explicit instantiations -namespace aspect -{ - namespace internal - { - namespace Plugins - { - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - } - } - - namespace MeshRefinement - { -#define INSTANTIATE(dim) \ - template class Interface; \ - template class Manager; - - ASPECT_INSTANTIATE(INSTANTIATE) - -#undef INSTANTIATE - } -} diff --git a/source/mesh_refinement/isosurfaces.cc.bak b/source/mesh_refinement/isosurfaces.cc.bak deleted file mode 100644 index c834b26fc08..00000000000 --- a/source/mesh_refinement/isosurfaces.cc.bak +++ /dev/null @@ -1,404 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - - -#include -#include -#include -#include -#include -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - namespace internal - { - bool - Isosurface::are_all_values_in_range(const std::vector &values) const - { - // This assumes that all the vectors in isosurfaces already have the - // same length. - Assert(values.size() == min_values.size(), - ExcMessage("internal error: Vector of values passed to the isosurface class " - "function are_all_values_in_range, does not have the correct size.")); - for (unsigned int index = 0; index < values.size(); ++index) - { - if (values[index] < min_values[index] || values[index] > max_values[index]) - { - // outside this isosurface, no need to search further - return false; - } - } - // If we made it this far, then we are inside the conditions, so return true. - return true; - } - - Property::Property(const std::string &property_name, - const std::vector &available_compositions) - { - bool found = false; - if (property_name == "Temperature") - { - type = PropertyType::Temperature; - index = 0; - found = true; - } - else - { - auto p = std::find(available_compositions.begin(), available_compositions.end(), property_name); - if (p != available_compositions.end()) - { - type = PropertyType::Composition; - index = std::distance(available_compositions.begin(), p); - found = true; - } - } - if (found == false) - { - // The property name has not been found. This could be because the compositional field is not present. - // Abort and warn the user. - std::string key_list = "Temperature"; - for (auto &composition : available_compositions) - key_list += ", " + composition; - - AssertThrow(false, - ExcMessage("The key given for the isosurface could not be converted. The provided key was: " + property_name + ". " - "The following keys are allowed for this model: " + key_list + ".")); - } - } - - /** - * Convert a string describing the refinement level which potentially contains the words "min" - * or "max" to an integer. The format is "min", "max", "min+X", "max-X", or "X", where X is a positive integer. - * - * For example if minimum_refinement_level is 1, and the string is 'min+1', it will return 2. - * The returned value will be capped by the provided @p minimum_refinement_level and @p maximum_refinement_level. - * The @p minimum_refinement_level and @p maximum_refinement_level are set in this input file subsection for this - * plugin, but in the Mesh refinement subsection. - * - * This function will throw an assertion when the string contains `max+` or `min-` since - * that is always incorrect. - */ - unsigned int min_max_string_to_int(const std::string &string_value, - const unsigned int minimum_refinement_level, - const unsigned int maximum_refinement_level) - { - // start with removing the spaces so that a ' min + 1 ' would become 'min+1'. - std::string string = string_value; - std::string::iterator end_pos = std::remove(string.begin(), string.end(), ' '); - string.erase(end_pos, string.end()); - - // check whether the field starts with a 'min' - if (string.compare(0,3,"min") == 0) - { - if (string.compare(0,4,"min+") == 0) - { - std::vector tmpNumber = Utilities::split_string_list(string,'+'); - AssertThrow(tmpNumber.size() == 2, - ExcMessage("Could not convert value '" + string + "' to an int because it contains more than one '+' sign.")); - return std::min(std::max(minimum_refinement_level+Utilities::string_to_int(tmpNumber[1]),minimum_refinement_level),maximum_refinement_level); - } - else - { - AssertThrow(string == "min", - ExcMessage("A value of " + string_value + " was provided, but you can't provide a smaller value than the minimum.")); - return minimum_refinement_level; - } - } - else if (string.compare(0,3,"max") == 0) - { - if (string.compare(0,4,"max-") == 0) - { - std::vector tmpNumber = Utilities::split_string_list(string,'-'); - AssertThrow(tmpNumber.size() == 2, - ExcMessage("Could not convert value '" + string + "' to an int because it contains more than one '-' sign.")); - return std::min(std::max(maximum_refinement_level-Utilities::string_to_int(tmpNumber[1]),minimum_refinement_level),maximum_refinement_level); - } - else - { - AssertThrow(string=="max", - ExcMessage("A value of " + string_value + " was provided, but you can't provide a larger value than the maximum.")); - return maximum_refinement_level; - } - } - else - { - return std::min(std::max(static_cast(Utilities::string_to_int(string)),minimum_refinement_level),maximum_refinement_level); - } - - } - } - - template - void - Isosurfaces::update () - { } - - template - void - Isosurfaces::tag_additional_cells () const - { - if (this->get_dof_handler().n_locally_owned_dofs() == 0) - return; - - const Quadrature quadrature(this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_support_points()); - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature, - update_quadrature_points | update_values | update_gradients); - - MaterialModel::MaterialModelInputs in(quadrature.size(), - this->n_compositional_fields()); - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - { - if (cell->is_locally_owned()) - { - bool coarsen = false; - bool clear_refine = false; - bool refine = false; - bool clear_coarsen = false; - - fe_values.reinit(cell); - in.reinit(fe_values, cell, this->introspection(), this->get_solution()); - - for (unsigned int i_quad=0; i_quad values(isosurface.min_values.size()); - for (unsigned int index = 0; index < isosurface.properties.size(); ++index) - { - if (isosurface.properties[index].type == internal::PropertyType::Temperature) - { - values[index] = in.temperature[i_quad]; - } - else if (isosurface.properties[index].type == internal::PropertyType::Composition) - { - values[index] = in.composition[i_quad][isosurface.properties[index].index]; - } - } - - if ( isosurface.are_all_values_in_range(values)) - { - // If the current refinement level is smaller than or equal to the minimum - // refinement level, any coarsening flag should be cleared. - if (cell->level() <= isosurface.min_refinement) - { - clear_coarsen = true; - } - - // If the current refinement level is smaller than the minimum - // refinement level, a refinement flag should be placed. - if (cell->level() < isosurface.min_refinement) - { - refine = true; - break; - } - - // If the current refinement level is larger than or equal to the maximum refinement - // level, any refinement flag should be cleared. - if (cell->level() >= isosurface.max_refinement) - { - clear_refine = true; - } - - // If the current refinement level is larger than the maximum refinement level, - // a coarsening flag should be placed. - if (cell->level() > isosurface.max_refinement) - { - coarsen = true; - } - } - } - } - - // if both coarsen and refine are true, give preference to refinement - if (coarsen && refine) - coarsen = false; - if (refine) - clear_refine = false; - if (clear_coarsen) - coarsen = false; - - // Perform the actual placement of the coarsening and refinement flags. - if (clear_coarsen) - cell->clear_coarsen_flag (); - if (clear_refine) - cell->clear_refine_flag (); - if (coarsen) - cell->set_coarsen_flag (); - if (refine) - cell->set_refine_flag (); - } - } - } - - template - void - Isosurfaces:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Isosurfaces"); - { - prm.declare_entry ("Isosurfaces", "", - Patterns::Anything(), - "A list of isosurfaces separated by semi-colons (;). Each isosurface entry consists of " - "multiple entries separated by a comma. The first two entries indicate the minimum and maximum " - "refinement levels respectively. The entries after the first two describe the fields the isosurface " - "applies to, followed by a colon (:), which is again followed by the minimum and maximum property values separated by " - "bar (|). An example for an isosurface is '0, 2, Temperature: 300 | 600; 2, 2, C\\_1: 0.5 | 1'. " - "In this example the mesh refinement is kept between level 0 and level 2 if the temperature is between " - "300 and 600 and at level 2 when the compositional field C\\_1 is between 0.5 and 1. If both happen at " - "the same location and the current refinement level is 1, it means that the first isoline will not set any flag and the " - "second isoline will set a refinement flag. This means the cell will be refined. If both the coarsening and refinement flags " - "are set, preference is given to refinement. " - "\n\n" - "The first two entries for each isosurface, describing the minimum and maximum grid levels, can be " - "two numbers or contain one of the key values 'min' and 'max'. This indicates the key will be replaced with " - "the global minimum and maximum refinement levels. The 'min' and 'max' keys also accept adding " - "values to be added or subtracted from them respectively. This is done by adding a '+' or '-' and a " - "number behind them (e.g. min+2 or max-1). Note that you can't subtract a value from a minimum value or " - "add a value to the maximum value. If, for example, `max-4` drops below the minimum or `min+4` goes above the " - "maximum, it will simply use the global minimum and maximum values respectively. The same holds for any " - "mesh refinement level below the global minimum or above the global maximum."); - - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - Isosurfaces::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - // lookup the minimum and maximum refinement - const unsigned int minimum_refinement_level = this->get_parameters().min_grid_level; - const unsigned int maximum_refinement_level = this->get_parameters().initial_global_refinement + - this->get_parameters().initial_adaptive_refinement; - - const std::vector &compositions = this->introspection().get_composition_names(); - prm.enter_subsection("Isosurfaces"); - { - // Split the list by comma delimited components. - const std::vector isosurface_entries = dealii::Utilities::split_string_list(prm.get("Isosurfaces"), ';'); - unsigned int isosurface_entry_number = 0; - for (auto &isosurface_entry : isosurface_entries) - { - ++isosurface_entry_number; - aspect::MeshRefinement::internal::Isosurface isosurface; - std::vector properties; - std::vector min_value_inputs; - std::vector max_value_inputs; - const std::vector field_entries = dealii::Utilities::split_string_list(isosurface_entry, ','); - - AssertThrow(field_entries.size() >= 3, - ExcMessage("An isosurface needs to contain at least 3 entries, but isosurface " + std::to_string(isosurface_entry_number) - + " contains only " + std::to_string(field_entries.size()) + " entries: " + isosurface_entry + ".")); - - // convert a potential min, min+1, min + 1, min+10, max, max-1, etc. to actual integers. - isosurface.min_refinement = internal::min_max_string_to_int(field_entries[0], minimum_refinement_level, maximum_refinement_level); - isosurface.max_refinement = internal::min_max_string_to_int(field_entries[1], minimum_refinement_level, maximum_refinement_level); - AssertThrow(isosurface.min_refinement <= isosurface.max_refinement, - ExcMessage("The provided maximum refinement level has to be larger than the minimum refinement level.")); - for (auto field_entry = field_entries.begin()+2; field_entry != field_entries.end(); ++field_entry) - { - AssertThrow(Patterns::Map(Patterns::Anything(), - Patterns::List(Patterns::Double(), 0, std::numeric_limits::max(), "|") - ).match(*field_entry), - ExcMessage("The isosurface is not formatted correctly.")); - std::vector key_and_value = Utilities::split_string_list (*field_entry, ':'); - AssertThrow(key_and_value.size() == 2, - ExcMessage("The isosurface property must have a key (e.g. Temperature) and two values separated by a | (e.g. (300 | 600).")); - properties.emplace_back(key_and_value[0], compositions); // convert key to property name - const std::vector values = dealii::Utilities::split_string_list(key_and_value[1], '|'); - AssertThrow(values.size() == 2, - ExcMessage("Both a maximum and a minimum value are required for each isosurface.")); - min_value_inputs.push_back(Utilities::string_to_double(values[0])); // get min and max values of the range - max_value_inputs.push_back(Utilities::string_to_double(values[1])); - AssertThrow(min_value_inputs.back() < max_value_inputs.back(), - ExcMessage("The provided maximum property value has to be larger than the provided minimum property value.")); - } - isosurface.min_values = min_value_inputs; - isosurface.max_values = max_value_inputs; - isosurface.properties = properties; - isosurfaces.push_back(isosurface); - } - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Isosurfaces, - "isosurfaces", - "A mesh refinement criterion that computes " - "coarsening and refinement indicators between two isosurfaces of " - "specific field entries (e.g. temperature, composition)." - "\n\n" - "The way these indicators are derived between pairs of isosurfaces is by " - "checking whether the solutions of specific " - "fields are within the ranges of the isosurface values given. If these conditions " - "hold, then coarsening and refinement indicators are set such that " - "the mesh refinement levels lies within the range of levels " - "given. Usage of this plugin allows the user to put a conditional " - "minimum and maximum refinement function onto fields that they " - "are interested in." - "\n\n" - "For now, only temperature and compositional fields are allowed as " - "field entries. The key words could be 'Temperature' or one of the names " - "of the compositional fields which are either specified by user or set up " - "as C\\_0, C\\_1, etc." - "\n\n" - "Usage: A list of isosurfaces separated by semi-colons (;). Each " - "isosurface entry consists of multiple entries separated by a comma. " - "The first two entries indicate the minimum and maximum refinement " - "levels respectively. The entries after the first two describe the " - "fields the isosurface applies to, followed by a colon (:), which again " - "is followed by the minimum and maximum field values separated by a bar (|). An " - "example for two isosurface entries is '0, 2, Temperature: 300 | 600; 2, 2, C\\_1: 0.5 | 1'. " - "If both isoterm entries are triggered at the same location and the current refinement level is 1, " - "it means that the first isoline will not set any flag and the second isoline will set a refinement flag. " - "This means the cell will be refined. If both the coarsening and refinement flags " - "are set, preference is given to refinement. " - "\n\n" - "The minimum and maximum refinement levels per isosurface can be provided in absolute values relative to " - "the global minimum and maximum refinement. This is done with the 'min' and 'max' key words. For example: " - "'set Isosurfaces = max-2, max, Temperature: 0 | 600 ; min + 1,min+2, Temperature: 1600 | 3000, C\\_2 : 0.0 | 0.5'." - ) - } -} diff --git a/source/mesh_refinement/maximum_refinement_function.cc.bak b/source/mesh_refinement/maximum_refinement_function.cc.bak deleted file mode 100644 index 1d133dbb817..00000000000 --- a/source/mesh_refinement/maximum_refinement_function.cc.bak +++ /dev/null @@ -1,193 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - - -#include -#include -#include - -#include -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - MaximumRefinementFunction::update () - { - const double time = this->get_time() / - (this->convert_output_to_years() - ? - year_in_seconds - : - 1.0); - - max_refinement_level.set_time(time); - } - - template - void - MaximumRefinementFunction::tag_additional_cells () const - { - for (const auto &cell : this->get_triangulation().active_cell_iterators()) - { - if (cell->is_locally_owned()) - { - const Point center = cell->center(); - const Utilities::NaturalCoordinate point = - this->get_geometry_model().cartesian_to_other_coordinates(center, coordinate_system); - - const double maximum_refinement_level = max_refinement_level.value(Utilities::convert_array_to_point(point.get_coordinates())); - - if (cell->level() >= static_cast(std::round(maximum_refinement_level))) - cell->clear_refine_flag (); - - if (cell->level() > static_cast(std::round(maximum_refinement_level))) - cell->set_coarsen_flag (); - } - } - } - - template - void - MaximumRefinementFunction:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - - prm.enter_subsection("Maximum refinement function"); - { - /** - * Choose the coordinates to evaluate the maximum refinement level - * function. The function can be declared in dependence of depth, - * cartesian coordinates or spherical coordinates. Note that the order - * of spherical coordinates is r,phi,theta and not r,theta,phi, since - * this allows for dimension independent expressions. - */ - prm.declare_entry ("Coordinate system", "depth", - Patterns::Selection ("depth|cartesian|spherical"), - "A selection that determines the assumed coordinate " - "system for the function variables. Allowed values " - "are `depth', `cartesian' and `spherical'. `depth' " - "will create a function, in which only the first " - "variable is non-zero, which is interpreted to " - "be the depth of the point. `spherical' coordinates " - "are interpreted as r,phi or r,phi,theta in 2d/3d " - "respectively with theta being the polar angle."); - /** - * Let the function that describes the maximal level of refinement - * as a function of position declare its parameters. - * This defines the maximum refinement level each cell should have, - * and that can not be exceeded by coarsening. - */ - Functions::ParsedFunction::declare_parameters (prm, 1); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - MaximumRefinementFunction::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Maximum refinement function"); - { - if (prm.get ("Coordinate system") == "depth") - coordinate_system = Utilities::Coordinates::depth; - else if (prm.get ("Coordinate system") == "cartesian") - coordinate_system = Utilities::Coordinates::cartesian; - else if (prm.get ("Coordinate system") == "spherical") - coordinate_system = Utilities::Coordinates::spherical; - else - AssertThrow (false, ExcNotImplemented()); - - try - { - max_refinement_level.parse_parameters (prm); - } - catch (...) - { - std::cerr << "ERROR: FunctionParser failed to parse\n" - << "\t'Mesh refinement.Maximum refinement function'\n" - << "with expression\n" - << "\t'" << prm.get("Function expression") << "'" - << "More information about the cause of the parse error \n" - << "is shown below.\n"; - throw; - } - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(MaximumRefinementFunction, - "maximum refinement function", - "A mesh refinement criterion that ensures a " - "maximum refinement level described by an " - "explicit formula with the depth or position " - "as argument. Which coordinate representation " - "is used is determined by an input parameter. " - "Whatever the coordinate system chosen, the " - "function you provide in the input file will " - "by default depend on variables `x', `y' and " - "`z' (if in 3d). However, the meaning of these " - "symbols depends on the coordinate system. In " - "the Cartesian coordinate system, they simply " - "refer to their natural meaning. If you have " - "selected `depth' for the coordinate system, " - "then `x' refers to the depth variable and `y' " - "and `z' will simply always be zero. If you " - "have selected a spherical coordinate system, " - "then `x' will refer to the radial distance of " - "the point to the origin, `y' to the azimuth " - "angle and `z' to the polar angle measured " - "positive from the north pole. Note that the " - "order of spherical coordinates is r,phi,theta " - "and not r,theta,phi, since this allows for " - "dimension independent expressions. " - "Each coordinate system also includes a final `t' " - "variable which represents the model time, evaluated " - "in years if the 'Use years in output instead of seconds' " - "parameter is set, otherwise evaluated in seconds. " - "After evaluating the function, its values are " - "rounded to the nearest integer." - "\n\n" - "The format of these " - "functions follows the syntax understood by the " - "muparser library, see " - "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") - } -} diff --git a/source/mesh_refinement/minimum_refinement_function.cc.bak b/source/mesh_refinement/minimum_refinement_function.cc.bak deleted file mode 100644 index 4c5b67b64d2..00000000000 --- a/source/mesh_refinement/minimum_refinement_function.cc.bak +++ /dev/null @@ -1,192 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - - -#include -#include -#include - -#include -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - MinimumRefinementFunction::update () - { - const double time = this->get_time() / - (this->convert_output_to_years() - ? - year_in_seconds - : - 1.0); - - min_refinement_level.set_time(time); - } - - template - void - MinimumRefinementFunction::tag_additional_cells () const - { - for (const auto &cell : this->get_triangulation().active_cell_iterators()) - { - if (cell->is_locally_owned()) - { - const Point center = cell->center(); - const Utilities::NaturalCoordinate point = - this->get_geometry_model().cartesian_to_other_coordinates(center, coordinate_system); - - const double minimum_refinement_level = min_refinement_level.value(Utilities::convert_array_to_point(point.get_coordinates())); - - if (cell->level() <= static_cast(std::round(minimum_refinement_level))) - cell->clear_coarsen_flag (); - if (cell->level() < static_cast(std::round(minimum_refinement_level))) - cell->set_refine_flag (); - } - } - } - - template - void - MinimumRefinementFunction:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - - prm.enter_subsection("Minimum refinement function"); - { - /** - * Choose the coordinates to evaluate the minimum refinement level - * function. The function can be declared in dependence of depth, - * cartesian coordinates or spherical coordinates. Note that the order - * of spherical coordinates is r,phi,theta and not r,theta,phi, since - * this allows for dimension independent expressions. - */ - prm.declare_entry ("Coordinate system", "depth", - Patterns::Selection ("depth|cartesian|spherical"), - "A selection that determines the assumed coordinate " - "system for the function variables. Allowed values " - "are `depth', `cartesian' and `spherical'. `depth' " - "will create a function, in which only the first " - "variable is non-zero, which is interpreted to " - "be the depth of the point. `spherical' coordinates " - "are interpreted as r,phi or r,phi,theta in 2d/3d " - "respectively with theta being the polar angle."); - /** - * Let the function that describes the minimal level of refinement - * as a function of position declare its parameters. - * This defines the minimum refinement level each cell should have, - * and that can not be exceeded by coarsening. - */ - Functions::ParsedFunction::declare_parameters (prm, 1); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - MinimumRefinementFunction::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Minimum refinement function"); - { - if (prm.get ("Coordinate system") == "depth") - coordinate_system = Utilities::Coordinates::depth; - else if (prm.get ("Coordinate system") == "cartesian") - coordinate_system = Utilities::Coordinates::cartesian; - else if (prm.get ("Coordinate system") == "spherical") - coordinate_system = Utilities::Coordinates::spherical; - else - AssertThrow (false, ExcNotImplemented()); - - try - { - min_refinement_level.parse_parameters (prm); - } - catch (...) - { - std::cerr << "ERROR: FunctionParser failed to parse\n" - << "\t'Mesh refinement.Minimum refinement function'\n" - << "with expression\n" - << "\t'" << prm.get("Function expression") << "'" - << "More information about the cause of the parse error \n" - << "is shown below.\n"; - throw; - } - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(MinimumRefinementFunction, - "minimum refinement function", - "A mesh refinement criterion that ensures a " - "minimum refinement level described by an " - "explicit formula with the depth or position " - "as argument. Which coordinate representation " - "is used is determined by an input parameter. " - "Whatever the coordinate system chosen, the " - "function you provide in the input file will " - "by default depend on variables `x', `y' and " - "`z' (if in 3d). However, the meaning of these " - "symbols depends on the coordinate system. In " - "the Cartesian coordinate system, they simply " - "refer to their natural meaning. If you have " - "selected `depth' for the coordinate system, " - "then `x' refers to the depth variable and `y' " - "and `z' will simply always be zero. If you " - "have selected a spherical coordinate system, " - "then `x' will refer to the radial distance of " - "the point to the origin, `y' to the azimuth " - "angle and `z' to the polar angle measured " - "positive from the north pole. Note that the " - "order of spherical coordinates is r,phi,theta " - "and not r,theta,phi, since this allows for " - "dimension independent expressions. " - "Each coordinate system also includes a final `t' " - "variable which represents the model time, evaluated " - "in years if the 'Use years in output instead of seconds' " - "parameter is set, otherwise evaluated in seconds. " - "After evaluating the function, its values are " - "rounded to the nearest integer." - "\n\n" - "The format of these " - "functions follows the syntax understood by the " - "muparser library, see " - "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") - } -} diff --git a/source/mesh_refinement/nonadiabatic_temperature.cc.bak b/source/mesh_refinement/nonadiabatic_temperature.cc.bak deleted file mode 100644 index 3177c52d25b..00000000000 --- a/source/mesh_refinement/nonadiabatic_temperature.cc.bak +++ /dev/null @@ -1,127 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include -#include -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - NonadiabaticTemperature::execute(Vector &indicators) const - { - indicators = 0; - - // create a vector in which we set the temperature block to - // be a finite element interpolation of the nonadiabatic temperature. - // we do so by setting up a quadrature formula with the - // temperature unit support points, then looping over these - // points, compute the output quantity at them, and writing - // the result into the output vector in the same order - // (because quadrature points and temperature dofs are, - // by design of the quadrature formula, numbered in the - // same way) - LinearAlgebra::BlockVector vec_distributed (this->introspection().index_sets.system_partitioning, - this->get_mpi_communicator()); - - const Quadrature quadrature(this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_support_points()); - std::vector local_dof_indices (this->get_fe().dofs_per_cell); - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature, - update_quadrature_points | update_values); - - MaterialModel::MaterialModelInputs in(quadrature.size(), - this->n_compositional_fields()); - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit(cell); - fe_values[this->introspection().extractors.temperature].get_function_values (this->get_solution(), - in.temperature); - in.position = fe_values.get_quadrature_points(); - - cell->get_dof_indices (local_dof_indices); - - // for each temperature dof, write into the output - // vector the nonadiabatic temperature. note that quadrature points and - // dofs are enumerated in the same order - for (unsigned int i=0; iget_fe().base_element(this->introspection().base_elements.temperature).dofs_per_cell; ++i) - { - const unsigned int system_local_dof - = this->get_fe().component_to_system_index(this->introspection().component_indices.temperature, - /*dof index within component=*/i); - - vec_distributed(local_dof_indices[system_local_dof]) - = in.temperature[i] - this->get_adiabatic_conditions().temperature(in.position[i]); - } - } - - vec_distributed.compress(VectorOperation::insert); - - // now create a vector with the requisite ghost elements - // and use it for estimating the gradients - LinearAlgebra::BlockVector vec (this->introspection().index_sets.system_partitioning, - this->introspection().index_sets.system_relevant_partitioning, - this->get_mpi_communicator()); - vec = vec_distributed; - - DerivativeApproximation::approximate_gradient (this->get_mapping(), - this->get_dof_handler(), - vec, - indicators, - this->introspection().component_indices.temperature); - - // Scale gradient in each cell with the correct power of h. Otherwise, - // error indicators do not reduce when refined if there is a density - // jump. We need at least order 1 for the error not to grow when - // refining, so anything >1 should work. (note that the gradient - // itself scales like 1/h, so multiplying it with any factor h^s, s>1 - // will yield convergence of the error indicators to zero as h->0) - const double power = 1.0 + dim/2.0; - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - indicators(cell->active_cell_index()) *= std::pow(cell->diameter(), power); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(NonadiabaticTemperature, - "nonadiabatic temperature", - "A mesh refinement criterion that computes " - "refinement indicators from the excess temperature" - "(difference between temperature and adiabatic " - "temperature.") - } -} diff --git a/source/mesh_refinement/nonadiabatic_temperature_threshold.cc.bak b/source/mesh_refinement/nonadiabatic_temperature_threshold.cc.bak deleted file mode 100644 index eb8b2c8007d..00000000000 --- a/source/mesh_refinement/nonadiabatic_temperature_threshold.cc.bak +++ /dev/null @@ -1,158 +0,0 @@ -/* - Copyright (C) 2015 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - NonadiabaticTemperatureThreshold::tag_additional_cells () const - { - // tag_additional_cells is executed before the equations are solved - // for the very first time. If we do not have the finite element, we - // do not have the temperature and just do nothing in this plugin. - if (this->get_dof_handler().n_locally_owned_dofs() == 0) - return; - - const Quadrature quadrature(this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_support_points()); - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature, - update_quadrature_points | update_values); - - std::vector temperature_values (quadrature.size()); - const unsigned int n_dofs_per_cell = this->get_fe().base_element(this->introspection().base_elements.temperature).dofs_per_cell; - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - bool refine = false; - - fe_values.reinit(cell); - fe_values[this->introspection().extractors.temperature].get_function_values (this->get_solution(), - temperature_values); - - // if the nonadiabatic temperature exceeds the threshold, cell is marked for refinement - for (unsigned int j=0; jget_adiabatic_conditions().temperature(fe_values.quadrature_point(j)); - - double nonadiabatic_temperature = 0; - if (temperature_anomaly_type == absolute_value) - nonadiabatic_temperature = std::abs(temperature_values[j] - adiabatic_temperature); - else if (temperature_anomaly_type == positive_only) - nonadiabatic_temperature = temperature_values[j] - adiabatic_temperature; - else if (temperature_anomaly_type == negative_only) - nonadiabatic_temperature = adiabatic_temperature - temperature_values[j]; - else - AssertThrow (false, ExcNotImplemented()); - - if (nonadiabatic_temperature > threshold) - { - refine = true; - break; - } - } - - if (refine) - { - cell->clear_coarsen_flag (); - cell->set_refine_flag (); - } - } - } - - template - void - NonadiabaticTemperatureThreshold:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Nonadiabatic temperature threshold"); - { - prm.declare_entry ("Threshold", - "100", - Patterns::Double (0.), - "A threshold that the nonadiabatic temperature " - "will be evaluated against. " - "Units: \\si{\\kelvin}"); - prm.declare_entry ("Temperature anomaly type", - "absolute value", - Patterns::Selection ("negative only|positive only|absolute value"), - "What type of temperature anomaly should be considered when " - "evaluating against the threshold: Only negative anomalies " - "(negative only), only positive anomalies (positive only) " - "or the absolute value of the nonadiabatic temperature."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - NonadiabaticTemperatureThreshold::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Nonadiabatic temperature threshold"); - { - threshold = prm.get_double("Threshold"); - - if (prm.get ("Temperature anomaly type") == "negative only") - temperature_anomaly_type = negative_only; - else if (prm.get ("Temperature anomaly type") == "positive only") - temperature_anomaly_type = positive_only; - else if (prm.get ("Temperature anomaly type") == "absolute value") - temperature_anomaly_type = absolute_value; - else - AssertThrow (false, ExcNotImplemented()); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(NonadiabaticTemperatureThreshold, - "nonadiabatic temperature threshold", - "A mesh refinement criterion that computes refinement " - "indicators from the temperature difference between the " - "actual temperature and the adiabatic conditions (the " - "nonadiabatic temperature). If the temperature anomaly " - "exceeds the threshold given in the input file, the cell " - "is marked for refinement.") - } -} diff --git a/source/mesh_refinement/particle_density.cc.bak b/source/mesh_refinement/particle_density.cc.bak deleted file mode 100644 index 9113dcd71e4..00000000000 --- a/source/mesh_refinement/particle_density.cc.bak +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright (C) 2015 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - ParticleDensity::execute(Vector &indicators) const - { - AssertThrow(this->n_particle_worlds() > 0, - ExcMessage("The mesh refinement plugin `particle density' requires the " - "postprocessor plugin `particles' to be selected. Please activate the " - "particles or deactivate this mesh refinement plugin.")); - - const Particle::ParticleHandler &particle_handler = this->get_particle_world(0).get_particle_handler(); - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - // Note that this refinement indicator will level out the number - // of particles per cell, therefore creating fine cells in regions - // of high particle density and coarse cells in low particle - // density regions. - indicators(cell->active_cell_index()) = static_cast(particle_handler.n_particles_in_cell(cell)); - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(ParticleDensity, - "particle density", - "A mesh refinement criterion that computes " - "refinement indicators based on the density " - "of particles. In practice this plugin " - "equilibrates the number of particles per cell, " - "leading to fine cells in high particle density regions " - "and coarse cells in low particle density regions. " - "This plugin is mostly useful for models with inhomogeneous " - "particle density, e.g. when tracking an initial interface " - "with a high particle density, or when the spatial particle " - "density denotes the region of interest. Additionally, this " - "plugin tends to balance the computational load between " - "processes in parallel computations, because the particle " - "and mesh density is more aligned.") - } -} diff --git a/source/mesh_refinement/slope.cc.bak b/source/mesh_refinement/slope.cc.bak deleted file mode 100644 index e0804b371d6..00000000000 --- a/source/mesh_refinement/slope.cc.bak +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright (C) 2011 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include -#include -#include - -#include -#include - - -namespace aspect -{ - namespace MeshRefinement - { - template - void - Slope::execute(Vector &indicators) const - { - const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); - - indicators = 0; - - QMidpoint quadrature; - UpdateFlags update_flags = UpdateFlags(update_normal_vectors | update_quadrature_points ); - FEFaceValues fe_face_values (this->get_mapping(), this->get_fe(), quadrature, update_flags); - - // iterate over all of the cells, get a face normal, then - // dot it with the local gravity - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned() && cell->at_boundary()) - { - const unsigned int idx = cell->active_cell_index(); - for (const unsigned int face_no : cell->face_indices()) - if (cell->face(face_no)->at_boundary()) - { - const types::boundary_id boundary_indicator - = cell->face(face_no)->boundary_id(); - - // Use cases for this plugin include a deforming mesh, - // or a fixed mesh with initial topography - if ( (this->get_parameters().mesh_deformation_enabled && - this->get_mesh_deformation_boundary_indicators().find(boundary_indicator) != - this->get_mesh_deformation_boundary_indicators().end()) || - (Plugins::plugin_type_matches>(this->get_initial_topography_model()) && - boundary_indicator == top_boundary_id) ) - { - fe_face_values.reinit(cell, face_no); - - const Tensor<1,dim> normal( fe_face_values.normal_vector(0) ); // Only one q point - const Point midpoint = fe_face_values.quadrature_point(0); - const Tensor<1,dim> gravity = this->get_gravity_model().gravity_vector(midpoint); - - indicators(idx) = std::acos( std::abs ( normal * gravity / gravity.norm() ) ) // Don't care whether gravity is in the opposite direction - * std::pow( cell->diameter(), static_cast(dim-1)); // scale with approximate surface area of the cell - break; // no need to loop over the rest of the faces - } - } - } - - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Slope, - "slope", - "A class that implements a mesh refinement criterion intended for " - "use with deforming mesh boundaries, like the free surface. " - "It calculates a local slope based on " - "the angle between the surface normal and the local gravity vector. " - "Cells with larger angles are marked for refinement." - "\n\n" - "To use this refinement criterion, you may want to combine " - "it with other refinement criteria, setting the 'Normalize " - "individual refinement criteria' flag and using the `max' " - "setting for 'Refinement criteria merge operation'.") - } -} diff --git a/source/mesh_refinement/strain_rate.cc.bak b/source/mesh_refinement/strain_rate.cc.bak deleted file mode 100644 index e12467a1f18..00000000000 --- a/source/mesh_refinement/strain_rate.cc.bak +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright (C) 2011 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include -#include -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - StrainRate::execute(Vector &indicators) const - { - indicators = 0; - - const QMidpoint quadrature; - - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature, - update_quadrature_points | update_values | update_gradients); - - std::vector> strain_rates (quadrature.size()); - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - const unsigned int idx = cell->active_cell_index(); - fe_values.reinit(cell); - - fe_values[this->introspection().extractors.velocities].get_function_symmetric_gradients (this->get_solution(), - strain_rates); - - indicators(idx) = strain_rates[0].norm(); - } - - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(StrainRate, - "strain rate", - "A mesh refinement criterion that computes the " - "refinement indicators equal to the strain rate " - "norm computed at the center of the elements.") - } -} diff --git a/source/mesh_refinement/temperature.cc.bak b/source/mesh_refinement/temperature.cc.bak deleted file mode 100644 index a8216ccc404..00000000000 --- a/source/mesh_refinement/temperature.cc.bak +++ /dev/null @@ -1,83 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - Temperature::execute(Vector &indicators) const - { - indicators = 0; - - const Quadrature &quadrature = this->introspection().face_quadratures.temperature; - KellyErrorEstimator::estimate (this->get_mapping(), - this->get_dof_handler(), - quadrature, - std::map*>(), - this->get_solution(), - indicators, - this->introspection().component_masks.temperature, - nullptr, - 0, - this->get_triangulation().locally_owned_subdomain()); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Temperature, - "temperature", - "A mesh refinement criterion that computes " - "refinement indicators from the temperature field." - "\n\n" - "The way these indicators are computed is by " - "evaluating the `Kelly error indicator' on the " - "temperature field. This error indicator takes the " - "finite element approximation of the temperature " - "field and uses it to compute an approximation " - "of the second derivatives of the temperature for " - "each cell. This approximation is then multiplied " - "by an appropriate power of the cell's diameter " - "to yield an indicator for how large the error " - "is likely going to be on this cell. This " - "construction rests on the observation that for " - "many partial differential equations, the error " - "on each cell is proportional to some power of " - "the cell's diameter times the second derivatives " - "of the solution on that cell." - "\n\n" - "For complex equations such as those we solve " - "here, this observation may not be strictly " - "true in the mathematical sense, but it often " - "yields meshes that are surprisingly good.") - } -} diff --git a/source/mesh_refinement/thermal_energy_density.cc.bak b/source/mesh_refinement/thermal_energy_density.cc.bak deleted file mode 100644 index 61b3d2ed4cc..00000000000 --- a/source/mesh_refinement/thermal_energy_density.cc.bak +++ /dev/null @@ -1,144 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include -#include -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - ThermalEnergyDensity::execute(Vector &indicators) const - { - indicators = 0; - - // create a vector in which we set the temperature block to - // be a finite element interpolation of the thermal energy density - // rho*C_p*T. we do so by setting up a quadrature formula with the - // temperature unit support points, then looping over these - // points, compute the output quantity at them, and writing - // the result into the output vector in the same order - // (because quadrature points and temperature dofs are, - // by design of the quadrature formula, numbered in the - // same way) - LinearAlgebra::BlockVector vec_distributed (this->introspection().index_sets.system_partitioning, - this->get_mpi_communicator()); - - const Quadrature quadrature(this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_support_points()); - std::vector local_dof_indices (this->get_fe().dofs_per_cell); - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature, - update_quadrature_points | update_values | update_gradients); - - // the values of the compositional fields are stored as block vectors for each field - // we have to extract them in this structure - std::vector> prelim_composition_values (this->n_compositional_fields(), - std::vector (quadrature.size())); - - MaterialModel::MaterialModelInputs in(quadrature.size(), this->n_compositional_fields()); - MaterialModel::MaterialModelOutputs out(quadrature.size(), this->n_compositional_fields()); - in.requested_properties = MaterialModel::MaterialProperties::equation_of_state_properties; - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit(cell); - // Set use_strain_rates to false since we don't need viscosity - in.reinit(fe_values, cell, this->introspection(), this->get_solution()); - this->get_material_model().evaluate(in, out); - - cell->get_dof_indices (local_dof_indices); - - // for each temperature dof, write into the output - // vector the density. note that quadrature points and - // dofs are enumerated in the same order - for (unsigned int i=0; iget_fe().base_element(this->introspection().base_elements.temperature).dofs_per_cell; ++i) - { - const unsigned int system_local_dof - = this->get_fe().component_to_system_index(this->introspection().component_indices.temperature, - /*dof index within component=*/i); - - vec_distributed(local_dof_indices[system_local_dof]) - = out.densities[i] - * in.temperature[i] - * out.specific_heat[i]; - } - } - - vec_distributed.compress(VectorOperation::insert); - - // now create a vector with the requisite ghost elements - // and use it for estimating the gradients - LinearAlgebra::BlockVector vec (this->introspection().index_sets.system_partitioning, - this->introspection().index_sets.system_relevant_partitioning, - this->get_mpi_communicator()); - vec = vec_distributed; - - DerivativeApproximation::approximate_gradient (this->get_mapping(), - this->get_dof_handler(), - vec, - indicators, - this->introspection().component_indices.temperature); - - // Scale gradient in each cell with the correct power of h. Otherwise, - // error indicators do not reduce when refined if there is a density - // jump. We need at least order 1 for the error not to grow when - // refining, so anything >1 should work. (note that the gradient - // itself scales like 1/h, so multiplying it with any factor h^s, s>1 - // will yield convergence of the error indicators to zero as h->0) - const double power = 1.5; - { - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - indicators(cell->active_cell_index()) *= std::pow(cell->diameter(), power); - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(ThermalEnergyDensity, - "thermal energy density", - "A mesh refinement criterion that computes " - "refinement indicators from a field that describes " - "the spatial variability of the thermal energy density, $\\rho C_p T$. " - "Because this quantity may not be a continuous function ($\\rho$ " - "and $C_p$ may be discontinuous functions along discontinuities in the " - "medium, for example due to phase changes), we approximate the " - "gradient of this quantity to refine the mesh. The error indicator " - "defined here takes the magnitude of the approximate gradient " - "and scales it by $h_K^{1.5}$ where $h_K$ is the diameter of each cell. " - "This scaling ensures that the error indicators converge to zero as " - "$h_K\\rightarrow 0$ even if the energy density is discontinuous, since " - "the gradient of a discontinuous function grows like $1/h_K$.") - } -} diff --git a/source/mesh_refinement/topography.cc.bak b/source/mesh_refinement/topography.cc.bak deleted file mode 100644 index 8606afd221e..00000000000 --- a/source/mesh_refinement/topography.cc.bak +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright (C) 2011 - 2019 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - Topography::execute(Vector &indicators) const - { - // For calculating surface topography in the respective postprocessor - // we use the pressure in the middle of the cell. Thus, to get an - // accurate result, all the cells at the upper boundary should have - // the same level of refinement. This postprocessor causes a refinement - // in the uppermost cells, which also makes sure that the upper - // boundary layer is resolved as good as possible. - - indicators = 0; - - // need quadrature formula to calculate the depth - // evaluate a single point per cell - const QMidpoint quadrature_formula; - - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_quadrature_points | - update_JxW_values); - - // iterate over all of the cells and choose the ones at the upper - // boundary for refinement (assign the largest error to them) - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit (cell); - const double depth = this->get_geometry_model().depth(fe_values.quadrature_point(0)); - if (cell->at_boundary() && depth < cell->diameter()) - indicators(cell->active_cell_index()) = 1.0; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Topography, - "topography", - "A class that implements a mesh refinement criterion, which " - "always flags all cells in the uppermost layer for refinement. " - "This is useful to provide high accuracy for processes at or " - "close to the surface." - "\n\n" - "To use this refinement criterion, you may want to combine " - "it with other refinement criteria, setting the 'Normalize " - "individual refinement criteria' flag and using the `max' " - "setting for 'Refinement criteria merge operation'.") - } -} diff --git a/source/mesh_refinement/velocity.cc.bak b/source/mesh_refinement/velocity.cc.bak deleted file mode 100644 index 0690d20f828..00000000000 --- a/source/mesh_refinement/velocity.cc.bak +++ /dev/null @@ -1,83 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - Velocity::execute(Vector &indicators) const - { - indicators = 0; - - const Quadrature &quadrature = this->introspection().face_quadratures.velocities; - KellyErrorEstimator::estimate (this->get_mapping(), - this->get_dof_handler(), - quadrature, - std::map*>(), - this->get_solution(), - indicators, - this->introspection().component_masks.velocities, - nullptr, - 0, - this->get_triangulation().locally_owned_subdomain()); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Velocity, - "velocity", - "A mesh refinement criterion that computes " - "refinement indicators from the velocity field." - "\n\n" - "The way these indicators are computed is by " - "evaluating the `Kelly error indicator' on the " - "velocity field. This error indicator takes the " - "finite element approximation of the velocity " - "field and uses it to compute an approximation " - "of the second derivatives of the velocity for " - "each cell. This approximation is then multiplied " - "by an appropriate power of the cell's diameter " - "to yield an indicator for how large the error " - "is likely going to be on this cell. This " - "construction rests on the observation that for " - "many partial differential equations, the error " - "on each cell is proportional to some power of " - "the cell's diameter times the second derivatives " - "of the solution on that cell." - "\n\n" - "For complex equations such as those we solve " - "here, this observation may not be strictly " - "true in the mathematical sense, but it often " - "yields meshes that are surprisingly good.") - } -} diff --git a/source/mesh_refinement/viscosity.cc.bak b/source/mesh_refinement/viscosity.cc.bak deleted file mode 100644 index ab4cc0b167a..00000000000 --- a/source/mesh_refinement/viscosity.cc.bak +++ /dev/null @@ -1,148 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include -#include -#include -#include - -namespace aspect -{ - namespace MeshRefinement - { - template - void - Viscosity::execute(Vector &indicators) const - { - indicators = 0; - -//TODO: if the viscosity doesn't actually depend on the solution - // then we can get away with simply interpolating it spatially - - - // create a vector in which we set the temperature block to - // be a finite element interpolation of the viscosity. - // we do so by setting up a quadrature formula with the - // temperature unit support points, then looping over these - // points, compute the output quantity at them, and writing - // the result into the output vector in the same order - // (because quadrature points and temperature dofs are, - // by design of the quadrature formula, numbered in the - // same way) - LinearAlgebra::BlockVector vec_distributed (this->introspection().index_sets.system_partitioning, - this->get_mpi_communicator()); - - const Quadrature quadrature(this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_support_points()); - std::vector local_dof_indices (this->get_fe().dofs_per_cell); - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature, - update_quadrature_points | update_values | update_gradients); - - // the values of the compositional fields are stored as block vectors for each field - // we have to extract them in this structure - std::vector> prelim_composition_values (this->n_compositional_fields(), - std::vector (quadrature.size())); - - MaterialModel::MaterialModelInputs in(quadrature.size(), - this->n_compositional_fields()); - MaterialModel::MaterialModelOutputs out(quadrature.size(), - this->n_compositional_fields()); - in.requested_properties = MaterialModel::MaterialProperties::viscosity; - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit(cell); - in.reinit(fe_values, cell, this->introspection(), this->get_solution()); - this->get_material_model().evaluate(in, out); - - cell->get_dof_indices (local_dof_indices); - - // for each temperature dof, write into the output - // vector the viscosity. note that quadrature points and - // dofs are enumerated in the same order - for (unsigned int i=0; iget_fe().base_element(this->introspection().base_elements.temperature).dofs_per_cell; ++i) - { - const unsigned int system_local_dof - = this->get_fe().component_to_system_index(this->introspection().component_indices.temperature, - /*dof index within component=*/i); - - vec_distributed(local_dof_indices[system_local_dof]) - = std::log(out.viscosities[i]); - } - } - - vec_distributed.compress(VectorOperation::insert); - - // now create a vector with the requisite ghost elements - // and use it for estimating the gradients - LinearAlgebra::BlockVector vec (this->introspection().index_sets.system_partitioning, - this->introspection().index_sets.system_relevant_partitioning, - this->get_mpi_communicator()); - vec = vec_distributed; - - DerivativeApproximation::approximate_gradient (this->get_mapping(), - this->get_dof_handler(), - vec, - indicators, - this->introspection().component_indices.temperature); - - // Scale gradient in each cell with the correct power of h. Otherwise, - // error indicators do not reduce when refined if there is a viscosity - // jump. We need at least order 1 for the error not to grow when - // refining, so anything >1 should work. (note that the gradient - // itself scales like 1/h, so multiplying it with any factor h^s, s>1 - // will yield convergence of the error indicators to zero as h->0) - const double power = 1.0 + dim/2.0; - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - indicators(cell->active_cell_index()) *= std::pow(cell->diameter(), power); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(Viscosity, - "viscosity", - "A mesh refinement criterion that computes " - "refinement indicators from a field that describes " - "the spatial variability of the logarithm of the viscosity, $\\log\\eta$. " - "(We choose the logarithm of the viscosity because it can vary by " - "orders of magnitude.)" - "Because this quantity may not be a continuous function ($\\eta$ " - "may be a discontinuous function along discontinuities in the " - "medium, for example due to phase changes), we approximate the " - "gradient of this quantity to refine the mesh. The error indicator " - "defined here takes the magnitude of the approximate gradient " - "and scales it by $h_K^{1+d/2}$ where $h_K$ is the diameter of each cell " - "and $d$ is the dimension. " - "This scaling ensures that the error indicators converge to zero as " - "$h_K\\rightarrow 0$ even if the viscosity is discontinuous, since " - "the gradient of a discontinuous function grows like $1/h_K$.") - } -} diff --git a/source/mesh_refinement/volume_of_fluid_interface.cc.bak b/source/mesh_refinement/volume_of_fluid_interface.cc.bak deleted file mode 100644 index 3bc7d3e2d51..00000000000 --- a/source/mesh_refinement/volume_of_fluid_interface.cc.bak +++ /dev/null @@ -1,345 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file doc/COPYING. If not see - . -*/ - - -#include -#include - -#include -#include - -#include - -#include - -#include - -namespace aspect -{ - namespace MeshRefinement - { - - template - void - VolumeOfFluidInterface::tag_additional_cells() const - { - // Break early if DoFs have not been distributed yet. - if (this->get_dof_handler().n_dofs() == 0) - return; - - const QMidpoint qMidC; - - // Create a map from vertices to adjacent cells - const std::vector::active_cell_iterator>> - vertex_to_cells(GridTools::vertex_to_cell_map(this->get_triangulation())); - - std::set::active_cell_iterator> marked_cells; - FEValues fe_values (this->get_mapping(), - this->get_fe(), - qMidC, - update_values | - update_quadrature_points); - - // Create block vector to indicate when other mpi process believes cell - // borders an interface cell and therefore neighbors should be refined - // Use the first vof block, due to being the correct size, and only - // needing one indicator - LinearAlgebra::BlockVector interface_contained_local( - this->introspection().index_sets.system_partitioning, - this->get_mpi_communicator()); - - const FiniteElement &system_fe = this->get_fe(); - - const VolumeOfFluidField vof_field = this->get_volume_of_fluid_handler().field_struct_for_field_index(0); - const unsigned int volume_fraction_block = vof_field.volume_fraction.block_index; - const unsigned int volume_of_fluid_c_index = vof_field.volume_fraction.first_component_index; - const unsigned int volume_of_fluid_ind - = this->get_fe().component_to_system_index(volume_of_fluid_c_index, 0); - - interface_contained_local.block(volume_fraction_block) = 0.0; - - std::vector local_dof_indices (system_fe.dofs_per_cell); - - for (unsigned int f=0; fget_volume_of_fluid_handler().get_n_fields(); ++f) - { - - const double volume_fraction_threshold = this->get_volume_of_fluid_handler().get_volume_fraction_threshold(); - - const FEValuesExtractors::Scalar volume_of_fluid_field = this->get_volume_of_fluid_handler().field_struct_for_field_index(f) - .volume_fraction.extractor_scalar(); - - std::vector volume_of_fluid_values(qMidC.size()); - std::vector neighbor_volume_of_fluid_values(qMidC.size()); - - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (!cell->is_artificial()) - { - bool refine_current_cell = false; - - // Get cell volume_of_fluid - fe_values.reinit(cell); - fe_values[volume_of_fluid_field].get_function_values(this->get_solution(), - volume_of_fluid_values); - - // Handle overshoots - volume_of_fluid_values[0] = std::min(volume_of_fluid_values[0], 1.0); - volume_of_fluid_values[0] = std::max(volume_of_fluid_values[0], 0.0); - - // Check if at interface - if (volume_of_fluid_values[0] > volume_fraction_threshold && volume_of_fluid_values[0] < (1.0 - volume_fraction_threshold)) - { - refine_current_cell = true; - } - - if (!refine_current_cell) - { - for (const unsigned int f : cell->face_indices()) - { - const bool cell_has_periodic_neighbor = cell->has_periodic_neighbor(f); - const typename DoFHandler::face_iterator face = cell->face(f); - - // Skip if face is at boundary, and does not have a periodic neighbor - if (face->at_boundary() && !cell_has_periodic_neighbor) - continue; - - const typename DoFHandler::cell_iterator neighbor = cell->neighbor_or_periodic_neighbor(f); - - Assert(cell.state()==IteratorState::valid, ExcInternalError()); - - if ((!face->at_boundary() && !face->has_children()) - || - (face->at_boundary() && cell->periodic_neighbor_is_coarser(f)) - || - (face->at_boundary() && neighbor->level() == cell->level() && neighbor->is_active())) - { - if (neighbor->is_active() && !neighbor->is_artificial()) - { - fe_values.reinit(neighbor); - fe_values[volume_of_fluid_field].get_function_values(this->get_solution(), - neighbor_volume_of_fluid_values); - - // Handle overshoots - neighbor_volume_of_fluid_values[0] = std::min(neighbor_volume_of_fluid_values[0], 1.0); - neighbor_volume_of_fluid_values[0] = std::max(neighbor_volume_of_fluid_values[0], 0.0); - - if (std::abs(neighbor_volume_of_fluid_values[0]-volume_of_fluid_values[0])>volume_fraction_threshold) - { - refine_current_cell = true; - break; - } - } - } - else - { - for (unsigned int subface=0; subface < face->n_children(); ++subface) - { - const typename DoFHandler::active_cell_iterator neighbor_sub = - (cell_has_periodic_neighbor - ? - cell->periodic_neighbor_child_on_subface(f, subface) - : - cell->neighbor_child_on_subface(f, subface)); - - Assert(neighbor_sub.state()==IteratorState::valid, ExcInternalError()); - - if (neighbor_sub->is_artificial()) - continue; - - fe_values.reinit(neighbor_sub); - fe_values[volume_of_fluid_field].get_function_values(this->get_solution(), - neighbor_volume_of_fluid_values); - - // Handle overshoots - neighbor_volume_of_fluid_values[0] = std::min(neighbor_volume_of_fluid_values[0], 1.0); - neighbor_volume_of_fluid_values[0] = std::max(neighbor_volume_of_fluid_values[0], 0.0); - - if (std::abs(neighbor_volume_of_fluid_values[0]-volume_of_fluid_values[0])>volume_fraction_threshold) - { - refine_current_cell = true; - break; - } - - } - if (refine_current_cell) - break; - } - } - } - - if (refine_current_cell) - { - // Fractional volume - marked_cells.insert(cell); - if (cell->is_locally_owned()) - { - cell->clear_coarsen_flag (); - cell->set_refine_flag (); - // Mark in vector, will be true here if true on any process - cell->get_dof_indices(local_dof_indices); - interface_contained_local(local_dof_indices[volume_of_fluid_ind]) = 1.0; - } - } - - } - } - - // Now communicate and mark any cells not already included, this could be - // reduced to only loop over cells bordering another process - LinearAlgebra::BlockVector interface_contained_global( - this->introspection().index_sets.system_partitioning, - this->introspection().index_sets.system_relevant_partitioning, - this->get_mpi_communicator()); - - interface_contained_global.block(volume_fraction_block) = interface_contained_local.block(volume_fraction_block); - interface_contained_global.update_ghost_values(); - - const FEValuesExtractors::Scalar ic_extract = this->get_volume_of_fluid_handler().field_struct_for_field_index(0) - .volume_fraction.extractor_scalar(); - std::vector ic_values(qMidC.size()); - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (!cell->is_artificial()) - { - fe_values.reinit(cell); - fe_values[ic_extract].get_function_values(interface_contained_global, - ic_values); - - // If the cell has been indicated to need refinement add it - if (ic_values[0]>0.5) - { - marked_cells.insert(cell); - } - } - - // Now mark for refinement all cells that are a neighbor of a cell that contains the interface - - std::set::active_cell_iterator> marked_cells_and_neighbors = marked_cells; - typename std::set::active_cell_iterator>::const_iterator mcells = marked_cells.begin(), - endmc = marked_cells.end(); - for (; mcells != endmc; ++mcells) - { - typename parallel::distributed::Triangulation::active_cell_iterator mcell = *mcells; - for (const unsigned int vertex_index : mcell->vertex_indices()) - { - const std::set::active_cell_iterator> &neighbor_cells = vertex_to_cells[mcell->vertex_index(vertex_index)]; - for (const auto &neighbor_cell : neighbor_cells) - { - if (neighbor_cell->is_active() && neighbor_cell->is_locally_owned()) - { - neighbor_cell->clear_coarsen_flag (); - neighbor_cell->set_refine_flag (); - marked_cells_and_neighbors.insert(neighbor_cell); - } - } - } - - // Check for periodic neighbors, and refine if existing - for (const unsigned int f : mcell->face_indices()) - { - if (mcell->has_periodic_neighbor(f)) - { - typename Triangulation::cell_iterator itr_tmp = mcell->periodic_neighbor(f); - - if (itr_tmp->is_active() && itr_tmp->is_locally_owned()) - { - itr_tmp->clear_coarsen_flag (); - itr_tmp->set_refine_flag (); - marked_cells_and_neighbors.insert(itr_tmp); - } - } - } - } - - if (strict_coarsening) - { - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - if (marked_cells_and_neighbors.find(cell) != marked_cells_and_neighbors.end()) - { - //Refinement already requested - } - else - { - if (cell->is_active()) - { - cell->set_coarsen_flag(); - cell->clear_refine_flag(); - } - } - } - - } - - } - - template - void - VolumeOfFluidInterface:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Volume of fluid interface"); - { - prm.declare_entry("Strict coarsening", "false", - Patterns::Bool(), - "If true, then explicitly coarsen any cells not " - "neighboring the VolumeOfFluid interface."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - VolumeOfFluidInterface::parse_parameters (ParameterHandler &prm) - { - AssertThrow(this->get_parameters().volume_of_fluid_tracking_enabled, - ExcMessage("The 'volume_of_fluid boundary' mesh refinement strategy requires that the 'Use interface tracking' parameter is enabled.")); - - prm.enter_subsection("Mesh refinement"); - { - prm.enter_subsection("Volume of fluid interface"); - { - strict_coarsening = prm.get_bool("Strict coarsening"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - } -} - -// explicit instantiations -namespace aspect -{ - namespace MeshRefinement - { - ASPECT_REGISTER_MESH_REFINEMENT_CRITERION(VolumeOfFluidInterface, - "volume of fluid interface", - "A class that implements a mesh refinement criterion, which " - "ensures a minimum level of refinement near the volume of fluid interface boundary.") - } -} diff --git a/source/particle/generator/ascii_file.cc.bak b/source/particle/generator/ascii_file.cc.bak deleted file mode 100644 index 539c55f496f..00000000000 --- a/source/particle/generator/ascii_file.cc.bak +++ /dev/null @@ -1,133 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include - - -namespace aspect -{ - namespace Particle - { - namespace Generator - { - template - void - AsciiFile::generate_particles(Particles::ParticleHandler &particle_handler) - { - const std::string filename = data_directory+data_filename; - - // Read data from disk and distribute among processes - std::istringstream in(Utilities::read_and_distribute_file_content(filename, this->get_mpi_communicator())); - - // Skip header lines - while (in.peek() == '#') - { - std::string temp; - std::getline(in,temp); - } - - // Read data lines - types::particle_index particle_index = 0; - Point particle_position; - - while (in >> particle_position) - { - this->insert_particle_at_position(particle_position, particle_index, particle_handler); - ++particle_index; - } - particle_handler.update_cached_numbers(); - } - - - template - void - AsciiFile::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Generator"); - { - prm.enter_subsection("Ascii file"); - { - prm.declare_entry ("Data directory", - "$ASPECT_SOURCE_DIR/data/particle/generator/ascii/", - Patterns::DirectoryName (), - "The name of a directory that contains the particle data. This path " - "may either be absolute (if starting with a '/') or relative to " - "the current directory. The path may also include the special " - "text '$ASPECT_SOURCE_DIR' which will be interpreted as the path " - "in which the ASPECT source files were located when ASPECT was " - "compiled. This interpretation allows, for example, to reference " - "files located in the `data/' subdirectory of ASPECT. "); - prm.declare_entry ("Data file name", "particle.dat", - Patterns::Anything (), - "The name of the particle file."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - template - void - AsciiFile::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Generator"); - { - prm.enter_subsection("Ascii file"); - { - data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get ("Data directory")); - - data_filename = prm.get ("Data file name"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Generator - { - ASPECT_REGISTER_PARTICLE_GENERATOR(AsciiFile, - "ascii file", - "Generates a distribution of particles from coordinates " - "specified in an Ascii data file. The file format is " - "a simple text file, with as many columns as spatial " - "dimensions and as many lines as particles to be generated. " - "Initial comment lines starting with `#' will be discarded. " - "Note that this plugin always generates as many particles " - "as there are coordinates in the data file, the " - "``Particles/Number of particles'' parameter " - "has no effect on this plugin. " - "All of the values that define this generator are read " - "from a section ``Particles/Generator/Ascii file'' in the " - "input file, see " - "Section~\\ref{parameters:Particles/Generator/Ascii_20file}.") - } - } -} diff --git a/source/particle/generator/interface.cc.bak b/source/particle/generator/interface.cc.bak deleted file mode 100644 index f48c36c2525..00000000000 --- a/source/particle/generator/interface.cc.bak +++ /dev/null @@ -1,306 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -#include -#include - -#include - -namespace aspect -{ - namespace Particle - { - namespace Generator - { - template - void - Interface::initialize () - { - const unsigned int my_rank = Utilities::MPI::this_mpi_process(this->get_mpi_communicator()); - random_number_generator.seed(5432+my_rank); - } - - - - template - void - Interface::generate_particles(std::multimap> &/*particles*/) - { - AssertThrow(false,ExcInternalError()); - } - - - - template - void - Interface::generate_particles(Particles::ParticleHandler &particle_handler) - { - // This function is implemented to ensure backwards compatibility to an old interface. - // Once the old interface function has been removed this implementation can be removed - // as well and the function can be made pure. - - std::multimap> particles; - - // avoid deprecation warnings about calling the old interface - DEAL_II_DISABLE_EXTRA_DIAGNOSTICS - generate_particles(particles); - DEAL_II_ENABLE_EXTRA_DIAGNOSTICS - - std::multimap::active_cell_iterator, Particles::Particle> new_particles; - - for (const auto &particle : particles) - new_particles.insert(new_particles.end(), - std::make_pair(typename Triangulation::active_cell_iterator(&this->get_triangulation(), - particle.first.first, particle.first.second), - particle.second)); - - particle_handler.insert_particles(new_particles); - } - - - - template - std::pair> - Interface::generate_particle(const Point &position, - const types::particle_index id) const - { - // Try to find the cell of the given position. If the position is not - // in the domain on the local process, throw a ExcParticlePointNotInDomain - // exception. - std::pair::active_cell_iterator, - Point> it = - GridTools::find_active_cell_around_point<> (this->get_mapping(), this->get_triangulation(), position); - - // Only try to add the point if the cell it is in, is on this processor - AssertThrow(it.first.state() == IteratorState::valid && it.first->is_locally_owned(), - ExcParticlePointNotInDomain()); - - const Particle particle(position, it.second, id); - const Particles::internal::LevelInd cell(it.first->level(), it.first->index()); - return std::make_pair(cell,particle); - - // Avoid warnings about missing return - return {}; - } - - - - template - Particles::ParticleIterator - Interface::insert_particle_at_position(const Point &position, - const types::particle_index id, - Particles::ParticleHandler &particle_handler) const - { - // Try to find the cell of the given position. - const std::pair::active_cell_iterator, - Point> it = - GridTools::find_active_cell_around_point<> (this->get_mapping(), this->get_triangulation(), position); - - if (it.first.state() != IteratorState::valid || it.first->is_locally_owned() == false) - return particle_handler.end(); - - return particle_handler.insert_particle(Particle(position, it.second, id), it.first); - } - - - - template - std::pair> - Interface::generate_particle (const typename parallel::distributed::Triangulation::active_cell_iterator &cell, - const types::particle_index id) - { - // Uniform distribution on the interval [0,1]. This - // will be used to generate random particle locations. - std::uniform_real_distribution uniform_distribution_01(0.0, 1.0); - - const BoundingBox cell_bounding_box = cell->bounding_box(); - - // Generate random points in these bounds until one is within the cell - unsigned int iteration = 0; - const unsigned int maximum_iterations = 100; - Point particle_position; - while (iteration < maximum_iterations) - { - // First generate a random point in the bounding box... - for (unsigned int d=0; d p_unit = this->get_mapping().transform_real_to_unit_cell(cell, particle_position); - if ( - cell->reference_cell().contains_point(p_unit) - ) - { - // Add the generated particle to the set - const Particle new_particle(particle_position, p_unit, id); - const Particles::internal::LevelInd cellid(cell->level(), cell->index()); - return std::make_pair(cellid,new_particle); - } - } - catch (typename Mapping::ExcTransformationFailed &) - { - // The point is not in this cell. Do nothing, just try again. - } - ++iteration; - } - - // If the above algorithm has not worked (e.g. because of badly - // deformed cells), retry generating particles - // randomly within the reference cell. This is not generating a - // uniform distribution in real space, but will always succeed. - for (unsigned int d=0; d p_real = this->get_mapping().transform_unit_to_real_cell(cell,particle_position); - - // Add the generated particle to the set - const Particle new_particle(p_real, particle_position, id); - const Particles::internal::LevelInd cellid(cell->level(), cell->index()); - - return std::make_pair(cellid, new_particle); - } - - -// -------------------------------- Deal with registering models and automating -// -------------------------------- their setup and selection at run time - - namespace - { - std::tuple - >, - aspect::internal::Plugins::PluginList>> registered_plugins; - } - - - - template - void - register_particle_generator (const std::string &name, - const std::string &description, - void (*declare_parameters_function) (ParameterHandler &), - std::unique_ptr> (*factory_function) ()) - { - std::get(registered_plugins).register_plugin (name, - description, - declare_parameters_function, - factory_function); - } - - - - template - std::unique_ptr> - create_particle_generator (ParameterHandler &prm) - { - std::string name; - name = prm.get ("Particle generator name"); - - return std::get(registered_plugins).create_plugin (name, - "Particle::Generator name"); - } - - - - template - void - declare_parameters (ParameterHandler &prm) - { - // declare the entry in the parameter file - const std::string pattern_of_names - = std::get(registered_plugins).get_pattern_of_names (); - - prm.declare_entry ("Particle generator name", "random uniform", - Patterns::Selection (pattern_of_names), - "Select one of the following models:\n\n" - + - std::get(registered_plugins).get_description_string()); - - std::get(registered_plugins).declare_parameters (prm); - } - - - - template - void - write_plugin_graph (std::ostream &out) - { - std::get(registered_plugins).write_plugin_graph ("Particle generator interface", - out); - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace internal - { - namespace Plugins - { - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - } - } - - namespace Particle - { - namespace Generator - { -#define INSTANTIATE(dim) \ - template class Interface; \ - \ - template \ - void \ - register_particle_generator (const std::string &, \ - const std::string &, \ - void ( *) (ParameterHandler &), \ - std::unique_ptr>( *) ()); \ - \ - template \ - void \ - declare_parameters (ParameterHandler &); \ - \ - template \ - void \ - write_plugin_graph (std::ostream &); \ - \ - template \ - std::unique_ptr> \ - create_particle_generator (ParameterHandler &prm); - - ASPECT_INSTANTIATE(INSTANTIATE) - -#undef INSTANTIATE - } - } -} diff --git a/source/particle/generator/probability_density_function.cc.bak b/source/particle/generator/probability_density_function.cc.bak deleted file mode 100644 index d276fd2399e..00000000000 --- a/source/particle/generator/probability_density_function.cc.bak +++ /dev/null @@ -1,149 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -#include -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Generator - { - template - void - ProbabilityDensityFunction::generate_particles(Particles::ParticleHandler &particle_handler) - { - Particles::Generators::probabilistic_locations(this->get_triangulation(), - function, - random_cell_selection, - n_particles, - particle_handler, - this->get_mapping(), - random_number_seed); - } - - - - template - void - ProbabilityDensityFunction::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Generator"); - { - prm.enter_subsection("Probability density function"); - { - Functions::ParsedFunction::declare_parameters (prm, 1); - - prm.declare_entry ("Number of particles", "1000", - Patterns::Double (0.), - "Total number of particles to create (not per processor or per element). " - "The number is parsed as a floating point number (so that one can " - "specify, for example, '1e4' particles) but it is interpreted as " - "an integer, of course."); - - prm.declare_entry ("Random cell selection", "true", - Patterns::Bool(), - "If true, particle numbers per cell are calculated randomly " - "according to their respective probability density. " - "This means particle numbers per cell can deviate statistically from " - "the integral of the probability density. If false, " - "first determine how many particles each cell should have " - "based on the integral of the density over each of the cells, " - "and then once we know how many particles we want on each cell, " - "choose their locations randomly within each cell."); - - prm.declare_entry ("Random number seed", "5432", - Patterns::Integer(0), - "The seed for the random number generator that controls " - "the particle generation. Keep constant to generate " - "identical particle distributions in subsequent model " - "runs. Change to get a different distribution. In parallel " - "computations the seed is further modified on each process " - "to ensure different particle patterns on different " - "processes. Note that the number of particles per processor " - "is not affected by the seed."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - template - void - ProbabilityDensityFunction::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Generator"); - { - prm.enter_subsection("Probability density function"); - { - n_particles = static_cast(prm.get_double ("Number of particles")); - random_cell_selection = prm.get_bool("Random cell selection"); - random_number_seed = prm.get_integer("Random number seed"); - - try - { - function.parse_parameters (prm); - } - catch (...) - { - std::cerr << "ERROR: FunctionParser failed to parse\n" - << "\t'Particle.Generator.Probability density function'\n" - << "with expression\n" - << "\t'" << prm.get("Function expression") << "'"; - throw; - } - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Generator - { - ASPECT_REGISTER_PARTICLE_GENERATOR(ProbabilityDensityFunction, - "probability density function", - "Generate a random distribution of " - "particles over the entire simulation domain. " - "The probability density is prescribed in the " - "form of a user-prescribed function. The " - "format of this function follows the syntax " - "understood by the muparser library, see " - "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`. The " - "return value of the function is always " - "checked to be a non-negative probability " - "density but it can be zero in " - "parts of the domain.") - } - } -} diff --git a/source/particle/generator/quadrature_points.cc.bak b/source/particle/generator/quadrature_points.cc.bak deleted file mode 100644 index 5264920e257..00000000000 --- a/source/particle/generator/quadrature_points.cc.bak +++ /dev/null @@ -1,63 +0,0 @@ -/* - Copyright (C) 2016 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -#include - -namespace aspect -{ - namespace Particle - { - namespace Generator - { - template - void - QuadraturePoints::generate_particles(Particles::ParticleHandler &particle_handler) - { - const Quadrature &quadrature_formula - = this->introspection().quadratures.velocities; - - Particles::Generators::regular_reference_locations( - this->get_triangulation(), - quadrature_formula.get_points(), - particle_handler, - this->get_mapping()); - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Generator - { - ASPECT_REGISTER_PARTICLE_GENERATOR(QuadraturePoints, - "quadrature points", - "Generates particles at the quadrature points of each active cell of " - "the triangulation. Here, Gauss quadrature of degree (velocity\\_degree + 1), " - "is used similarly to the assembly of Stokes matrix.") - } - } -} diff --git a/source/particle/generator/random_uniform.cc.bak b/source/particle/generator/random_uniform.cc.bak deleted file mode 100644 index 3fa2c84efca..00000000000 --- a/source/particle/generator/random_uniform.cc.bak +++ /dev/null @@ -1,123 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -#include - -namespace aspect -{ - namespace Particle - { - namespace Generator - { - template - void - RandomUniform::generate_particles(Particles::ParticleHandler &particle_handler) - { - Particles::Generators::probabilistic_locations(this->get_triangulation(), - Functions::ConstantFunction(1.0), - random_cell_selection, - n_particles, - particle_handler, - this->get_mapping(), - random_number_seed); - } - - - - template - void - RandomUniform::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Generator"); - { - prm.enter_subsection("Probability density function"); - { - prm.declare_entry ("Number of particles", "1000", - Patterns::Double (0.), - "Total number of particles to create (not per processor or per element). " - "The number is parsed as a floating point number (so that one can " - "specify, for example, '1e4' particles) but it is interpreted as " - "an integer, of course."); - - prm.declare_entry ("Random cell selection", "true", - Patterns::Bool(), - "If true, particle numbers per cell are calculated randomly " - "according to their respective probability density. " - "This means particle numbers per cell can deviate statistically from " - "the integral of the probability density. If false, " - "first determine how many particles each cell should have " - "based on the integral of the density over each of the cells, " - "and then once we know how many particles we want on each cell, " - "choose their locations randomly within each cell."); - - prm.declare_entry ("Random number seed", "5432", - Patterns::Integer(0), - "The seed for the random number generator that controls " - "the particle generation. Keep constant to generate " - "identical particle distributions in subsequent model " - "runs. Change to get a different distribution. In parallel " - "computations the seed is further modified on each process " - "to ensure different particle patterns on different " - "processes. Note that the number of particles per processor " - "is not affected by the seed."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - template - void - RandomUniform::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Generator"); - { - prm.enter_subsection("Probability density function"); - { - n_particles = static_cast(prm.get_double ("Number of particles")); - random_cell_selection = prm.get_bool("Random cell selection"); - random_number_seed = prm.get_integer("Random number seed"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Generator - { - ASPECT_REGISTER_PARTICLE_GENERATOR(RandomUniform, - "random uniform", - "Generates a random uniform distribution of " - "particles over the entire simulation domain.") - } - } -} diff --git a/source/particle/generator/reference_cell.cc.bak b/source/particle/generator/reference_cell.cc.bak deleted file mode 100644 index cc63692f827..00000000000 --- a/source/particle/generator/reference_cell.cc.bak +++ /dev/null @@ -1,148 +0,0 @@ -/* - Copyright (C) 2016 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -#include - -namespace aspect -{ - namespace Particle - { - namespace Generator - { - template - void - ReferenceCell::generate_particles(Particles::ParticleHandler &particle_handler) - { - const std::vector> reference_locations = generate_particle_positions_in_unit_cell(); - - Particles::Generators::regular_reference_locations(this->get_triangulation(), - reference_locations, - particle_handler, - this->get_mapping()); - } - - - template - std::vector> - ReferenceCell::generate_particle_positions_in_unit_cell() - { - std::vector> particle_positions; - std::array spacing; - - // Calculate separation of particles - for (unsigned int i = 0; i < dim; ++i) - spacing[i] = 1.0 / number_of_particles[i]; - - for (unsigned int i = 0; i < number_of_particles[0]; ++i) - { - for (unsigned int j = 0; j < number_of_particles[1]; ++j) - { - if (dim == 2) - { - const Point position_unit = Point(i * spacing[0] + spacing[0] / 2, - j * spacing[1] + spacing[1] / 2); - particle_positions.push_back(position_unit); - } - else if (dim == 3) - { - for (unsigned int k = 0; k < number_of_particles[2]; ++k) - { - const Point position_unit = Point(i * spacing[0] + spacing[0] / 2, - j * spacing[1] + spacing[1] / 2, - k * spacing[2] + spacing[2] / 2); - particle_positions.push_back(position_unit); - } - } - else - ExcNotImplemented(); - } - } - - return particle_positions; - } - - - template - void - ReferenceCell::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Generator"); - { - prm.enter_subsection("Reference cell"); - { - prm.declare_entry ("Number of particles per cell per direction", "2", - Patterns::List(Patterns::Integer(1)), - "List of number of particles to create per cell and spatial dimension. " - "The size of the list is the number of spatial dimensions. If only " - "one value is given, then each spatial dimension is set to the same value. " - "The list of numbers are parsed as a floating point number (so that one can " - "specify, for example, '1e4' particles) but it is interpreted as " - "an integer, of course."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - template - void - ReferenceCell::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Generator"); - { - prm.enter_subsection("Reference cell"); - { - const auto n_particles_per_direction = Utilities::possibly_extend_from_1_to_N ( - Utilities::string_to_int( - Utilities::split_string_list(prm.get("Number of particles per cell per direction"))), - dim, - "Number of particles per cell per direction"); - - for (const auto &n_particle_direction: n_particles_per_direction) - number_of_particles.push_back(static_cast (n_particle_direction)); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Generator - { - ASPECT_REGISTER_PARTICLE_GENERATOR(ReferenceCell, - "reference cell", - "Generates a uniform distribution of particles per cell and spatial direction in " - "the unit cell and transforms each of the particles back to real region in the model " - "domain. Uniform here means the particles will be generated with an equal spacing in " - "each spatial dimension.") - } - } -} diff --git a/source/particle/generator/uniform_box.cc.bak b/source/particle/generator/uniform_box.cc.bak deleted file mode 100644 index ca452055b7a..00000000000 --- a/source/particle/generator/uniform_box.cc.bak +++ /dev/null @@ -1,175 +0,0 @@ -/* - Copyright (C) 2015 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -#include - -#include -#include - - -namespace aspect -{ - namespace Particle - { - namespace Generator - { - template - void - UniformBox::generate_particles(Particles::ParticleHandler &particle_handler) - { - const Tensor<1,dim> P_diff = P_max - P_min; - - double volume(1.0); - for (unsigned int i = 0; i < dim; ++i) - volume *= P_diff[i]; - - std::array n_particles_per_direction; - std::array spacing; - - // Calculate separation of particles - for (unsigned int i = 0; i < dim; ++i) - { - n_particles_per_direction[i] = static_cast(round(std::pow(n_particles * std::pow(P_diff[i],dim) / volume, 1./dim))); - spacing[i] = P_diff[i] / fmax(n_particles_per_direction[i] - 1,1); - } - - types::particle_index particle_index = 0; - - for (unsigned int i = 0; i < n_particles_per_direction[0]; ++i) - { - for (unsigned int j = 0; j < n_particles_per_direction[1]; ++j) - { - if (dim == 2) - { - const Point particle_position = Point (P_min[0]+i*spacing[0],P_min[1]+j*spacing[1]); - this->insert_particle_at_position(particle_position, particle_index, particle_handler); - ++particle_index; - } - else if (dim == 3) - for (unsigned int k = 0; k < n_particles_per_direction[2]; ++k) - { - const Point particle_position = Point (P_min[0]+i*spacing[0],P_min[1]+j*spacing[1],P_min[2]+k*spacing[2]); - this->insert_particle_at_position(particle_position, particle_index, particle_handler); - ++particle_index; - } - - } - } - - particle_handler.update_cached_numbers(); - } - - - template - void - UniformBox::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Generator"); - { - prm.enter_subsection("Uniform box"); - { - prm.declare_entry ("Number of particles", "1000", - Patterns::Double (0.), - "Total number of particles to create (not per processor or per element). " - "The number is parsed as a floating point number (so that one can " - "specify, for example, '1e4' particles) but it is interpreted as " - "an integer, of course."); - - prm.declare_entry ("Minimum x", "0.", - Patterns::Double (), - "Minimum x coordinate for the region of particles."); - prm.declare_entry ("Maximum x", "1.", - Patterns::Double (), - "Maximum x coordinate for the region of particles."); - prm.declare_entry ("Minimum y", "0.", - Patterns::Double (), - "Minimum y coordinate for the region of particles."); - prm.declare_entry ("Maximum y", "1.", - Patterns::Double (), - "Maximum y coordinate for the region of particles."); - prm.declare_entry ("Minimum z", "0.", - Patterns::Double (), - "Minimum z coordinate for the region of particles."); - prm.declare_entry ("Maximum z", "1.", - Patterns::Double (), - "Maximum z coordinate for the region of particles."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - template - void - UniformBox::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Generator"); - { - prm.enter_subsection("Uniform box"); - { - n_particles = static_cast(prm.get_double ("Number of particles")); - - P_min(0) = prm.get_double ("Minimum x"); - P_max(0) = prm.get_double ("Maximum x"); - P_min(1) = prm.get_double ("Minimum y"); - P_max(1) = prm.get_double ("Maximum y"); - - AssertThrow(P_min(0) < P_max(0), ExcMessage("Minimum x must be less than maximum x")); - AssertThrow(P_min(1) < P_max(1), ExcMessage("Minimum y must be less than maximum y")); - - if (dim == 3) - { - P_min(2) = prm.get_double ("Minimum z"); - P_max(2) = prm.get_double ("Maximum z"); - - AssertThrow(P_min(2) < P_max(2), ExcMessage("Minimum z must be less than maximum z")); - } - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Generator - { - ASPECT_REGISTER_PARTICLE_GENERATOR(UniformBox, - "uniform box", - "Generate a uniform distribution of particles " - "over a rectangular domain in 2d or 3d. Uniform here means " - "the particles will be generated with an equal spacing in " - "each spatial dimension. Note that in order " - "to produce a regular distribution the number of generated " - "particles might not exactly match the one specified in the " - "input file.") - } - } -} diff --git a/source/particle/generator/uniform_radial.cc.bak b/source/particle/generator/uniform_radial.cc.bak deleted file mode 100644 index 5604feb5ecb..00000000000 --- a/source/particle/generator/uniform_radial.cc.bak +++ /dev/null @@ -1,254 +0,0 @@ -/* - Copyright (C) 2015 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -#include - - -namespace aspect -{ - namespace Particle - { - namespace Generator - { - template - void - UniformRadial::generate_particles(Particles::ParticleHandler &particle_handler) - { - // Create the array of shell to deal with - const double radial_spacing = (P_max[0] - P_min[0]) / fmax(radial_layers-1,1); - - // Calculate number of particles per shell. - // The number of particles depend on the fraction of the area - // (or length in 2d) that this shell occupies compared to the total domain - std::vector particles_per_layer(radial_layers); - if (dim == 2) - { - double total_radius = 0; - for (unsigned int i = 0; i < radial_layers; ++i) - total_radius += P_min[0] + (radial_spacing * i); - for (unsigned int i = 0; i < radial_layers; ++i) - { - const double radius = P_min[0] + (radial_spacing * i); - particles_per_layer[i] = static_cast(round(n_particles * radius / total_radius)); - } - } - else if (dim == 3) - { - double total_area = 0; - for (unsigned int i = 0; i < radial_layers; ++i) - total_area += std::pow(P_min[0] + (radial_spacing * i),2); - for (unsigned int i = 0; i < radial_layers; ++i) - { - const double area = std::pow(P_min[0] + (radial_spacing * i),2); - particles_per_layer[i] = static_cast(round(n_particles * area / total_area)); - } - } - else - ExcNotImplemented(); - - // Generate particles - - types::particle_index particle_index = 0; - std::array spherical_coordinates; - for (unsigned int i = 0; i < radial_layers; ++i) - { - spherical_coordinates[0] = P_min[0] + (radial_spacing * i); - if (dim == 2) - { - const double phi_spacing = (P_max[1] - P_min[1]) / fmax(particles_per_layer[i]-1,1); - - for (unsigned int j = 0; j < particles_per_layer[i]; ++j) - { - spherical_coordinates[1] = P_min[1] + j * phi_spacing; - const Point particle_position = Utilities::Coordinates::spherical_to_cartesian_coordinates(spherical_coordinates) + P_center; - this->insert_particle_at_position(particle_position, particle_index, particle_handler); - ++particle_index; - } - } - else if (dim == 3) - { - const unsigned int theta_particles = static_cast( - round(sqrt(particles_per_layer[i]))); - const unsigned int phi_particles = static_cast( - round( - static_cast(particles_per_layer[i]) - / - static_cast(theta_particles))); - const double theta_spacing = (P_max[2] - P_min[2]) / fmax(theta_particles-1,1); - - for (unsigned int j = 0; j < theta_particles; ++j) - { - spherical_coordinates[2] = P_min[2] + j * theta_spacing; - - // Average value of sin(n) from 0 to 180 degrees is (2/pi) - const unsigned int adjusted_phi_particles = std::max(static_cast (phi_particles * std::sin(spherical_coordinates[2])), 1u); - const double phi_spacing = (P_max[1] - P_min[1]) / fmax(adjusted_phi_particles-1,1); - for (unsigned int k = 0; k < adjusted_phi_particles; ++k) - { - spherical_coordinates[1] = P_min[1] + k * phi_spacing; - const Point particle_position = Utilities::Coordinates::spherical_to_cartesian_coordinates(spherical_coordinates) + P_center; - this->insert_particle_at_position(particle_position, particle_index, particle_handler); - ++particle_index; - } - } - } - } - - particle_handler.update_cached_numbers(); - } - - - template - void - UniformRadial::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Generator"); - { - prm.enter_subsection("Uniform radial"); - { - prm.declare_entry ("Number of particles", "1000", - Patterns::Double (0.), - "Total number of particles to create (not per processor or per element). " - "The number is parsed as a floating point number (so that one can " - "specify, for example, '1e4' particles) but it is interpreted as " - "an integer, of course."); - - prm.declare_entry ("Center x", "0.", - Patterns::Double (), - "x coordinate for the center of the spherical region, " - "where particles are generated."); - prm.declare_entry ("Center y", "0.", - Patterns::Double (), - "y coordinate for the center of the spherical region, " - "where particles are generated."); - prm.declare_entry ("Center z", "0.", - Patterns::Double (), - "z coordinate for the center of the spherical region, " - "where particles are generated."); - prm.declare_entry ("Minimum radius", "0.", - Patterns::Double (0.), - "Minimum radial coordinate for the region of particles. " - "Measured from the center position."); - prm.declare_entry ("Maximum radius", "1.", - Patterns::Double (), - "Maximum radial coordinate for the region of particles. " - "Measured from the center position."); - prm.declare_entry ("Minimum longitude", "0.", - Patterns::Double (-180., 360.), - "Minimum longitude coordinate for the region of particles " - "in degrees. Measured from the center position."); - prm.declare_entry ("Maximum longitude", "360.", - Patterns::Double (-180., 360.), - "Maximum longitude coordinate for the region of particles " - "in degrees. Measured from the center position."); - prm.declare_entry ("Minimum latitude", "0.", - Patterns::Double (0., 180.), - "Minimum latitude coordinate for the region of particles " - "in degrees. Measured from the center position, and from " - "the north pole."); - prm.declare_entry ("Maximum latitude", "180.", - Patterns::Double (0., 180.), - "Maximum latitude coordinate for the region of particles " - "in degrees. Measured from the center position, and from " - "the north pole."); - prm.declare_entry ("Radial layers", "1", - Patterns::Integer(1), - "The number of radial shells of particles that will be generated " - "around the central point."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - template - void - UniformRadial::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Generator"); - { - prm.enter_subsection("Uniform radial"); - { - n_particles = static_cast(prm.get_double ("Number of particles")); - - P_center[0] = prm.get_double ("Center x"); - P_center[1] = prm.get_double ("Center y"); - - P_min[0] = prm.get_double ("Minimum radius"); - P_max[0] = prm.get_double ("Maximum radius"); - P_min[1] = prm.get_double ("Minimum longitude") * constants::degree_to_radians; - P_max[1] = prm.get_double ("Maximum longitude") * constants::degree_to_radians; - - AssertThrow(P_max[1] > P_min[1], - ExcMessage("The maximum longitude you prescribed in the uniform radial" - "particle generator has to be higher than the minimum longitude.")); - AssertThrow(P_max[1] - P_min[1] <= 2.0 * numbers::PI, - ExcMessage("The difference between the maximum and minimum longitude you " - "prescribed in the uniform radial particle generator has to be " - "less than 360 degrees.")); - - if (dim ==3) - { - P_center[2] = prm.get_double ("Center z"); - - P_min[2] = prm.get_double ("Minimum latitude") * constants::degree_to_radians; - P_max[2] = prm.get_double ("Maximum latitude") * constants::degree_to_radians; - - AssertThrow(P_max[2] > P_min[2], - ExcMessage("The maximum latitude you prescribed in the uniform radial" - "particle generator has to be higher than the minimum latitude.")); - } - - radial_layers = prm.get_integer("Radial layers"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Generator - { - ASPECT_REGISTER_PARTICLE_GENERATOR(UniformRadial, - "uniform radial", - "Generate a uniform distribution of particles " - "over a spherical domain in 2d or 3d. Uniform here means " - "the particles will be generated with an equal spacing in " - "each spherical spatial dimension, i.e., the particles are " - "created at positions that increase linearly with equal " - "spacing in radius, colatitude and longitude around a " - "certain center point. Note that in order " - "to produce a regular distribution the number of generated " - "particles might not exactly match the one specified in the " - "input file.") - } - } -} diff --git a/source/particle/integrator/euler.cc.bak b/source/particle/integrator/euler.cc.bak deleted file mode 100644 index 791d7e095df..00000000000 --- a/source/particle/integrator/euler.cc.bak +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright (C) 2015 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Integrator - { - template - void - Euler::local_integrate_step(const typename ParticleHandler::particle_iterator &begin_particle, - const typename ParticleHandler::particle_iterator &end_particle, - const std::vector> &old_velocities, - const std::vector> &, - const double dt) - { - Assert(static_cast (std::distance(begin_particle, end_particle)) == old_velocities.size(), - ExcMessage("The particle integrator expects the velocity vector to be of equal size " - "to the number of particles to advect. For some unknown reason they are different, " - "most likely something went wrong in the calling function.")); - - const auto cell = begin_particle->get_surrounding_cell(); - bool at_periodic_boundary = false; - if (this->get_triangulation().get_periodic_face_map().empty() == false) - for (const auto face_index: cell->face_indices()) - if (cell->at_boundary(face_index)) - if (cell->has_periodic_neighbor(face_index)) - { - at_periodic_boundary = true; - break; - } - - typename std::vector>::const_iterator old_velocity = old_velocities.begin(); - - for (typename ParticleHandler::particle_iterator it = begin_particle; - it != end_particle; ++it, ++old_velocity) - { -#if DEAL_II_VERSION_GTE(9, 6, 0) - // Get a reference to the particle location, so that we can update it in-place - Point &location = it->get_location(); -#else - Point location = it->get_location(); -#endif - location += dt * (*old_velocity); - - if (at_periodic_boundary) - this->get_geometry_model().adjust_positions_for_periodicity(location); - -#if !DEAL_II_VERSION_GTE(9, 6, 0) - it->set_location(location); -#endif - } - } - - - - template - std::array - Euler::required_solution_vectors() const - { - return {{false, true, false}}; - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Integrator - { - ASPECT_REGISTER_PARTICLE_INTEGRATOR(Euler, - "euler", - "Explicit Euler scheme integrator, where " - "$y_{n+1} = y_n + \\Delta t \\, v(y_n)$. " - "This requires only one integration substep per timestep.") - } - } -} diff --git a/source/particle/integrator/interface.cc.bak b/source/particle/integrator/interface.cc.bak deleted file mode 100644 index 88a8342876f..00000000000 --- a/source/particle/integrator/interface.cc.bak +++ /dev/null @@ -1,248 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include - -#include - -namespace aspect -{ - namespace Particle - { - namespace Integrator - { - template - bool - Interface::new_integration_step() - { - return false; - } - - - - template - std::size_t - Interface::get_data_size() const - { - return 0; - } - - - - template - const void * - Interface::read_data(const typename ParticleHandler::particle_iterator &/*particle*/, - const void *data) - { - return data; - } - - - - template - void * - Interface::write_data(const typename ParticleHandler::particle_iterator &/*particle*/, - void *data) const - { - return data; - } - - - -// -------------------------------- Deal with registering models and automating -// -------------------------------- their setup and selection at run time - - namespace - { - std::tuple - >, - aspect::internal::Plugins::PluginList>> registered_plugins; - } - - - - template - void - register_particle_integrator (const std::string &name, - const std::string &description, - void (*declare_parameters_function) (ParameterHandler &), - std::unique_ptr> (*factory_function) ()) - { - std::get(registered_plugins).register_plugin (name, - description, - declare_parameters_function, - factory_function); - } - - - - template - std::unique_ptr> - create_particle_integrator (ParameterHandler &prm) - { - std::string name; - name = prm.get ("Integration scheme"); - - return std::get(registered_plugins).create_plugin (name, - "Particle::Integrator name"); - } - - - - template - void - declare_parameters (ParameterHandler &prm) - { - // declare the entry in the parameter file - const std::string pattern_of_names - = std::get(registered_plugins).get_pattern_of_names (); - - prm.declare_entry ("Integration scheme", "rk2", - Patterns::Selection (pattern_of_names), - "This parameter is used to decide which method to " - "use to solve the equation that describes the position " - "of particles, i.e., $\\frac{d}{dt}\\mathbf x_k(t) = " - "\\mathbf u(\\mathbf x_k(t),t)$, where $k$ is an index " - "that runs over all particles, and $\\mathbf u(\\mathbf x,t)$ " - "is the velocity field that results from the Stokes " - "equations." - "\n\n" - "In practice, the exact velocity $\\mathbf u(\\mathbf x,t)$ " - "is of course not available, but only a numerical " - "approximation $\\mathbf u_h(\\mathbf x,t)$. Furthermore, " - "this approximation is only available at discrete time steps, " - "$\\mathbf u^n(\\mathbf x)=\\mathbf u(\\mathbf x,t^n)$, and " - "these need to be interpolated between time steps if the " - "integrator for the equation above requires an evaluation at " - "time points between the discrete time steps. If we denote this " - "interpolation in time by $\\tilde{\\mathbf u}_h(\\mathbf x,t)$ " - "where $\\tilde{\\mathbf u}_h(\\mathbf x,t^n)=" - "\\mathbf u^n(\\mathbf x)$, then the equation the differential " - "equation solver really tries to solve is " - "$\\frac{d}{dt}\\tilde{\\mathbf x}_k(t) = " - " \\tilde{\\mathbf u}_h(\\mathbf x_k(t),t)$." - "\n\n" - "As a consequence of these considerations, if you try to " - "assess convergence properties of an ODE integrator -- for " - "example to verify that the RK4 integrator converges with " - "fourth order --, it is important to recall that the " - "integrator may not solve the equation you think it " - "solves. If, for example, we call the numerical solution " - "of the ODE $\\tilde{\\mathbf x}_{k,h}(t)$, then the " - "error will typically satisfy a relationship like " - "\\[" - " \\| \\tilde{\\mathbf x}_k(T) - \\tilde{\\mathbf x}_{k,h}(T) \\|" - " \\le" - " C(T) \\Delta t^p" - "\\] " - "where $\\Delta t$ is the time step and $p$ the convergence order " - "of the method, and $C(T)$ is a (generally unknown) constant " - "that depends on the end time $T$ at which one compares the " - "solutions. On the other hand, an analytically computed " - "trajectory would likely use the \\textit{exact} velocity, " - "and one may be tempted to compute " - "$\\| \\mathbf x_k(T) - \\tilde{\\mathbf x}_{k,h}(T) \\|$, " - "but this quantity will, in the best case, only satisfy an " - "estimate of the form " - "\\[" - " \\| \\mathbf x_k(T) - \\tilde{\\mathbf x}_{k,h}(T) \\|" - " \\le" - " C_1(T) \\Delta t^p" - " + C_2(T) \\| \\mathbf u-\\mathbf u_h \\|" - " + C_3(T) \\| \\mathbf u_h-\\tilde{\\mathbf u}_h \\|" - "\\] " - "with appropriately chosen norms for the second and third " - "term. These second and third terms typically converge to " - "zero at relatively low rates (compared to the order $p$ of " - "the integrator, which can often be chosen relatively high) " - "in the mesh size $h$ and the time step size $\\\\Delta t$, " - "limiting the overall accuracy of the ODE integrator." - "\n\n" - "Select one of the following models:\n\n" - + - std::get(registered_plugins).get_description_string()); - - std::get(registered_plugins).declare_parameters (prm); - } - - - - template - void - write_plugin_graph (std::ostream &out) - { - std::get(registered_plugins).write_plugin_graph ("Particle integrator interface", - out); - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace internal - { - namespace Plugins - { - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - } - } - - namespace Particle - { - namespace Integrator - { -#define INSTANTIATE(dim) \ - template class Interface; \ - \ - template \ - void \ - register_particle_integrator (const std::string &, \ - const std::string &, \ - void ( *) (ParameterHandler &), \ - std::unique_ptr>( *) ()); \ - \ - template \ - void \ - declare_parameters (ParameterHandler &); \ - \ - template \ - void \ - write_plugin_graph (std::ostream &); \ - \ - template \ - std::unique_ptr> \ - create_particle_integrator (ParameterHandler &prm); - - ASPECT_INSTANTIATE(INSTANTIATE) - -#undef INSTANTIATE - } - } -} diff --git a/source/particle/integrator/rk_2.cc.bak b/source/particle/integrator/rk_2.cc.bak deleted file mode 100644 index eec91bde25c..00000000000 --- a/source/particle/integrator/rk_2.cc.bak +++ /dev/null @@ -1,242 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Integrator - { - template - RK2::RK2() - : - integrator_substep(0) - {} - - - - template - void - RK2::initialize () - { - const auto &property_information = this->get_particle_world(this->get_particle_world_index()).get_property_manager().get_data_info(); - property_index_old_location = property_information.get_position_by_field_name("internal: integrator properties"); - } - - - - template - void - RK2::local_integrate_step(const typename ParticleHandler::particle_iterator &begin_particle, - const typename ParticleHandler::particle_iterator &end_particle, - const std::vector> &old_velocities, - const std::vector> &velocities, - const double dt) - { - Assert(static_cast (std::distance(begin_particle, end_particle)) == old_velocities.size(), - ExcMessage("The particle integrator expects the old velocity vector to be of equal size " - "to the number of particles to advect. For some unknown reason they are different, " - "most likely something went wrong in the calling function.")); - - if (higher_order_in_time == true && integrator_substep == 1) - Assert(old_velocities.size() == velocities.size(), - ExcMessage("The particle integrator expects the velocity vector to be of equal size " - "to the number of particles to advect. For some unknown reason they are different, " - "most likely something went wrong in the calling function.")); - - const auto cell = begin_particle->get_surrounding_cell(); - bool at_periodic_boundary = false; - if (this->get_triangulation().get_periodic_face_map().empty() == false) - for (const auto &face_index: cell->face_indices()) - if (cell->at_boundary(face_index)) - if (cell->has_periodic_neighbor(face_index)) - { - at_periodic_boundary = true; - break; - } - - typename std::vector>::const_iterator old_velocity = old_velocities.begin(); - typename std::vector>::const_iterator velocity = velocities.begin(); - - for (typename ParticleHandler::particle_iterator it = begin_particle; - it != end_particle; ++it, ++velocity, ++old_velocity) - { - ArrayView properties = it->get_properties(); - - if (integrator_substep == 0) - { - const Tensor<1,dim> k1 = dt * (*old_velocity); -#if DEAL_II_VERSION_GTE(9, 6, 0) - // Get a reference to the particle location, so that we can update it in-place - Point &location = it->get_location(); -#else - Point location = it->get_location(); -#endif - Point new_location = location + 0.5 * k1; - - // Check if we crossed a periodic boundary and if necessary adjust positions - if (at_periodic_boundary) - this->get_geometry_model().adjust_positions_for_periodicity(new_location, - ArrayView>(location)); - - for (unsigned int i=0; iset_location(new_location); -#endif - } - else if (integrator_substep == 1) - { - const Tensor<1,dim> k2 = (higher_order_in_time == true) - ? - dt * (*old_velocity + *velocity) * 0.5 - : - dt * (*old_velocity); - -#if DEAL_II_VERSION_GTE(9, 6, 0) - Point &location = it->get_location(); -#else - Point location = it->get_location(); -#endif - - for (unsigned int i=0; iget_geometry_model().adjust_positions_for_periodicity(location); - -#if !DEAL_II_VERSION_GTE(9, 6, 0) - it->set_location(location); -#endif - } - else - { - Assert(false, - ExcMessage("The RK2 integrator should never continue after two integration steps.")); - } - } - } - - - - template - bool - RK2::new_integration_step() - { - integrator_substep = (integrator_substep + 1) % 2; - - // Continue until we're at the last step - return (integrator_substep != 0); - } - - - - template - std::array - RK2::required_solution_vectors() const - { - switch (integrator_substep) - { - case 0: - return {{false, true, false}}; - case 1: - { - if (higher_order_in_time) - return {{false, true, true}}; - else - return {{false, true, false}}; - } - default: - Assert(false, - ExcMessage("The RK4 integrator should never continue after four integration steps.")); - - return {{false, false, false}}; - } - } - - - - template - void - RK2::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Integrator"); - { - prm.enter_subsection("RK2"); - { - prm.declare_entry ("Higher order accurate in time", "true", - Patterns::Bool(), - "Whether to correctly evaluate old and current velocity " - "solution to reach higher-order accuracy in time. If set to " - "'false' only the old velocity solution is evaluated to " - "simulate a first order method in time. This is only " - "recommended for benchmark purposes."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - template - void - RK2::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Integrator"); - { - prm.enter_subsection("RK2"); - { - higher_order_in_time = prm.get_bool("Higher order accurate in time"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Integrator - { - ASPECT_REGISTER_PARTICLE_INTEGRATOR(RK2, - "rk2", - "Second Order Runge Kutta integrator " - "$y_{n+1} = y_n + \\Delta t\\, v(t_{n+1/2}, y_{n} + \\frac{1}{2} k_1)$ " - "where $k_1 = \\Delta t\\, v(t_{n}, y_{n})$") - } - } -} diff --git a/source/particle/integrator/rk_4.cc.bak b/source/particle/integrator/rk_4.cc.bak deleted file mode 100644 index e94b454783f..00000000000 --- a/source/particle/integrator/rk_4.cc.bak +++ /dev/null @@ -1,281 +0,0 @@ -/* - Copyright (C) 2015 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Integrator - { - template - RK4::RK4() - : - integrator_substep(0) - {} - - - - template - void - RK4::initialize () - { - const auto &property_information = this->get_particle_world(this->get_particle_world_index()).get_property_manager().get_data_info(); - - property_indices[0] = property_information.get_position_by_field_name("internal: integrator properties"); - property_indices[1] = property_indices[0] + dim; - property_indices[2] = property_indices[1] + dim; - property_indices[3] = property_indices[2] + dim; - } - - - - template - void - RK4::local_integrate_step(const typename ParticleHandler::particle_iterator &begin_particle, - const typename ParticleHandler::particle_iterator &end_particle, - const std::vector> &old_velocities, - const std::vector> &velocities, - const double dt) - { - if (integrator_substep < 3) - { - Assert(static_cast (std::distance(begin_particle, end_particle)) == old_velocities.size(), - ExcMessage("The particle integrator expects the old velocity vector to be of equal size " - "to the number of particles to advect. For some unknown reason they are different, " - "most likely something went wrong in the calling function.")); - } - - if (integrator_substep >= 1 && integrator_substep < 4) - { - Assert(static_cast (std::distance(begin_particle, end_particle)) == velocities.size(), - ExcMessage("The particle integrator expects the velocity vector to be of equal size " - "to the number of particles to advect. For some unknown reason they are different, " - "most likely something went wrong in the calling function.")); - } - - const auto cell = begin_particle->get_surrounding_cell(); - bool at_periodic_boundary = false; - if (this->get_triangulation().get_periodic_face_map().empty() == false) - for (const auto &face_index: cell->face_indices()) - if (cell->at_boundary(face_index)) - if (cell->has_periodic_neighbor(face_index)) - { - at_periodic_boundary = true; - break; - } - - typename std::vector>::const_iterator old_velocity = old_velocities.begin(); - typename std::vector>::const_iterator velocity = velocities.begin(); - - std::array,4> k; - for (typename ParticleHandler::particle_iterator it = begin_particle; - it != end_particle; ++it, ++velocity, ++old_velocity) - { - ArrayView properties = it->get_properties(); - - if (integrator_substep == 0) - { -#if DEAL_II_VERSION_GTE(9, 6, 0) - // Get a reference to the particle location, so that we can update it in-place - Point &location = it->get_location(); -#else - Point location = it->get_location(); -#endif - k[0] = dt * (*old_velocity); - - Point new_location = location + 0.5 * k[0]; - - // Check if we crossed a periodic boundary and if necessary adjust positions - if (at_periodic_boundary) - this->get_geometry_model().adjust_positions_for_periodicity(new_location, - ArrayView>(&location,1), - ArrayView>(&k[0],1)); - - for (unsigned int i=0; iset_location(new_location); -#endif - } - else if (integrator_substep == 1) - { - k[1] = dt * ((*old_velocity) + (*velocity)) * 0.5; - - Point old_location; - for (unsigned int i=0; i new_location = old_location + 0.5 * k[1]; - - if (at_periodic_boundary) - { - for (unsigned int i=0; iget_geometry_model().adjust_positions_for_periodicity(new_location, - ArrayView>(&old_location,1), - ArrayView>(&k[0],2)); - - for (unsigned int i=0; iset_location(new_location); - } - else if (integrator_substep == 2) - { - k[2] = dt * (*old_velocity + *velocity) * 0.5; - - Point old_location; - for (unsigned int i=0; i new_location = old_location + k[2]; - - if (at_periodic_boundary) - { - for (unsigned int i=0; iget_geometry_model().adjust_positions_for_periodicity(new_location, - ArrayView>(&old_location,1), - ArrayView>(&k[0],3)); - - for (unsigned int i=0; iset_location(new_location); - } - else if (integrator_substep == 3) - { - k[3] = dt * (*velocity); - - Point old_location; - for (unsigned int i=0; i new_location = old_location + (k[0] + 2.0*k[1] + 2.0*k[2] + k[3])/6.0; - - // No need to fix intermediate values, this is the last integrator step - if (at_periodic_boundary) - this->get_geometry_model().adjust_positions_for_periodicity(new_location); - - it->set_location(new_location); - } - else - { - Assert(false, - ExcMessage("The RK4 integrator should never continue after four integration stages.")); - } - } - } - - - - template - bool - RK4::new_integration_step() - { - integrator_substep = (integrator_substep+1)%4; - - // Continue until we're at the last step - return (integrator_substep != 0); - } - - - template - std::array - RK4::required_solution_vectors() const - { - switch (integrator_substep) - { - case 0: - return {{false, true, false}}; - case 1: - return {{false, true, true}}; - case 2: - return {{false, true, true}}; - case 3: - return {{false, false, true}}; - default: - Assert(false, - ExcMessage("The RK4 integrator should never continue after four integration steps.")); - } - - return {{false, false, false}}; - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Integrator - { - ASPECT_REGISTER_PARTICLE_INTEGRATOR(RK4, - "rk4", - "Runge Kutta fourth order integrator, where " - "$y_{n+1} = y_n + \\frac{1}{6} k_1 + \\frac{1}{3} k_2 " - "+ \\frac{1}{3} k_3 + \\frac{1}{6} k_4$ " - "and $k_1$, $k_2$, $k_3$, $k_4$ are defined as usual.") - } - } -} diff --git a/source/particle/interface.cc.bak b/source/particle/interface.cc.bak deleted file mode 100644 index 659e348739c..00000000000 --- a/source/particle/interface.cc.bak +++ /dev/null @@ -1,42 +0,0 @@ -/* - Copyright (C) 2024 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - - -namespace aspect -{ - namespace Particle - { - void - ParticleInterfaceBase::set_particle_world_index(const unsigned int particle_world_index) - { - this->particle_world_index = particle_world_index; - } - - - - unsigned int - ParticleInterfaceBase::get_particle_world_index() const - { - return particle_world_index; - } - } -} diff --git a/source/particle/interpolator/bilinear_least_squares.cc.bak b/source/particle/interpolator/bilinear_least_squares.cc.bak deleted file mode 100644 index da2fc320bce..00000000000 --- a/source/particle/interpolator/bilinear_least_squares.cc.bak +++ /dev/null @@ -1,364 +0,0 @@ -/* - Copyright (C) 2017 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include - -#include -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Interpolator - { - template - std::vector> - BilinearLeastSquares::properties_at_points(const ParticleHandler &particle_handler, - const std::vector> &positions, - const ComponentMask &selected_properties, - const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const - { - const unsigned int n_particle_properties = particle_handler.n_properties_per_particle(); - const unsigned int property_index = selected_properties.first_selected_component(selected_properties.size()); - - AssertThrow(property_index != numbers::invalid_unsigned_int, - ExcMessage("Internal error: the particle property interpolator was " - "called without a specified component to interpolate.")); - - const typename ParticleHandler::particle_iterator_range particle_range = - particle_handler.particles_in_cell(cell); - - std::vector> cell_properties(positions.size(), - std::vector(n_particle_properties, - numbers::signaling_nan())); - - const unsigned int n_particles = std::distance(particle_range.begin(), particle_range.end()); - const unsigned int n_matrix_columns = (dim == 2) ? 3 : 4; - - // If there are too few particles, we can not perform a least squares interpolation - // fall back to a simpler method instead. - if (n_particles < n_matrix_columns) - return fallback_interpolator.properties_at_points(particle_handler, - positions, - selected_properties, - cell); - - // Noticed that the size of matrix A is n_particles x n_matrix_columns - // which usually is not a square matrix. Therefore, we find the - // least squares solution of Ac=r by solving the reduced QR factorization - // Ac = QRc = b -> Q^TQRc = Rc =Q^Tb - // A is a std::vector of Vectors(which are it's columns) so that we - // create what the ImplicitQR class needs. - std::vector> A(n_matrix_columns, Vector(n_particles)); - std::vector> b(n_particle_properties, Vector(n_particles)); - - unsigned int particle_index = 0; - // The unit cell of deal.II is [0,1]^dim. The limiter needs a 'unit' cell of [-.5,.5]^dim. - const double unit_offset = 0.5; - std::vector property_minimums(n_particle_properties, std::numeric_limits::max()); - std::vector property_maximums(n_particle_properties, std::numeric_limits::lowest()); - for (typename ParticleHandler::particle_iterator particle = particle_range.begin(); - particle != particle_range.end(); ++particle, ++particle_index) - { - const ArrayView particle_property_value = particle->get_properties(); - for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) - { - if (selected_properties[property_index] == true) - { - b[property_index][particle_index] = particle_property_value[property_index]; - if (use_linear_least_squares_limiter[property_index] == true) - { - property_minimums[property_index] = std::min(property_minimums[property_index], particle_property_value[property_index]); - property_maximums[property_index] = std::max(property_maximums[property_index], particle_property_value[property_index]); - } - } - } - Point relative_particle_position = particle->get_reference_location(); - - // A is accessed by A[column][row] here since we will need to append - // columns into the qr matrix - A[0][particle_index] = 1; - for (unsigned int i = 1; i < n_matrix_columns; ++i) - { - relative_particle_position[i - 1] -= unit_offset; - A[i][particle_index] = relative_particle_position[i - 1]; - } - } - - // If the limiter is enabled for at least one property then we know that we can access ghost cell - // particles to determine the bounds of the properties on the mode (due to the assert of - // 'Exchange ghost particles' in parse_parameters). Otherwise we do not need to access those particles - if (use_linear_least_squares_limiter.n_selected_components() != 0) - { - std::vector::active_cell_iterator> active_neighbors; - GridTools::get_active_neighbors>(cell, active_neighbors); - for (const auto &active_neighbor : active_neighbors) - { - if (active_neighbor->is_artificial()) - continue; - const std::vector neighbor_cell_average = fallback_interpolator.properties_at_points(particle_handler, positions, selected_properties, active_neighbor)[0]; - for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) - { - if (selected_properties[property_index] == true && use_linear_least_squares_limiter[property_index] == true) - { - property_minimums[property_index] = std::min(property_minimums[property_index], neighbor_cell_average[property_index]); - property_maximums[property_index] = std::max(property_maximums[property_index], neighbor_cell_average[property_index]); - } - } - } - if (cell->at_boundary()) - { - const std::vector cell_average_values = fallback_interpolator.properties_at_points(particle_handler, {positions[0]}, selected_properties, cell)[0]; - for (unsigned int face_id = 0; face_id < cell->reference_cell().n_faces(); ++face_id) - { - if (cell->at_boundary(face_id)) - { - const unsigned int opposing_face_id = GeometryInfo::opposite_face[face_id]; - const auto &opposing_cell = cell->neighbor(opposing_face_id); - if (opposing_cell.state() == IteratorState::IteratorStates::valid && opposing_cell->is_active() && opposing_cell->is_artificial() == false) - { - const auto neighbor_cell_average = fallback_interpolator.properties_at_points(particle_handler, {positions[0]}, selected_properties, opposing_cell)[0]; - for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) - { - if (selected_properties[property_index] == true && use_boundary_extrapolation[property_index] == true) - { - Assert(cell->reference_cell().is_hyper_cube() == true, ExcNotImplemented()); - const double expected_boundary_value = 1.5 * cell_average_values[property_index] - 0.5 * neighbor_cell_average[property_index]; - property_minimums[property_index] = std::min(property_minimums[property_index], expected_boundary_value); - property_maximums[property_index] = std::max(property_maximums[property_index], expected_boundary_value); - } - } - } - } - } - } - } - - ImplicitQR> qr; - for (const auto &column : A) - qr.append_column(column); - // If A is rank deficent then qr.append_column will not append - // the first column that can be written as a linear combination of - // other columns. We check that all columns were added or we - // rely on the fallback interpolator - if (qr.size() != n_matrix_columns) - return fallback_interpolator.properties_at_points(particle_handler, - positions, - selected_properties, - cell); - - std::vector> QTb(n_particle_properties, Vector(n_matrix_columns)); - std::vector> c(n_particle_properties, Vector(n_matrix_columns)); - for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) - { - if (selected_properties[property_index] == true) - { - qr.multiply_with_QT(QTb[property_index], b[property_index]); - qr.solve(c[property_index], QTb[property_index]); - } - } - const double half_h = .5; - for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) - { - if (selected_properties[property_index] == true) - { - if (use_linear_least_squares_limiter[property_index] == true) - { - c[property_index][0] = std::max(c[property_index][0], property_minimums[property_index]); - c[property_index][0] = std::min(c[property_index][0], property_maximums[property_index]); - - const double max_total_slope = std::min(c[property_index][0] - property_minimums[property_index], - property_maximums[property_index] - c[property_index][0]) - / half_h; - double current_total_slope = 0.0; - for (unsigned int i = 1; i < n_matrix_columns; ++i) - { - current_total_slope += std::abs(c[property_index][i]); - } - - if (current_total_slope > max_total_slope && current_total_slope > std::numeric_limits::min()) - { - double slope_change_ratio = max_total_slope/current_total_slope; - for (unsigned int i = 1; i < n_matrix_columns; ++i) - c[property_index][i] *= slope_change_ratio; - } - } - std::size_t positions_index = 0; - for (typename std::vector>::const_iterator itr = positions.begin(); itr != positions.end(); ++itr, ++positions_index) - { - Point relative_support_point_location = this->get_mapping().transform_real_to_unit_cell(cell, *itr); - double interpolated_value = c[property_index][0]; - for (unsigned int i = 1; i < n_matrix_columns; ++i) - { - relative_support_point_location[i - 1] -= unit_offset; - interpolated_value += c[property_index][i] * relative_support_point_location[i - 1]; - } - if (use_linear_least_squares_limiter[property_index] == true) - { - // Assert that the limiter was reasonably effective. We can not expect perfect accuracy - // due to inaccuracies e.g. in the inversion of the mapping. - const double tolerance = std::sqrt(std::numeric_limits::epsilon()) - * std::max(std::abs(property_minimums[property_index]), - std::abs(property_maximums[property_index])); - (void) tolerance; - Assert(interpolated_value >= property_minimums[property_index] - tolerance, - ExcMessage("The particle interpolation limiter did not succeed. Interpolated value: " + std::to_string(interpolated_value) - + " is smaller than the minimum particle property value: " + std::to_string(property_minimums[property_index]) + ".")); - Assert(interpolated_value <= property_maximums[property_index] + tolerance, - ExcMessage("The particle interpolation limiter did not succeed. Interpolated value: " + std::to_string(interpolated_value) - + " is larger than the maximum particle property value: " + std::to_string(property_maximums[property_index]) + ".")); - - interpolated_value = std::min(interpolated_value, property_maximums[property_index]); - interpolated_value = std::max(interpolated_value, property_minimums[property_index]); - } - cell_properties[positions_index][property_index] = interpolated_value; - } - - } - } - return cell_properties; - } - - - - template - void - BilinearLeastSquares::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Interpolator"); - { - prm.enter_subsection("Bilinear least squares"); - { - prm.declare_entry("Use linear least squares limiter", "false", - Patterns::List(Patterns::Bool()), - "Limit the interpolation of particle properties onto the cell, so that " - "the value of each property is no smaller than its minimum and no " - "larger than its maximum on the particles of each cell, and the " - "average of neighboring cells. If more than one value is given, " - "it will be treated as a list with one component per particle property."); - prm.declare_entry("Use boundary extrapolation", "false", - Patterns::List(Patterns::Bool()), - "Extends the range used by 'Use linear least squares limiter' " - "by linearly interpolating values at cell boundaries from neighboring " - "cells. If more than one value is given, it will be treated as a list " - "with one component per particle property. Enabling 'Use boundary " - "extrapolation' requires enabling 'Use linear least squares " - "limiter'."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - template - void - BilinearLeastSquares::parse_parameters (ParameterHandler &prm) - { - fallback_interpolator.parse_parameters(prm); - prm.enter_subsection("Interpolator"); - { - prm.enter_subsection("Bilinear least squares"); - { - const auto &particle_property_information = this->get_particle_world(this->get_particle_world_index()).get_property_manager().get_data_info(); - const unsigned int n_property_components = particle_property_information.n_components(); - const unsigned int n_internal_components = particle_property_information.get_components_by_field_name("internal: integrator properties"); - - std::vector linear_least_squares_limiter_split = Utilities::split_string_list(prm.get("Use linear least squares limiter")); - std::vector linear_least_squares_limiter_parsed; - if (linear_least_squares_limiter_split.size() == 1) - { - linear_least_squares_limiter_parsed = std::vector(n_property_components - n_internal_components, Utilities::string_to_bool(linear_least_squares_limiter_split[0])); - } - else if (linear_least_squares_limiter_split.size() == n_property_components - n_internal_components) - { - for (const auto &component: linear_least_squares_limiter_split) - linear_least_squares_limiter_parsed.push_back(Utilities::string_to_bool(component)); - } - else - { - AssertThrow(false, ExcMessage("The size of 'Use linear least squares limiter' should either be 1 or the number of particle properties")); - } - for (unsigned int i = 0; i < n_internal_components; ++i) - linear_least_squares_limiter_parsed.push_back(false); - use_linear_least_squares_limiter = ComponentMask(linear_least_squares_limiter_parsed); - - - - const std::vector boundary_extrapolation_split = Utilities::split_string_list(prm.get("Use boundary extrapolation")); - std::vector boundary_extrapolation_parsed; - if (boundary_extrapolation_split.size() == 1) - { - boundary_extrapolation_parsed = std::vector(n_property_components - n_internal_components, Utilities::string_to_bool(boundary_extrapolation_split[0])); - } - else if (boundary_extrapolation_split.size() == n_property_components - n_internal_components) - { - for (const auto &component: boundary_extrapolation_split) - boundary_extrapolation_parsed.push_back(Utilities::string_to_bool(component)); - } - else - { - AssertThrow(false, ExcMessage("The size of 'Use boundary extrapolation' should either be 1 or the number of particle properties")); - } - for (unsigned int i = 0; i < n_internal_components; ++i) - boundary_extrapolation_parsed.push_back(false); - use_boundary_extrapolation = ComponentMask(boundary_extrapolation_parsed); - for (unsigned int property_index = 0; property_index < n_property_components - n_internal_components; ++property_index) - { - AssertThrow(use_linear_least_squares_limiter[property_index] || !use_boundary_extrapolation[property_index], - ExcMessage("'Use boundary extrapolation' must be set with 'Use linear least squares limiter' to be valid.")); - } - } - prm.leave_subsection(); - } - prm.leave_subsection(); - const bool limiter_enabled_for_at_least_one_property = (use_linear_least_squares_limiter.n_selected_components() != 0); - AssertThrow(limiter_enabled_for_at_least_one_property == false || prm.get_bool("Update ghost particles") == true, - ExcMessage("If 'Use linear least squares limiter' is enabled for any particle property, then 'Update ghost particles' must be set to true")); - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Interpolator - { - ASPECT_REGISTER_PARTICLE_INTERPOLATOR(BilinearLeastSquares, - "bilinear least squares", - "Uses linear least squares to obtain the slopes and center of a 2d or " - "3d plane from the particle positions and a particular property value " - "on those particles. " - "Interpolate this property onto a vector of points. If the limiter is " - "enabled then it will ensure the interpolated properties do not exceed the " - "range of the minimum and maximum of the values of the property on the " - "particles. Note that deal.II must be configured with BLAS and LAPACK to " - "support this operation.") - } - } -} diff --git a/source/particle/interpolator/cell_average.cc.bak b/source/particle/interpolator/cell_average.cc.bak deleted file mode 100644 index 1a7f4ddfc35..00000000000 --- a/source/particle/interpolator/cell_average.cc.bak +++ /dev/null @@ -1,161 +0,0 @@ -/* - Copyright (C) 2016 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Interpolator - { - template - std::vector> - CellAverage::properties_at_points(const ParticleHandler &particle_handler, - const std::vector> &positions, - const ComponentMask &selected_properties, - const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const - { - const typename ParticleHandler::particle_iterator_range particle_range = - particle_handler.particles_in_cell(cell); - - const unsigned int n_particles = std::distance(particle_range.begin(),particle_range.end()); - const unsigned int n_particle_properties = particle_handler.n_properties_per_particle(); - - std::vector cell_properties (n_particle_properties,numbers::signaling_nan()); - - for (unsigned int i = 0; i < n_particle_properties; ++i) - if (selected_properties[i]) - cell_properties[i] = 0.0; - - if (n_particles > 0) - { - for (const auto &particle : particle_range) - { - const ArrayView &particle_properties = particle.get_properties(); - - for (unsigned int i = 0; i < particle_properties.size(); ++i) - if (selected_properties[i]) - cell_properties[i] += particle_properties[i]; - } - - for (unsigned int i = 0; i < n_particle_properties; ++i) - if (selected_properties[i]) - cell_properties[i] /= n_particles; - } - // If there are no particles in this cell use the average of the - // neighboring cells. - else - { - std::vector::active_cell_iterator> neighbors; - GridTools::get_active_neighbors>(cell,neighbors); - - unsigned int non_empty_neighbors = 0; - for (unsigned int i=0; iis_locally_owned()) - continue; - // Only recursively call this function if the neighbor cell contains - // particles (else we end up in an endless recursion) - if (particle_handler.n_particles_in_cell(neighbors[i]) == 0) - continue; - - const std::vector neighbor_properties = properties_at_points(particle_handler, - std::vector> (1,neighbors[i]->center(true,false)), - selected_properties, - neighbors[i])[0]; - - for (unsigned int i = 0; i < n_particle_properties; ++i) - if (selected_properties[i]) - cell_properties[i] += neighbor_properties[i]; - - ++non_empty_neighbors; - } - - if (!allow_cells_without_particles) - { - AssertThrow(non_empty_neighbors != 0, - ExcMessage("A cell and all of its neighbors do not contain any particles. " - "The `cell average' interpolation scheme does not support this case unless specified " - "in Allow cells without particles.")); - } - - for (unsigned int i = 0; i < n_particle_properties; ++i) - { - if (selected_properties[i] && non_empty_neighbors != 0) - cell_properties[i] /= non_empty_neighbors; - // Assume property is zero for any areas with no particles - else if (allow_cells_without_particles && non_empty_neighbors == 0) - cell_properties[i] = 0; - } - - } - - return std::vector> (positions.size(),cell_properties); - } - - - - template - void - CellAverage::declare_parameters (ParameterHandler &prm) - { - prm.declare_entry ("Allow cells without particles", "false", - Patterns::Bool (), - "By default, every cell needs to contain particles to use this interpolator " - "plugin. If this parameter is set to true, cells are allowed to have no particles, " - "In case both the current cell and its neighbors are empty, " - "the interpolator will return 0 for the current cell's properties."); - } - - - - template - void - CellAverage::parse_parameters (ParameterHandler &prm) - { - allow_cells_without_particles = prm.get_bool("Allow cells without particles"); - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Interpolator - { - ASPECT_REGISTER_PARTICLE_INTERPOLATOR(CellAverage, - "cell average", - "Return the arithmetic average of all particle properties in the given cell, " - "or in the neighboring cells if the given cell is empty. " - "In case the neighboring cells are also empty, and 'Allow cells " - "without particles' is set to true, the interpolator returns 0. " - "Otherwise, an exception is thrown. ") - } - } -} diff --git a/source/particle/interpolator/harmonic_average.cc.bak b/source/particle/interpolator/harmonic_average.cc.bak deleted file mode 100644 index 6ae071041e3..00000000000 --- a/source/particle/interpolator/harmonic_average.cc.bak +++ /dev/null @@ -1,169 +0,0 @@ -/* - Copyright (C) 2017 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Interpolator - { - template - std::vector> - HarmonicAverage::properties_at_points(const ParticleHandler &particle_handler, - const std::vector> &positions, - const ComponentMask &selected_properties, - const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const - { - const typename ParticleHandler::particle_iterator_range particle_range = - particle_handler.particles_in_cell(cell); - - const unsigned int n_particles = std::distance(particle_range.begin(),particle_range.end()); - const unsigned int n_particle_properties = particle_handler.n_properties_per_particle(); - - std::vector cell_properties (n_particle_properties,numbers::signaling_nan()); - - for (unsigned int i = 0; i < n_particle_properties; ++i) - if (selected_properties[i]) - cell_properties[i] = 0.0; - - if (n_particles > 0) - { - for (const auto &particle : particle_range) - { - const ArrayView &particle_properties = particle.get_properties(); - - for (unsigned int i = 0; i < particle_properties.size(); ++i) - if (selected_properties[i]) - { - AssertThrow(particle_properties[i] > 0, - ExcMessage ("All particle property values must be greater than 0 for harmonic averaging!")); - cell_properties[i] += 1/particle_properties[i]; - } - } - - for (unsigned int i = 0; i < n_particle_properties; ++i) - if (selected_properties[i]) - { - cell_properties[i] = n_particles/cell_properties[i]; - } - } - // If there are no particles in this cell use the average of the - // neighboring cells. - else - { - std::vector::active_cell_iterator> neighbors; - GridTools::get_active_neighbors>(cell,neighbors); - - unsigned int non_empty_neighbors = 0; - for (unsigned int i=0; i neighbor_properties = properties_at_points(particle_handler, - std::vector> (1,neighbors[i]->center(true,false)), - selected_properties, - neighbors[i])[0]; - - for (unsigned int i = 0; i < n_particle_properties; ++i) - if (selected_properties[i]) - { - AssertThrow(neighbor_properties[i] > 0, - ExcMessage ("All particle property values must be greater than 0 for harmonic averaging!")); - cell_properties[i] += 1/neighbor_properties[i]; - } - - ++non_empty_neighbors; - } - - if (!allow_cells_without_particles) - { - AssertThrow(non_empty_neighbors != 0, - ExcMessage("A cell and all of its neighbors do not contain any particles. " - "The `harmonic average' interpolation scheme does not support this case unless specified " - "in Allow cells without particles.")); - } - - for (unsigned int i = 0; i < n_particle_properties; ++i) - { - if (selected_properties[i] && non_empty_neighbors !=0) - cell_properties[i] = non_empty_neighbors/cell_properties[i]; - // Assume property is zero for any areas with no particles - else if (allow_cells_without_particles && non_empty_neighbors == 0) - cell_properties[i] = 0; - } - - } - - return std::vector> (positions.size(),cell_properties); - } - - - - template - void - HarmonicAverage::declare_parameters (ParameterHandler &prm) - { - prm.declare_entry ("Allow cells without particles", "false", - Patterns::Bool (), - "By default, every cell needs to contain particles to use this interpolator " - "plugin. If this parameter is set to true, cells are allowed to have no particles. " - "In case both the current cell and its neighbors are empty, " - "the interpolator will return 0 for the current cell's properties."); - } - - - - template - void - HarmonicAverage::parse_parameters (ParameterHandler &prm) - { - allow_cells_without_particles = prm.get_bool("Allow cells without particles"); - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Interpolator - { - ASPECT_REGISTER_PARTICLE_INTERPOLATOR(HarmonicAverage, - "harmonic average", - "Return the harmonic average of all particle properties in the " - "given cell. If the cell contains no particles, return the " - "harmonic average of the properties in the neighboring cells. " - "In case the neighboring cells are also empty, and 'Allow cells " - "without particles' is set to true, the interpolator returns 0. " - "Otherwise, an exception is thrown. ") - } - } -} diff --git a/source/particle/interpolator/interface.cc.bak b/source/particle/interpolator/interface.cc.bak deleted file mode 100644 index 83a50104dec..00000000000 --- a/source/particle/interpolator/interface.cc.bak +++ /dev/null @@ -1,149 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Interpolator - { -// -------------------------------- Deal with registering models and automating -// -------------------------------- their setup and selection at run time - - namespace - { - std::tuple - >, - aspect::internal::Plugins::PluginList>> registered_plugins; - } - - - - template - void - register_particle_interpolator (const std::string &name, - const std::string &description, - void (*declare_parameters_function) (ParameterHandler &), - std::unique_ptr> (*factory_function) ()) - { - std::get(registered_plugins).register_plugin (name, - description, - declare_parameters_function, - factory_function); - } - - - - template - std::unique_ptr> - create_particle_interpolator (ParameterHandler &prm) - { - std::string name; - name = prm.get ("Interpolation scheme"); - - return std::get(registered_plugins).create_plugin (name, - "Particle::Interpolator name"); - } - - - - template - void - declare_parameters (ParameterHandler &prm) - { - // declare the entry in the parameter file - const std::string pattern_of_names - = std::get(registered_plugins).get_pattern_of_names (); - - prm.declare_entry ("Interpolation scheme", "cell average", - Patterns::Selection (pattern_of_names), - "Select one of the following models:\n\n" - + - std::get(registered_plugins).get_description_string()); - - std::get(registered_plugins).declare_parameters (prm); - } - - - - template - void - write_plugin_graph (std::ostream &out) - { - std::get(registered_plugins).write_plugin_graph ("Particle interpolator interface", - out); - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace internal - { - namespace Plugins - { - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - } - } - - namespace Particle - { - namespace Interpolator - { -#define INSTANTIATE(dim) \ - template class Interface; \ - \ - template \ - void \ - register_particle_interpolator (const std::string &, \ - const std::string &, \ - void ( *) (ParameterHandler &), \ - std::unique_ptr>( *) ()); \ - \ - template \ - void \ - declare_parameters (ParameterHandler &); \ - \ - template \ - void \ - write_plugin_graph (std::ostream &); \ - \ - template \ - std::unique_ptr> \ - create_particle_interpolator (ParameterHandler &prm); - - ASPECT_INSTANTIATE(INSTANTIATE) - -#undef INSTANTIATE - } - } -} diff --git a/source/particle/interpolator/nearest_neighbor.cc.bak b/source/particle/interpolator/nearest_neighbor.cc.bak deleted file mode 100644 index 9903cb18a4d..00000000000 --- a/source/particle/interpolator/nearest_neighbor.cc.bak +++ /dev/null @@ -1,161 +0,0 @@ -/* - Copyright (C) 2017 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -#include - -namespace aspect -{ - namespace Particle - { - namespace Interpolator - { - template - std::vector> - NearestNeighbor::properties_at_points(const ParticleHandler &particle_handler, - const std::vector> &positions, - const ComponentMask &selected_properties, - const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const - { - const typename ParticleHandler::particle_iterator_range particle_range = particle_handler.particles_in_cell(cell); - - const unsigned int n_particles = std::distance(particle_range.begin(),particle_range.end()); - const unsigned int n_particle_properties = particle_handler.n_properties_per_particle(); - - std::vector temp(n_particle_properties, 0.0); - std::vector> point_properties(positions.size(), temp); - - for (unsigned int pos_idx=0; pos_idx < positions.size(); ++pos_idx) - { - double minimum_distance = std::numeric_limits::max(); - if (n_particles > 0) - { - typename ParticleHandler::particle_iterator nearest_neighbor; - for (typename ParticleHandler::particle_iterator particle = particle_range.begin(); - particle != particle_range.end(); ++particle) - { - const double dist = (positions[pos_idx] - particle->get_location()).norm_square(); - if (dist < minimum_distance) - { - minimum_distance = dist; - nearest_neighbor = particle; - } - } - const dealii::ArrayView neighbor_props = nearest_neighbor->get_properties(); - for (unsigned int i = 0; i < n_particle_properties; ++i) - if (selected_properties[i]) - point_properties[pos_idx][i] = neighbor_props[i]; - } - else - { - std::vector::active_cell_iterator> neighbors; - GridTools::get_active_neighbors>(cell,neighbors); - - unsigned int nearest_neighbor_cell = numbers::invalid_unsigned_int; - for (unsigned int i=0; icenter()).norm_square(); - if (dist < minimum_distance) - { - minimum_distance = dist; - nearest_neighbor_cell = i; - } - } - - if (!allow_cells_without_particles) - { - AssertThrow(nearest_neighbor_cell != numbers::invalid_unsigned_int, - ExcMessage("A cell and all of its neighbors do not contain any particles. " - "The `nearest neighbor' interpolation scheme does not support this case unless specified " - "in Allow cells without particles.")); - } - - if (nearest_neighbor_cell != numbers::invalid_unsigned_int) - { - point_properties[pos_idx] = properties_at_points(particle_handler, - std::vector> (1,positions[pos_idx]), - selected_properties, - neighbors[nearest_neighbor_cell])[0]; - } - else if (allow_cells_without_particles && nearest_neighbor_cell == numbers::invalid_unsigned_int) - { - for (unsigned int i = 0; i < n_particle_properties; ++i) - if (selected_properties[i]) - point_properties[pos_idx][i] = 0; - } - - } - - } - - return point_properties; - } - - - - template - void - NearestNeighbor::declare_parameters (ParameterHandler &prm) - { - prm.declare_entry ("Allow cells without particles", "false", - Patterns::Bool (), - "By default, every cell needs to contain particles to use this interpolator " - "plugin. If this parameter is set to true, cells are allowed to have no particles. " - "In case both the current cell and its neighbors are empty, " - "the interpolator will return 0 for the current cell's properties."); - } - - - - template - void - NearestNeighbor::parse_parameters (ParameterHandler &prm) - { - allow_cells_without_particles = prm.get_bool("Allow cells without particles"); - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Interpolator - { - ASPECT_REGISTER_PARTICLE_INTERPOLATOR(NearestNeighbor, - "nearest neighbor", - "Return the properties of the nearest neighboring particle " - "in the current cell, or nearest particle in nearest neighboring " - "cell if current cell is empty. " - "In case the neighboring cells are also empty, and 'Allow cells " - "without particles' is set to true, the interpolator returns 0. " - "Otherwise, an exception is thrown. ") - } - } -} diff --git a/source/particle/interpolator/quadratic_least_squares.cc.bak b/source/particle/interpolator/quadratic_least_squares.cc.bak deleted file mode 100644 index 4dfdfe715f6..00000000000 --- a/source/particle/interpolator/quadratic_least_squares.cc.bak +++ /dev/null @@ -1,640 +0,0 @@ -/* - Copyright (C) 2019 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include - -#include -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Interpolator - { - template - double QuadraticLeastSquares::evaluate_interpolation_function(const Vector &coefficients, const Point &position) const - { - if (dim == 2) - { - return coefficients[0] + - coefficients[1] * position[0] + - coefficients[2] * position[1] + - coefficients[3] * position[0] * position[1] + - coefficients[4] * position[0] * position[0] + - coefficients[5] * position[1] * position[1]; - } - else - { - return coefficients[0] + - coefficients[1] * position[0] + - coefficients[2] * position[1] + - coefficients[3] * position[2] + - coefficients[4] * position[0] * position[1] + - coefficients[5] * position[0] * position[2] + - coefficients[6] * position[1] * position[2] + - coefficients[7] * position[0] * position[0] + - coefficients[8] * position[1] * position[1] + - coefficients[9] * position[2] * position[2]; - } - } - - - template - std::pair QuadraticLeastSquares::get_interpolation_bounds(const Vector &coefficients) const - { - double interpolation_min = std::numeric_limits::max(); - double interpolation_max = std::numeric_limits::lowest(); - for (const auto &critical_point : get_critical_points(coefficients)) - { - bool critical_point_in_cell = true; - for (unsigned int d = 0; d < dim; ++d) - { - if (critical_point[d] < -0.5 || critical_point[d] > 0.5) - critical_point_in_cell = false; - } - if (critical_point_in_cell) - { - const double value_at_critical_point = evaluate_interpolation_function(coefficients, critical_point); - interpolation_min = std::min(interpolation_min, value_at_critical_point); - interpolation_max = std::max(interpolation_max, value_at_critical_point); - } - } - return {interpolation_min, interpolation_max}; - } - - - template - std::vector> QuadraticLeastSquares::get_critical_points(const Vector &coefficients) const - { - std::vector> critical_points; - const double epsilon = 10. * coefficients.linfty_norm() * std::numeric_limits::epsilon(); - if (dim == 2) - { - // reserve the maximum number of critical points - // in 2d: one inside, 4 edges, and 4 corners - critical_points.reserve(1 + 4 + 4); - // If finding the critical point of the function (or along a cell edge) would - // require division by 0, or the solve of a singular matrix, then there is not - // a unique critical point. There cannot be two critical points to this function, - // so there must be infinitely many points with the same value, so it should be - // caught by one of the other checks of the value of the interpolation - - // compute the location of the global critical point - Tensor<2, dim, double> critical_point_A; - critical_point_A[0][0] = 2 * coefficients[4]; - critical_point_A[0][1] = coefficients[3]; - critical_point_A[1][0] = coefficients[3]; - critical_point_A[1][1] = 2 * coefficients[5]; - Tensor<1, dim, double> critical_point_b; - critical_point_b[0] = -coefficients[1]; - critical_point_b[1] = -coefficients[2]; - if (std::abs(determinant(critical_point_A)) > epsilon) - { - critical_points.emplace_back(invert(critical_point_A) * critical_point_b); - } - - // Compute the critical value for each of the edges. This is necessary even if we found the - // critical point inside the unit cell, because the value at the edges can be a minimum, while - // the critical point inside the cell is a maximum, or vice-versa. Additionally the critical - // point could be a saddle point, in which case we would still need to find a minimum and maximum over the cell. - if (std::abs(coefficients[5]) > epsilon) - { - critical_points.emplace_back(-0.5, -(2 * coefficients[2] - coefficients[3])/(4 * coefficients[5])); - critical_points.emplace_back( 0.5, -(2 * coefficients[2] + coefficients[3])/(4 * coefficients[5])); - } - if (std::abs(coefficients[4]) > epsilon) - { - critical_points.emplace_back(-(2 * coefficients[1] - coefficients[3])/(4 * coefficients[4]), -0.5); - critical_points.emplace_back(-(2 * coefficients[1] + coefficients[3])/(4 * coefficients[4]), 0.5); - } - - // Compute the critical value for each of the corners. This is necessary even if critical points - // have already been found in previous steps, as the global critical point could be a minimum, - // and the edge critical points could also be minimums. - for (double x = -0.5; x <= 0.5; ++x) - { - for (double y = -0.5; y <= 0.5; ++y) - { - critical_points.emplace_back(x,y); - } - } - } - else if (dim == 3) - { - // reserve the maximum number of critical points - // in 3d: one inside, 6 faces, 12 edges, and 8 corners - critical_points.reserve(1 + 6 + 12 + 8); - // If finding the critical point of the function (or along a cell edge) would - // require division by 0, or the solve of a singular matrix, then there is not - // a unique critical point. There cannot be two critical points to this function, - // so there must be infinitely many points with the same value, so it should be - // caught by one of the other checks of the value of the interpolation - - // Compute the location of the global critical point - { - Tensor<2, dim, double> critical_point_A; - critical_point_A[0][0] = 2 * coefficients[7]; - critical_point_A[0][1] = coefficients[4]; - critical_point_A[0][2] = coefficients[5]; - critical_point_A[1][0] = coefficients[4]; - critical_point_A[1][1] = 2 * coefficients[8]; - critical_point_A[1][2] = coefficients[6]; - critical_point_A[2][0] = coefficients[5]; - critical_point_A[2][1] = coefficients[6]; - critical_point_A[2][2] = 2 * coefficients[9]; - Tensor<1, dim, double> critical_point_b; - critical_point_b[0] = -coefficients[1]; - critical_point_b[1] = -coefficients[2]; - critical_point_b[2] = -coefficients[3]; - if (std::abs(determinant(critical_point_A)) > epsilon) - { - critical_points.emplace_back(invert(critical_point_A) * critical_point_b); - } - } - - // Compute the location of critical points along the faces of the cell. - // This is is necessary even if we found a global critical point as it - // could be a minimum and the faces could have a maximum or vice-versa. - Tensor<2, 2, double> critical_point_A; - Tensor<1, 2, double> critical_point_b; - Tensor<1, 2, double> critical_point_X; - // The columns of this critical_point_A correspond to Y and Z. - critical_point_A[0][0] = 2 * coefficients[8]; - critical_point_A[0][1] = coefficients[6]; - critical_point_A[1][0] = coefficients[6]; - critical_point_A[1][1] = 2 * coefficients[9]; - if (std::abs(determinant(critical_point_A)) > epsilon) - { - const Tensor<2, 2, double> critical_point_A_inv = invert(critical_point_A); - double x = -0.5; - critical_point_b[0] = -(coefficients[2] + coefficients[4] * x); - critical_point_b[1] = -(coefficients[3] + coefficients[5] * x); - critical_point_X = critical_point_A_inv * critical_point_b; - critical_points.emplace_back(x, critical_point_X[0], critical_point_X[1]); - x = 0.5; - critical_point_b[0] = -(coefficients[2] + coefficients[4] * x); - critical_point_b[1] = -(coefficients[3] + coefficients[5] * x); - critical_point_X = critical_point_A_inv * critical_point_b; - critical_points.emplace_back(x, critical_point_X[0], critical_point_X[1]); - } - // The columns of this critical_point_A correspond to X and Z. - critical_point_A[0][0] = 2 * coefficients[7]; - critical_point_A[0][1] = coefficients[5]; - critical_point_A[1][0] = coefficients[5]; - critical_point_A[1][1] = 2 * coefficients[9]; - if (std::abs(determinant(critical_point_A)) > epsilon) - { - const Tensor<2, 2, double> critical_point_A_inv = invert(critical_point_A); - double y = -0.5; - critical_point_b[0] = -(coefficients[1] + coefficients[4] * y); - critical_point_b[1] = -(coefficients[3] + coefficients[6] * y); - critical_point_X = critical_point_A_inv * critical_point_b; - critical_points.emplace_back(critical_point_X[0], y, critical_point_X[1]); - y = 0.5; - critical_point_b[0] = -(coefficients[1] + coefficients[4] * y); - critical_point_b[1] = -(coefficients[3] + coefficients[6] * y); - critical_point_X = critical_point_A_inv * critical_point_b; - critical_points.emplace_back(critical_point_X[0], y, critical_point_X[1]); - } - // The columns of this critical_point_A correspond to X and Y. - critical_point_A[0][0] = 2 * coefficients[7]; - critical_point_A[0][1] = coefficients[4]; - critical_point_A[1][0] = coefficients[4]; - critical_point_A[1][1] = 2 * coefficients[8]; - if (std::abs(determinant(critical_point_A)) > epsilon) - { - const Tensor<2, 2, double> critical_point_A_inv = invert(critical_point_A); - double z = -0.5; - critical_point_b[0] = -(coefficients[1] + coefficients[5] * z); - critical_point_b[1] = -(coefficients[2] + coefficients[6] * z); - critical_point_X = critical_point_A_inv * critical_point_b; - critical_points.emplace_back(critical_point_X[0], critical_point_X[1], z); - z = 0.5; - critical_point_b[0] = -(coefficients[1] + coefficients[5] * z); - critical_point_b[1] = -(coefficients[2] + coefficients[6] * z); - critical_point_X = critical_point_A_inv * critical_point_b; - critical_points.emplace_back(critical_point_X[0], critical_point_X[1], z); - } - - // Compute the location of critical points along the edges. - // This is necessary even if critical points have been found in previous - // steps, as the global critial point and critical points on faces could - // all be minimums. - if (std::abs(coefficients[9]) > epsilon) - { - for (double x = -0.5; x <= 0.5; ++x) - { - for (double y = -0.5; y <= 0.5; ++y) - { - critical_points.emplace_back(x,y, -(coefficients[3] + coefficients[5] * x + coefficients[6] * y)/(2 * coefficients[9])); - } - } - } - if (std::abs(coefficients[8]) > epsilon) - { - for (double x = -0.5; x <= 0.5; ++x) - { - for (double z = -0.5; z <= 0.5; ++z) - { - critical_points.emplace_back(x, -(coefficients[2] + coefficients[4] * x + coefficients[6] * z) / (2 * coefficients[8]), z); - } - } - } - if (std::abs(coefficients[7]) > epsilon) - { - for (double y = -0.5; y <= 0.5; ++y) - { - for (double z = -0.5; z <= 0.5; ++z) - { - critical_points.emplace_back(-(coefficients[1] + coefficients[4] * y + coefficients[5] * z)/(2*coefficients[7]), y, z); - } - } - } - - // Compute the location of critical points along the corners - // This is necessary even if critical points have been found in previous - // steps, as the previously found critical points could all be minimums - // and the corners could hold the maximum value over the cell. - for (double x = -0.5; x <= 0.5; ++x) - { - for (double y = -0.5; y <= 0.5; ++y) - { - for (double z = -0.5; z <= 0.5; ++z) - { - critical_points.emplace_back(x, y, z); - } - } - } - } - return critical_points; - } - - template - std::vector> - QuadraticLeastSquares::properties_at_points(const ParticleHandler &particle_handler, - const std::vector> &positions, - const ComponentMask &selected_properties, - const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const - { - const unsigned int n_particle_properties = particle_handler.n_properties_per_particle(); - - const unsigned int property_index = selected_properties.first_selected_component(selected_properties.size()); - - AssertThrow(property_index != numbers::invalid_unsigned_int, - ExcMessage("Internal error: the particle property interpolator was " - "called without a specified component to interpolate.")); - - const typename ParticleHandler::particle_iterator_range particle_range = - particle_handler.particles_in_cell(cell); - - std::vector> cell_properties(positions.size(), - std::vector(n_particle_properties, - numbers::signaling_nan())); - - const unsigned int n_particles = std::distance(particle_range.begin(), particle_range.end()); - - const unsigned int n_matrix_columns = (dim == 2) ? 6 : 10; - if (n_particles < n_matrix_columns) - return fallback_interpolator.properties_at_points(particle_handler, - positions, - selected_properties, - cell); - const std::vector cell_average_values = fallback_interpolator.properties_at_points(particle_handler, - {positions[0]}, - selected_properties, - cell)[0]; - - - // Notice that the size of matrix A is n_particles x n_matrix_columns - // which usually is not a square matrix. Therefore, we find the - // least squares solution of Ac=r by solving the reduced QR factorization - // Ac = QRc = b -> Q^TQRc = Rc =Q^Tb - // A is a std::vector of Vectors(which are it's columns) so that we - // create what the ImplicitQR class needs. - std::vector> A(n_matrix_columns, Vector(n_particles)); - std::vector> b(n_particle_properties, Vector(n_particles)); - - unsigned int particle_index = 0; - // The unit cell of deal.II is [0, 1]^dim. The limiter needs a 'unit' cell of [-0.5, 0.5]^dim - const double unit_offset = 0.5; - std::vector property_minimums(n_particle_properties, std::numeric_limits::max()); - std::vector property_maximums(n_particle_properties, std::numeric_limits::lowest()); - for (typename ParticleHandler::particle_iterator particle = particle_range.begin(); - particle != particle_range.end(); ++particle, ++particle_index) - { - const ArrayView particle_property_value = particle->get_properties(); - for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) - { - if (selected_properties[property_index] == true) - { - b[property_index][particle_index] = particle_property_value[property_index]; - property_minimums[property_index] = std::min(property_minimums[property_index], particle_property_value[property_index]); - property_maximums[property_index] = std::max(property_maximums[property_index], particle_property_value[property_index]); - } - } - - Point relative_particle_position = particle->get_reference_location(); - for (unsigned int d = 0; d < dim; ++d) - relative_particle_position[d] -= unit_offset; - // A is accessed by A[column][row] here since we need to append - // columns into the qr matrix. - - // There is a potential that in the future we may change to - // interpolate to $Q_2$ instead of the current $P_2$. This would - // involve adding more terms to the interpolation for some problems. - // We for now leave those terms out of the interpolation because they - // would require more particles per cell and we are not yet aware of - // a benchmark where those terms have affected the convegence. - A[0][particle_index] = 1; - A[1][particle_index] = relative_particle_position[0]; - A[2][particle_index] = relative_particle_position[1]; - if (dim == 2) - { - A[3][particle_index] = relative_particle_position[0] * relative_particle_position[1]; - A[4][particle_index] = relative_particle_position[0] * relative_particle_position[0]; - A[5][particle_index] = relative_particle_position[1] * relative_particle_position[1]; - } - else - { - A[3][particle_index] = relative_particle_position[2]; - A[4][particle_index] = relative_particle_position[0] * relative_particle_position[1]; - A[5][particle_index] = relative_particle_position[0] * relative_particle_position[2]; - A[6][particle_index] = relative_particle_position[1] * relative_particle_position[2]; - A[7][particle_index] = relative_particle_position[0] * relative_particle_position[0]; - A[8][particle_index] = relative_particle_position[1] * relative_particle_position[1]; - A[9][particle_index] = relative_particle_position[2] * relative_particle_position[2]; - } - } - - // If the limiter is enabled for at least one property then we know that we can access ghost cell - // particles to determine the bounds of the properties on the model (due to the assert of - // 'Exchange ghost particles' in parse_parameters). Otherwise we do not need to access those particles - if (use_quadratic_least_squares_limiter.n_selected_components(n_particle_properties) != 0) - { - std::vector::active_cell_iterator> active_neighbors; - GridTools::get_active_neighbors>(cell, active_neighbors); - for (const auto &active_neighbor : active_neighbors) - { - if (active_neighbor->is_artificial()) - continue; - const std::vector neighbor_cell_average = fallback_interpolator.properties_at_points(particle_handler, positions, selected_properties, active_neighbor)[0]; - for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) - { - if (selected_properties[property_index] == true && use_quadratic_least_squares_limiter[property_index] == true) - { - property_minimums[property_index] = std::min(property_minimums[property_index], neighbor_cell_average[property_index]); - property_maximums[property_index] = std::max(property_maximums[property_index], neighbor_cell_average[property_index]); - } - } - - } - if (cell->at_boundary()) - { - for (unsigned int face_id = 0; face_id < cell->reference_cell().n_faces(); ++face_id) - { - if (cell->at_boundary(face_id)) - { - const unsigned int opposing_face_id = GeometryInfo::opposite_face[face_id]; - const auto &opposing_cell = cell->neighbor(opposing_face_id); - if (opposing_cell.state() == IteratorState::IteratorStates::valid && opposing_cell->is_active() && !opposing_cell->is_artificial()) - { - - const auto neighbor_cell_average = fallback_interpolator.properties_at_points(particle_handler, {positions[0]}, selected_properties, opposing_cell)[0]; - for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) - { - if (selected_properties[property_index] == true && use_boundary_extrapolation[property_index] == true) - { - Assert(cell->reference_cell().is_hyper_cube() == true, ExcNotImplemented()); - const double expected_boundary_value = 1.5 * cell_average_values[property_index] - 0.5 * neighbor_cell_average[property_index]; - property_minimums[property_index] = std::min(property_minimums[property_index], expected_boundary_value); - property_maximums[property_index] = std::max(property_maximums[property_index], expected_boundary_value); - } - } - } - } - } - } - } - ImplicitQR> qr; - for (const auto &column : A) - qr.append_column(column); - // If A is rank deficent then qr.append_column will not append - // the first column that can be written as a linear combination of - // other columns. We check that all columns were added or we - // rely on the fallback interpolator - if (qr.size() != n_matrix_columns) - return fallback_interpolator.properties_at_points(particle_handler, - positions, - selected_properties, - cell); - std::vector> QTb(n_particle_properties, Vector(n_matrix_columns)); - std::vector> c(n_particle_properties, Vector(n_matrix_columns)); - for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) - { - if (selected_properties[property_index]) - { - qr.multiply_with_QT(QTb[property_index], b[property_index]); - qr.solve(c[property_index], QTb[property_index]); - if (use_quadratic_least_squares_limiter[property_index]) - { - - const std::pair interpolation_bounds = get_interpolation_bounds(c[property_index]); - const double interpolation_min = interpolation_bounds.first; - const double interpolation_max = interpolation_bounds.second; - if ((interpolation_max - cell_average_values[property_index]) > std::numeric_limits::epsilon() && - (cell_average_values[property_index] - interpolation_min) > std::numeric_limits::epsilon()) - { - const double alpha = std::max(std::min((cell_average_values[property_index] - property_minimums[property_index])/(cell_average_values[property_index] - interpolation_min), - (property_maximums[property_index]-cell_average_values[property_index])/(interpolation_max - cell_average_values[property_index])), 0.0); - // If alpha > 1, then using it would make the function grow to meet the bounds. - if (alpha < 1.0) - { - c[property_index] *= alpha; - c[property_index][0] += (1-alpha) * cell_average_values[property_index]; - } - } - } - } - } - unsigned int index_positions = 0; - for (typename std::vector>::const_iterator itr = positions.begin(); itr != positions.end(); ++itr, ++index_positions) - { - Point relative_support_point_location = this->get_mapping().transform_real_to_unit_cell(cell, *itr); - for (unsigned int d = 0; d < dim; ++d) - relative_support_point_location[d] -= unit_offset; - for (unsigned int property_index = 0; property_index < n_particle_properties; ++property_index) - { - if (selected_properties[property_index] == true) - { - double interpolated_value = evaluate_interpolation_function(c[property_index], relative_support_point_location); - // Overshoot and undershoot correction of interpolated particle property. - if (use_quadratic_least_squares_limiter[property_index]) - { - // Assert that the limiter was reasonably effective. We can not expect perfect accuracy - // due to inaccuracies e.g. in the inversion of the mapping. - const double tolerance = std::sqrt(std::numeric_limits::epsilon()) - * std::max(std::abs(property_minimums[property_index]), - std::abs(property_maximums[property_index])); - (void) tolerance; - Assert(interpolated_value >= property_minimums[property_index] - tolerance, - ExcMessage("The particle interpolation limiter did not succeed. Interpolated value: " + std::to_string(interpolated_value) - + " is smaller than the minimum particle property value: " + std::to_string(property_minimums[property_index]) + ".")); - Assert(interpolated_value <= property_maximums[property_index] + tolerance, - ExcMessage("The particle interpolation limiter did not succeed. Interpolated value: " + std::to_string(interpolated_value) - + " is larger than the maximum particle property value: " + std::to_string(property_maximums[property_index]) + ".")); - - // This chopping is done to avoid values that are just outside - // of the limiting bounds. - interpolated_value = std::min(interpolated_value, property_maximums[property_index]); - interpolated_value = std::max(interpolated_value, property_minimums[property_index]); - } - cell_properties[index_positions][property_index] = interpolated_value; - } - - } - } - return cell_properties; - } - - - - template - void - QuadraticLeastSquares::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Interpolator"); - { - prm.enter_subsection("Quadratic least squares"); - { - prm.declare_entry("Use quadratic least squares limiter", "true", - Patterns::List(Patterns::Bool()), - "Limit the interpolation of particle properties onto the cell, so that " - "the value of each property is no smaller than its minimum and no " - "larger than its maximum on the particles of each cell, and the " - "average of neighboring cells. If more than one value is given, " - "it will be treated as a list with one component per particle property."); - prm.declare_entry("Use boundary extrapolation", "false", - Patterns::List(Patterns::Bool()), - "Extends the range used by 'Use quadratic least squares limiter' " - "by linearly interpolating values at cell boundaries from neighboring " - "cells. If more than one value is given, it will be treated as a list " - "with one component per particle property. Enabling 'Use boundary " - "extrapolation' requires enabling 'Use quadratic least squares " - "limiter'."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - QuadraticLeastSquares::parse_parameters (ParameterHandler &prm) - { - fallback_interpolator.parse_parameters(prm); - - prm.enter_subsection("Interpolator"); - { - prm.enter_subsection("Quadratic least squares"); - { - const auto &particle_property_information = this->get_particle_world(this->get_particle_world_index()).get_property_manager().get_data_info(); - const unsigned int n_property_components = particle_property_information.n_components(); - const unsigned int n_internal_components = particle_property_information.get_components_by_field_name("internal: integrator properties"); - - const std::vector quadratic_least_squares_limiter_split = Utilities::split_string_list(prm.get("Use quadratic least squares limiter")); - std::vector quadratic_least_squares_limiter_parsed; - if (quadratic_least_squares_limiter_split.size() == 1) - { - quadratic_least_squares_limiter_parsed = std::vector(n_property_components - n_internal_components, Utilities::string_to_bool(quadratic_least_squares_limiter_split[0])); - } - else if (quadratic_least_squares_limiter_split.size() == n_property_components - n_internal_components) - { - for (const auto &component: quadratic_least_squares_limiter_split) - quadratic_least_squares_limiter_parsed.push_back(Utilities::string_to_bool(component)); - } - else - { - AssertThrow(false, ExcMessage("The size of 'Use quadratic least squares limiter' should either be 1 or the number of particle properties")); - } - for (unsigned int i = 0; i < n_internal_components; ++i) - quadratic_least_squares_limiter_parsed.push_back(false); - use_quadratic_least_squares_limiter = ComponentMask(quadratic_least_squares_limiter_parsed); - - - const std::vector boundary_extrapolation_split = Utilities::split_string_list(prm.get("Use boundary extrapolation")); - std::vector boundary_extrapolation_parsed; - if (boundary_extrapolation_split.size() == 1) - { - boundary_extrapolation_parsed = std::vector(n_property_components - n_internal_components, Utilities::string_to_bool(boundary_extrapolation_split[0])); - } - else if (boundary_extrapolation_split.size() == n_property_components - n_internal_components) - { - for (const auto &component: boundary_extrapolation_split) - boundary_extrapolation_parsed.push_back(Utilities::string_to_bool(component)); - } - else - { - AssertThrow(false, ExcMessage("The size of 'Use boundary extrapolation' should either be 1 or the number of particle properties")); - } - for (unsigned int i = 0; i < n_internal_components; ++i) - boundary_extrapolation_parsed.push_back(false); - use_boundary_extrapolation = ComponentMask(boundary_extrapolation_parsed); - for (unsigned int property_index = 0; property_index < n_property_components - n_internal_components; ++property_index) - { - AssertThrow(use_quadratic_least_squares_limiter[property_index] || !use_boundary_extrapolation[property_index], - ExcMessage("'Use boundary extrapolation' must be set with 'Use quadratic least squares limiter' to be valid.")); - } - - } - prm.leave_subsection(); - } - prm.leave_subsection(); - - // In general n_selected_components() requests an argument of the ComponentMask's size since it could be initialized to be entirely true without a size. - // Here it is given a size equal to n_property_components, so that argument is not necessary. - const bool limiter_enabled_for_at_least_one_property = (use_quadratic_least_squares_limiter.n_selected_components() != 0); - AssertThrow(limiter_enabled_for_at_least_one_property == false || prm.get_bool("Update ghost particles") == true, - ExcMessage("If 'Use quadratic least squares limiter' is enabled for any particle property, then 'Update ghost particles' must be set to true")); - - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Interpolator - { - ASPECT_REGISTER_PARTICLE_INTERPOLATOR(QuadraticLeastSquares, - "quadratic least squares", - "Interpolates particle properties onto a vector of points using a " - "quadratic least squares method. Note that deal.II must be configured " - "with BLAS/LAPACK.") - } - } -} diff --git a/source/particle/property/composition.cc.bak b/source/particle/property/composition.cc.bak deleted file mode 100644 index 8584d0f65ad..00000000000 --- a/source/particle/property/composition.cc.bak +++ /dev/null @@ -1,110 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - - -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - void - Composition::initialize_one_particle_property(const Point &position, - std::vector &data) const - { - for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) - data.push_back(this->get_initial_composition_manager().initial_composition(position,i)); - } - - template - void - Composition::update_particle_property(const unsigned int data_position, - const Vector &solution, - const std::vector> &/*gradients*/, - typename ParticleHandler::particle_iterator &particle) const - { - for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) - { - const unsigned int solution_component = this->introspection().component_indices.compositional_fields[i]; - particle->get_properties()[data_position+i] = solution[solution_component]; - } - } - - template - UpdateTimeFlags - Composition::need_update() const - { - return update_time_step; - } - - template - UpdateFlags - Composition::get_needed_update_flags () const - { - return update_values; - } - - template - std::vector> - Composition::get_property_information() const - { - - AssertThrow(this->n_compositional_fields() > 0, - ExcMessage("You have requested the particle property , " - "but the number of compositional fields is 0. " - "Please add compositional fields to your model, or remove " - "this particle property.")); - - std::vector> property_information; - - - - for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) - { - const std::string field_name = this->introspection().name_for_compositional_index(i); - property_information.emplace_back(field_name,1); - } - return property_information; - } - - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(Composition, - "composition", - "Implementation of a plugin in which the particle " - "property is defined by the compositional fields in " - "the model. This can be used to track solid composition" - "evolution over time.") - } - } -} diff --git a/source/particle/property/cpo_bingham_average.cc.bak b/source/particle/property/cpo_bingham_average.cc.bak deleted file mode 100644 index 8ccba63ae27..00000000000 --- a/source/particle/property/cpo_bingham_average.cc.bak +++ /dev/null @@ -1,284 +0,0 @@ -/* - Copyright (C) 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include - -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - void - CpoBinghamAverage::initialize () - { - const unsigned int my_rank = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); - this->random_number_generator.seed(random_number_seed+my_rank); - const auto &manager = this->get_particle_world(this->get_particle_world_index()).get_property_manager(); - AssertThrow(manager.plugin_name_exists("crystal preferred orientation"), - ExcMessage("No crystal preferred orientation property plugin found.")); - - AssertThrow(manager.check_plugin_order("crystal preferred orientation","cpo bingham average"), - ExcMessage("To use the cpo bingham average plugin, the cpo plugin need to be defined before this plugin.")); - - cpo_data_position = manager.get_data_info().get_position_by_plugin_index(manager.get_plugin_index_by_name("crystal preferred orientation")); - - } - - - - template - void - CpoBinghamAverage::initialize_one_particle_property(const Point &, - std::vector &data) const - { - std::vector volume_fractions_grains(n_grains); - std::vector> rotation_matrices_grains(n_grains); - for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) - { - // create volume fractions and rotation matrix vectors in the order that it is stored in the data array - for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) - { - volume_fractions_grains[grain_i] = cpo_particle_property->get_volume_fractions_grains(cpo_data_position,data,mineral_i,grain_i); - rotation_matrices_grains[grain_i] = cpo_particle_property->get_rotation_matrix_grains(cpo_data_position,data,mineral_i,grain_i); - } - - const std::vector> weighted_rotation_matrices = - Utilities::rotation_matrices_random_draw_volume_weighting(volume_fractions_grains, - rotation_matrices_grains, - n_samples, - this->random_number_generator); - const std::array,3> bingham_average = compute_bingham_average(weighted_rotation_matrices); - - for (unsigned int i = 0; i < 3; ++i) - for (unsigned int j = 0; j < 6; ++j) - data.emplace_back(bingham_average[i][j]); - } - } - - - - template - void - CpoBinghamAverage::update_particle_property(const unsigned int data_position, - const Vector &/*solution*/, - const std::vector> &/*gradients*/, - typename ParticleHandler::particle_iterator &particle) const - { - std::vector volume_fractions_grains(n_grains); - std::vector> rotation_matrices_grains(n_grains); - ArrayView data = particle->get_properties(); - for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) - { - // create volume fractions and rotation matrix vectors in the order that it is stored in the data array - for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) - { - volume_fractions_grains[grain_i] = cpo_particle_property->get_volume_fractions_grains(cpo_data_position,data,mineral_i,grain_i); - rotation_matrices_grains[grain_i] = cpo_particle_property->get_rotation_matrix_grains(cpo_data_position,data,mineral_i,grain_i); - } - - const std::vector> weighted_rotation_matrices = Utilities::rotation_matrices_random_draw_volume_weighting(volume_fractions_grains, rotation_matrices_grains, n_samples, this->random_number_generator); - std::array,3> bingham_average = compute_bingham_average(weighted_rotation_matrices); - - for (unsigned int i = 0; i < 3; ++i) - for (unsigned int j = 0; j < 6; ++j) - { - data[data_position + mineral_i*18 + i*3 + j] = bingham_average[i][j]; - } - } - } - - - - template - std::array,3> - CpoBinghamAverage::compute_bingham_average(std::vector> matrices) const - { - SymmetricTensor<2,3> sum_matrix_a; - SymmetricTensor<2,3> sum_matrix_b; - SymmetricTensor<2,3> sum_matrix_c; - - // extracting the a, b and c orientations from the olivine a matrix - // see https://courses.eas.ualberta.ca/eas421/lecturepages/orientation.html - const unsigned int n_matrices = matrices.size(); - for (unsigned int i_grain = 0; i_grain < n_matrices; ++i_grain) - { - sum_matrix_a[0][0] += matrices[i_grain][0][0] * matrices[i_grain][0][0]; // SUM(l^2) - sum_matrix_a[1][1] += matrices[i_grain][0][1] * matrices[i_grain][0][1]; // SUM(m^2) - sum_matrix_a[2][2] += matrices[i_grain][0][2] * matrices[i_grain][0][2]; // SUM(n^2) - sum_matrix_a[0][1] += matrices[i_grain][0][0] * matrices[i_grain][0][1]; // SUM(l*m) - sum_matrix_a[0][2] += matrices[i_grain][0][0] * matrices[i_grain][0][2]; // SUM(l*n) - sum_matrix_a[1][2] += matrices[i_grain][0][1] * matrices[i_grain][0][2]; // SUM(m*n) - - - sum_matrix_b[0][0] += matrices[i_grain][1][0] * matrices[i_grain][1][0]; // SUM(l^2) - sum_matrix_b[1][1] += matrices[i_grain][1][1] * matrices[i_grain][1][1]; // SUM(m^2) - sum_matrix_b[2][2] += matrices[i_grain][1][2] * matrices[i_grain][1][2]; // SUM(n^2) - sum_matrix_b[0][1] += matrices[i_grain][1][0] * matrices[i_grain][1][1]; // SUM(l*m) - sum_matrix_b[0][2] += matrices[i_grain][1][0] * matrices[i_grain][1][2]; // SUM(l*n) - sum_matrix_b[1][2] += matrices[i_grain][1][1] * matrices[i_grain][1][2]; // SUM(m*n) - - - sum_matrix_c[0][0] += matrices[i_grain][2][0] * matrices[i_grain][2][0]; // SUM(l^2) - sum_matrix_c[1][1] += matrices[i_grain][2][1] * matrices[i_grain][2][1]; // SUM(m^2) - sum_matrix_c[2][2] += matrices[i_grain][2][2] * matrices[i_grain][2][2]; // SUM(n^2) - sum_matrix_c[0][1] += matrices[i_grain][2][0] * matrices[i_grain][2][1]; // SUM(l*m) - sum_matrix_c[0][2] += matrices[i_grain][2][0] * matrices[i_grain][2][2]; // SUM(l*n) - sum_matrix_c[1][2] += matrices[i_grain][2][1] * matrices[i_grain][2][2]; // SUM(m*n) - - } - const std::array>, 3> eigenvectors_a = eigenvectors(sum_matrix_a, SymmetricTensorEigenvectorMethod::jacobi); - const std::array>, 3> eigenvectors_b = eigenvectors(sum_matrix_b, SymmetricTensorEigenvectorMethod::jacobi); - const std::array>, 3> eigenvectors_c = eigenvectors(sum_matrix_c, SymmetricTensorEigenvectorMethod::jacobi); - - // average axis = eigenvector * largest eigenvalue - const Tensor<1,3,double> averaged_a = eigenvectors_a[0].second * eigenvectors_a[0].first; - const Tensor<1,3,double> averaged_b = eigenvectors_b[0].second * eigenvectors_b[0].first; - const Tensor<1,3,double> averaged_c = eigenvectors_c[0].second * eigenvectors_a[0].first; - - // eigenvalues of all axes, used in the anisotropic viscosity material model to compute Hill's coefficients - const double eigenvalue_a1 = eigenvectors_a[0].first/matrices.size(); - const double eigenvalue_a2 = eigenvectors_a[1].first/matrices.size(); - const double eigenvalue_a3 = eigenvectors_a[2].first/matrices.size(); - const double eigenvalue_b1 = eigenvectors_b[0].first/matrices.size(); - const double eigenvalue_b2 = eigenvectors_b[1].first/matrices.size(); - const double eigenvalue_b3 = eigenvectors_b[2].first/matrices.size(); - const double eigenvalue_c1 = eigenvectors_c[0].first/matrices.size(); - const double eigenvalue_c2 = eigenvectors_c[1].first/matrices.size(); - const double eigenvalue_c3 = eigenvectors_c[2].first/matrices.size(); - - return - { - { - {{averaged_a[0],averaged_a[1],averaged_a[2], eigenvalue_a1, eigenvalue_a2, eigenvalue_a3}}, - {{averaged_b[0],averaged_b[1],averaged_b[2], eigenvalue_b1, eigenvalue_b2, eigenvalue_b3}}, - {{averaged_c[0],averaged_c[1],averaged_c[2], eigenvalue_c1, eigenvalue_c2, eigenvalue_c3}} - } - }; - - } - - - - template - UpdateTimeFlags - CpoBinghamAverage::need_update() const - { - return update_output_step; - } - - - - template - UpdateFlags - CpoBinghamAverage::get_needed_update_flags () const - { - return update_default; - } - - - - template - std::vector> - CpoBinghamAverage::get_property_information() const - { - std::vector> property_information; - property_information.reserve(6*n_minerals); - for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) - { - property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " bingham average a axis",3); - property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " eigenvalues a axis",3); - property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " bingham average b axis",3); - property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " eigenvalues b axis",3); - property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " bingham average c axis",3); - property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " eigenvalues c axis",3); - } - - return property_information; - } - - - - template - void - CpoBinghamAverage::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("CPO Bingham Average"); - { - prm.declare_entry ("Random number seed", "1", - Patterns::Integer (0), - "The seed used to generate random numbers. This will make sure that " - "results are reproducible as long as the problem is run with the " - "same amount of MPI processes. It is implemented as final seed = " - "Random number seed + MPI Rank. "); - - prm.declare_entry ("Number of samples", "0", - Patterns::Double(0), - "This determines how many samples are taken when using the random " - "draw volume averaging. Setting it to zero means that the number of " - "samples is set to be equal to the number of grains."); - } - prm.leave_subsection (); - } - - - - template - void - CpoBinghamAverage::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("CPO Bingham Average"); - { - // Get a pointer to the CPO particle property. - cpo_particle_property = std::make_unique> ( - this->get_particle_world(this->get_particle_world_index()).get_property_manager().template get_matching_property>()); - - random_number_seed = prm.get_integer ("Random number seed"); - n_grains = cpo_particle_property->get_number_of_grains(); - n_minerals = cpo_particle_property->get_number_of_minerals(); - n_samples = prm.get_integer("Number of samples"); - if (n_samples == 0) - n_samples = n_grains; - } - prm.leave_subsection (); - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(CpoBinghamAverage, - "cpo bingham average", - "This is a particle property plugin which computes the Bingham " - "average for the Crystal Preferred Orientation particle property " - "plugin so that it can be visualized.") - } - } -} diff --git a/source/particle/property/cpo_elastic_tensor.cc.bak b/source/particle/property/cpo_elastic_tensor.cc.bak deleted file mode 100644 index e15c4436b70..00000000000 --- a/source/particle/property/cpo_elastic_tensor.cc.bak +++ /dev/null @@ -1,261 +0,0 @@ -/* - Copyright (C) 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include - -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - - - template - CpoElasticTensor::CpoElasticTensor () - { - // The following values are directly from D-Rex. - // Todo: make them a input parameter - // Stiffness matrix for Olivine (GigaPascals) - stiffness_matrix_olivine[0][0] = 320.71; - stiffness_matrix_olivine[0][1] = 69.84; - stiffness_matrix_olivine[0][2] = 71.22; - stiffness_matrix_olivine[1][1] = 197.25; - stiffness_matrix_olivine[1][2] = 74.8; - stiffness_matrix_olivine[2][2] = 234.32; - stiffness_matrix_olivine[3][3] = 63.77; - stiffness_matrix_olivine[4][4] = 77.67; - stiffness_matrix_olivine[5][5] = 78.36; - - - // Stiffness matrix for Enstatite (GPa) - stiffness_matrix_enstatite[0][0] = 236.9; - stiffness_matrix_enstatite[0][1] = 79.6; - stiffness_matrix_enstatite[0][2] = 63.2; - stiffness_matrix_enstatite[1][1] = 180.5; - stiffness_matrix_enstatite[1][2] = 56.8; - stiffness_matrix_enstatite[2][2] = 230.4; - stiffness_matrix_enstatite[3][3] = 84.3; - stiffness_matrix_enstatite[4][4] = 79.4; - stiffness_matrix_enstatite[5][5] = 80.1; - } - - - - template - void - CpoElasticTensor::initialize () - { - const auto &manager = this->get_particle_world(this->get_particle_world_index()).get_property_manager(); - AssertThrow(manager.plugin_name_exists("crystal preferred orientation"), - ExcMessage("No crystal preferred orientation property plugin found.")); - - AssertThrow(manager.check_plugin_order("crystal preferred orientation","cpo elastic tensor"), - ExcMessage("To use the cpo elastic tensor plugin, the cpo plugin needs to be defined before this plugin.")); - - cpo_data_position = manager.get_data_info().get_position_by_plugin_index(manager.get_plugin_index_by_name("crystal preferred orientation")); - } - - - - template - SymmetricTensor<2,6> - CpoElasticTensor::voigt_average_elastic_tensor (const Particle::Property::CrystalPreferredOrientation &cpo_particle_property, - const unsigned int cpo_data_position, - const ArrayView &data) const - { - SymmetricTensor<2,6> C_average; - const SymmetricTensor<2,6> *stiffness_matrix = &stiffness_matrix_olivine; - for (size_t mineral_i = 0; mineral_i < n_minerals; ++mineral_i) - { - if (cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i) == DeformationType::olivine_a_fabric - || cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i) == DeformationType::olivine_b_fabric - || cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i) == DeformationType::olivine_d_fabric - || cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i) == DeformationType::olivine_c_fabric - || cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i) == DeformationType::olivine_e_fabric - ) - { - stiffness_matrix = &stiffness_matrix_olivine; - } - else if (cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i) == DeformationType::enstatite) - { - stiffness_matrix = &stiffness_matrix_enstatite; - } - else - { - AssertThrow(false, ExcMessage("Stiffness matrix not implemented for deformation type " - + std::to_string(static_cast(cpo_particle_property.get_deformation_type(cpo_data_position,data,mineral_i))))); - } - - for (size_t grain_i = 0; grain_i < n_grains; grain_i++) - { - const auto rotated_matrix = Utilities::Tensors::rotate_voigt_stiffness_matrix(transpose(cpo_particle_property.get_rotation_matrix_grains(cpo_data_position,data,mineral_i,grain_i)),*stiffness_matrix); - C_average += cpo_particle_property.get_volume_fractions_grains(cpo_data_position,data,mineral_i,grain_i) * cpo_particle_property.get_volume_fraction_mineral(cpo_data_position,data,mineral_i) * rotated_matrix; - } - } - - return C_average; - } - - - - template - void - CpoElasticTensor::initialize_one_particle_property(const Point &, - std::vector &data) const - { - - // At initialization, the deformation type for cpo is initialized to -1. - // Initialize with the stiffness matrix of olivine to avoid errors in the computation. - - for (unsigned int i = 0; i < SymmetricTensor<2,6>::n_independent_components ; ++i) - { - data.push_back(stiffness_matrix_olivine[SymmetricTensor<2,6>::unrolled_to_component_indices(i)]); - } - - - } - - - - template - void - CpoElasticTensor::update_particle_property(const unsigned int data_position, - const Vector &/*solution*/, - const std::vector> &/*gradients*/, - typename ParticleHandler::particle_iterator &particle) const - { - // Get a reference to the CPO particle property. - const Particle::Property::CrystalPreferredOrientation &cpo_particle_property = - this->get_particle_world(this->get_particle_world_index()).get_property_manager().template get_matching_property>(); - - - const SymmetricTensor<2,6> C_average = voigt_average_elastic_tensor(cpo_particle_property, - cpo_data_position, - particle->get_properties()); - - Particle::Property::CpoElasticTensor::set_elastic_tensor(data_position, - particle->get_properties(), - C_average); - - - } - - - - template - SymmetricTensor<2,6> - CpoElasticTensor::get_elastic_tensor(unsigned int cpo_data_position, - const ArrayView &data) - { - return Utilities::Tensors::to_symmetric_tensor<6>(&data[cpo_data_position], - &data[cpo_data_position]+SymmetricTensor<2,6>::n_independent_components); - } - - - - template - void - CpoElasticTensor::set_elastic_tensor(unsigned int cpo_data_position, - const ArrayView &data, - const SymmetricTensor<2,6> &elastic_tensor) - { - Utilities::Tensors::unroll_symmetric_tensor_into_array(elastic_tensor, - &data[cpo_data_position], - &data[cpo_data_position]+SymmetricTensor<2,6>::n_independent_components); - } - - - - template - UpdateTimeFlags - CpoElasticTensor::need_update() const - { - return update_output_step; - } - - - - template - UpdateFlags - CpoElasticTensor::get_needed_update_flags () const - { - return update_default; - } - - - - template - std::vector> - CpoElasticTensor::get_property_information() const - { - std::vector> property_information; - - property_information.emplace_back("cpo_elastic_tensor", SymmetricTensor<2,6>::n_independent_components); - return property_information; - } - - - - template - void - CpoElasticTensor::declare_parameters (ParameterHandler &) - {} - - - - template - void - CpoElasticTensor::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Crystal Preferred Orientation"); - { - n_grains = prm.get_integer("Number of grains per particle"); - prm.enter_subsection("Initial grains"); - { - n_minerals = dealii::Utilities::split_string_list(prm.get("Minerals")).size(); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(CpoElasticTensor, - "cpo elastic tensor", - "A plugin in which the particle property tensor is " - "defined as the Voigt average of the " - "elastic tensors of the minerals in the textured rock." - "Currently only Olivine and Enstatite are supported.") - } - } -} diff --git a/source/particle/property/crystal_preferred_orientation.cc.bak b/source/particle/property/crystal_preferred_orientation.cc.bak deleted file mode 100644 index 3f849f0ca4d..00000000000 --- a/source/particle/property/crystal_preferred_orientation.cc.bak +++ /dev/null @@ -1,1275 +0,0 @@ -/* - Copyright (C) 2022 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include -#include - -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - - template - void - CrystalPreferredOrientation::initialize () - { - CitationInfo::add("CPO"); - const unsigned int my_rank = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); - this->random_number_generator.seed(random_number_seed+my_rank); - - // Don't assert when called by the unit tester. - if (this->simulator_is_past_initialization()) - { - AssertThrow(this->introspection().compositional_name_exists("water"), - ExcMessage("Particle property CPO only works if" - "there is a compositional field called water.")); - water_index = this->introspection().compositional_index_for_name("water"); - } - } - - - - template - void - CrystalPreferredOrientation::compute_random_rotation_matrix(Tensor<2,3> &rotation_matrix) const - { - - // This function is based on an article in Graphic Gems III, written by James Arvo, Cornell University (p 116-120). - // The original code can be found on http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/rand_rotation.c - // and is licenced according to this website with the following licence: - // - // "The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and - // resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit - // is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems - // code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, - // don't be a jerk, and remember that anything free comes with no guarantee."" - // - // The book states in the preface the following: "As in the first two volumes, all of the C and C++ code in this book is in - // the public domain, and is yours to study, modify, and use." - - // first generate three random numbers between 0 and 1 and multiply them with 2 PI or 2 for z. Note that these are not the same as phi_1, theta and phi_2. - - boost::random::uniform_real_distribution uniform_distribution(0,1); - double one = uniform_distribution(this->random_number_generator); - double two = uniform_distribution(this->random_number_generator); - double three = uniform_distribution(this->random_number_generator); - - double theta = 2.0 * M_PI * one; // Rotation about the pole (Z) - double phi = 2.0 * M_PI * two; // For direction of pole deflection. - double z = 2.0* three; //For magnitude of pole deflection. - - // Compute a vector V used for distributing points over the sphere - // via the reflection I - V Transpose(V). This formulation of V - // will guarantee that if x[1] and x[2] are uniformly distributed, - // the reflected points will be uniform on the sphere. Note that V - // has length sqrt(2) to eliminate the 2 in the Householder matrix. - - double r = std::sqrt( z ); - double Vx = std::sin( phi ) * r; - double Vy = std::cos( phi ) * r; - double Vz = std::sqrt( 2.f - z ); - - // Compute the row vector S = Transpose(V) * R, where R is a simple - // rotation by theta about the z-axis. No need to compute Sz since - // it's just Vz. - - double st = std::sin( theta ); - double ct = std::cos( theta ); - double Sx = Vx * ct - Vy * st; - double Sy = Vx * st + Vy * ct; - - // Construct the rotation matrix ( V Transpose(V) - I ) R, which - // is equivalent to V S - R. - - rotation_matrix[0][0] = Vx * Sx - ct; - rotation_matrix[0][1] = Vx * Sy - st; - rotation_matrix[0][2] = Vx * Vz; - rotation_matrix[1][0] = Vy * Sx + st; - rotation_matrix[1][1] = Vy * Sy - ct; - rotation_matrix[1][2] = Vy * Vz; - rotation_matrix[2][0] = Vz * Sx; - rotation_matrix[2][1] = Vz * Sy; - rotation_matrix[2][2] = 1.0 - z; // This equals Vz * Vz - 1.0 - } - - - - template - void - CrystalPreferredOrientation::initialize_one_particle_property(const Point &position, - std::vector &data) const - { - // the layout of the data vector per particle is the following: - // 1. M mineral times - // 1.1 olivine deformation type -> 1 double, at location - // => data_position + 0 + mineral_i * (n_grains * 10 + 2) - // 2.1. Mineral volume fraction -> 1 double, at location - // => data_position + 1 + mineral_i *(n_grains * 10 + 2) - // 2.2. N grains times: - // 2.1. volume fraction grain -> 1 double, at location: - // => data_position + 2 + i_grain * 10 + mineral_i *(n_grains * 10 + 2), or - // => data_position + 2 + i_grain * (2 * Tensor<2,3>::n_independent_components+ 2) + mineral_i * (n_grains * 10 + 2) - // 2.2. rotation matrix grain -> 9 (Tensor<2,dim>::n_independent_components) doubles, starts at: - // => data_position + 3 + i_grain * 10 + mineral_i * (n_grains * 10 + 2), or - // => data_position + 3 + i_grain * (2 * Tensor<2,3>::n_independent_components+ 2) + mineral_i * (n_grains * 10 + 2) - // - // Note that we store exactly the same number of grains of all minerals (e.g. olivine and enstatite - // grains), although their volume fractions may not be the same. We need a minimum amount - // of grains per tracer to perform reliable statistics on it. This minimum is the same for all phases. - // and enstatite. - // - // Furthermore, for this plugin the following dims are always 3. When using 2d an infinitely thin 3d domain is assumed. - // - // The rotation matrix is a direction cosine matrix, representing the orientation of the grain in the domain. - // The fabric is determined later in the computations, so initialize it to -1. - std::vector deformation_type(n_minerals, -1.0); - std::vector>volume_fractions_grains(n_minerals); - std::vector>> rotation_matrices_grains(n_minerals); - - for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) - { - volume_fractions_grains[mineral_i].resize(n_grains); - rotation_matrices_grains[mineral_i].resize(n_grains); - - // This will be set by the initial grain subsection. - if (initial_grains_model == CPOInitialGrainsModel::world_builder) - { -#ifdef ASPECT_WITH_WORLD_BUILDER - WorldBuilder::grains wb_grains = this->get_world_builder().grains(Utilities::convert_point_to_array(position), - -this->get_geometry_model().height_above_reference_surface(position), - mineral_i, - n_grains); - double sum_volume_fractions = 0; - for (unsigned int grain_i = 0; grain_i < n_grains ; ++grain_i) - { - sum_volume_fractions += wb_grains.sizes[grain_i]; - volume_fractions_grains[mineral_i][grain_i] = wb_grains.sizes[grain_i]; - // we are receiving a array,3> from the world builder, - // which needs to be copied in the correct way into a tensor<2,3>. - for (unsigned int component_i = 0; component_i < 3 ; ++component_i) - { - for (unsigned int component_j = 0; component_j < 3 ; ++component_j) - { - Assert(!std::isnan(wb_grains.rotation_matrices[grain_i][component_i][component_j]), ExcMessage("Error: not a number.")); - rotation_matrices_grains[mineral_i][grain_i][component_i][component_j] = wb_grains.rotation_matrices[grain_i][component_i][component_j]; - } - } - } - - AssertThrow(sum_volume_fractions != 0, ExcMessage("Sum of volumes is equal to zero, which is not supposed to happen. " - "Make sure that all parts of the domain which contain particles are covered by the world builder.")); -#else - AssertThrow(false, - ExcMessage("The world builder was requested but not provided. Make sure that aspect is " - "compiled with the World Builder and that you provide a world builder file in the input.")); -#endif - } - else - { - // set volume fraction - const double initial_volume_fraction = 1.0/n_grains; - - for (unsigned int grain_i = 0; grain_i < n_grains ; ++grain_i) - { - // set volume fraction - volume_fractions_grains[mineral_i][grain_i] = initial_volume_fraction; - - // set a uniform random rotation_matrix per grain - this->compute_random_rotation_matrix(rotation_matrices_grains[mineral_i][grain_i]); - } - } - } - - for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) - { - data.emplace_back(deformation_type[mineral_i]); - data.emplace_back(volume_fractions_minerals[mineral_i]); - for (unsigned int grain_i = 0; grain_i < n_grains ; ++grain_i) - { - data.emplace_back(volume_fractions_grains[mineral_i][grain_i]); - for (unsigned int i = 0; i < Tensor<2,3>::n_independent_components ; ++i) - { - const dealii::TableIndices<2> index = Tensor<2,3>::unrolled_to_component_indices(i); - data.emplace_back(rotation_matrices_grains[mineral_i][grain_i][index]); - } - } - } - } - - - - template - void - CrystalPreferredOrientation::update_particle_property(const unsigned int data_position, - const Vector &solution, - const std::vector> &gradients, - typename ParticleHandler::particle_iterator &particle) const - { - // STEP 1: Load data and preprocess it. - - // need access to the pressure, viscosity, - // get velocity - Tensor<1,dim> velocity; - for (unsigned int i = 0; i < dim; ++i) - velocity[i] = solution[this->introspection().component_indices.velocities[i]]; - - // get velocity gradient tensor. - Tensor<2,dim> velocity_gradient; - for (unsigned int i = 0; i < dim; ++i) - velocity_gradient[i] = gradients[this->introspection().component_indices.velocities[i]]; - - // Calculate strain rate from velocity gradients - const SymmetricTensor<2,dim> strain_rate = symmetrize (velocity_gradient); - const SymmetricTensor<2,dim> deviatoric_strain_rate - = (this->get_material_model().is_compressible() - ? - strain_rate - 1./3 * trace(strain_rate) * unit_symmetric_tensor() - : - strain_rate); - - const double pressure = solution[this->introspection().component_indices.pressure]; - const double temperature = solution[this->introspection().component_indices.temperature]; - const double water_content = solution[this->introspection().component_indices.compositional_fields[water_index]]; - - // get the composition of the particle - std::vector compositions; - for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) - { - const unsigned int solution_component = this->introspection().component_indices.compositional_fields[i]; - compositions.push_back(solution[solution_component]); - } - - const double dt = this->get_timestep(); - - // even in 2d we need 3d strain-rates and velocity gradient tensors. So we make them 3d by - // adding an extra dimension which is zero. - SymmetricTensor<2,3> strain_rate_3d; - strain_rate_3d[0][0] = strain_rate[0][0]; - strain_rate_3d[0][1] = strain_rate[0][1]; - //sym: strain_rate_3d[1][0] = strain_rate[1][0]; - strain_rate_3d[1][1] = strain_rate[1][1]; - - if (dim == 3) - { - strain_rate_3d[0][2] = strain_rate[0][2]; - strain_rate_3d[1][2] = strain_rate[1][2]; - //sym: strain_rate_3d[2][0] = strain_rate[0][2]; - //sym: strain_rate_3d[2][1] = strain_rate[1][2]; - strain_rate_3d[2][2] = strain_rate[2][2]; - } - Tensor<2,3> velocity_gradient_3d; - velocity_gradient_3d[0][0] = velocity_gradient[0][0]; - velocity_gradient_3d[0][1] = velocity_gradient[0][1]; - velocity_gradient_3d[1][0] = velocity_gradient[1][0]; - velocity_gradient_3d[1][1] = velocity_gradient[1][1]; - if (dim == 3) - { - velocity_gradient_3d[0][2] = velocity_gradient[0][2]; - velocity_gradient_3d[1][2] = velocity_gradient[1][2]; - velocity_gradient_3d[2][0] = velocity_gradient[2][0]; - velocity_gradient_3d[2][1] = velocity_gradient[2][1]; - velocity_gradient_3d[2][2] = velocity_gradient[2][2]; - } - - ArrayView data = particle->get_properties(); - - for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) - { - - /** - * Now we have loaded all the data and can do the actual computation. - * The computation consists of two parts. The first part is computing - * the derivatives for the directions and grain sizes. Then those - * derivatives are used to advect the particle properties. - */ - double sum_volume_mineral = 0; - std::pair, std::vector>> - derivatives_grains = this->compute_derivatives(data_position, - data, - mineral_i, - strain_rate_3d, - velocity_gradient_3d, - particle->get_location(), - temperature, - pressure, - velocity, - compositions, - strain_rate, - deviatoric_strain_rate, - water_content); - - switch (advection_method) - { - case AdvectionMethod::forward_euler: - - sum_volume_mineral = this->advect_forward_euler(data_position, - data, - mineral_i, - dt, - derivatives_grains); - - break; - - case AdvectionMethod::backward_euler: - sum_volume_mineral = this->advect_backward_euler(data_position, - data, - mineral_i, - dt, - derivatives_grains); - - break; - } - - // normalize the volume fractions back to a total of 1 for each mineral - const double inv_sum_volume_mineral = 1.0/sum_volume_mineral; - - Assert(std::isfinite(inv_sum_volume_mineral), - ExcMessage("inv_sum_volume_mineral is not finite. sum_volume_enstatite = " - + std::to_string(sum_volume_mineral))); - - for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) - { - const double volume_fraction_grains = get_volume_fractions_grains(data_position,data,mineral_i,grain_i)*inv_sum_volume_mineral; - set_volume_fractions_grains(data_position,data,mineral_i,grain_i,volume_fraction_grains); - Assert(isfinite(get_volume_fractions_grains(data_position,data,mineral_i,grain_i)), - ExcMessage("volume_fractions_grains[mineral_i]" + std::to_string(grain_i) + "] is not finite: " - + std::to_string(get_volume_fractions_grains(data_position,data,mineral_i,grain_i)) + ", inv_sum_volume_mineral = " - + std::to_string(inv_sum_volume_mineral) + ".")); - - /** - * Correct direction rotation matrices numerical error (orthnormality) after integration - * Follows same method as in matlab version from Thissen (see https://github.com/cthissen/Drex-MATLAB/) - * of finding the nearest orthonormal matrix using the SVD - */ - Tensor<2,3> rotation_matrix = get_rotation_matrix_grains(data_position,data,mineral_i,grain_i); - for (size_t i = 0; i < 3; ++i) - { - for (size_t j = 0; j < 3; ++j) - { - Assert(!std::isnan(rotation_matrix[i][j]), ExcMessage("rotation_matrix is nan before orthogonalization.")); - } - } - - rotation_matrix = dealii::project_onto_orthogonal_tensors(rotation_matrix); - for (size_t i = 0; i < 3; ++i) - for (size_t j = 0; j < 3; ++j) - { - // I don't think this should happen with the projection, but D-Rex - // does not do the orthogonal projection, but just clamps the values - // to 1 and -1. - Assert(std::fabs(rotation_matrix[i][j]) <= 1.0, - ExcMessage("The rotation_matrix has a entry larger than 1.")); - - Assert(!std::isnan(rotation_matrix[i][j]), - ExcMessage("rotation_matrix is nan after orthoganalization: " - + std::to_string(rotation_matrix[i][j]))); - - Assert(abs(rotation_matrix[i][j]) <= 1.0, - ExcMessage("3. rotation_matrix[" + std::to_string(i) + "][" + std::to_string(j) + - "] is larger than one: " - + std::to_string(rotation_matrix[i][j]) + " (" + std::to_string(rotation_matrix[i][j]-1.0) + "). rotation_matrix = \n" - + std::to_string(rotation_matrix[0][0]) + " " + std::to_string(rotation_matrix[0][1]) + " " + std::to_string(rotation_matrix[0][2]) + "\n" - + std::to_string(rotation_matrix[1][0]) + " " + std::to_string(rotation_matrix[1][1]) + " " + std::to_string(rotation_matrix[1][2]) + "\n" - + std::to_string(rotation_matrix[2][0]) + " " + std::to_string(rotation_matrix[2][1]) + " " + std::to_string(rotation_matrix[2][2]))); - } - } - } - } - - - - template - UpdateTimeFlags - CrystalPreferredOrientation::need_update() const - { - return update_time_step; - } - - - - template - InitializationModeForLateParticles - CrystalPreferredOrientation::late_initialization_mode () const - { - return InitializationModeForLateParticles::interpolate; - } - - - - template - UpdateFlags - CrystalPreferredOrientation::get_needed_update_flags () const - { - return update_values | update_gradients; - } - - - - template - std::vector> - CrystalPreferredOrientation::get_property_information() const - { - std::vector> property_information; - property_information.reserve(n_minerals * n_grains * (1+Tensor<2,3>::n_independent_components)); - - for (unsigned int mineral_i = 0; mineral_i < n_minerals; ++mineral_i) - { - property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " type",1); - property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " volume fraction",1); - - for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) - { - property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " grain " + std::to_string(grain_i) + " volume fraction",1); - - for (unsigned int index = 0; index < Tensor<2,3>::n_independent_components; ++index) - { - property_information.emplace_back("cpo mineral " + std::to_string(mineral_i) + " grain " + std::to_string(grain_i) + " rotation_matrix " + std::to_string(index),1); - } - } - } - - return property_information; - } - - - - template - double - CrystalPreferredOrientation::advect_forward_euler(const unsigned int cpo_index, - const ArrayView &data, - const unsigned int mineral_i, - const double dt, - const std::pair, std::vector>> &derivatives) const - { - double sum_volume_fractions = 0; - Tensor<2,3> rotation_matrix; - for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) - { - // Do the volume fraction of the grain - Assert(std::isfinite(get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i)),ExcMessage("volume_fractions[grain_i] is not finite before it is set.")); - double volume_fraction_grains = get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i); - volume_fraction_grains = volume_fraction_grains + dt * volume_fraction_grains * derivatives.first[grain_i]; - set_volume_fractions_grains(cpo_index,data,mineral_i,grain_i, volume_fraction_grains); - Assert(std::isfinite(get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i)),ExcMessage("volume_fractions[grain_i] is not finite. grain_i = " - + std::to_string(grain_i) + ", volume_fractions[grain_i] = " + std::to_string(get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i)) - + ", derivatives.first[grain_i] = " + std::to_string(derivatives.first[grain_i]))); - - sum_volume_fractions += get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i); - - // Do the rotation matrix for this grain - rotation_matrix = get_rotation_matrix_grains(cpo_index,data,mineral_i,grain_i); - rotation_matrix += dt * rotation_matrix * derivatives.second[grain_i]; - set_rotation_matrix_grains(cpo_index,data,mineral_i,grain_i,rotation_matrix); - } - - Assert(sum_volume_fractions != 0, ExcMessage("The sum of all grain volume fractions of a mineral is equal to zero. This should not happen.")); - return sum_volume_fractions; - } - - - - template - double - CrystalPreferredOrientation::advect_backward_euler(const unsigned int cpo_index, - const ArrayView &data, - const unsigned int mineral_i, - const double dt, - const std::pair, std::vector>> &derivatives) const - { - double sum_volume_fractions = 0; - Tensor<2,3> cosine_ref; - for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) - { - // Do the volume fraction of the grain - double vf_old = get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i); - double vf_new = get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i); - Assert(std::isfinite(vf_new),ExcMessage("vf_new is not finite before it is set.")); - for (size_t iteration = 0; iteration < property_advection_max_iterations; ++iteration) - { - Assert(std::isfinite(vf_new),ExcMessage("vf_new is not finite before it is set. grain_i = " - + std::to_string(grain_i) + ", volume_fractions[grain_i] = " + std::to_string(get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i)) - + ", derivatives.first[grain_i] = " + std::to_string(derivatives.first[grain_i]))); - - vf_new = get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i) + dt * vf_new * derivatives.first[grain_i]; - - Assert(std::isfinite(get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i)),ExcMessage("volume_fractions[grain_i] is not finite. grain_i = " - + std::to_string(grain_i) + ", volume_fractions[grain_i] = " + std::to_string(get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i)) - + ", derivatives.first[grain_i] = " + std::to_string(derivatives.first[grain_i]))); - if (std::fabs(vf_new-vf_old) < property_advection_tolerance) - { - break; - } - vf_old = vf_new; - } - - set_volume_fractions_grains(cpo_index,data,mineral_i,grain_i,vf_new); - sum_volume_fractions += vf_new; - - // Do the rotation matrix for this grain - cosine_ref = get_rotation_matrix_grains(cpo_index,data,mineral_i,grain_i); - Tensor<2,3> cosine_old = cosine_ref; - Tensor<2,3> cosine_new = cosine_ref; - - for (size_t iteration = 0; iteration < property_advection_max_iterations; ++iteration) - { - cosine_new = cosine_ref + dt * cosine_new * derivatives.second[grain_i]; - - if ((cosine_new-cosine_old).norm() < property_advection_tolerance) - { - break; - } - cosine_old = cosine_new; - } - - set_rotation_matrix_grains(cpo_index,data,mineral_i,grain_i,cosine_new); - - } - - - Assert(sum_volume_fractions != 0, ExcMessage("The sum of all grain volume fractions of a mineral is equal to zero. This should not happen.")); - return sum_volume_fractions; - } - - - - template - std::pair, std::vector>> - CrystalPreferredOrientation::compute_derivatives(const unsigned int cpo_index, - const ArrayView &data, - const unsigned int mineral_i, - const SymmetricTensor<2,3> &strain_rate_3d, - const Tensor<2,3> &velocity_gradient_tensor, - const Point &position, - const double temperature, - const double pressure, - const Tensor<1,dim> &velocity, - const std::vector &compositions, - const SymmetricTensor<2,dim> &strain_rate, - const SymmetricTensor<2,dim> &deviatoric_strain_rate, - const double water_content) const - { - std::pair, std::vector>> derivatives; - switch (cpo_derivative_algorithm) - { - case CPODerivativeAlgorithm::spin_tensor: - { - return compute_derivatives_spin_tensor(velocity_gradient_tensor); - break; - } - case CPODerivativeAlgorithm::drex_2004: - { - - const DeformationType deformation_type = determine_deformation_type(deformation_type_selector[mineral_i], - position, - temperature, - pressure, - velocity, - compositions, - strain_rate, - deviatoric_strain_rate, - water_content); - - set_deformation_type(cpo_index,data,mineral_i,deformation_type); - - const std::array ref_resolved_shear_stress = reference_resolved_shear_stress_from_deformation_type(deformation_type); - - return compute_derivatives_drex_2004(cpo_index, - data, - mineral_i, - strain_rate_3d, - velocity_gradient_tensor, - ref_resolved_shear_stress); - break; - } - default: - AssertThrow(false, ExcMessage("Internal error.")); - break; - } - AssertThrow(false, ExcMessage("Internal error.")); - return derivatives; - } - - - - template - std::pair, std::vector>> - CrystalPreferredOrientation::compute_derivatives_spin_tensor(const Tensor<2,3> &velocity_gradient_tensor) const - { - // dA/dt = W * A, where W is the spin tensor and A is the rotation matrix - // The spin tensor is defined as W = 0.5 * ( L - L^T ), where L is the velocity gradient tensor. - const Tensor<2,3> spin_tensor = -0.5 *(velocity_gradient_tensor - dealii::transpose(velocity_gradient_tensor)); - - return std::pair, std::vector>>(std::vector(n_grains,0.0), std::vector>(n_grains, spin_tensor)); - } - - - template - std::pair, std::vector>> - CrystalPreferredOrientation::compute_derivatives_drex_2004(const unsigned int cpo_index, - const ArrayView &data, - const unsigned int mineral_i, - const SymmetricTensor<2,3> &strain_rate_3d, - const Tensor<2,3> &velocity_gradient_tensor, - const std::array ref_resolved_shear_stress, - const bool prevent_nondimensionalization) const - { - // This if statement is only there for the unit test. In normal situations it should always be set to false, - // because the nondimensionalization should always be done (in this exact way), unless you really know what - // you are doing. - double nondimensionalization_value = 1.0; - if (!prevent_nondimensionalization) - { - const std::array< double, 3 > eigenvalues = dealii::eigenvalues(strain_rate_3d); - nondimensionalization_value = std::max(std::abs(eigenvalues[0]),std::abs(eigenvalues[2])); - - Assert(!std::isnan(nondimensionalization_value), ExcMessage("The second invariant of the strain rate is not a number.")); - } - - - // Make the strain-rate and velocity gradient tensor non-dimensional - // by dividing it through the second invariant - const Tensor<2,3> strain_rate_nondimensional = nondimensionalization_value != 0 ? strain_rate_3d/nondimensionalization_value : strain_rate_3d; - const Tensor<2,3> velocity_gradient_tensor_nondimensional = nondimensionalization_value != 0 ? velocity_gradient_tensor/nondimensionalization_value : velocity_gradient_tensor; - - // create output variables - std::vector deriv_volume_fractions(n_grains); - std::vector> deriv_a_cosine_matrices(n_grains); - - // create shortcuts - const std::array &tau = ref_resolved_shear_stress; - - std::vector strain_energy(n_grains); - double mean_strain_energy = 0; - - for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) - { - // Compute the Schmidt tensor for this grain (nu), s is the slip system. - // We first compute beta_s,nu (equation 5, Kaminski & Ribe, 2001) - // Then we use the beta to calculate the Schmidt tensor G_{ij} (Eq. 5, Kaminski & Ribe, 2001) - Tensor<2,3> G; - Tensor<1,3> w; - Tensor<1,4> beta({1.0, 1.0, 1.0, 1.0}); - std::array,4> slip_normal_reference {{Tensor<1,3>({0,1,0}),Tensor<1,3>({0,0,1}),Tensor<1,3>({0,1,0}),Tensor<1,3>({1,0,0})}}; - std::array,4> slip_direction_reference {{Tensor<1,3>({1,0,0}),Tensor<1,3>({1,0,0}),Tensor<1,3>({0,0,1}),Tensor<1,3>({0,0,1})}}; - - // these are variables we only need for olivine, but we need them for both - // within this if block and the next ones - // Ordered vector where the first entry is the max/weakest and the last entry is the inactive slip system. - std::array indices {}; - - // compute G and beta - Tensor<1,4> bigI; - const Tensor<2,3> rotation_matrix = get_rotation_matrix_grains(cpo_index,data,mineral_i,grain_i); - const Tensor<2,3> rotation_matrix_transposed = transpose(rotation_matrix); - for (unsigned int slip_system_i = 0; slip_system_i < 4; ++slip_system_i) - { - const Tensor<1,3> slip_normal_global = rotation_matrix_transposed*slip_normal_reference[slip_system_i]; - const Tensor<1,3> slip_direction_global = rotation_matrix_transposed*slip_direction_reference[slip_system_i]; - const Tensor<2,3> slip_cross_product = outer_product(slip_direction_global,slip_normal_global); - bigI[slip_system_i] = scalar_product(slip_cross_product,strain_rate_nondimensional); - } - - if (bigI.norm() < 1e-10) - { - // In this case there is no shear, only (possibly) a rotation. So \gamma_y and/or G should be zero. - // Which is the default value, so do nothing. - } - else - { - // compute the element wise absolute value of the element wise - // division of BigI by tau (tau = ref_resolved_shear_stress). - std::array q_abs; - for (unsigned int i = 0; i < 4; ++i) - { - q_abs[i] = std::abs(bigI[i] / tau[i]); - } - - // here we find the indices starting at the largest value and ending at the smallest value - // and assign them to special variables. Because all the variables are absolute values, - // we can set them to a negative value to ignore them. This should be faster then deleting - // the element, which would require allocation. (not tested) - for (unsigned int slip_system_i = 0; slip_system_i < 4; ++slip_system_i) - { - indices[slip_system_i] = std::distance(q_abs.begin(),std::max_element(q_abs.begin(), q_abs.end())); - q_abs[indices[slip_system_i]] = -1; - } - - // compute the ordered beta vector, which is the relative slip rates of the active slip systems. - // Test whether the max element is not equal to zero. - Assert(bigI[indices[0]] != 0.0, ExcMessage("Internal error: bigI is zero.")); - beta[indices[0]] = 1.0; // max q_abs, weak system (most deformation) "s=1" - - const double ratio = tau[indices[0]]/bigI[indices[0]]; - for (unsigned int slip_system_i = 1; slip_system_i < 4-1; ++slip_system_i) - { - beta[indices[slip_system_i]] = std::pow(std::abs(ratio * (bigI[indices[slip_system_i]]/tau[indices[slip_system_i]])), stress_exponent); - } - beta[indices.back()] = 0.0; - - // Now compute the crystal rate of deformation tensor. equation 4 of Kaminski&Ribe 2001 - // rotation_matrix_transposed = inverse of rotation matrix - // (see Engler et al., 2024 book: Intro to Texture analysis chp 2.3.2 The Rotation Matrix) - // this transform the crystal reference frame to specimen reference frame - for (unsigned int slip_system_i = 0; slip_system_i < 4; ++slip_system_i) - { - const Tensor<1,3> slip_normal_global = rotation_matrix_transposed*slip_normal_reference[slip_system_i]; - const Tensor<1,3> slip_direction_global = rotation_matrix_transposed*slip_direction_reference[slip_system_i]; - const Tensor<2,3> slip_cross_product = outer_product(slip_direction_global,slip_normal_global); - G += 2.0 * beta[slip_system_i] * slip_cross_product; - } - } - - // Now calculate the analytic solution to the deformation minimization problem - // compute gamma (equation 7, Kaminiski & Ribe, 2001) - - // Top is the numerator and bottom is the denominator in equation 7. - double top = 0; - double bottom = 0; - for (unsigned int i = 0; i < 3; ++i) - { - // Following the actual Drex implementation we use i+2, which differs - // from the EPSL paper, which says gamma_nu depends on i+1 - const unsigned int i_offset = (i==0) ? (i+2) : (i-1); - - top = top - (velocity_gradient_tensor_nondimensional[i][i_offset]-velocity_gradient_tensor_nondimensional[i_offset][i])*(G[i][i_offset]-G[i_offset][i]); - bottom = bottom - (G[i][i_offset]-G[i_offset][i])*(G[i][i_offset]-G[i_offset][i]); - - for (unsigned int j = 0; j < 3; ++j) - { - top = top + 2.0 * G[i][j]*velocity_gradient_tensor_nondimensional[i][j]; - bottom = bottom + 2.0* G[i][j] * G[i][j]; - } - } - // see comment on if all BigI are zero. In that case gamma should be zero. - const double gamma = (bottom != 0.0) ? top/bottom : 0.0; - - // compute w (equation 8, Kaminiski & Ribe, 2001) - // w is the Rotation rate vector of the crystallographic axes of grain - w[0] = 0.5*(velocity_gradient_tensor_nondimensional[2][1]-velocity_gradient_tensor_nondimensional[1][2]) - 0.5*(G[2][1]-G[1][2])*gamma; - w[1] = 0.5*(velocity_gradient_tensor_nondimensional[0][2]-velocity_gradient_tensor_nondimensional[2][0]) - 0.5*(G[0][2]-G[2][0])*gamma; - w[2] = 0.5*(velocity_gradient_tensor_nondimensional[1][0]-velocity_gradient_tensor_nondimensional[0][1]) - 0.5*(G[1][0]-G[0][1])*gamma; - - // Compute strain energy for this grain (abbreviated Estr) - // For olivine: DREX only sums over 1-3. But Christopher Thissen's matlab - // code (https://github.com/cthissen/Drex-MATLAB) corrected - // this and writes each term using the indices created when calculating bigI. - // Note tau = RRSS = (tau_m^s/tau_o), this why we get tau^(p-n) - for (unsigned int slip_system_i = 0; slip_system_i < 4; ++slip_system_i) - { - const double rhos = std::pow(tau[indices[slip_system_i]],exponent_p-stress_exponent) * - std::pow(std::abs(gamma*beta[indices[slip_system_i]]),exponent_p/stress_exponent); - strain_energy[grain_i] += rhos * std::exp(-nucleation_efficiency * rhos * rhos); - - Assert(isfinite(strain_energy[grain_i]), ExcMessage("strain_energy[" + std::to_string(grain_i) + "] is not finite: " + std::to_string(strain_energy[grain_i]) - + ", rhos (" + std::to_string(slip_system_i) + ") = " + std::to_string(rhos) - + ", nucleation_efficiency = " + std::to_string(nucleation_efficiency) + ".")); - } - - - // compute the derivative of the rotation matrix: \frac{\partial a_{ij}}{\partial t} - // (Eq. 9, Kaminski & Ribe 2001) - deriv_a_cosine_matrices[grain_i] = 0; - const double volume_fraction_grain = get_volume_fractions_grains(cpo_index,data,mineral_i,grain_i); - if (volume_fraction_grain >= threshold_GBS/n_grains) - { - deriv_a_cosine_matrices[grain_i] = Utilities::Tensors::levi_civita<3>() * w * nondimensionalization_value; - - // volume averaged strain energy - mean_strain_energy += volume_fraction_grain * strain_energy[grain_i]; - - Assert(isfinite(mean_strain_energy), ExcMessage("mean_strain_energy when adding grain " + std::to_string(grain_i) + " is not finite: " + std::to_string(mean_strain_energy) - + ", volume_fraction_grain = " + std::to_string(volume_fraction_grain) + ".")); - } - else - { - strain_energy[grain_i] = 0; - } - } - - // Change of volume fraction of grains by grain boundary migration - for (unsigned int grain_i = 0; grain_i < n_grains; ++grain_i) - { - // Different than D-Rex. Here we actually only compute the derivative and do not multiply it with the volume_fractions. We do that when we advect. - deriv_volume_fractions[grain_i] = get_volume_fraction_mineral(cpo_index,data,mineral_i) * mobility * (mean_strain_energy - strain_energy[grain_i]) * nondimensionalization_value; - - Assert(isfinite(deriv_volume_fractions[grain_i]), - ExcMessage("deriv_volume_fractions[" + std::to_string(grain_i) + "] is not finite: " - + std::to_string(deriv_volume_fractions[grain_i]))); - } - - return std::pair, std::vector>>(deriv_volume_fractions, deriv_a_cosine_matrices); - } - - - template - DeformationType - CrystalPreferredOrientation::determine_deformation_type(const DeformationTypeSelector deformation_type_selector, - const Point &position, - const double temperature, - const double pressure, - const Tensor<1,dim> &velocity, - const std::vector &compositions, - const SymmetricTensor<2,dim> &strain_rate, - const SymmetricTensor<2,dim> &deviatoric_strain_rate, - const double water_content) const - { - // Now compute what type of deformation takes place. - switch (deformation_type_selector) - { - case DeformationTypeSelector::passive: - return DeformationType::passive; - case DeformationTypeSelector::olivine_a_fabric: - return DeformationType::olivine_a_fabric; - case DeformationTypeSelector::olivine_b_fabric: - return DeformationType::olivine_b_fabric; - case DeformationTypeSelector::olivine_c_fabric: - return DeformationType::olivine_c_fabric; - case DeformationTypeSelector::olivine_d_fabric: - return DeformationType::olivine_d_fabric; - case DeformationTypeSelector::olivine_e_fabric: - return DeformationType::olivine_e_fabric; - case DeformationTypeSelector::enstatite: - return DeformationType::enstatite; - case DeformationTypeSelector::olivine_karato_2008: - // construct the material model inputs and outputs - // Since this function is only evaluating one particle, - // we use 1 for the amount of quadrature points. - MaterialModel::MaterialModelInputs material_model_inputs(1,this->n_compositional_fields()); - material_model_inputs.position[0] = position; - material_model_inputs.temperature[0] = temperature; - material_model_inputs.pressure[0] = pressure; - material_model_inputs.velocity[0] = velocity; - material_model_inputs.composition[0] = compositions; - material_model_inputs.strain_rate[0] = strain_rate; - - MaterialModel::MaterialModelOutputs material_model_outputs(1,this->n_compositional_fields()); - this->get_material_model().evaluate(material_model_inputs, material_model_outputs); - double eta = material_model_outputs.viscosities[0]; - - const SymmetricTensor<2,dim> stress = 2*eta*deviatoric_strain_rate + - pressure * unit_symmetric_tensor(); - const std::array< double, dim > eigenvalues = dealii::eigenvalues(stress); - double differential_stress = eigenvalues[0]-eigenvalues[dim-1]; - return determine_deformation_type_karato_2008(differential_stress, water_content); - - } - - AssertThrow(false, ExcMessage("Internal error. Deformation type not implemented.")); - return DeformationType::passive; - } - - - template - DeformationType - CrystalPreferredOrientation::determine_deformation_type_karato_2008(const double stress, const double water_content) const - { - constexpr double MPa = 1e6; - constexpr double ec_line_slope = -500./1050.; - if (stress > (380. - 0.05 * water_content)*MPa) - { - if (stress > (625. - 2.5 * water_content)*MPa) - { - return DeformationType::olivine_b_fabric; - } - else - { - return DeformationType::olivine_d_fabric; - } - } - else - { - if (stress < (625.0 -2.5 * water_content)*MPa) - { - return DeformationType::olivine_a_fabric; - } - else - { - if (stress < (500.0 + ec_line_slope*-100. + ec_line_slope * water_content)*MPa) - { - return DeformationType::olivine_e_fabric; - } - else - { - return DeformationType::olivine_c_fabric; - } - } - } - } - - - template - std::array - CrystalPreferredOrientation::reference_resolved_shear_stress_from_deformation_type(DeformationType deformation_type, - double max_value) const - { - std::array ref_resolved_shear_stress; - switch (deformation_type) - { - // from Kaminski and Ribe, GJI 2004 and - // Becker et al., 2007 (http://www-udc.ig.utexas.edu/external/becker/preprints/bke07.pdf) - case DeformationType::olivine_a_fabric : - ref_resolved_shear_stress[0] = 1; - ref_resolved_shear_stress[1] = 2; - ref_resolved_shear_stress[2] = 3; - ref_resolved_shear_stress[3] = max_value; - break; - - // from Kaminski and Ribe, GJI 2004 and - // Becker et al., 2007 (http://www-udc.ig.utexas.edu/external/becker/preprints/bke07.pdf) - case DeformationType::olivine_b_fabric : - ref_resolved_shear_stress[0] = 3; - ref_resolved_shear_stress[1] = 2; - ref_resolved_shear_stress[2] = 1; - ref_resolved_shear_stress[3] = max_value; - break; - - // from Kaminski and Ribe, GJI 2004 and - // Becker et al., 2007 (http://www-udc.ig.utexas.edu/external/becker/preprints/bke07.pdf) - case DeformationType::olivine_c_fabric : - ref_resolved_shear_stress[0] = 3; - ref_resolved_shear_stress[1] = max_value; - ref_resolved_shear_stress[2] = 2; - ref_resolved_shear_stress[3] = 1; - break; - - // from Kaminski and Ribe, GRL 2002 and - // Becker et al., 2007 (http://www-udc.ig.utexas.edu/external/becker/preprints/bke07.pdf) - case DeformationType::olivine_d_fabric : - ref_resolved_shear_stress[0] = 1; - ref_resolved_shear_stress[1] = 1; - ref_resolved_shear_stress[2] = 3; - ref_resolved_shear_stress[3] = max_value; - break; - - // Kaminski, Ribe and Browaeys, GJI, 2004 (same as in the matlab code) and - // Becker et al., 2007 (http://www-udc.ig.utexas.edu/external/becker/preprints/bke07.pdf) - case DeformationType::olivine_e_fabric : - ref_resolved_shear_stress[0] = 2; - ref_resolved_shear_stress[1] = 1; - ref_resolved_shear_stress[2] = max_value; - ref_resolved_shear_stress[3] = 3; - break; - - // from Kaminski and Ribe, GJI 2004. - // Todo: this one is not used in practice, since there is an optimization in - // the code. So maybe remove it in the future. - case DeformationType::enstatite : - ref_resolved_shear_stress[0] = max_value; - ref_resolved_shear_stress[1] = max_value; - ref_resolved_shear_stress[2] = max_value; - ref_resolved_shear_stress[3] = 1; - break; - - default: - AssertThrow(false, - ExcMessage("Deformation type enum with number " + std::to_string(static_cast(deformation_type)) - + " was not found.")); - break; - } - return ref_resolved_shear_stress; - } - - template - unsigned int - CrystalPreferredOrientation::get_number_of_grains() const - { - return n_grains; - } - - - - template - unsigned int - CrystalPreferredOrientation::get_number_of_minerals() const - { - return n_minerals; - } - - - - template - void - CrystalPreferredOrientation::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Crystal Preferred Orientation"); - { - prm.declare_entry ("Random number seed", "1", - Patterns::Integer (0), - "The seed used to generate random numbers. This will make sure that " - "results are reproducible as long as the problem is run with the " - "same number of MPI processes. It is implemented as final seed = " - "user seed + MPI Rank. "); - - prm.declare_entry ("Number of grains per particle", "50", - Patterns::Integer (1), - "The number of grains of each different mineral " - "each particle contains."); - - prm.declare_entry ("Property advection method", "Backward Euler", - Patterns::Anything(), - "Options: Forward Euler, Backward Euler"); - - prm.declare_entry ("Property advection tolerance", "1e-10", - Patterns::Double(0), - "The Backward Euler property advection method involve internal iterations. " - "This option allows for setting a tolerance. When the norm of tensor new - tensor old is " - "smaller than this tolerance, the iteration is stopped."); - - prm.declare_entry ("Property advection max iterations", "100", - Patterns::Integer(0), - "The Backward Euler property advection method involve internal iterations. " - "This option allows for setting the maximum number of iterations. Note that when the iteration " - "is ended by the max iteration amount an assert is thrown."); - - prm.declare_entry ("CPO derivatives algorithm", "Spin tensor", - Patterns::List(Patterns::Anything()), - "Options: Spin tensor"); - - prm.enter_subsection("Initial grains"); - { - prm.declare_entry("Model name","Uniform grains and random uniform rotations", - Patterns::Anything(), - "The model used to initialize the CPO for all particles. " - "Currently 'Uniform grains and random uniform rotations' and 'World Builder' are the only valid option."); - - prm.declare_entry ("Minerals", "Olivine: Karato 2008, Enstatite", - Patterns::List(Patterns::Anything()), - "This determines what minerals and fabrics or fabric selectors are used used for the LPO/CPO calculation. " - "The options are Olivine: Passive, A-fabric, Olivine: B-fabric, Olivine: C-fabric, Olivine: D-fabric, " - "Olivine: E-fabric, Olivine: Karato 2008 or Enstatite. Passive sets all RRSS entries to the maximum. The " - "Karato 2008 selector selects a fabric based on stress and water content as defined in " - "figure 4 of the Karato 2008 review paper (doi: 10.1146/annurev.earth.36.031207.124120)."); - - - prm.declare_entry ("Volume fractions minerals", "0.7, 0.3", - Patterns::List(Patterns::Double(0)), - "The volume fractions for the different minerals. " - "There need to be the same number of values as there are minerals." - "Note that the currently implemented scheme is incompressible and " - "does not allow chemical interaction or the formation of new phases"); - } - prm.leave_subsection (); - - prm.enter_subsection("D-Rex 2004"); - { - - prm.declare_entry ("Mobility", "50", - Patterns::Double(0), - "The dimensionless intrinsic grain boundary mobility for both olivine and enstatite."); - - prm.declare_entry ("Volume fractions minerals", "0.5, 0.5", - Patterns::List(Patterns::Double(0)), - "The volume fraction for the different minerals. " - "There need to be the same amount of values as there are minerals"); - - prm.declare_entry ("Stress exponents", "3.5", - Patterns::Double(0), - "This is the power law exponent that characterizes the rheology of the " - "slip systems. It is used in equation 11 of Kaminski et al., 2004."); - - prm.declare_entry ("Exponents p", "1.5", - Patterns::Double(0), - "This is exponent p as defined in equation 11 of Kaminski et al., 2004. "); - - prm.declare_entry ("Nucleation efficiency", "5", - Patterns::Double(0), - "This is the dimensionless nucleation rate as defined in equation 8 of " - "Kaminski et al., 2004. "); - - prm.declare_entry ("Threshold GBS", "0.3", - Patterns::Double(0), - "The Dimensionless Grain Boundary Sliding (GBS) threshold. " - "This is a grain size threshold below which grain deform by GBS and " - "become strain-free grains."); - } - prm.leave_subsection(); - } - prm.leave_subsection (); - } - - - - template - void - CrystalPreferredOrientation::parse_parameters (ParameterHandler &prm) - { - AssertThrow(dim == 3, ExcMessage("CPO computations are currently only supported for 3d models. " - "2d computations will work when this assert is removed, but you will need to make sure that the " - "correct 3d strain-rate and velocity gradient tensors are provided to the algorithm.")); - - prm.enter_subsection("Crystal Preferred Orientation"); - { - random_number_seed = prm.get_integer ("Random number seed"); - n_grains = prm.get_integer("Number of grains per particle"); - - property_advection_tolerance = prm.get_double("Property advection tolerance"); - property_advection_max_iterations = prm.get_integer ("Property advection max iterations"); - - const std::string temp_cpo_derivative_algorithm = prm.get("CPO derivatives algorithm"); - - if (temp_cpo_derivative_algorithm == "Spin tensor") - { - cpo_derivative_algorithm = CPODerivativeAlgorithm::spin_tensor; - } - else if (temp_cpo_derivative_algorithm == "D-Rex 2004") - { - cpo_derivative_algorithm = CPODerivativeAlgorithm::drex_2004; - } - else - { - AssertThrow(false, - ExcMessage("The CPO derivatives algorithm needs to be one of the following: " - "Spin tensor, D-Rex 2004.")); - } - - const std::string temp_advection_method = prm.get("Property advection method"); - if (temp_advection_method == "Forward Euler") - { - advection_method = AdvectionMethod::forward_euler; - } - else if (temp_advection_method == "Backward Euler") - { - advection_method = AdvectionMethod::backward_euler; - } - else - { - AssertThrow(false, ExcMessage("particle property advection method not found: \"" + temp_advection_method + "\"")); - } - - prm.enter_subsection("Initial grains"); - { - const std::string model_name = prm.get("Model name"); - if (model_name == "Uniform grains and random uniform rotations") - { - initial_grains_model = CPOInitialGrainsModel::uniform_grains_and_random_uniform_rotations; - } - else if (model_name == "World Builder") - { - initial_grains_model = CPOInitialGrainsModel::world_builder; - } - else - { - AssertThrow(false, - ExcMessage("No model named " + model_name + "for CPO particle property initialization. " - + "Only the model \"Uniform grains and random uniform rotations\" and " - "\"World Builder\" are available.")); - } - - const std::vector temp_deformation_type_selector = dealii::Utilities::split_string_list(prm.get("Minerals")); - n_minerals = temp_deformation_type_selector.size(); - deformation_type_selector.resize(n_minerals); - - for (size_t mineral_i = 0; mineral_i < n_minerals; ++mineral_i) - { - if (temp_deformation_type_selector[mineral_i] == "Passive") - { - deformation_type_selector[mineral_i] = DeformationTypeSelector::passive; - } - else if (temp_deformation_type_selector[mineral_i] == "Olivine: Karato 2008") - { - deformation_type_selector[mineral_i] = DeformationTypeSelector::olivine_karato_2008; - } - else if (temp_deformation_type_selector[mineral_i] == "Olivine: A-fabric") - { - deformation_type_selector[mineral_i] = DeformationTypeSelector::olivine_a_fabric; - } - else if (temp_deformation_type_selector[mineral_i] == "Olivine: B-fabric") - { - deformation_type_selector[mineral_i] = DeformationTypeSelector::olivine_b_fabric; - } - else if (temp_deformation_type_selector[mineral_i] == "Olivine: C-fabric") - { - deformation_type_selector[mineral_i] = DeformationTypeSelector::olivine_c_fabric; - } - else if (temp_deformation_type_selector[mineral_i] == "Olivine: D-fabric") - { - deformation_type_selector[mineral_i] = DeformationTypeSelector::olivine_d_fabric; - } - else if (temp_deformation_type_selector[mineral_i] == "Olivine: E-fabric") - { - deformation_type_selector[mineral_i] = DeformationTypeSelector::olivine_e_fabric; - } - else if (temp_deformation_type_selector[mineral_i] == "Enstatite") - { - deformation_type_selector[mineral_i] = DeformationTypeSelector::enstatite; - } - else - { - AssertThrow(false, - ExcMessage("The fabric needs to be assigned one of the following comma-delimited values: Olivine: Karato 2008, " - "Olivine: A-fabric, Olivine: B-fabric, Olivine: C-fabric, Olivine: D-fabric," - "Olivine: E-fabric, Enstatite, Passive.")); - } - } - - volume_fractions_minerals = Utilities::string_to_double(dealii::Utilities::split_string_list(prm.get("Volume fractions minerals"))); - double volume_fractions_minerals_sum = 0; - for (auto fraction : volume_fractions_minerals) - { - volume_fractions_minerals_sum += fraction; - } - - AssertThrow(abs(volume_fractions_minerals_sum-1.0) < 2.0 * std::numeric_limits::epsilon(), - ExcMessage("The sum of the CPO volume fractions should be one.")); - } - prm.leave_subsection(); - - prm.enter_subsection("D-Rex 2004"); - { - mobility = prm.get_double("Mobility"); - volume_fractions_minerals = Utilities::string_to_double(dealii::Utilities::split_string_list(prm.get("Volume fractions minerals"))); - stress_exponent = prm.get_double("Stress exponents"); - exponent_p = prm.get_double("Exponents p"); - nucleation_efficiency = prm.get_double("Nucleation efficiency"); - threshold_GBS = prm.get_double("Threshold GBS"); - } - prm.leave_subsection(); - } - prm.leave_subsection (); - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(CrystalPreferredOrientation, - "crystal preferred orientation", - "WARNING: all the CPO plugins are a work in progress and not ready for production use yet. " - "See https://github.com/geodynamics/aspect/issues/3885 for current status and alternatives. " - "The plugin manages and computes the evolution of Lattice/Crystal Preferred Orientations (LPO/CPO) " - "on particles. Each ASPECT particle can be assigned many grains. Each grain is assigned a size and a orientation " - "matrix. This allows for CPO evolution tracking with polycrystalline kinematic CrystalPreferredOrientation evolution models such " - "as D-Rex (Kaminski and Ribe, 2001; Kaminski et al., 2004).") - } - } -} diff --git a/source/particle/property/elastic_stress.cc.bak b/source/particle/property/elastic_stress.cc.bak deleted file mode 100644 index f0be9a72362..00000000000 --- a/source/particle/property/elastic_stress.cc.bak +++ /dev/null @@ -1,199 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - ElasticStress::ElasticStress () - : - material_inputs(1,0), - material_outputs(1,0) - {} - - - - template - void - ElasticStress::initialize () - { - material_inputs = MaterialModel::MaterialModelInputs(1, this->n_compositional_fields()); - - material_outputs = MaterialModel::MaterialModelOutputs(1, this->n_compositional_fields()); - - AssertThrow((Plugins::plugin_type_matches>(this->get_material_model()) - || - Plugins::plugin_type_matches>(this->get_material_model())), - ExcMessage("This particle property only makes sense in combination with the viscoelastic or visco_plastic material model.")); - - AssertThrow(this->get_parameters().enable_elasticity == true, - ExcMessage ("This particle property should only be used if 'Enable elasticity' is set to true")); - - } - - - - template - void - ElasticStress::initialize_one_particle_property(const Point &position, - std::vector &data) const - { - // Give each elastic stress field its initial composition if one is prescribed. - data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_xx"))); - - data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_yy"))); - - if (dim == 2) - { - data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_xy"))); - } - else if (dim == 3) - { - data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_zz"))); - - data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_xy"))); - - data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_xz"))); - - data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("ve_stress_yz"))); - } - - } - - - - template - void - ElasticStress::update_particle_property(const unsigned int data_position, - const Vector &solution, - const std::vector> &gradients, - typename ParticleHandler::particle_iterator &particle) const - { - material_inputs.position[0] = particle->get_location(); - - - material_inputs.current_cell = typename DoFHandler::active_cell_iterator(*particle->get_surrounding_cell(), - &(this->get_dof_handler())); - - material_inputs.temperature[0] = solution[this->introspection().component_indices.temperature]; - - material_inputs.pressure[0] = solution[this->introspection().component_indices.pressure]; - - for (unsigned int d = 0; d < dim; ++d) - material_inputs.velocity[0][d] = solution[this->introspection().component_indices.velocities[d]]; - - for (unsigned int n = 0; n < this->n_compositional_fields(); ++n) - material_inputs.composition[0][n] = solution[this->introspection().component_indices.compositional_fields[n]]; - - Tensor<2,dim> grad_u; - for (unsigned int d=0; dget_material_model().evaluate (material_inputs,material_outputs); - - for (unsigned int i = 0; i < SymmetricTensor<2,dim>::n_independent_components ; ++i) - particle->get_properties()[data_position + i] += material_outputs.reaction_terms[0][i]; - } - - - - template - UpdateTimeFlags - ElasticStress::need_update() const - { - return update_time_step; - } - - - - template - UpdateFlags - ElasticStress::get_needed_update_flags () const - { - return update_values | update_gradients; - } - - - - template - std::vector> - ElasticStress::get_property_information() const - { - std::vector> property_information; - - //Check which fields are used in model and make an output for each. - if (this->introspection().compositional_name_exists("ve_stress_xx")) - property_information.emplace_back("ve_stress_xx",1); - - if (this->introspection().compositional_name_exists("ve_stress_yy")) - property_information.emplace_back("ve_stress_yy",1); - - if (dim == 2) - { - if (this->introspection().compositional_name_exists("ve_stress_xy")) - property_information.emplace_back("ve_stress_xy",1); - } - else if (dim == 3) - { - if (this->introspection().compositional_name_exists("ve_stress_zz")) - property_information.emplace_back("ve_stress_zz",1); - - if (this->introspection().compositional_name_exists("ve_stress_xy")) - property_information.emplace_back("ve_stress_xy",1); - - if (this->introspection().compositional_name_exists("ve_stress_xz")) - property_information.emplace_back("ve_stress_xz",1); - - if (this->introspection().compositional_name_exists("ve_stress_yz")) - property_information.emplace_back("ve_stress_yz",1); - } - - return property_information; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(ElasticStress, - "elastic stress", - "A plugin in which the particle property tensor is " - "defined as the total elastic stress a particle has " - "accumulated. See the viscoelastic material model " - "documentation for more detailed information.") - - } - } -} diff --git a/source/particle/property/elastic_tensor_decomposition.cc.bak b/source/particle/property/elastic_tensor_decomposition.cc.bak deleted file mode 100644 index 25308ff2623..00000000000 --- a/source/particle/property/elastic_tensor_decomposition.cc.bak +++ /dev/null @@ -1,468 +0,0 @@ -/* - Copyright (C) 2023 by the authors of the ASPECT code. - This file is part of ASPECT. - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - ASPECT 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 General Public License for more details. - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include -#include - -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - namespace Utilities - { - std::array - indexed_even_permutation(const unsigned int index) - { - // there are 6 permutations, but only the odd or even are needed. We use the even - // permutation here. - switch (index) - { - case 0 : - return {{0,1,2}}; - case 1 : - return {{1,2,0}}; - case 2: - return {{2,0,1}}; - /*case 3: - return {0,2,1}; - case 4 : - return {1,0,2}; - case 5: - return {2,1,0};*/ - default: - AssertThrow(false,ExcMessage("Provided index larger then 2 (" + std::to_string(index)+ ").")); - return {{0,0,0}}; - } - - } - - - - SymmetricTensor<2,3> - compute_voigt_stiffness_tensor(const SymmetricTensor<2,6> &elastic_matrix) - { - /** - * the Voigt stiffness tensor (see Browaeys and Chevrot, 2004) - * It defines the stress needed to cause an isotropic strain in the - * material - */ - SymmetricTensor<2,3> voigt_stiffness_tensor; - voigt_stiffness_tensor[0][0]=elastic_matrix[0][0]+elastic_matrix[5][5]+elastic_matrix[4][4]; - voigt_stiffness_tensor[1][1]=elastic_matrix[5][5]+elastic_matrix[1][1]+elastic_matrix[3][3]; - voigt_stiffness_tensor[2][2]=elastic_matrix[4][4]+elastic_matrix[3][3]+elastic_matrix[2][2]; - voigt_stiffness_tensor[1][0]=elastic_matrix[0][5]+elastic_matrix[1][5]+elastic_matrix[3][4]; - voigt_stiffness_tensor[2][0]=elastic_matrix[0][4]+elastic_matrix[2][4]+elastic_matrix[3][5]; - voigt_stiffness_tensor[2][1]=elastic_matrix[1][3]+elastic_matrix[2][3]+elastic_matrix[4][5]; - - return voigt_stiffness_tensor; - } - - - - SymmetricTensor<2,3> - compute_dilatation_stiffness_tensor(const SymmetricTensor<2,6> &elastic_matrix) - { - /** - * The dilatational stiffness tensor (see Browaeys and Chevrot, 2004) - * It defines the stress to cause isotropic dilatation in the material. - */ - SymmetricTensor<2,3> dilatation_stiffness_tensor; - for (size_t i = 0; i < 3; i++) - { - dilatation_stiffness_tensor[0][0]=elastic_matrix[0][i]+dilatation_stiffness_tensor[0][0]; - dilatation_stiffness_tensor[1][1]=elastic_matrix[1][i]+dilatation_stiffness_tensor[1][1]; - dilatation_stiffness_tensor[2][2]=elastic_matrix[2][i]+dilatation_stiffness_tensor[2][2]; - dilatation_stiffness_tensor[1][0]=elastic_matrix[5][i]+dilatation_stiffness_tensor[1][0]; - dilatation_stiffness_tensor[2][0]=elastic_matrix[4][i]+dilatation_stiffness_tensor[2][0]; - dilatation_stiffness_tensor[2][1]=elastic_matrix[3][i]+dilatation_stiffness_tensor[2][1]; - } - return dilatation_stiffness_tensor; - } - - - - Tensor<2,3> - compute_unpermutated_SCCS(const SymmetricTensor<2,3> &dilatation_stiffness_tensor, - const SymmetricTensor<2,3> &voigt_stiffness_tensor) - { - // computing the eigenvector of the dilation and Voigt stiffness matrices and then averaging them by bysection. - const std::array>, 3> voigt_eigenvectors_a = eigenvectors(voigt_stiffness_tensor, SymmetricTensorEigenvectorMethod::jacobi); - const std::array>, 3> dilatation_eigenvectors_a = eigenvectors(dilatation_stiffness_tensor, SymmetricTensorEigenvectorMethod::jacobi); - - - std::array,3> unpermutated_SCCS; - // Averaging dilatation and voigt eigenvectors - // To do this we need to find the eigenvectors which are closest to each other and average those. - // The next function looks for the smallest angle and returns the corresponding vector index for - // that vector. - int vector_index_signed = 0; - for (unsigned int i1 = 0; i1 < 3; i1++) - { - vector_index_signed = 0; - double smallest_angle = std::numeric_limits::max(); // angle D VeCtor - for (unsigned int i2 = 0; i2 < 3; i2++) - { - double dv_dot_product = dilatation_eigenvectors_a[i1].second*voigt_eigenvectors_a[i2].second; - // limit the dot product between 1 and -1 so we can use the arccos function safely. - if (std::abs(dv_dot_product) >= 1.0) - dv_dot_product = std::copysign(1.0,dv_dot_product); - // Compute the angle between the vectors and account for that vector in the opposite - // direction are the same (0 == 180 degrees). So limit the direction of the vectors between - // 0 and 90 degrees such that it represents the minimum angle between the two lines. - const double angle = dv_dot_product < 0.0 ? std::acos(-1.0)-std::acos(dv_dot_product) : std::acos(dv_dot_product); - // store this if the angle is smaller - if (angle < smallest_angle) - { - vector_index_signed = (dv_dot_product < 0.0) ? -i2 : i2; - smallest_angle = angle; - } - } - - // Adds to the dilatation eigenvectors to the Voigt eigenvectors with the smallest angle - // Note that the voigt eigenvector is multiplied with a value which can be negative, which means it would be a subtraction. - // Lastly we normalize the unpermutated_SCCS. - unpermutated_SCCS[i1] = 0.5*(dilatation_eigenvectors_a[i1].second + static_cast(vector_index_signed)*voigt_eigenvectors_a[std::abs(vector_index_signed)].second); - unpermutated_SCCS[i1] /= unpermutated_SCCS[i1].norm(); - } - - return Tensor<2,3>( - { - {unpermutated_SCCS[0][0],unpermutated_SCCS[0][1],unpermutated_SCCS[0][2]}, - {unpermutated_SCCS[1][0],unpermutated_SCCS[1][1],unpermutated_SCCS[1][2]}, - {unpermutated_SCCS[2][0],unpermutated_SCCS[2][1],unpermutated_SCCS[2][2]} - }); - } - - - - std::array,7> - compute_elastic_tensor_SCCS_decompositions( - const Tensor<2,3> &unpermutated_SCCS, - const SymmetricTensor<2,6> &elastic_matrix) - { - /** - * Try the different permutations to determine what is the best hexagonal projection. - * This is based on Browaeys and Chevrot (2004), GJI (doi: 10.1111/j.1365-246X.2004.024115.x), - * which states at the end of paragraph 3.3 that "... an important property of an orthogonal projection - * is that the distance between a vector $X$ and its orthogonal projection $X_H = p(X)$ on a given - * subspace is minimum. These two features ensure that the decomposition is optimal once a 3-D Cartesian - * coordinate system is chosen.". The other property they talk about is that "The space of elastic - * vectors has a finite dimension [...], i.e. using a different norm from eq. (2.3 will change distances - * but not the resulting decomposition.". - */ - std::array,3> permutated; - std::array,3> rotated_elastic_matrix; - // The norms variable contains the square norms of the different symmetry approximations of the elastic tensor. - std::array,7> squared_norms_to_projections; - - for (unsigned int permutation_i = 0; permutation_i < 3; permutation_i++) - { - std::array permutation = indexed_even_permutation(permutation_i); - - for (size_t j = 0; j < 3; j++) - { - permutated[permutation_i][j] = unpermutated_SCCS[permutation[j]]; - } - - rotated_elastic_matrix[permutation_i] = aspect::Utilities::Tensors::rotate_voigt_stiffness_matrix((permutated[permutation_i]),elastic_matrix); - - const Tensor<1,21> full_elastic_vector_rotated = aspect::Utilities::Tensors::to_voigt_stiffness_vector(rotated_elastic_matrix[permutation_i]); - - - const double full_norm_square = full_elastic_vector_rotated.norm_square(); - squared_norms_to_projections[6][permutation_i] = full_norm_square; - - // Get the monoclinic and higher symmetry axes, which can be comptued by taking specific elements from the full vector. - // This means that this vector contains all symmetry axes, but the isotropic part is removed. - // The following line would do the same as the lines below, but is is very slow. It has therefore been - // replaced by the lines below. - //auto monoclinic_and_higher_vector = projection_matrix_triclinic_to_monoclinic*full_elastic_vector_rotated; - dealii::Tensor<1,21> monoclinic_and_higher_vector; - monoclinic_and_higher_vector[0] = full_elastic_vector_rotated[0]; - monoclinic_and_higher_vector[1] = full_elastic_vector_rotated[1]; - monoclinic_and_higher_vector[2] = full_elastic_vector_rotated[2]; - monoclinic_and_higher_vector[3] = full_elastic_vector_rotated[3]; - monoclinic_and_higher_vector[4] = full_elastic_vector_rotated[4]; - monoclinic_and_higher_vector[5] = full_elastic_vector_rotated[5]; - monoclinic_and_higher_vector[6] = full_elastic_vector_rotated[6]; - monoclinic_and_higher_vector[7] = full_elastic_vector_rotated[7]; - monoclinic_and_higher_vector[8] = full_elastic_vector_rotated[8]; - monoclinic_and_higher_vector[11] = full_elastic_vector_rotated[11]; - monoclinic_and_higher_vector[14] = full_elastic_vector_rotated[14]; - monoclinic_and_higher_vector[17] = full_elastic_vector_rotated[17]; - monoclinic_and_higher_vector[20] = full_elastic_vector_rotated[20]; - - // The triclinic vector is the full elastic tensor minux the monoclinic and higher symmetry axes vector. - auto triclinic_vector = full_elastic_vector_rotated-monoclinic_and_higher_vector; - squared_norms_to_projections[0][permutation_i] = triclinic_vector.norm_square(); - - // Only the first 9 elements are now non-zero, so crop the vector to the first 9 elements. - // The following line would do the same as the lines below, but it is slow. It has therefore been - // replaced by the lines below. - //auto orthorhombic_and_higher_vector = projection_matrix_monoclinic_to_orthorhombic*monoclinic_and_higher_vector; - dealii::Tensor<1,9> monoclinic_and_higher_vector_cropped; - monoclinic_and_higher_vector_cropped[0] = monoclinic_and_higher_vector[0]; - monoclinic_and_higher_vector_cropped[1] = monoclinic_and_higher_vector[1]; - monoclinic_and_higher_vector_cropped[2] = monoclinic_and_higher_vector[2]; - monoclinic_and_higher_vector_cropped[3] = monoclinic_and_higher_vector[3]; - monoclinic_and_higher_vector_cropped[4] = monoclinic_and_higher_vector[4]; - monoclinic_and_higher_vector_cropped[5] = monoclinic_and_higher_vector[5]; - monoclinic_and_higher_vector_cropped[6] = monoclinic_and_higher_vector[6]; - monoclinic_and_higher_vector_cropped[7] = monoclinic_and_higher_vector[7]; - monoclinic_and_higher_vector_cropped[8] = monoclinic_and_higher_vector[8]; - dealii::Tensor<1,9> orthorhombic_and_higher_vector; - orthorhombic_and_higher_vector[0] = monoclinic_and_higher_vector[0]; - orthorhombic_and_higher_vector[1] = monoclinic_and_higher_vector[1]; - orthorhombic_and_higher_vector[2] = monoclinic_and_higher_vector[2]; - orthorhombic_and_higher_vector[3] = monoclinic_and_higher_vector[3]; - orthorhombic_and_higher_vector[4] = monoclinic_and_higher_vector[4]; - orthorhombic_and_higher_vector[5] = monoclinic_and_higher_vector[5]; - orthorhombic_and_higher_vector[6] = monoclinic_and_higher_vector[6]; - orthorhombic_and_higher_vector[7] = monoclinic_and_higher_vector[7]; - orthorhombic_and_higher_vector[8] = monoclinic_and_higher_vector[8]; - - // The monoclinic vector is the monoclinic and higher symmetry axes vector minux the orthoclinic and higher symmetry axes vector. - auto monoclinic_vector = monoclinic_and_higher_vector_cropped-orthorhombic_and_higher_vector; - squared_norms_to_projections[1][permutation_i] = monoclinic_vector.norm_square(); - - - auto tetragonal_and_higher_vector = projection_matrix_orthorhombic_to_tetragonal*orthorhombic_and_higher_vector; - auto orthorhombic_vector = orthorhombic_and_higher_vector-tetragonal_and_higher_vector; - squared_norms_to_projections[2][permutation_i] = orthorhombic_vector.norm_square(); - - auto hexagonal_and_higher_vector = projection_matrix_tetragonal_to_hexagonal*tetragonal_and_higher_vector; - auto tetragonal_vector = tetragonal_and_higher_vector-hexagonal_and_higher_vector; - squared_norms_to_projections[3][permutation_i] = tetragonal_vector.norm_square(); - - auto isotropic_vector = projection_matrix_hexagonal_to_isotropic*hexagonal_and_higher_vector; - auto hexagonal_vector = hexagonal_and_higher_vector-isotropic_vector; - squared_norms_to_projections[4][permutation_i] = hexagonal_vector.norm_square(); - squared_norms_to_projections[5][permutation_i] = isotropic_vector.norm_square(); - - } - return squared_norms_to_projections; - - } - } - - - - template - void - ElasticTensorDecomposition::initialize () - { - const Particle::Property::Manager &manager = this->get_particle_world(this->get_particle_world_index()).get_property_manager(); - AssertThrow(manager.plugin_name_exists("crystal preferred orientation"), - ExcMessage("No cpo property plugin found.")); - AssertThrow(manager.plugin_name_exists("cpo elastic tensor"), - ExcMessage("No cpo elastic tensor property plugin found.")); - - AssertThrow(manager.check_plugin_order("crystal preferred orientation","elastic tensor decomposition"), - ExcMessage("To use the elastic tensor decomposition plugin, the cpo plugin needs to be defined before this plugin.")); - - AssertThrow(manager.check_plugin_order("cpo elastic tensor","elastic tensor decomposition"), - ExcMessage("To use the elastic tensor decomposition plugin, the cpo elastic tensor plugin needs to be defined before this plugin.")); - - cpo_elastic_tensor_data_position = manager.get_data_info().get_position_by_plugin_index(manager.get_plugin_index_by_name("cpo elastic tensor")); - } - - - - template - void - ElasticTensorDecomposition::initialize_one_particle_property(const Point &, - std::vector &data) const - { - const SymmetricTensor<2,6> elastic_matrix = Particle::Property::CpoElasticTensor::get_elastic_tensor(cpo_elastic_tensor_data_position, - data); - - const SymmetricTensor<2,3> dilatation_stiffness_tensor_full = Property::Utilities::compute_dilatation_stiffness_tensor(elastic_matrix); - const SymmetricTensor<2,3> voigt_stiffness_tensor_full = Property::Utilities::compute_voigt_stiffness_tensor(elastic_matrix); - const Tensor<2,3> SCCS_full = Property::Utilities::compute_unpermutated_SCCS(dilatation_stiffness_tensor_full, voigt_stiffness_tensor_full); - - const std::array,7 > norms = Property::Utilities::compute_elastic_tensor_SCCS_decompositions(SCCS_full, elastic_matrix); - - // get max hexagonal element index, which is the same as the permutation index - const size_t max_hexagonal_element_index = std::max_element(norms[4].begin(),norms[4].end())-norms[4].begin(); - std::array permutation = Property::Utilities::indexed_even_permutation(max_hexagonal_element_index); - // reorder the SCCS be the SCCS permutation which yields the largest hexagonal vector (percentage of anisotropy) - Tensor<2,3> hexagonal_permutated_SCCS; - for (size_t index = 0; index < 3; ++index) - { - hexagonal_permutated_SCCS[index] = SCCS_full[permutation[index]]; - } - - data.push_back(SCCS_full[0][0]); - data.push_back(SCCS_full[0][1]); - data.push_back(SCCS_full[0][2]); - data.push_back(SCCS_full[1][0]); - data.push_back(SCCS_full[1][1]); - data.push_back(SCCS_full[1][2]); - data.push_back(SCCS_full[2][0]); - data.push_back(SCCS_full[2][1]); - data.push_back(SCCS_full[2][2]); - data.push_back(hexagonal_permutated_SCCS[2][0]); - data.push_back(hexagonal_permutated_SCCS[2][1]); - data.push_back(hexagonal_permutated_SCCS[2][2]); - data.push_back(norms[6][0]); - data.push_back(norms[0][0]); // triclinic - data.push_back(norms[0][1]); // triclinic - data.push_back(norms[0][2]); // triclinic - data.push_back(norms[1][0]); // monoclinic - data.push_back(norms[1][1]); // monoclinic - data.push_back(norms[1][2]); // monoclinic - data.push_back(norms[2][0]); // orthorhomic - data.push_back(norms[2][1]); // orthorhomic - data.push_back(norms[2][2]); // orthorhomic - data.push_back(norms[3][0]); // tetragonal - data.push_back(norms[3][1]); // tetragonal - data.push_back(norms[3][2]); // tetragonal - data.push_back(norms[4][0]); // hexagonal - data.push_back(norms[4][1]); // hexagonal - data.push_back(norms[4][2]); // hexagonal - data.push_back(norms[5][0]); // isotropic - - } - - - - template - void - ElasticTensorDecomposition::update_particle_property(const unsigned int data_position, - const Vector &/*solution*/, - const std::vector> &/*gradients*/, - typename ParticleHandler::particle_iterator &particle) const - { - ArrayView data = particle->get_properties(); - const SymmetricTensor<2,6> elastic_matrix = Particle::Property::CpoElasticTensor::get_elastic_tensor(cpo_elastic_tensor_data_position, - data); - - const SymmetricTensor<2,3> dilatation_stiffness_tensor_full = Utilities::compute_dilatation_stiffness_tensor(elastic_matrix); - const SymmetricTensor<2,3> voigt_stiffness_tensor_full = Utilities::compute_voigt_stiffness_tensor(elastic_matrix); - const Tensor<2,3> SCCS_full = Utilities::compute_unpermutated_SCCS(dilatation_stiffness_tensor_full, voigt_stiffness_tensor_full); - - const std::array,7 > norms = Utilities::compute_elastic_tensor_SCCS_decompositions(SCCS_full, elastic_matrix); - - // get max hexagonal element index, which is the same as the permutation index - const size_t max_hexagonal_element_index = std::max_element(norms[4].begin(),norms[4].end())-norms[4].begin(); - std::array permutation = Utilities::indexed_even_permutation(max_hexagonal_element_index); - // reorder the SCCS by the SCCS permutation which yields the largest hexagonal vector (percentage of anisotropy) - Tensor<2,3> hexagonal_permutated_SCCS; - for (size_t index = 0; index < 3; ++index) - { - hexagonal_permutated_SCCS[index] = SCCS_full[permutation[index]]; - } - - data[data_position] = SCCS_full[0][0]; - data[data_position+1] = SCCS_full[0][1]; - data[data_position+2] = SCCS_full[0][2]; - data[data_position+3] = SCCS_full[1][0]; - data[data_position+4] = SCCS_full[1][1]; - data[data_position+5] = SCCS_full[1][2]; - data[data_position+6] = SCCS_full[2][0]; - data[data_position+7] = SCCS_full[2][1]; - data[data_position+8] = SCCS_full[2][2]; - data[data_position+9] = hexagonal_permutated_SCCS[2][0]; - data[data_position+10] = hexagonal_permutated_SCCS[2][1]; - data[data_position+11] = hexagonal_permutated_SCCS[2][2]; - data[data_position+12] = norms[6][0]; - data[data_position+13] = norms[0][0]; // triclinic - data[data_position+14] = norms[0][1]; // triclinic - data[data_position+15] = norms[0][2]; // triclinic - data[data_position+16] = norms[1][0]; // monoclinic - data[data_position+17] = norms[1][1]; // monoclinic - data[data_position+18] = norms[1][2]; // monoclinic - data[data_position+19] = norms[2][0]; // orthorhomic - data[data_position+20] = norms[2][1]; // orthorhomic - data[data_position+21] = norms[2][2]; // orthorhomic - data[data_position+22] = norms[3][0]; // tetragonal - data[data_position+23] = norms[3][1]; // tetragonal - data[data_position+24] = norms[3][2]; // tetragonal - data[data_position+25] = norms[4][0]; // hexagonal - data[data_position+26] = norms[4][1]; // hexagonal - data[data_position+27] = norms[4][2]; // hexagonal - data[data_position+28] = norms[5][0]; // isotropic - } - - - - template - UpdateTimeFlags - ElasticTensorDecomposition::need_update() const - { - return update_output_step; - } - - - - template - std::vector> - ElasticTensorDecomposition::get_property_information() const - { - std::vector> property_information = - { - {"cpo elastic axis e1",3}, - {"cpo elastic axis e2",3}, - {"cpo elastic axis e3",3}, - {"cpo elastic hexagonal axis",3}, - {"cpo elastic vector norm square",1}, - {"cpo elastic triclinic vector norm square p1",1}, - {"cpo elastic triclinic vector norm square p2",1}, - {"cpo elastic triclinic vector norm square p3",1}, - {"cpo elastic monoclinic vector norm square p1",1}, - {"cpo elastic monoclinic vector norm square p2",1}, - {"cpo elastic monoclinic vector norm square p3",1}, - {"cpo elastic orthorhombic vector norm square p1",1}, - {"cpo elastic orthorhombic vector norm square p2",1}, - {"cpo elastic orthorhombic vector norm square p3",1}, - {"cpo elastic tetragonal vector norm square p1",1}, - {"cpo elastic tetragonal vector norm square p2",1}, - {"cpo elastic tetragonal vector norm square p3",1}, - {"cpo elastic hexagonal vector norm square p1",1}, - {"cpo elastic hexagonal vector norm square p2",1}, - {"cpo elastic hexagonal vector norm square p3",1}, - {"cpo elastic isotropic vector norm square",1} - }; - - return property_information; - } - } - } -} - - - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(ElasticTensorDecomposition, - "elastic tensor decomposition", - "A plugin which decomposes the elastic tensor into different approximations " - "(Isotropic, Hexagonal, Tetragonal, Orthorhombic, Monoclinic and Triclinic) " - "and provides the eigenvectors of the tensor.") - } - } -} diff --git a/source/particle/property/function.cc.bak b/source/particle/property/function.cc.bak deleted file mode 100644 index d88dd252001..00000000000 --- a/source/particle/property/function.cc.bak +++ /dev/null @@ -1,113 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - Function::Function() - : - n_components (0) - {} - - template - void - Function::initialize_one_particle_property(const Point &position, - std::vector &data) const - { - for (unsigned int i = 0; i < n_components; ++i) - data.push_back(function->value(position, i)); - } - - template - std::vector> - Function::get_property_information() const - { - const std::vector> property_information (1,std::make_pair("function",n_components)); - return property_information; - } - - - template - void - Function::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Function"); - { - prm.declare_entry ("Number of components", "1", - Patterns::Integer (0), - "The number of function components where each component is described " - "by a function expression delimited by a ';'."); - Functions::ParsedFunction::declare_parameters (prm, 1); - } - prm.leave_subsection(); - } - - - template - void - Function::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Function"); - n_components = prm.get_integer ("Number of components"); - try - { - function = std::make_unique>(n_components); - function->parse_parameters (prm); - } - catch (...) - { - std::cerr << "ERROR: FunctionParser failed to parse\n" - << "\t'Particles.Function'\n" - << "with expression\n" - << "\t'" << prm.get("Function expression") << "'"; - throw; - } - prm.leave_subsection(); - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(Function, - "function", - "Implementation of a model in which the particle " - "property is set by evaluating an explicit function " - "at the initial position of each particle. The " - "function is defined in the parameters in section " - "``Particles|Function''. The format of these " - "functions follows the syntax understood by the " - "muparser library, see " - "{ref}\\`sec:run-aspect:parameters-overview:muparser-format\\`.") - } - } -} diff --git a/source/particle/property/grain_size.cc.bak b/source/particle/property/grain_size.cc.bak deleted file mode 100644 index 145d00f267c..00000000000 --- a/source/particle/property/grain_size.cc.bak +++ /dev/null @@ -1,173 +0,0 @@ -/* - Copyright (C) 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - GrainSize::GrainSize () - : - material_inputs(1,0), - material_outputs(1,0) - {} - - - - template - void - GrainSize::initialize () - { - material_inputs = MaterialModel::MaterialModelInputs(1, this->n_compositional_fields()); - material_outputs = MaterialModel::MaterialModelOutputs(1, this->n_compositional_fields()); - - AssertThrow(this->introspection().compositional_name_exists("grain_size"), - ExcMessage("This particle property only makes sense if " - "there is a compositional field named 'grain_size'.")); - - grain_size_index = this->introspection().compositional_index_for_name("grain_size"); - } - - - - template - void - GrainSize::initialize_one_particle_property(const Point &position, - std::vector &data) const - { - // Set the initial composition to the initial grain size. - data.push_back(this->get_initial_composition_manager().initial_composition(position,grain_size_index)); - } - - - - template - void - GrainSize::update_particle_properties(const unsigned int data_position, - const std::vector> &solution, - const std::vector>> &gradients, - typename ParticleHandler::particle_iterator_range &particles) const - { - material_inputs = MaterialModel::MaterialModelInputs(solution.size(), this->n_compositional_fields()); - material_outputs = MaterialModel::MaterialModelOutputs(solution.size(), this->n_compositional_fields()); - material_inputs.requested_properties = MaterialModel::MaterialProperties::reaction_terms; - material_inputs.current_cell = typename DoFHandler::active_cell_iterator(*particles.begin()->get_surrounding_cell(), - &(this->get_dof_handler())); - - unsigned int i = 0; - for (auto particle: particles) - { - // Make sure all particles are in the same cell - Assert(particle.get_surrounding_cell() == particles.begin()->get_surrounding_cell(), - ExcMessage("All particles must be in the same cell.")); - - material_inputs.position[i] = particle.get_location(); - material_inputs.temperature[i] = solution[i][this->introspection().component_indices.temperature]; - material_inputs.pressure[i] = solution[i][this->introspection().component_indices.pressure]; - - for (unsigned int d = 0; d < dim; ++d) - material_inputs.velocity[i][d] = solution[i][this->introspection().component_indices.velocities[d]]; - - for (unsigned int n = 0; n < this->n_compositional_fields(); ++n) - material_inputs.composition[i][n] = solution[i][this->introspection().component_indices.compositional_fields[n]]; - - material_inputs.composition[i][grain_size_index] = particle.get_properties()[data_position]; - - Tensor<2,dim> grad_u; - for (unsigned int d=0; dget_material_model().evaluate(material_inputs, - material_outputs); - - i = 0; - for (auto particle: particles) - { - particle.get_properties()[data_position] += material_outputs.reaction_terms[i][grain_size_index]; - ++i; - } - } - - - - template - InitializationModeForLateParticles - GrainSize::late_initialization_mode () const - { - return interpolate_respect_boundary; - } - - - - template - UpdateTimeFlags - GrainSize::need_update() const - { - return update_time_step; - } - - - - template - UpdateFlags - GrainSize::get_needed_update_flags () const - { - return update_values | update_gradients; - } - - - - template - std::vector> - GrainSize::get_property_information() const - { - return {{"grain_size",1}}; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(GrainSize, - "grain size", - "A plugin in which the particle property is " - "defined as the evolving grain size of a particle. " - "See the grain_size material model " - "documentation for more detailed information.") - - } - } -} diff --git a/source/particle/property/initial_composition.cc.bak b/source/particle/property/initial_composition.cc.bak deleted file mode 100644 index 4c603e02744..00000000000 --- a/source/particle/property/initial_composition.cc.bak +++ /dev/null @@ -1,91 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - void - InitialComposition::initialize_one_particle_property(const Point &position, - std::vector &data) const - { - for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) - data.push_back(this->get_initial_composition_manager().initial_composition(position,i)); - } - - - - template - InitializationModeForLateParticles - InitialComposition::late_initialization_mode () const - { - return interpolate_respect_boundary; - } - - - - template - std::vector> - InitialComposition::get_property_information() const - { - AssertThrow(this->n_compositional_fields() > 0, - ExcMessage("You have requested the particle property , but the number of compositional fields is 0. " - "Please add compositional fields to your model, or remove " - "this particle property.")); - - std::vector> property_information; - - for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) - { - std::ostringstream field_name; - field_name << "initial " << this->introspection().name_for_compositional_index(i); - property_information.emplace_back(field_name.str(),1); - } - - return property_information; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(InitialComposition, - "initial composition", - "Implementation of a plugin in which the particle " - "property is given as the initial composition " - "at the particle's initial position. The particle " - "gets as many properties as there are " - "compositional fields.") - } - } -} diff --git a/source/particle/property/initial_position.cc.bak b/source/particle/property/initial_position.cc.bak deleted file mode 100644 index ee44d3f0874..00000000000 --- a/source/particle/property/initial_position.cc.bak +++ /dev/null @@ -1,72 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - void - InitialPosition::initialize_one_particle_property(const Point &position, - std::vector &data) const - { - for (unsigned int i = 0; i < dim; ++i) - data.push_back(position[i]); - } - - template - std::vector> - InitialPosition::get_property_information() const - { - const std::vector> property_information (1,std::make_pair("initial position",static_cast (dim))); - return property_information; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(InitialPosition, - "initial position", - "Implementation of a plugin in which the particle " - "property is given as the initial position " - "of the particle. This property is vector-valued with " - "as many components as there are space dimensions. " - "In practice, it is often most useful to only " - "visualize one of the components of this vector, " - "or the magnitude of the vector. For example, in " - "a spherical mantle simulation, the magnitude of this " - "property equals the starting radius of a particle, " - "and is thereby indicative of which part of the " - "mantle a particle comes from.") - } - } -} diff --git a/source/particle/property/integrated_strain.cc.bak b/source/particle/property/integrated_strain.cc.bak deleted file mode 100644 index 7afa788bad3..00000000000 --- a/source/particle/property/integrated_strain.cc.bak +++ /dev/null @@ -1,124 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - void - IntegratedStrain::initialize_one_particle_property(const Point &, - std::vector &data) const - { - const static Tensor<2,dim> identity = unit_symmetric_tensor(); - for (unsigned int i = 0; i < Tensor<2,dim>::n_independent_components ; ++i) - data.push_back(identity[Tensor<2,dim>::unrolled_to_component_indices(i)]); - } - - template - void - IntegratedStrain::update_particle_property(const unsigned int data_position, - const Vector &/*solution*/, - const std::vector> &gradients, - typename ParticleHandler::particle_iterator &particle) const - { - const Tensor<2,dim> old_strain(make_array_view(&particle->get_properties()[data_position], - &particle->get_properties()[data_position] + Tensor<2,dim>::n_independent_components)); - - Tensor<2,dim> grad_u; - for (unsigned int d=0; dget_timestep(); - - Tensor<2,dim> new_strain; - - // here we integrate the equation - // new_deformation_gradient = velocity_gradient * old_deformation_gradient - // using a RK4 integration scheme. - const Tensor<2,dim> k1 = grad_u * old_strain * dt; - new_strain = old_strain + 0.5*k1; - - const Tensor<2,dim> k2 = grad_u * new_strain * dt; - new_strain = old_strain + 0.5*k2; - - const Tensor<2,dim> k3 = grad_u * new_strain * dt; - new_strain = old_strain + k3; - - const Tensor<2,dim> k4 = grad_u * new_strain * dt; - - // the new strain is the rotated old strain plus the - // strain of the current time step - new_strain = old_strain + (k1 + 2.0*k2 + 2.0*k3 + k4)/6.0; - - // unroll and store the new strain - new_strain.unroll(&particle->get_properties()[data_position], - &particle->get_properties()[data_position] + Tensor<2,dim>::n_independent_components); - } - - template - UpdateTimeFlags - IntegratedStrain::need_update() const - { - return update_time_step; - } - - template - UpdateFlags - IntegratedStrain::get_needed_update_flags () const - { - return update_gradients; - } - - template - std::vector> - IntegratedStrain::get_property_information() const - { - const unsigned int n_components = Tensor<2,dim>::n_independent_components; - const std::vector> property_information (1,std::make_pair("integrated strain",n_components)); - return property_information; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(IntegratedStrain, - "integrated strain", - "A plugin in which the particle property tensor is " - "defined as the deformation gradient tensor " - "$\\mathbf F$ this particle has experienced. " - "$\\mathbf F$ can be polar-decomposed into the left stretching tensor " - "$\\mathbf L$ (the finite strain we are interested in), and the " - "rotation tensor $\\mathbf Q$. See the corresponding cookbook in " - "the manual for more detailed information.") - } - } -} diff --git a/source/particle/property/integrated_strain_invariant.cc.bak b/source/particle/property/integrated_strain_invariant.cc.bak deleted file mode 100644 index a0d13bb0f82..00000000000 --- a/source/particle/property/integrated_strain_invariant.cc.bak +++ /dev/null @@ -1,118 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - void - IntegratedStrainInvariant::initialize_one_particle_property(const Point &, - std::vector &data) const - { - data.push_back(0.0); - } - - - - template - void - IntegratedStrainInvariant::update_particle_property(const unsigned int data_position, - const Vector &/*solution*/, - const std::vector> &gradients, - typename ParticleHandler::particle_iterator &particle) const - { - // Integrated strain invariant from prior time step - const auto data = particle->get_properties(); - double old_strain = data[data_position]; - - // Current timestep - const double dt = this->get_timestep(); - - // Velocity gradients - Tensor<2,dim> grad_u; - for (unsigned int d=0; d strain_rate = symmetrize (grad_u); - - // Calculate strain rate second invariant - const double edot_ii = std::sqrt(std::max(-second_invariant(deviator(strain_rate)), 0.)); - - // New strain is the old strain plus dt*edot_ii - const double new_strain = old_strain + dt*edot_ii; - data[data_position] = new_strain; - } - - - - template - UpdateTimeFlags - IntegratedStrainInvariant::need_update() const - { - return update_time_step; - } - - - - template - UpdateFlags - IntegratedStrainInvariant::get_needed_update_flags () const - { - return update_gradients; - } - - - - template - std::vector> - IntegratedStrainInvariant::get_property_information() const - { - const std::vector> property_information (1,std::make_pair("integrated strain invariant",1)); - return property_information; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(IntegratedStrainInvariant, - "integrated strain invariant", - "A plugin in which the particle property is defined as " - "the finite strain invariant ($\\varepsilon_{ii}$). " - "This property is calculated with the timestep ($dt$) and " - "the second invariant of the deviatoric strain rate tensor " - "($\\dot{\\varepsilon}_{ii}$), where the value at time step $n$ is " - "$\\varepsilon_{ii}^{n} = \\varepsilon_{ii}^{n-1} + " - "dt\\dot{\\varepsilon}_{ii}$.") - } - } -} diff --git a/source/particle/property/interface.cc.bak b/source/particle/property/interface.cc.bak deleted file mode 100644 index 47027dc7d45..00000000000 --- a/source/particle/property/interface.cc.bak +++ /dev/null @@ -1,820 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include - -#include -#include -#include - - -#include - -#include - -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - ParticlePropertyInformation::ParticlePropertyInformation() - : - number_of_components(numbers::invalid_unsigned_int), - number_of_fields(numbers::invalid_unsigned_int), - number_of_plugins(numbers::invalid_unsigned_int) - {} - - - - ParticlePropertyInformation::ParticlePropertyInformation(const std::vector< - std::vector< - std::pair>> &properties) - { - unsigned int global_component_index = 0; - for (const auto &property : properties) - { - unsigned int component_per_plugin = 0; - unsigned int field_per_plugin = 0; - - position_per_plugin.push_back(global_component_index); - - for (const auto &entry : property) - { - const std::string name = entry.first; - const unsigned int n_components = entry.second; - - field_names.push_back(name); - components_per_field.push_back(n_components); - position_per_field.push_back(global_component_index); - component_per_plugin += n_components; - global_component_index += n_components; - ++field_per_plugin; - } - - fields_per_plugin.push_back(field_per_plugin); - components_per_plugin.push_back(component_per_plugin); - } - - number_of_components = global_component_index; - number_of_fields = field_names.size(); - number_of_plugins = properties.size(); - } - - - - bool - ParticlePropertyInformation::fieldname_exists(const std::string &name) const - { - return (std::find(field_names.begin(),field_names.end(),name) != field_names.end()); - } - - unsigned int - ParticlePropertyInformation::get_field_index_by_name(const std::string &name) const - { - const std::vector::const_iterator field = std::find(field_names.begin(), - field_names.end(), - name); - - AssertThrow(field != field_names.end(), - ExcMessage("The particle property manager was asked for a property " - "field with the name <" + name + ">, but no such field could " - "be found.")); - return std::distance(field_names.begin(),field); - } - - std::string - ParticlePropertyInformation::get_field_name_by_index(const unsigned int field_index) const - { - Assert(field_index < field_names.size(), - ExcMessage("The number of field names (" + std::to_string(field_names.size()) - + ") is smaller than the requested field index (" - + std::to_string(field_index) + ").")); - - return field_names[field_index]; - } - - - - unsigned int - ParticlePropertyInformation::get_position_by_field_name(const std::string &name) const - { - const unsigned int field_index = get_field_index_by_name(name); - return position_per_field[field_index]; - } - - - - unsigned int - ParticlePropertyInformation::get_components_by_field_name(const std::string &name) const - { - const unsigned int field_index = get_field_index_by_name(name); - return components_per_field[field_index]; - } - - - - unsigned int - ParticlePropertyInformation::get_position_by_field_index(const unsigned int field_index) const - { - return position_per_field[field_index]; - } - - - - unsigned int - ParticlePropertyInformation::get_components_by_field_index(const unsigned int field_index) const - { - return components_per_field[field_index]; - } - - - - unsigned int - ParticlePropertyInformation::get_position_by_plugin_index(const unsigned int plugin_index) const - { - return position_per_plugin[plugin_index]; - } - - - - unsigned int - ParticlePropertyInformation::get_components_by_plugin_index(const unsigned int plugin_index) const - { - return components_per_plugin[plugin_index]; - } - - - - unsigned int - ParticlePropertyInformation::get_fields_by_plugin_index(const unsigned int plugin_index) const - { - return fields_per_plugin[plugin_index]; - } - - - - unsigned int - ParticlePropertyInformation::n_plugins() const - { - return number_of_plugins; - } - - - - unsigned int - ParticlePropertyInformation::n_fields() const - { - return number_of_fields; - } - - - - unsigned int - ParticlePropertyInformation::n_components() const - { - return number_of_components; - } - - - - template - void - Interface::initialize_one_particle_property (const Point &, - std::vector &) const - {} - - - - DEAL_II_DISABLE_EXTRA_DIAGNOSTICS - template - void - Interface::update_particle_properties (const unsigned int data_position, - const std::vector> &solution, - const std::vector>> &gradients, - typename ParticleHandler::particle_iterator_range &particles) const - { - unsigned int i = 0; - for (typename ParticleHandler::particle_iterator particle = particles.begin(); - particle != particles.end(); ++particle, ++i) - { - // call the deprecated version of this function - update_particle_property(data_position, - solution[i], - gradients[i], - particle); - } - } - DEAL_II_ENABLE_EXTRA_DIAGNOSTICS - - - - template - void - Interface::update_particle_property (const unsigned int /*data_position*/, - const Vector &/*solution*/, - const std::vector> &/*gradients*/, - typename ParticleHandler::particle_iterator &/*particle*/) const - {} - - - - template - UpdateTimeFlags - Interface::need_update () const - { - return update_never; - } - - - - template - UpdateFlags - Interface::get_needed_update_flags () const - { - return update_default; - } - - - - template - InitializationModeForLateParticles - Interface::late_initialization_mode () const - { - return interpolate; - } - - - - template - void - IntegratorProperties::initialize_one_particle_property(const Point &/*position*/, - std::vector &data) const - { - data.resize(data.size() + n_integrator_properties, 0.0); - } - - - - template - std::vector> - IntegratorProperties::get_property_information() const - { - return {{"internal: integrator properties", n_integrator_properties}}; - } - - - - template - void - IntegratorProperties::parse_parameters (ParameterHandler &prm) - { - std::string name; - name = prm.get ("Integration scheme"); - - if (name == "rk2") - n_integrator_properties = Particle::Integrator::RK2::n_integrator_properties; - else if (name == "rk4") - n_integrator_properties = Particle::Integrator::RK4::n_integrator_properties; - else if (name == "euler") - n_integrator_properties = Particle::Integrator::Euler::n_integrator_properties; - else - AssertThrow(false, - ExcMessage("Unknown integrator scheme. The particle property 'Integrator properties' " - "does not know how many particle properties to store for this integration scheme.")); - } - - - - template - inline - Manager::Manager () - = default; - - - - template - inline - Manager::~Manager () - = default; - - - - template - void - Manager::initialize () - { - std::vector>> info; - - // Get the property information of the selected plugins - for (const auto &p : this->plugin_objects) - { - info.push_back(p->get_property_information()); - } - - // Initialize our property information - property_information = ParticlePropertyInformation(info); - for (const auto &p : this->plugin_objects) - { - p->initialize(); - } - } - - - - template - void - Manager::update () - { - for (const auto &p : this->plugin_objects) - p->update(); - } - - - - template - void - Manager::initialize_one_particle (typename ParticleHandler::particle_iterator &particle) const - { - if (property_information.n_components() == 0) - return; - - std::vector particle_properties; - particle_properties.reserve(property_information.n_components()); - - for (const auto &p : this->plugin_objects) - { - p->initialize_one_particle_property(particle->get_location(), - particle_properties); - } - - Assert(particle_properties.size() == property_information.n_components(), - ExcMessage("The reported numbers of particle property components do not sum up " - "to the number of particle properties that were initialized by " - "the property plugins. Check the selected property plugins for " - "consistency between reported size and actually set properties.")); - - particle->set_properties(particle_properties); - } - - - - template - std::vector - Manager::initialize_late_particle (const Point &particle_location, - const ParticleHandler &particle_handler, - const Interpolator::Interface &interpolator, - const typename parallel::distributed::Triangulation::active_cell_iterator &cell) const - { - if (property_information.n_components() == 0) - return {}; - - std::vector particle_properties; - particle_properties.reserve(property_information.n_components()); - - unsigned int property_index = 0; - for (typename std::list>>::const_iterator - p = this->plugin_objects.begin(); p!=this->plugin_objects.end(); ++p, ++property_index) - { - switch ((*p)->late_initialization_mode()) - { - case aspect::Particle::Property::initialize_to_zero: - { - for (unsigned int property_component = 0; property_component < property_information.get_components_by_plugin_index(property_index); ++property_component) - particle_properties.push_back(0.0); - break; - } - - case aspect::Particle::Property::initialize: - { - (*p)->initialize_one_particle_property(particle_location, - particle_properties); - break; - } - - case aspect::Particle::Property::interpolate: - { - typename parallel::distributed::Triangulation::cell_iterator found_cell; - - if (cell == typename parallel::distributed::Triangulation::active_cell_iterator()) - { - found_cell = (GridTools::find_active_cell_around_point<> (this->get_mapping(), - this->get_triangulation(), - particle_location)).first; - } - else - found_cell = cell; - - std::vector> interpolated_properties; - - try - { - interpolated_properties = interpolator.properties_at_points(particle_handler, - std::vector> (1,particle_location), - ComponentMask(property_information.n_components(),true), - found_cell); - } - // interpolators that throw exceptions usually do not result in - // anything good, because they result in an unwinding of the stack - // and, if only one processor triggers an exception, the - // destruction of objects often causes a deadlock or completely - // unrelated MPI error messages. Thus, if an exception is - // generated, catch it, print an error message, and abort the program. - catch (std::exception &exc) - { - std::cerr << std::endl << std::endl - << "----------------------------------------------------" - << std::endl; - std::cerr << "Exception on MPI process <" - << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) - << "> while generating new particle properties: " - << std::endl - << exc.what() << std::endl - << "Aborting!" << std::endl - << "----------------------------------------------------" - << std::endl; - - // terminate the program! - MPI_Abort (MPI_COMM_WORLD, 1); - } - - for (unsigned int property_component = 0; property_component < property_information.get_components_by_plugin_index(property_index); ++property_component) - particle_properties.push_back(interpolated_properties[0][property_information.get_position_by_plugin_index(property_index)+property_component]); - break; - } - - case aspect::Particle::Property::interpolate_respect_boundary: - { - typename parallel::distributed::Triangulation::cell_iterator found_cell; - - if (cell == typename parallel::distributed::Triangulation::active_cell_iterator()) - { - found_cell = (GridTools::find_active_cell_around_point<> (this->get_mapping(), - this->get_triangulation(), - particle_location)).first; - } - else - found_cell = cell; - - const auto &manager = this->get_boundary_composition_manager(); - const auto &fixed_boundaries = manager.get_fixed_composition_boundary_indicators(); - - // Determine if the current cell is at a Dirichlet boundary - bool cell_at_fixed_boundary = false; - unsigned int boundary_face = numbers::invalid_unsigned_int; - double minimum_face_distance = std::numeric_limits::max(); - for (const unsigned int f : cell->face_indices()) - if (cell->at_boundary(f) && fixed_boundaries.count(cell->face(f)->boundary_id()) == 1) - { - const double face_center_distance = particle_location.distance_square(cell->face(f)->center(true)); - if (face_center_distance < minimum_face_distance) - { - minimum_face_distance = face_center_distance; - boundary_face = f; - cell_at_fixed_boundary = true; - } - } - - // If no Dirichlet boundary, interpolate - if (cell_at_fixed_boundary == false) - { - const std::vector> interpolated_properties = interpolator.properties_at_points(particle_handler, - std::vector> (1,particle_location), - ComponentMask(property_information.n_components(),true), - found_cell); - for (unsigned int property_component = 0; property_component < property_information.get_components_by_plugin_index(property_index); ++property_component) - particle_properties.push_back(interpolated_properties[0][property_information.get_position_by_plugin_index(property_index)+property_component]); - } - // Otherwise use the boundary condition - else - { - Assert(property_information.get_components_by_plugin_index(property_index) == this->n_compositional_fields(), - ExcInternalError()); - - const types::boundary_id boundary_id = cell->face(boundary_face)->boundary_id(); - - for (unsigned int c=0; cn_compositional_fields(); ++c) - { - const double composition = manager.boundary_composition(boundary_id,particle_location,c); - particle_properties.push_back(composition); - } - } - - break; - } - - default: - Assert (false, ExcInternalError()); - } - } - - Assert (particle_properties.size() == property_information.n_components(), ExcInternalError()); - - return particle_properties; - } - - - - template - void - Manager::update_particles (typename ParticleHandler::particle_iterator_range &particles, - const std::vector> &solution, - const std::vector>> &gradients) const - { - unsigned int plugin_index = 0; - for (typename std::list>>::const_iterator - p = this->plugin_objects.begin(); p!=this->plugin_objects.end(); ++p,++plugin_index) - { - (*p)->update_particle_properties(property_information.get_position_by_plugin_index(plugin_index), - solution, - gradients, - particles); - } - } - - - - template - UpdateTimeFlags - Manager::need_update () const - { - UpdateTimeFlags update = update_never; - for (const auto &p : this->plugin_objects) - { - update = std::max(update, p->need_update()); - } - return update; - } - - - - template - UpdateFlags - Manager::get_needed_update_flags () const - { - UpdateFlags update = update_default; - for (const auto &p : this->plugin_objects) - { - update |= p->get_needed_update_flags(); - } - - return (update & (update_default | update_values | update_gradients)); - } - - - - template - bool - Manager::plugin_name_exists(const std::string &name) const - { - return (std::find(plugin_names.begin(),plugin_names.end(),name) != plugin_names.end()); - } - - - - template - bool - Manager::check_plugin_order(const std::string &first, const std::string &second) const - { - - AssertThrow(first != second, - ExcMessage("The first and second string are the same, so can not check the order.")); - AssertThrow(plugin_name_exists(first), - ExcMessage("Could not find a plugin with the name <" + first + ">.")); - AssertThrow(plugin_name_exists(second), - ExcMessage("Could not find a plugin with the name <" + second + ">.")); - - return (std::find(plugin_names.begin(),plugin_names.end(),first) - < std::find(plugin_names.begin(),plugin_names.end(),second)); - } - - - - template - unsigned int - Manager::get_plugin_index_by_name(const std::string &name) const - { - const std::vector::const_iterator plugin = std::find(plugin_names.begin(), - plugin_names.end(), - name); - - AssertThrow(plugin != plugin_names.end(), - ExcMessage("The particle property manager was asked for a plugin " - "with the name <" + name + ">, but no such plugin could " - "be found.")); - return std::distance(plugin_names.begin(),plugin); - } - - - - template - unsigned int - Manager::get_n_property_components () const - { - return property_information.n_components(); - } - - - - template - std::size_t - Manager::get_particle_size () const - { - return (property_information.n_components()+2*dim) * sizeof(double) + sizeof(types::particle_index); - } - - - - template - const ParticlePropertyInformation & - Manager::get_data_info () const - { - return property_information; - } - - - - template - unsigned int - Manager::get_property_component_by_name(const std::string &name) const - { - return property_information.get_position_by_field_name(name); - } - - - - namespace - { - std::tuple - >, - aspect::internal::Plugins::PluginList>> registered_plugins; - } - - - - template - void - Manager::declare_parameters (ParameterHandler &prm) - { - // finally also construct a string for Patterns::MultipleSelection that - // contains the names of all registered particle properties - const std::string pattern_of_names - = std::get(registered_plugins).get_pattern_of_names (); - - prm.declare_entry("List of particle properties", - "", - Patterns::MultipleSelection(pattern_of_names), - "A comma separated list of particle properties that should be tracked. " - "By default none is selected, which means only position, velocity " - "and id of the particles are output. \n\n" - "The following properties are available:\n\n" - + - std::get(registered_plugins).get_description_string()); - - // now declare the parameters of each of the registered - // particle properties in turn - std::get(registered_plugins).declare_parameters (prm); - } - - - - template - void - Manager::parse_parameters (ParameterHandler &prm) - { - Assert (std::get(registered_plugins).plugins != nullptr, - ExcMessage ("No postprocessors registered!?")); - - // now also see which derived quantities we are to compute - plugin_names = Utilities::split_string_list(prm.get("List of particle properties")); - AssertThrow(Utilities::has_unique_entries(plugin_names), - ExcMessage("The list of strings for the parameter " - "'Particles/List of particle properties' contains entries more than once. " - "This is not allowed. Please check your parameter file.")); - - // see if 'all' was selected (or is part of the list). if so - // simply replace the list with one that contains all names - if (std::find (plugin_names.begin(), - plugin_names.end(), - "all") != plugin_names.end()) - { - plugin_names.clear(); - for (typename std::list>::PluginInfo>::const_iterator - p = std::get(registered_plugins).plugins->begin(); - p != std::get(registered_plugins).plugins->end(); ++p) - plugin_names.push_back (std::get<0>(*p)); - } - - // then go through the list, create objects and let them parse - // their own parameters - for (auto &plugin_name : plugin_names) - { - this->plugin_objects.emplace_back (std::get(registered_plugins) - .create_plugin (plugin_name, - "Particle property plugins")); - - if (SimulatorAccess *sim = dynamic_cast*>(this->plugin_objects.back().get())) - sim->initialize_simulator (this->get_simulator()); - - this->plugin_objects.back()->parse_parameters (prm); - } - - // lastly store internal integrator properties - this->plugin_objects.emplace_back (std::make_unique>()); - this->plugin_objects.back()->parse_parameters (prm); - } - - - - template - void - Manager::set_particle_world_index(unsigned int particle_world_index) - { - for (auto &property : this->plugin_objects) - { - property->set_particle_world_index(particle_world_index); - } - } - - - - template - void - Manager:: - register_particle_property (const std::string &name, - const std::string &description, - void (*declare_parameters_function) (ParameterHandler &), - std::unique_ptr> (*factory_function) ()) - { - std::get(registered_plugins).register_plugin (name, - description, - declare_parameters_function, - factory_function); - } - - - - template - void - Manager::write_plugin_graph (std::ostream &out) - { - std::get(registered_plugins).write_plugin_graph ("Particle property interface", - out); - } - - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace internal - { - namespace Plugins - { - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - } - } - - namespace Particle - { - namespace Property - { -#define INSTANTIATE(dim) \ - template class Interface; \ - template class Manager; - - ASPECT_INSTANTIATE(INSTANTIATE) - -#undef INSTANTIATE - } - } -} diff --git a/source/particle/property/melt_particle.cc.bak b/source/particle/property/melt_particle.cc.bak deleted file mode 100644 index fa80b32bee3..00000000000 --- a/source/particle/property/melt_particle.cc.bak +++ /dev/null @@ -1,126 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - - -#include -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - void - MeltParticle::initialize_one_particle_property(const Point &/*position*/, - std::vector &data) const - { - data.push_back(0.0); - } - - template - void - MeltParticle::update_particle_property(const unsigned int data_position, - const Vector &solution, - const std::vector> &/*gradients*/, - typename ParticleHandler::particle_iterator &particle) const - { - AssertThrow(this->introspection().compositional_name_exists("porosity"), - ExcMessage("Particle property melt particle only works if" - "there is a compositional field called porosity.")); - const unsigned int porosity_idx = this->introspection().compositional_index_for_name("porosity"); - - if (solution[this->introspection().component_indices.compositional_fields[porosity_idx]] > threshold_for_melt_presence) - particle->get_properties()[data_position] = 1.0; - else - particle->get_properties()[data_position] = 0.0; - } - - template - UpdateTimeFlags - MeltParticle::need_update() const - { - return update_time_step; - } - - template - UpdateFlags - MeltParticle::get_needed_update_flags () const - { - return update_values; - } - - template - std::vector> - MeltParticle::get_property_information() const - { - std::vector> property_information (1,std::make_pair("melt_presence",1)); - return property_information; - } - - template - void - MeltParticle::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Melt particle"); - { - prm.declare_entry ("Threshold for melt presence", "1e-3", - Patterns::Double (0., 1.), - "The minimum porosity that has to be present at the position of a particle " - "for it to be considered a melt particle (in the sense that the melt presence " - "property is set to 1)."); - } - prm.leave_subsection(); - } - - - template - void - MeltParticle::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Melt particle"); - { - threshold_for_melt_presence = prm.get_double ("Threshold for melt presence"); - } - prm.leave_subsection(); - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(MeltParticle, - "melt particle", - "Implementation of a plugin in which the particle " - "property is defined as presence of melt above a " - "threshold, which can be set as an input parameter. " - "This property is set to 0 if melt is not present and " - "set to 1 if melt is present.") - } - } -} diff --git a/source/particle/property/pT_path.cc.bak b/source/particle/property/pT_path.cc.bak deleted file mode 100644 index ffff2519a9e..00000000000 --- a/source/particle/property/pT_path.cc.bak +++ /dev/null @@ -1,123 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - void - PTPath::initialize() - { - // Make sure we keep track of the initial temperature manager and - // that it continues to live beyond the time when the simulator - // class releases its pointer to it. - initial_temperature = this->get_initial_temperature_manager_pointer(); - } - - - - - template - void - PTPath::initialize_one_particle_property(const Point &position, - std::vector &data) const - { - // The following is strictly only correct whenever a particle is - // created in the first time step. After that, taking pressure and - // temperature from adiabatic and initial temperature objects is - // not quite correct -- instead, we should be initializing from - // the current pressure and temperature, but that is substantially - // more complicated since we are not passed this information. - // - // The issue is probably not terribly important because at least for - // all following time steps, we set temperature and pressure to - // their correct then-current values. - data.push_back(this->get_adiabatic_conditions().pressure(position)); - data.push_back(initial_temperature->initial_temperature(position)); - } - - - - template - void - PTPath::update_particle_property(const unsigned int data_position, - const Vector &solution, - const std::vector> &/*gradients*/, - typename ParticleHandler::particle_iterator &particle) const - { - particle->get_properties()[data_position] = solution[this->introspection().component_indices.pressure]; - particle->get_properties()[data_position+1] = solution[this->introspection().component_indices.temperature]; - } - - - - template - UpdateTimeFlags - PTPath::need_update() const - { - return update_output_step; - } - - - - template - UpdateFlags - PTPath::get_needed_update_flags () const - { - return update_values; - } - - - - template - std::vector> - PTPath::get_property_information() const - { - return {{"p", 1}, {"T", 1}}; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(PTPath, - "pT path", - "Implementation of a plugin in which the particle " - "property is defined as the current pressure and " - "temperature at this position. This can be used " - "to generate pressure-temperature paths of " - "material points over time.") - } - } -} diff --git a/source/particle/property/position.cc.bak b/source/particle/property/position.cc.bak deleted file mode 100644 index a21a0837482..00000000000 --- a/source/particle/property/position.cc.bak +++ /dev/null @@ -1,80 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - void - Position::initialize_one_particle_property(const Point &position, - std::vector &data) const - { - for (unsigned int i = 0; i < dim; ++i) - data.push_back(position[i]); - } - - template - void - Position::update_particle_property(const unsigned int data_position, - const Vector &/*solution*/, - const std::vector> &/*gradients*/, - typename ParticleHandler::particle_iterator &particle) const - { - for (unsigned int i = 0; i < dim; ++i) - particle->get_properties()[data_position+i] = particle->get_location()[i]; - } - - template - UpdateTimeFlags - Position::need_update() const - { - return update_output_step; - } - - template - std::vector> - Position::get_property_information() const - { - const std::vector> property_information (1,std::make_pair("position",dim)); - return property_information; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(Position, - "position", - "Implementation of a plugin in which the particle " - "property is defined as the current position.") - } - } -} diff --git a/source/particle/property/reference_position.cc.bak b/source/particle/property/reference_position.cc.bak deleted file mode 100644 index 6d5fa5f978e..00000000000 --- a/source/particle/property/reference_position.cc.bak +++ /dev/null @@ -1,80 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - void - ReferencePosition::initialize_one_particle_property(const Point &position, - std::vector &data) const - { - for (unsigned int i = 0; i < dim; ++i) - data.push_back(position[i]); - } - - template - void - ReferencePosition::update_particle_property(const unsigned int data_position, - const Vector &/*solution*/, - const std::vector> &/*gradients*/, - typename ParticleHandler::particle_iterator &particle) const - { - for (unsigned int i = 0; i < dim; ++i) - particle->get_properties()[data_position+i] = particle->get_reference_location()[i]; - } - - template - UpdateTimeFlags - ReferencePosition::need_update() const - { - return update_output_step; - } - - template - std::vector> - ReferencePosition::get_property_information() const - { - const std::vector> property_information (1,std::make_pair("reference position",dim)); - return property_information; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(ReferencePosition, - "reference position", - "Implementation of a plugin in which the particle " - "property is defined as the current reference position.") - } - } -} diff --git a/source/particle/property/strain_rate.cc.bak b/source/particle/property/strain_rate.cc.bak deleted file mode 100644 index be79a182387..00000000000 --- a/source/particle/property/strain_rate.cc.bak +++ /dev/null @@ -1,102 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - void - StrainRate::initialize_one_particle_property(const Point &, - std::vector &data) const - { - const static Tensor<2,dim> identity = unit_symmetric_tensor(); - for (unsigned int i = 0; i < Tensor<2,dim>::n_independent_components ; ++i) - data.push_back(identity[Tensor<2,dim>::unrolled_to_component_indices(i)]); - - } - - template - void - StrainRate::update_particle_property(const unsigned int data_position, - const Vector &/*solution*/, - const std::vector> &gradients, - typename ParticleHandler::particle_iterator &particle) const - { - const auto data = particle->get_properties(); - // Velocity gradients - Tensor<2,dim> grad_u; - for (unsigned int d=0; d strain_rate = symmetrize (grad_u); - - for (unsigned int i = 0; i < Tensor<2,dim>::n_independent_components ; ++i) - data[data_position + i] = strain_rate[Tensor<2,dim>::unrolled_to_component_indices(i)]; - - } - - template - UpdateTimeFlags - StrainRate::need_update() const - { - return update_time_step; - } - - template - UpdateFlags - StrainRate::get_needed_update_flags () const - { - return update_gradients; - } - - template - std::vector> - StrainRate::get_property_information() const - { - const unsigned int n_components = Tensor<2,dim>::n_independent_components; - const std::vector> property_information (1,std::make_pair("strainrate",n_components)); - return property_information; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(StrainRate, - "strain rate", - "Implementation of a plugin in which the time evolution of " - "strain rate is saved and stored on the particles.") - } - } -} diff --git a/source/particle/property/velocity.cc.bak b/source/particle/property/velocity.cc.bak deleted file mode 100644 index 82270e8db5b..00000000000 --- a/source/particle/property/velocity.cc.bak +++ /dev/null @@ -1,88 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include - -namespace aspect -{ - namespace Particle - { - namespace Property - { - template - void - Velocity::initialize_one_particle_property(const Point &, - std::vector &data) const - { - for (unsigned int i = 0; i < dim; ++i) - data.push_back(0.0); - } - - template - void - Velocity::update_particle_property(const unsigned int data_position, - const Vector &solution, - const std::vector> &/*gradients*/, - typename ParticleHandler::particle_iterator &particle) const - { - for (unsigned int i = 0; i < dim; ++i) - particle->get_properties()[data_position+i] = solution[this->introspection().component_indices.velocities[i]]; - } - - template - UpdateTimeFlags - Velocity::need_update() const - { - return update_output_step; - } - - template - UpdateFlags - Velocity::get_needed_update_flags () const - { - return update_values; - } - - template - std::vector> - Velocity::get_property_information() const - { - const std::vector> property_information (1,std::make_pair("velocity",dim)); - return property_information; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(Velocity, - "velocity", - "Implementation of a plugin in which the particle " - "property is defined as the recent velocity at " - "this position.") - } - } -} diff --git a/source/particle/property/viscoplastic_strain_invariants.cc.bak b/source/particle/property/viscoplastic_strain_invariants.cc.bak deleted file mode 100644 index 8ea89a2cda2..00000000000 --- a/source/particle/property/viscoplastic_strain_invariants.cc.bak +++ /dev/null @@ -1,243 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include - - -namespace aspect -{ - namespace Particle - { - namespace Property - { - - template - ViscoPlasticStrainInvariant::ViscoPlasticStrainInvariant () - : - n_components(0), - material_inputs(1,0) - {} - - - - template - void - ViscoPlasticStrainInvariant::initialize () - { - AssertThrow(Plugins::plugin_type_matches> - (this->get_material_model()), - ExcMessage("This initial condition only makes sense in combination " - "with the visco_plastic material model.")); - - n_components = 0; - material_inputs = MaterialModel::MaterialModelInputs(1,this->n_compositional_fields()); - - // Find out which fields are used. - if (this->introspection().compositional_name_exists("plastic_strain")) - n_components += 1; - - if (this->introspection().compositional_name_exists("viscous_strain")) - n_components += 1; - - if (this->introspection().compositional_name_exists("total_strain")) - n_components += 1; - - if (this->introspection().compositional_name_exists("noninitial_plastic_strain")) - n_components += 1; - - if (n_components == 0) - AssertThrow(false, - ExcMessage("This particle property requires a compositional " - "strain field (plastic_strain, viscous_strain, " - "or total_strain).")); - } - - - - template - void - ViscoPlasticStrainInvariant::initialize_one_particle_property(const Point &position, - std::vector &data) const - { - // Give each strain field its initial composition if one is prescribed. - if (this->introspection().compositional_name_exists("plastic_strain")) - data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("plastic_strain"))); - - if (this->introspection().compositional_name_exists("viscous_strain")) - data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("viscous_strain"))); - - if (this->introspection().compositional_name_exists("total_strain")) - data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("total_strain"))); - - if (this->introspection().compositional_name_exists("noninitial_plastic_strain")) - data.push_back(this->get_initial_composition_manager().initial_composition(position,this->introspection().compositional_index_for_name("noninitial_plastic_strain"))); - - } - - - - template - void - ViscoPlasticStrainInvariant::update_particle_property(const unsigned int data_position, - const Vector &solution, - const std::vector> &gradients, - typename ParticleHandler::particle_iterator &particle) const - { - // Current timestep - const double dt = this->get_timestep(); - - // Velocity gradients - Tensor<2,dim> grad_u; - for (unsigned int d=0; dintrospection().component_indices.pressure]; - material_inputs.temperature[0] = solution[this->introspection().component_indices.temperature]; - material_inputs.position[0] = particle->get_location(); - - // Calculate strain rate from velocity gradients - material_inputs.strain_rate[0] = symmetrize (grad_u); - - // Put compositional fields into single variable - for (unsigned int i = 0; i < this->n_compositional_fields(); ++i) - { - material_inputs.composition[0][i] = solution[this->introspection().component_indices.compositional_fields[i]]; - } - - // Find out plastic yielding by calling function in material model. - const MaterialModel::ViscoPlastic &viscoplastic - = Plugins::get_plugin_as_type>(this->get_material_model()); - - const bool plastic_yielding = viscoplastic.is_yielding(material_inputs); - - // Next take the integrated strain invariant from the prior time step. - const auto data = particle->get_properties(); - - // Calculate strain rate second invariant - const double edot_ii = std::sqrt(std::max(-second_invariant(deviator(material_inputs.strain_rate[0])), 0.)); - - // Calculate strain invariant magnitude over the last time step - const double strain_update = dt*edot_ii; - - /* Update the strain values that are used in the simulation, which use the following assumptions - * to identify the correct position in the data vector for each value: - * (1) Total strain cannot be used in combination with any other strain field - * (2) If plastic strain is tracked, it will always be in the first data position - * (3) If noninitial plastic strain is tracked, it will always be in the last data position - * (4) If noninitial plastic strain is tracked, plastic strain is also being tracked - * (5) If only viscous strain is tracked, it will be in the first data position. - * (6) If both viscous and plastic strain are tracked, viscous strain will be in the second data position - * If these assumptions change in the future, they will need to be updated. - * */ - - if (this->introspection().compositional_name_exists("plastic_strain") && plastic_yielding == true) - data[data_position] += strain_update; - - if (this->introspection().compositional_name_exists("viscous_strain") && plastic_yielding == false) - { - // Not yielding and only one field, which tracks the viscous strain. - if (n_components == 1) - data[data_position] += strain_update; - - // Not yielding and either two or three fields are tracked. If two fields are tracked, - // they represent plastic strain (first data position) and viscous strain (second data - // data position, updated below). If three fields are tracked, they represent plastic - // strain (first data position), viscous strain (second data position, updated below), - // and noninitial plastic strain (third data position). In either case, the viscous - // strain is in the second data position, allowing us to use a single expression. - if (n_components > 1) - data[data_position+1] += strain_update; - } - - // Only one field, which tracks total strain and is updated regardless of whether the - // material is yielding or not. - if (this->introspection().compositional_name_exists("total_strain")) - data[data_position] += strain_update; - - // Yielding, and noninitial plastic strain (last data position, updated below) is tracked. - if (this->introspection().compositional_name_exists("noninitial_plastic_strain") && plastic_yielding == true) - data[data_position+(n_components-1)] += strain_update; - } - - - - template - UpdateTimeFlags - ViscoPlasticStrainInvariant::need_update() const - { - return update_time_step; - } - - - - template - UpdateFlags - ViscoPlasticStrainInvariant::get_needed_update_flags () const - { - // Need to update both of these to send into material model. - return update_values | update_gradients; - } - - template - std::vector> - ViscoPlasticStrainInvariant::get_property_information() const - { - std::vector> property_information; - - //Check which fields are used in model and make an output for each. - if (this->introspection().compositional_name_exists("plastic_strain")) - property_information.emplace_back("plastic_strain", 1); - - if (this->introspection().compositional_name_exists("viscous_strain")) - property_information.emplace_back("viscous_strain", 1); - - if (this->introspection().compositional_name_exists("total_strain")) - property_information.emplace_back("total_strain", 1); - - if (this->introspection().compositional_name_exists("noninitial_plastic_strain")) - property_information.emplace_back("noninitial_plastic_strain", 1); - - return property_information; - } - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Particle - { - namespace Property - { - ASPECT_REGISTER_PARTICLE_PROPERTY(ViscoPlasticStrainInvariant, - "viscoplastic strain invariants", - "A plugin that calculates the finite strain invariant a particle has " - "experienced and assigns it to either the plastic and/or viscous strain field based " - "on whether the material is plastically yielding, or the total strain field " - "used in the visco plastic material model. The implementation of this property " - "is equivalent to the implementation for compositional fields that is located in " - "the plugin in \\texttt{benchmarks/buiter\\_et\\_al\\_2008\\_jgr/plugin/}," - "and is effectively the same as what the visco plastic material model uses for compositional fields.") - } - } -} diff --git a/source/particle/world.cc.bak b/source/particle/world.cc.bak deleted file mode 100644 index 0c558f8a996..00000000000 --- a/source/particle/world.cc.bak +++ /dev/null @@ -1,1384 +0,0 @@ -/* - Copyright (C) 2015 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include - -namespace aspect -{ - namespace Particle - { - template - World::World() - = default; - - template - World::~World() - = default; - - template - void - World::initialize() - { - CitationInfo::add("particles"); - if (particle_load_balancing & ParticleLoadBalancing::repartition) - this->get_triangulation().signals.weight.connect( -#if DEAL_II_VERSION_GTE(9,6,0) - [&] (const typename parallel::distributed::Triangulation::cell_iterator &cell, - const CellStatus status) - -> unsigned int -#else - [&] (const typename parallel::distributed::Triangulation::cell_iterator &cell, - const typename parallel::distributed::Triangulation::CellStatus status) - -> unsigned int -#endif - { - return this->cell_weight(cell, status); - }); - - // Create a particle handler that stores the future particles. - // If we restarted from a checkpoint we will fill this particle handler - // later with its serialized variables and stored particles - particle_handler = std::make_unique>(this->get_triangulation(), - this->get_mapping(), - property_manager->get_n_property_components()); - - particle_handler_backup.initialize(this->get_triangulation(), - this->get_mapping(), - property_manager->get_n_property_components()); - - connect_to_signals(this->get_signals()); - - AssertThrow(this->introspection().get_composition_base_element_indices().size()<=1, - ExcNotImplemented("Particles are not supported in computations with compositional fields with different finite element types.")); - } - - - - template - void - World::update() - { - generator->update(); - integrator->update(); - interpolator->update(); - property_manager->update(); - } - - - - template - const Property::Manager & - World::get_property_manager() const - { - return *property_manager; - } - - - - template - const Particles::ParticleHandler & - World::get_particle_handler() const - { - return *particle_handler.get(); - } - - - - template - Particles::ParticleHandler & - World::get_particle_handler() - { - return *particle_handler.get(); - } - - - - template - void - World::copy_particle_handler (const Particles::ParticleHandler &from_particle_handler, - Particles::ParticleHandler &to_particle_handler) const - { - { - TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Copy"); - - to_particle_handler.copy_from(from_particle_handler); - } - } - - - - template - void - World::backup_particles () - { - copy_particle_handler (*particle_handler.get(), particle_handler_backup); - } - - - - template - void - World::restore_particles () - { - copy_particle_handler (particle_handler_backup, *particle_handler.get()); - } - - - - template - const Interpolator::Interface & - World::get_interpolator() const - { - return *interpolator; - } - - - - template - types::particle_index - World::n_global_particles() const - { - return particle_handler->n_global_particles(); - } - - - - template - void - World::connect_to_signals(aspect::SimulatorSignals &signals) - { - signals.post_set_initial_state.connect( - [&] (const SimulatorAccess &) - { - this->setup_initial_state(); - }); - - connect_particle_handler_signals(signals,*particle_handler); - // Particle handler backup will not be stored for checkpointing - connect_particle_handler_signals(signals, particle_handler_backup, false); - - signals.post_refinement_load_user_data.connect( - [&] (typename parallel::distributed::Triangulation &) - { - this->apply_particle_per_cell_bounds(); - }); - - signals.post_resume_load_user_data.connect( - [&] (typename parallel::distributed::Triangulation &) - { - this->apply_particle_per_cell_bounds(); - }); - } - - - - template - void - World::connect_particle_handler_signals(aspect::SimulatorSignals &signals, - ParticleHandler &particle_handler_, - const bool connect_to_checkpoint_signals) const - { - signals.pre_refinement_store_user_data.connect( - [&] (typename parallel::distributed::Triangulation &) - { - particle_handler_.prepare_for_coarsening_and_refinement(); - }); - - signals.post_refinement_load_user_data.connect( - [&] (typename parallel::distributed::Triangulation &) - { - particle_handler_.unpack_after_coarsening_and_refinement(); - }); - - // Only connect to checkpoint signals if requested - if (connect_to_checkpoint_signals) - { - signals.pre_checkpoint_store_user_data.connect( - [&] (typename parallel::distributed::Triangulation &) - { - particle_handler_.prepare_for_serialization(); - }); - - signals.post_resume_load_user_data.connect( - [&] (typename parallel::distributed::Triangulation &) - { - particle_handler_.deserialize(); - }); - } - - if (update_ghost_particles && - dealii::Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()) > 1) - { - auto do_ghost_exchange = [&] (typename parallel::distributed::Triangulation &) - { - particle_handler_.exchange_ghost_particles(); - }; - signals.post_refinement_load_user_data.connect(do_ghost_exchange); - signals.post_resume_load_user_data.connect(do_ghost_exchange); - } - - signals.post_mesh_deformation.connect( - [&] (const SimulatorAccess &) - { - particle_handler->sort_particles_into_subdomains_and_cells(); - }, - boost::signals2::at_front); - } - - - - template - void - World::apply_particle_per_cell_bounds() - { - // If any load balancing technique is selected that creates/destroys particles - if (particle_load_balancing & ParticleLoadBalancing::remove_and_add_particles) - { - // First do some preparation for particle generation in poorly - // populated areas. For this we need to know which particle ids to - // generate so that they are globally unique. - // Ensure this by communicating the number of particles that every - // process is going to generate. - particle_handler->update_cached_numbers(); - types::particle_index local_next_particle_index = particle_handler->get_next_free_particle_index(); - if (particle_load_balancing & ParticleLoadBalancing::add_particles) - { - types::particle_index particles_to_add_locally = 0; - - // Loop over all cells and determine the number of particles to generate - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - const unsigned int particles_in_cell = particle_handler->n_particles_in_cell(cell); - - if (particles_in_cell < min_particles_per_cell) - particles_to_add_locally += static_cast (min_particles_per_cell - particles_in_cell); - } - - // Determine the starting particle index of this process, which - // is the highest currently existing particle index plus the sum - // of the number of newly generated particles of all - // processes with a lower rank. - - types::particle_index local_start_index = 0.0; - - const int ierr = MPI_Scan(&particles_to_add_locally, &local_start_index, 1, DEAL_II_PARTICLE_INDEX_MPI_TYPE, MPI_SUM, this->get_mpi_communicator()); - AssertThrowMPI(ierr); - - local_start_index -= particles_to_add_locally; - local_next_particle_index += local_start_index; - - const types::particle_index globally_generated_particles = - dealii::Utilities::MPI::sum(particles_to_add_locally,this->get_mpi_communicator()); - - AssertThrow (particle_handler->get_next_free_particle_index() - <= std::numeric_limits::max() - globally_generated_particles, - ExcMessage("There is no free particle index left to generate a new particle id. Please check if your " - "model generates unusually many new particles (by repeatedly deleting and regenerating particles), or " - "recompile deal.II with the DEAL_II_WITH_64BIT_INDICES option enabled, to use 64-bit integers for " - "particle ids.")); - } - - std::mt19937 random_number_generator; - - // Loop over all cells and generate or remove the particles cell-wise - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - const unsigned int n_particles_in_cell = particle_handler->n_particles_in_cell(cell); - - // Add particles if necessary - if ((particle_load_balancing & ParticleLoadBalancing::add_particles) && - (n_particles_in_cell < min_particles_per_cell)) - { - for (unsigned int i = n_particles_in_cell; i < min_particles_per_cell; ++i,++local_next_particle_index) - { - std::pair> new_particle = generator->generate_particle(cell,local_next_particle_index); - - const std::vector particle_properties = - property_manager->initialize_late_particle(new_particle.second.get_location(), - *particle_handler, - *interpolator, - cell); - - typename ParticleHandler::particle_iterator particle = particle_handler->insert_particle(new_particle.second, - typename parallel::distributed::Triangulation::cell_iterator (&this->get_triangulation(), - new_particle.first.first, - new_particle.first.second)); - particle->set_properties(particle_properties); - } - } - - // Remove particles if necessary - else if ((particle_load_balancing & ParticleLoadBalancing::remove_particles) && - (n_particles_in_cell > max_particles_per_cell)) - { - const unsigned int n_particles_to_remove = n_particles_in_cell - max_particles_per_cell; - for (unsigned int i=0; i < n_particles_to_remove; ++i) - { - const unsigned int current_n_particles_in_cell = particle_handler->n_particles_in_cell(cell); - const unsigned int index_to_remove = std::uniform_int_distribution - (0,current_n_particles_in_cell-1)(random_number_generator); - - auto particle_to_remove = particle_handler->particles_in_cell(cell).begin(); - std::advance(particle_to_remove, index_to_remove); - particle_handler->remove_particle(particle_to_remove); - } - - } - } - - particle_handler->update_cached_numbers(); - } - } - - template - unsigned int - World::cell_weight(const typename parallel::distributed::Triangulation::cell_iterator &cell, -#if DEAL_II_VERSION_GTE(9,6,0) - const CellStatus status -#else - const typename parallel::distributed::Triangulation::CellStatus status -#endif - ) - { - if (cell->is_active() && !cell->is_locally_owned()) - return 0; - - const unsigned int base_weight = 1000; - unsigned int n_particles_in_cell = 0; - switch (status) - { -#if DEAL_II_VERSION_GTE(9,6,0) - case CellStatus::cell_will_persist: - case CellStatus::cell_will_be_refined: - n_particles_in_cell = particle_handler->n_particles_in_cell(cell); - break; - - case CellStatus::cell_invalid: - break; - - case CellStatus::children_will_be_coarsened: - for (const auto &child : cell->child_iterators()) - n_particles_in_cell += particle_handler->n_particles_in_cell(child); - break; -#else - case parallel::distributed::Triangulation::CELL_PERSIST: - case parallel::distributed::Triangulation::CELL_REFINE: - n_particles_in_cell = particle_handler->n_particles_in_cell(cell); - break; - - case parallel::distributed::Triangulation::CELL_INVALID: - break; - - case parallel::distributed::Triangulation::CELL_COARSEN: - for (const auto &child : cell->child_iterators()) - n_particles_in_cell += particle_handler->n_particles_in_cell(child); - break; -#endif - default: - Assert(false, ExcInternalError()); - break; - } - return base_weight + n_particles_in_cell * particle_weight; - } - - - template - std::map - World::get_subdomain_id_to_neighbor_map() const - { - std::map subdomain_id_to_neighbor_map; - const std::set ghost_owners = this->get_triangulation().ghost_owners(); - std::set::const_iterator ghost_owner = ghost_owners.begin(); - - for (unsigned int neighbor_id=0; neighbor_id - void - World::local_initialize_particles(const typename ParticleHandler::particle_iterator &begin_particle, - const typename ParticleHandler::particle_iterator &end_particle) - { - for (typename ParticleHandler::particle_iterator it = begin_particle; it!=end_particle; ++it) - property_manager->initialize_one_particle(it); - } - - - - template - void - World::local_update_particles(const typename DoFHandler::active_cell_iterator &cell, - internal::SolutionEvaluators &evaluators) - { - const unsigned int n_particles_in_cell = particle_handler->n_particles_in_cell(cell); - typename ParticleHandler::particle_iterator_range particles = particle_handler->particles_in_cell(cell); - - std::vector> positions; - positions.reserve(n_particles_in_cell); - - for (const auto &particle : particles) - positions.push_back(particle.get_reference_location()); - - const UpdateFlags update_flags = property_manager->get_needed_update_flags(); - - boost::container::small_vector solution_values(this->get_fe().dofs_per_cell); - - cell->get_dof_values(this->get_solution(), - solution_values.begin(), - solution_values.end()); - - if (update_flags & (update_values | update_gradients)) - evaluators.reinit(cell, positions, {solution_values.data(), solution_values.size()}, update_flags); - - std::vector> solution; - if (update_flags & update_values) - solution.resize(n_particles_in_cell,Vector(this->introspection().n_components)); - - std::vector>> gradients; - if (update_flags & update_gradients) - gradients.resize(n_particles_in_cell,std::vector>(this->introspection().n_components)); - - for (unsigned int i = 0; iupdate_particles(particles, - solution, - gradients); - } - - - - template - void - World::local_advect_particles(const typename DoFHandler::active_cell_iterator &cell, - const typename ParticleHandler::particle_iterator &begin_particle, - const typename ParticleHandler::particle_iterator &end_particle, - internal::SolutionEvaluators &evaluators) - { - const unsigned int n_particles_in_cell = particle_handler->n_particles_in_cell(cell); - - boost::container::small_vector, 100> positions; - positions.reserve(n_particles_in_cell); - for (auto particle = begin_particle; particle!=end_particle; ++particle) - positions.push_back(particle->get_reference_location()); - - const std::array required_solution_vectors = integrator->required_solution_vectors(); - - AssertThrow (required_solution_vectors[0] == false, - ExcMessage("The integrator requires the old old solution vector, but it is not available.")); - - - const bool use_fluid_velocity = this->include_melt_transport() && - property_manager->get_data_info().fieldname_exists("melt_presence"); - - auto &evaluator = evaluators.get_velocity_or_fluid_velocity_evaluator(use_fluid_velocity); - auto &mapping_info = evaluators.get_mapping_info(); - mapping_info.reinit(cell, {positions.data(),positions.size()}); - - std::vector> velocities; - std::vector> old_velocities; - - if (required_solution_vectors[1] == true) - { - boost::container::small_vector old_solution_values(this->get_fe().dofs_per_cell); - cell->get_dof_values(this->get_old_solution(), - old_solution_values.begin(), - old_solution_values.end()); - - evaluator.evaluate({old_solution_values.data(),old_solution_values.size()}, - EvaluationFlags::values); - - old_velocities.resize(n_particles_in_cell); - for (unsigned int i=0; i solution_values(this->get_fe().dofs_per_cell); - cell->get_dof_values(this->get_current_linearization_point(), - solution_values.begin(), - solution_values.end()); - evaluator.evaluate({solution_values.data(),solution_values.size()}, - EvaluationFlags::values); - - velocities.resize(n_particles_in_cell); - for (unsigned int i=0; ilocal_integrate_step(begin_particle, - end_particle, - old_velocities, - velocities, - this->get_timestep()); - } - - - - template - void - World::setup_initial_state () - { - // If we are in the first adaptive refinement cycle generate particles - if (this->get_pre_refinement_step() == 0) - generate_particles(); - - // And initialize the particle properties according to the initial - // conditions on the current mesh - initialize_particles(); - } - - - - template - void - World::generate_particles() - { - TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Generate"); - generator->generate_particles(*particle_handler); - } - - - - template - void - World::initialize_particles() - { - // TODO: Change this loop over all cells to use the WorkStream interface - if (property_manager->get_n_property_components() > 0) - { - TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Initialize properties"); - - particle_handler->get_property_pool().reserve(2 * particle_handler->n_locally_owned_particles()); - - - if (particle_handler->n_locally_owned_particles() > 0) - local_initialize_particles(particle_handler->begin(), - particle_handler->end()); - - if (update_ghost_particles && - dealii::Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()) > 1) - { - TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Exchange ghosts"); - particle_handler->exchange_ghost_particles(); - } - } - } - - - - namespace internal - { - // This class evaluates the solution vector at arbitrary positions inside a cell. - // It uses the deal.II class FEPointEvaluation to do this efficiently. Because - // FEPointEvaluation only supports a single finite element, but ASPECT uses a FESystem with - // many components, this class creates several FEPointEvaluation objects that are used for - // the individual finite elements of our solution (pressure, velocity, temperature, and - // all other optional variables). Because FEPointEvaluation is templated based on the - // number of components, but ASPECT only knows the number of components at runtime - // we create this derived class with an additional template. This makes it possible - // to access the functionality through the base class, but create an object of this - // derived class with the correct number of components at runtime. - template - class SolutionEvaluatorsImplementation: public SolutionEvaluators - { - public: - // Constructor. Create the member variables given a simulator and a set of - // update flags. The update flags control if only the solution or also the gradients - // should be evaluated. - SolutionEvaluatorsImplementation(const SimulatorAccess &simulator, - const UpdateFlags update_flags); - - // Reinitialize all variables to evaluate the given solution for the given cell - // and the given positions. The update flags control if only the solution or - // also the gradients should be evaluated. - // If other flags are set an assertion is triggered. - void - reinit(const typename DoFHandler::active_cell_iterator &cell, - const ArrayView> &positions, - const ArrayView &solution_values, - const UpdateFlags update_flags) override; - - // Return the value of all solution components at the given evaluation point. Note - // that this function only works after a successful call to reinit(), - // because this function only returns the results of the computation that - // happened in reinit(). - void get_solution(const unsigned int evaluation_point, - Vector &solution) override; - - // Return the value of all solution gradients at the given evaluation point. Note - // that this function only works after a successful call to reinit(), - // because this function only returns the results of the computation that - // happened in reinit(). - void get_gradients(const unsigned int evaluation_point, - std::vector> &gradients) override; - - // Return the evaluator for velocity or fluid velocity. This is the only - // information necessary for advecting particles. - FEPointEvaluation & - get_velocity_or_fluid_velocity_evaluator(const bool use_fluid_velocity) override; - - // Return the cached mapping information. - NonMatching::MappingInfo & - get_mapping_info() override; - private: - // MappingInfo object for the FEPointEvaluation objects - NonMatching::MappingInfo mapping_info; - - // FEPointEvaluation objects for all common - // components of ASPECT's finite element solution. - // These objects are used inside of the member functions of this class. - FEPointEvaluation velocity; - std::unique_ptr> pressure; - FEPointEvaluation<1, dim> temperature; - - // If instantiated evaluate multiple compositions at once, if - // not fall back to evaluating them individually. - FEPointEvaluation compositions; - std::vector> additional_compositions; - - // Pointers to FEPointEvaluation objects for all melt - // components of ASPECT's finite element solution, which only - // point to valid objects in case we use melt transport. Other - // documentation like for the objects directly above. - std::unique_ptr> fluid_velocity; - std::unique_ptr> compaction_pressure; - std::unique_ptr> fluid_pressure; - - // The component indices for the three melt formulation - // variables fluid velocity, compaction pressure, and - // fluid pressure (in this order). They are cached - // to avoid repeated expensive lookups. - std::array melt_component_indices; - - // Reference to the active simulator access object. Provides - // access to the general simulation variables. - const SimulatorAccess &simulator_access; - }; - - - - template - SolutionEvaluatorsImplementation::SolutionEvaluatorsImplementation(const SimulatorAccess &simulator, - const UpdateFlags update_flags) - : - mapping_info(simulator.get_mapping(), - update_flags), - velocity(mapping_info, - simulator.get_fe(), - simulator.introspection().component_indices.velocities[0]), - pressure(std::make_unique>(mapping_info, - simulator.get_fe(), - simulator.introspection().component_indices.pressure)), - temperature(mapping_info, - simulator.get_fe(), - simulator.introspection().component_indices.temperature), - compositions(mapping_info, - simulator.get_fe(), - simulator.n_compositional_fields() > 0 ? simulator.introspection().component_indices.compositional_fields[0] : simulator.introspection().component_indices.temperature), - - melt_component_indices(), - simulator_access(simulator) - { - // Create the evaluators for all compositional fields beyond the ones this class was - // instantiated for - const unsigned int n_total_compositional_fields = simulator_access.n_compositional_fields(); - const auto &component_indices = simulator_access.introspection().component_indices.compositional_fields; - for (unsigned int composition = n_compositional_fields; composition < n_total_compositional_fields; ++composition) - additional_compositions.emplace_back(FEPointEvaluation<1, dim>(mapping_info, - simulator_access.get_fe(), - component_indices[composition])); - - // The FE_DGP pressure element used in locally conservative discretization is not - // supported by the fast path of FEPointEvaluation. Replace with slow path. - if (simulator_access.get_parameters().use_locally_conservative_discretization == true) - pressure = std::make_unique>(simulator_access.get_mapping(), - simulator_access.get_fe(), - update_flags, - simulator.introspection().component_indices.pressure); - - // Create the melt evaluators, but only if we use melt transport in the model - if (simulator_access.include_melt_transport()) - { - // Store the melt component indices to avoid repeated string lookups later on - melt_component_indices[0] = simulator_access.introspection().variable("fluid velocity").first_component_index; - melt_component_indices[1] = simulator_access.introspection().variable("fluid pressure").first_component_index; - melt_component_indices[2] = simulator_access.introspection().variable("compaction pressure").first_component_index; - - fluid_velocity = std::make_unique>(mapping_info, - simulator_access.get_fe(), - melt_component_indices[0]); - if (simulator_access.get_parameters().use_locally_conservative_discretization == false) - fluid_pressure = std::make_unique>(mapping_info, - simulator_access.get_fe(), - melt_component_indices[1]); - else - { - fluid_pressure = std::make_unique>(simulator_access.get_mapping(), - simulator_access.get_fe(), - update_flags, - melt_component_indices[1]); - } - - if (simulator_access.get_melt_handler().melt_parameters.use_discontinuous_p_c == false) - compaction_pressure = std::make_unique>(mapping_info, - simulator_access.get_fe(), - melt_component_indices[2]); - else - compaction_pressure = std::make_unique>(simulator_access.get_mapping(), - simulator_access.get_fe(), - update_flags, - melt_component_indices[2]); - - - } - } - - - - template - void - SolutionEvaluatorsImplementation::reinit(const typename DoFHandler::active_cell_iterator &cell, - const ArrayView> &positions, - const ArrayView &solution_values, - const UpdateFlags update_flags) - { - // FEPointEvaluation uses different evaluation flags than the common UpdateFlags. - // Translate between the two. - EvaluationFlags::EvaluationFlags evaluation_flags = EvaluationFlags::nothing; - - if (update_flags & update_values) - evaluation_flags = evaluation_flags | EvaluationFlags::values; - - if (update_flags & update_gradients) - evaluation_flags = evaluation_flags | EvaluationFlags::gradients; - - // Make sure only the flags are set that we can deal with at the moment - Assert ((update_flags & ~(update_gradients | update_values)) == false, - ExcNotImplemented()); - - // Reinitialize and evaluate all evaluators. - // TODO: It would be nice to be able to hand over a ComponentMask - // to specify which evaluators to use. Currently, this is only - // possible by manually accessing the public members of this class. - mapping_info.reinit(cell,positions); - - if (simulator_access.get_parameters().use_locally_conservative_discretization == true) - { - pressure->reinit(cell, positions); - - if (simulator_access.include_melt_transport()) - { - fluid_pressure->reinit (cell, positions); - } - } - - if (simulator_access.include_melt_transport() - && simulator_access.get_melt_handler().melt_parameters.use_discontinuous_p_c == true) - { - compaction_pressure->reinit (cell, positions); - } - - - velocity.evaluate (solution_values, evaluation_flags); - pressure->evaluate (solution_values, evaluation_flags); - temperature.evaluate (solution_values, evaluation_flags); - compositions.evaluate (solution_values, evaluation_flags); - - for (auto &evaluator_composition: additional_compositions) - evaluator_composition.evaluate (solution_values, evaluation_flags); - - if (simulator_access.include_melt_transport()) - { - fluid_velocity->evaluate (solution_values, evaluation_flags); - fluid_pressure->evaluate (solution_values, evaluation_flags); - compaction_pressure->evaluate (solution_values, evaluation_flags); - } - } - - namespace - { - template - double - get_value(const Tensor<1,n_compositional_fields> &solution, - const unsigned int component_index) - { - AssertIndexRange(component_index, n_compositional_fields); - return solution[component_index]; - } - - template - double - get_value(const double &solution, - const unsigned int component_index) - { - (void) component_index; - AssertIndexRange(component_index, 1); - return solution; - } - - template - Tensor<1,dim> - get_gradient(const Tensor<1,n_compositional_fields,Tensor<1,dim>> &gradient, - const unsigned int component_index) - { - AssertIndexRange(component_index, n_compositional_fields); - return gradient[component_index]; - } - - - template - Tensor<1,dim> - get_gradient(const Tensor<1,dim> &gradient, - const unsigned int component_index) - { - (void) component_index; - AssertIndexRange(component_index, 1); - return gradient; - } - } - - - template - void - SolutionEvaluatorsImplementation::get_solution(const unsigned int evaluation_point, - Vector &solution) - { - Assert(solution.size() == simulator_access.introspection().n_components, - ExcDimensionMismatch(solution.size(), simulator_access.introspection().n_components)); - - const auto &component_indices = simulator_access.introspection().component_indices; - - const Tensor<1,dim> velocity_value = velocity.get_value(evaluation_point); - for (unsigned int j=0; jget_value(evaluation_point); - solution[component_indices.temperature] = temperature.get_value(evaluation_point); - - if (n_compositional_fields > 0) - for (unsigned int j=0; j( - compositions.get_value(evaluation_point), - j); - - const unsigned int n_additional_compositions = additional_compositions.size(); - for (unsigned int j=0; j fluid_velocity_value = velocity.get_value(evaluation_point); - for (unsigned int j=0; jget_value(evaluation_point); - solution[melt_component_indices[2]] = compaction_pressure->get_value(evaluation_point); - } - } - - - - template - void - SolutionEvaluatorsImplementation::get_gradients(const unsigned int evaluation_point, - std::vector> &gradients) - { - Assert(gradients.size() == simulator_access.introspection().n_components, - ExcDimensionMismatch(gradients.size(), simulator_access.introspection().n_components)); - - const auto &component_indices = simulator_access.introspection().component_indices; - - const Tensor<2,dim> velocity_gradient = velocity.get_gradient(evaluation_point); - for (unsigned int j=0; jget_gradient(evaluation_point); - gradients[component_indices.temperature] = temperature.get_gradient(evaluation_point); - - if (n_compositional_fields > 0) - for (unsigned int j=0; j( - compositions.get_gradient(evaluation_point), - j); - - const unsigned int n_additional_compositions = additional_compositions.size(); - for (unsigned int j=0; j fluid_velocity_gradient = velocity.get_gradient(evaluation_point); - for (unsigned int j=0; jget_gradient(evaluation_point); - gradients[melt_component_indices[2]] = compaction_pressure->get_gradient(evaluation_point); - } - } - - - template - FEPointEvaluation & - SolutionEvaluatorsImplementation::get_velocity_or_fluid_velocity_evaluator(const bool use_fluid_velocity) - { - if (use_fluid_velocity) - return *fluid_velocity; - else - return velocity; - - return velocity; - } - template - NonMatching::MappingInfo & - SolutionEvaluatorsImplementation::get_mapping_info() - { - return mapping_info; - } - - - - // A function to create a pointer to a SolutionEvaluators object. - template - std::unique_ptr> - construct_solution_evaluators (const SimulatorAccess &simulator_access, - const UpdateFlags update_flags) - { - switch (simulator_access.n_compositional_fields()) - { - case 0: - return std::make_unique>(simulator_access, update_flags); - case 1: - return std::make_unique>(simulator_access, update_flags); - case 2: - return std::make_unique>(simulator_access, update_flags); - case 3: - return std::make_unique>(simulator_access, update_flags); - case 4: - return std::make_unique>(simulator_access, update_flags); - case 5: - return std::make_unique>(simulator_access, update_flags); - case 6: - return std::make_unique>(simulator_access, update_flags); - case 7: - return std::make_unique>(simulator_access, update_flags); - case 8: - return std::make_unique>(simulator_access, update_flags); - case 9: - return std::make_unique>(simulator_access, update_flags); - case 10: - return std::make_unique>(simulator_access, update_flags); - case 11: - return std::make_unique>(simulator_access, update_flags); - case 12: - return std::make_unique>(simulator_access, update_flags); - case 13: - return std::make_unique>(simulator_access, update_flags); - case 14: - return std::make_unique>(simulator_access, update_flags); - case 15: - return std::make_unique>(simulator_access, update_flags); - case 16: - return std::make_unique>(simulator_access, update_flags); - case 17: - return std::make_unique>(simulator_access, update_flags); - case 18: - return std::make_unique>(simulator_access, update_flags); - case 19: - return std::make_unique>(simulator_access, update_flags); - // Return the maximally instantiated object. The class will handle additional compositional fields - // by dynamically allocating additional scalar evaluators. - default: - return std::make_unique>(simulator_access, update_flags); - } - } - } - - - - template - void - World::update_particles() - { - // TODO: Change this loop over all cells to use the WorkStream interface - - if (property_manager->get_n_property_components() > 0) - { - TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Update properties"); - - Assert(dealii::internal::FEPointEvaluation::is_fast_path_supported(this->get_mapping()) == true, - ExcMessage("The particle system was optimized for deal.II mappings that support the fast evaluation path " - "of the class FEPointEvaluation. The mapping currently in use does not support this path. " - "It is safe to uncomment this assertion, but you can expect a performance penalty.")); - - const UpdateFlags update_flags = property_manager->get_needed_update_flags(); - - std::unique_ptr> evaluators = internal::construct_solution_evaluators(*this, - update_flags); - - // Loop over all cells and update the particles cell-wise - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - // Only update particles if there are any in this cell - if (particle_handler->n_particles_in_cell(cell) > 0) - { - local_update_particles(cell, - *evaluators); - } - - } - } - } - - - - template - void - World::advect_particles() - { - { - // TODO: Change this loop over all cells to use the WorkStream interface - TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Advect"); - - Assert(dealii::internal::FEPointEvaluation::is_fast_path_supported(this->get_mapping()) == true, - ExcMessage("The particle system was optimized for deal.II mappings that support the fast evaluation path " - "of the class FEPointEvaluation. The mapping currently in use does not support this path. " - "It is safe to uncomment this assertion, but you can expect a performance penalty.")); - - std::unique_ptr> evaluators = - std::make_unique>(*this, - update_values); - - // Loop over all cells and advect the particles cell-wise - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - const typename ParticleHandler::particle_iterator_range - particles_in_cell = particle_handler->particles_in_cell(cell); - - // Only advect particles, if there are any in this cell - if (particles_in_cell.begin() != particles_in_cell.end()) - { - local_advect_particles(cell, - particles_in_cell.begin(), - particles_in_cell.end(), - *evaluators); - } - } - } - - { - TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Sort"); - // Find the cells that the particles moved to - particle_handler->sort_particles_into_subdomains_and_cells(); - } - } - - - - template - void - World::advance_timestep() - { - this->get_pcout() << " Advecting particles... " << std::flush; - do - { - advect_particles(); - } - // Keep calling the integrator until it indicates it is finished - while (integrator->new_integration_step()); - - apply_particle_per_cell_bounds(); - - // Update particle properties - if (property_manager->need_update() == Property::update_time_step) - update_particles(); - - // Now that all particle information was updated, exchange the new - // ghost particles. - if (update_ghost_particles && - dealii::Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()) > 1) - { - TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Exchange ghosts"); - particle_handler->exchange_ghost_particles(); - } - this->get_pcout() << " done." << std::endl; - } - - - - template - void - World::save (std::ostringstream &os) const - { - aspect::oarchive oa (os); - oa << (*this); - } - - - - template - void - World::load (std::istringstream &is) - { - aspect::iarchive ia (is); - ia >> (*this); - } - - - - template - void - World::declare_parameters (ParameterHandler &prm) - { - constexpr unsigned int number_of_particle_worlds = 1; - for (unsigned int world_index = 0; world_index < number_of_particle_worlds; ++world_index) - { - if (world_index == 0) - { - prm.enter_subsection("Particles"); - } - else - { - prm.enter_subsection("Particles " + std::to_string(world_index+1)); - } - { - prm.declare_entry ("Load balancing strategy", "repartition", - Patterns::MultipleSelection ("none|remove particles|add particles|" - "remove and add particles|repartition"), - "Strategy that is used to balance the computational " - "load across processors for adaptive meshes."); - prm.declare_entry ("Minimum particles per cell", "0", - Patterns::Integer (0), - "Lower limit for particle number per cell. This limit is " - "useful for adaptive meshes to prevent fine cells from being empty " - "of particles. It will be checked and enforced after mesh " - "refinement and after particle movement. " - "If there are " - "\\texttt{n\\_number\\_of\\_particles} $<$ \\texttt{min\\_particles\\_per\\_cell} " - "particles in one cell then " - "\\texttt{min\\_particles\\_per\\_cell} - \\texttt{n\\_number\\_of\\_particles} " - "particles are generated and randomly placed in " - "this cell. If the particles carry properties the " - "individual property plugins control how the " - "properties of the new particles are initialized."); - prm.declare_entry ("Maximum particles per cell", "100", - Patterns::Integer (0), - "Upper limit for particle number per cell. This limit is " - "useful for adaptive meshes to prevent coarse cells from slowing down " - "the whole model. It will be checked and enforced after mesh " - "refinement, after MPI transfer of particles and after particle " - "movement. If there are " - "\\texttt{n\\_number\\_of\\_particles} $>$ \\texttt{max\\_particles\\_per\\_cell} " - "particles in one cell then " - "\\texttt{n\\_number\\_of\\_particles} - \\texttt{max\\_particles\\_per\\_cell} " - "particles in this cell are randomly chosen and destroyed."); - prm.declare_entry ("Particle weight", "10", - Patterns::Integer (0), - "Weight that is associated with the computational load of " - "a single particle. The sum of particle weights will be added " - "to the sum of cell weights to determine the partitioning of " - "the mesh if the `repartition' particle load balancing strategy " - "is selected. The optimal weight depends on the used " - "integrator and particle properties. In general for a more " - "expensive integrator and more expensive properties a larger " - "particle weight is recommended. Before adding the weights " - "of particles, each cell already carries a weight of 1000 to " - "account for the cost of field-based computations."); - prm.declare_entry ("Update ghost particles", "false", - Patterns::Bool (), - "Some particle interpolation algorithms require knowledge " - "about particles in neighboring cells. To allow this, " - "particles in ghost cells need to be exchanged between the " - "processes neighboring this cell. This parameter determines " - "whether this transport is happening."); - - Generator::declare_parameters(prm); - Integrator::declare_parameters(prm); - Interpolator::declare_parameters(prm); - - Property::Manager::declare_parameters(prm); - } - prm.leave_subsection (); - } - - } - - - - template - void - World::parse_parameters (ParameterHandler &prm, const unsigned int world_index) - { - // First do some error checking. The current algorithm does not find - // the cells around particles, if the particles moved more than one - // cell in one timestep and we are running in parallel, because they - // skip the layer of ghost cells around our local domain. Assert this - // is not possible. - const double CFL_number = prm.get_double ("CFL number"); - const unsigned int n_processes = Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()); - - AssertThrow((n_processes == 1) || (CFL_number <= 1.0), - ExcMessage("The current particle algorithm does not work in " - "parallel if the CFL number is larger than 1.0, because " - "in this case particles can move more than one cell " - "diameter in one time step and therefore skip the layer " - "of ghost cells around the local subdomain.")); - - if (world_index == 0) - { - prm.enter_subsection("Particles"); - } - else - { - prm.enter_subsection("Particles " + std::to_string(world_index+1)); - } - { - min_particles_per_cell = prm.get_integer("Minimum particles per cell"); - max_particles_per_cell = prm.get_integer("Maximum particles per cell"); - - AssertThrow(min_particles_per_cell <= max_particles_per_cell, - ExcMessage("Please select a 'Minimum particles per cell' parameter " - "that is smaller than or equal to the 'Maximum particles per cell' parameter.")); - - particle_weight = prm.get_integer("Particle weight"); - - update_ghost_particles = prm.get_bool("Update ghost particles"); - - const std::vector strategies = Utilities::split_string_list(prm.get ("Load balancing strategy")); - AssertThrow(Utilities::has_unique_entries(strategies), - ExcMessage("The list of strings for the parameter " - "'Particles/Load balancing strategy' contains entries more than once. " - "This is not allowed. Please check your parameter file.")); - - particle_load_balancing = ParticleLoadBalancing::no_balancing; - - for (std::vector::const_iterator strategy = strategies.begin(); strategy != strategies.end(); ++strategy) - { - if (*strategy == "remove particles") - particle_load_balancing = typename ParticleLoadBalancing::Kind(particle_load_balancing | ParticleLoadBalancing::remove_particles); - else if (*strategy == "add particles") - particle_load_balancing = typename ParticleLoadBalancing::Kind(particle_load_balancing | ParticleLoadBalancing::add_particles); - else if (*strategy == "remove and add particles") - particle_load_balancing = typename ParticleLoadBalancing::Kind(particle_load_balancing | ParticleLoadBalancing::remove_and_add_particles); - else if (*strategy == "repartition") - particle_load_balancing = typename ParticleLoadBalancing::Kind(particle_load_balancing | ParticleLoadBalancing::repartition); - else if (*strategy == "none") - { - particle_load_balancing = ParticleLoadBalancing::no_balancing; - AssertThrow(strategies.size() == 1, - ExcMessage("The particle load balancing strategy `none' is not compatible " - "with any other strategy, yet it seems another is selected as well. " - "Please check the parameter file.")); - } - else - AssertThrow(false, - ExcMessage("The 'Load balancing strategy' parameter contains an unknown value: <" + *strategy - + ">. This value does not correspond to any known load balancing strategy. Possible values " - "are listed in the corresponding manual subsection.")); - } - - - TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Initialization"); - - // Create a generator object depending on what the parameters specify - generator = Generator::create_particle_generator (prm); - if (SimulatorAccess *sim = dynamic_cast*>(generator.get())) - sim->initialize_simulator (this->get_simulator()); - generator->set_particle_world_index(world_index); - generator->parse_parameters(prm); - generator->initialize(); - - // Create a property_manager object and initialize its properties - property_manager = std::make_unique> (); - SimulatorAccess *sim = dynamic_cast*>(property_manager.get()); - sim->initialize_simulator (this->get_simulator()); - property_manager->set_particle_world_index(world_index); - property_manager->parse_parameters(prm); - property_manager->initialize(); - - // Create an integrator object depending on the specified parameter - integrator = Integrator::create_particle_integrator (prm); - if (SimulatorAccess *sim = dynamic_cast*>(integrator.get())) - sim->initialize_simulator (this->get_simulator()); - integrator->set_particle_world_index(world_index); - integrator->parse_parameters(prm); - integrator->initialize(); - - // Create an interpolator object depending on the specified parameter - interpolator = Interpolator::create_particle_interpolator (prm); - if (SimulatorAccess *sim = dynamic_cast*>(interpolator.get())) - sim->initialize_simulator (this->get_simulator()); - interpolator->set_particle_world_index(world_index); - interpolator->parse_parameters(prm); - interpolator->initialize(); - - } - prm.leave_subsection (); - } - } -} - - -// explicit instantiation of the functions we implement in this file -namespace aspect -{ - namespace Particle - { -#define INSTANTIATE(dim) \ - template class World; - - ASPECT_INSTANTIATE(INSTANTIATE) - -#undef INSTANTIATE - } -} diff --git a/source/plugins.cc.bak b/source/plugins.cc.bak deleted file mode 100644 index 2964077a074..00000000000 --- a/source/plugins.cc.bak +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright (C) 2024 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file doc/COPYING. If not see - . -*/ - -#include - -namespace aspect -{ - namespace Plugins - { - void - InterfaceBase::initialize () - {} - - - - void - InterfaceBase::update () - {} - - - - void - InterfaceBase:: - declare_parameters (dealii::ParameterHandler &) - {} - - - - void - InterfaceBase::parse_parameters (dealii::ParameterHandler &) - {} - } -} diff --git a/source/postprocess/ODE_statistics.cc.bak b/source/postprocess/ODE_statistics.cc.bak deleted file mode 100644 index 263bf22f7ba..00000000000 --- a/source/postprocess/ODE_statistics.cc.bak +++ /dev/null @@ -1,108 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include -#include -#include - - - -namespace aspect -{ - namespace Postprocess - { - template - void - ODEStatistics::initialize() - { - this->get_signals().post_ARKode_solve.connect( - [&](const SimulatorAccess &/*simulator_access*/, - const unsigned int iteration_count) - { - this->store_ODE_solver_history(iteration_count); - }); - - this->clear_data(); - } - - - - template - void - ODEStatistics::clear_data() - { - total_iteration_count = 0; - number_of_solves = 0; - } - - - - template - void - ODEStatistics::store_ODE_solver_history(const unsigned int iteration_count) - { - total_iteration_count += iteration_count; - number_of_solves += 1; - } - - - - template - std::pair - ODEStatistics::execute (TableHandler &statistics) - { -#if DEAL_II_VERSION_GTE(9,6,0) - const double average_iteration_count = number_of_solves > 0 - ? - total_iteration_count / number_of_solves - : - total_iteration_count; -#else - // The computation is not correct for dealii versions older than - // June 2024. - const double average_iteration_count = std::numeric_limits::quiet_NaN(); -#endif - statistics.add_value("Average iterations for ODE solver", - average_iteration_count); - - clear_data(); - - return std::make_pair (std::string(),std::string()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(ODEStatistics, - "ODE statistics", - "A postprocessor that computes some statistics about " - "ODEs solved during the model evolution, specifically, " - "how many iterations are needed to solve these ODEs " - "on average. ") - } -} diff --git a/source/postprocess/basic_statistics.cc.bak b/source/postprocess/basic_statistics.cc.bak deleted file mode 100644 index ae0cea991ba..00000000000 --- a/source/postprocess/basic_statistics.cc.bak +++ /dev/null @@ -1,165 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include -#include -#include -#include -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - BasicStatistics::execute (TableHandler &) - { - if (!Plugins::plugin_type_matches>(this->get_material_model())) - return std::make_pair (std::string(),std::string()); - - if ((this->get_timestep_number() == 0) && - (this->get_pre_refinement_step() == std::numeric_limits::max())) - { - // Define the representative point (in this case a point with depth 0 -> at the surface) - const double reference_depth = 0.0; - const Point representative_point = this->get_geometry_model().representative_point(reference_depth); - const double gravity = this->get_gravity_model().gravity_vector(representative_point).norm(); - const double model_depth = this->get_geometry_model().maximal_depth(); - - // temperature contrast is only meaningful if boundary temperatures are prescribed, otherwise it is 0 - const double temperature_contrast = (this->has_boundary_temperature() - ? - this->get_boundary_temperature_manager().maximal_temperature(this->get_fixed_temperature_boundary_indicators()) - - this->get_boundary_temperature_manager().minimal_temperature(this->get_fixed_temperature_boundary_indicators()) - : - 0); - - // Compute material properties at the reference point using the adiabatic - // profile as reference temperature and pressure - const double temperature = this->get_adiabatic_conditions().temperature(representative_point); - const double pressure = this->get_adiabatic_conditions().pressure(representative_point); - - MaterialModel::MaterialModelInputs in (1, this->n_compositional_fields()); - MaterialModel::MaterialModelOutputs out (1, this->n_compositional_fields()); - in.requested_properties = MaterialModel::MaterialProperties::thermal_conductivity | - MaterialModel::MaterialProperties::equation_of_state_properties | - MaterialModel::MaterialProperties::viscosity; - - in.position[0] = representative_point; - in.temperature[0] = temperature; - in.pressure[0] = pressure; - for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) - in.composition[0][c] = 0.0; - - this->get_material_model().evaluate(in, out); - - const double thermal_diffusivity = ( (this->get_parameters().formulation_temperature_equation == - Parameters::Formulation::TemperatureEquation::reference_density_profile) - ? - out.thermal_conductivities[0] / - (this->get_adiabatic_conditions().density(in.position[0]) * out.specific_heat[0]) - : - out.thermal_conductivities[0] / (out.densities[0] * out.specific_heat[0]) - ); - - // check whether diffusivity is set to 0 (in case of backward advection) - const double Ra = (thermal_diffusivity != 0) ? - out.densities[0] * - gravity * - out.thermal_expansion_coefficients[0] * - temperature_contrast * std::pow(model_depth,3)/ - (thermal_diffusivity * out.viscosities[0]) - : - std::numeric_limits::infinity(); - - this->get_pcout() << std::endl; - this->get_pcout() << " Model domain depth (m): " - << model_depth - << std::endl; - this->get_pcout() << " Temperature contrast across model domain (K): " - << temperature_contrast - << std::endl; - this->get_pcout() << " Reference depth (m): " - << reference_depth - << std::endl; - this->get_pcout() << " Reference temperature (K): " - << temperature - << std::endl; - this->get_pcout() << " Reference pressure (Pa): " - << pressure - << std::endl; - this->get_pcout() << " Reference gravity (m/s^2): " - << gravity - << std::endl; - this->get_pcout() << " Reference density (kg/m^3): " - << out.densities[0] - << std::endl; - this->get_pcout() << " Reference thermal expansion coefficient (1/K): " - << out.thermal_expansion_coefficients[0] - << std::endl; - this->get_pcout() << " Reference specific heat capacity (J/(K*kg)): " - << out.specific_heat[0] - << std::endl; - this->get_pcout() << " Reference thermal conductivity (W/(m*K)): " - << out.thermal_conductivities[0] - << std::endl; - this->get_pcout() << " Reference viscosity (Pa*s): " - << out.viscosities[0] - << std::endl; - this->get_pcout() << " Reference thermal diffusivity (m^2/s): " - << thermal_diffusivity - << std::endl; - this->get_pcout() << " Rayleigh number: " - << Ra - << std::endl; - - this->get_pcout() << std::endl; - } - return std::make_pair (std::string(),std::string()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(BasicStatistics, - "basic statistics", - "A postprocessor that outputs some simplified statistics " - "like the Rayleigh number and other quantities that only " - "make sense in certain model setups. The output is written " - "after completing initial adaptive refinement steps. " - "The postprocessor assumes a point at the surface at the adiabatic " - "surface temperature and pressure is a reasonable reference condition " - "for computing these properties. Furthermore, the Rayleigh " - "number is computed using the model depth (i.e. not the " - "radius of the Earth), as we need a definition that is geometry " - "independent. Take care when comparing these values to published " - "studies and make sure they use the same definitions.") - } -} diff --git a/source/postprocess/boundary_densities.cc.bak b/source/postprocess/boundary_densities.cc.bak deleted file mode 100644 index ce4d9b71df1..00000000000 --- a/source/postprocess/boundary_densities.cc.bak +++ /dev/null @@ -1,177 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include -#include - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - BoundaryDensities::execute (TableHandler &statistics) - { - const Quadrature &quadrature_formula = this->introspection().face_quadratures.temperature; - - FEFaceValues fe_face_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_gradients | - update_quadrature_points | - update_JxW_values); - - double local_top_density = 0.; - double local_bottom_density = 0.; - double local_top_area = 0.; - double local_bottom_area = 0.; - - typename MaterialModel::Interface::MaterialModelInputs in(fe_face_values.n_quadrature_points, this->n_compositional_fields()); - typename MaterialModel::Interface::MaterialModelOutputs out(fe_face_values.n_quadrature_points, this->n_compositional_fields()); - in.requested_properties = MaterialModel::MaterialProperties::density; - std::vector> composition_values(this->n_compositional_fields(), std::vector(fe_face_values.n_quadrature_points)); - - const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); - const types::boundary_id bottom_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); - - // loop over all of the surface cells and if one less than h/3 away from - // the top or bottom surface, evaluate the density on that face - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned() && cell->at_boundary()) - for (const unsigned int f : cell->face_indices()) - { - bool cell_at_top = false; - bool cell_at_bottom = false; - - // Test for top or bottom surface cell faces - if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) - cell_at_top = true; - if (cell->at_boundary(f) && cell->face(f)->boundary_id() == bottom_boundary_id) - cell_at_bottom = true; - - if (cell_at_top || cell_at_bottom) - { - // handle surface cells - fe_face_values.reinit (cell, f); - fe_face_values[this->introspection().extractors.temperature] - .get_function_values (this->get_solution(), in.temperature); - fe_face_values[this->introspection().extractors.pressure] - .get_function_values (this->get_solution(), in.pressure); - fe_face_values[this->introspection().extractors.velocities] - .get_function_symmetric_gradients (this->get_solution(), in.strain_rate); - - in.position = fe_face_values.get_quadrature_points(); - - for (unsigned int c=0; cn_compositional_fields(); ++c) - fe_face_values[this->introspection().extractors.compositional_fields[c]] - .get_function_values(this->get_solution(), - composition_values[c]); - for (unsigned int i=0; in_compositional_fields(); ++c) - in.composition[i][c] = composition_values[c][i]; - } - - this->get_material_model().evaluate(in, out); - - // calculate the top/bottom properties - if (cell_at_top) - for ( unsigned int q = 0; q < fe_face_values.n_quadrature_points; ++q) - { - local_top_density += out.densities[q] * fe_face_values.JxW(q); - local_top_area += fe_face_values.JxW(q); - } - if (cell_at_bottom) - for ( unsigned int q = 0; q < fe_face_values.n_quadrature_points; ++q) - { - local_bottom_density += out.densities[q] * fe_face_values.JxW(q); - local_bottom_area += fe_face_values.JxW(q); - } - } - } - - // vector for packing local values before MPI summing them - double values[4] = {local_bottom_area, local_top_area, local_bottom_density, local_top_density}; - - Utilities::MPI::sum( values, this->get_mpi_communicator(), values ); - - top_density = values[3] / values[1]; // density over area - bottom_density = values[2] / values[0]; // density over area - - statistics.add_value ("Density at top (kg/m^3)", - top_density); - statistics.add_value ("Density at bottom (kg/m^3)", - bottom_density); - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - { - const char *columns[] = { "Density at top (kg/m^3)", - "Density at bottom (kg/m^3)" - }; - for (auto &column : columns) - { - statistics.set_precision (column, 8); - statistics.set_scientific (column, true); - } - } - - std::ostringstream output; - output.precision(4); - output << top_density << " kg/m^3, " - << bottom_density << " kg/m^3"; - - return std::pair ("Density at top/bottom of domain:", - output.str()); - } - - template - double - BoundaryDensities::density_at_top() const - { - return top_density; - } - - template - double - BoundaryDensities::density_at_bottom() const - { - return bottom_density; - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(BoundaryDensities, - "boundary densities", - "A postprocessor that computes the laterally averaged " - "density at the top and bottom of the domain.") - } -} diff --git a/source/postprocess/boundary_pressures.cc.bak b/source/postprocess/boundary_pressures.cc.bak deleted file mode 100644 index 4e52f793394..00000000000 --- a/source/postprocess/boundary_pressures.cc.bak +++ /dev/null @@ -1,156 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include -#include - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - BoundaryPressures::execute (TableHandler &statistics) - { - const Quadrature &quadrature_formula = this->introspection().face_quadratures.pressure; - - FEFaceValues fe_face_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_gradients | - update_quadrature_points | - update_JxW_values); - - double local_top_pressure = 0.; - double local_bottom_pressure = 0.; - double local_top_area = 0.; - double local_bottom_area = 0.; - - std::vector pressure_vals (fe_face_values.n_quadrature_points); - - const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); - const types::boundary_id bottom_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); - - // loop over all of the surface cells and if one less than h/3 away from - // the top or bottom surface, evaluate the pressure on that face - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned() && cell->at_boundary()) - for (const unsigned int f : cell->face_indices()) - { - bool cell_at_top = false; - bool cell_at_bottom = false; - - // Test for top or bottom surface cell faces - if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) - cell_at_top = true; - if (cell->at_boundary(f) && cell->face(f)->boundary_id() == bottom_boundary_id) - cell_at_bottom = true; - - - if (cell_at_top || cell_at_bottom) - { - // evaluate the pressure on the face - fe_face_values.reinit (cell, f); - fe_face_values[this->introspection().extractors.pressure].get_function_values (this->get_solution(), pressure_vals); - - // calculate the top properties - if (cell_at_top) - for ( unsigned int q = 0; q < fe_face_values.n_quadrature_points; ++q) - { - local_top_pressure += pressure_vals[q] * fe_face_values.JxW(q); - local_top_area += fe_face_values.JxW(q); - } - if (cell_at_bottom) - for ( unsigned int q = 0; q < fe_face_values.n_quadrature_points; ++q) - { - local_bottom_pressure += pressure_vals[q] * fe_face_values.JxW(q); - local_bottom_area += fe_face_values.JxW(q); - } - } - } - - // vector for packing local values before MPI summing them - double values[4] = {local_bottom_area, local_top_area, local_bottom_pressure, local_top_pressure}; - - Utilities::MPI::sum( values, this->get_mpi_communicator(), values ); - - top_pressure = values[3] / values[1]; // density over area - bottom_pressure = values[2] / values[0]; // density over area - - statistics.add_value ("Pressure at top (Pa)", - top_pressure); - statistics.add_value ("Pressure at bottom (Pa)", - bottom_pressure); - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - { - const char *columns[] = { "Pressure at top (Pa)", - "Pressure at bottom (Pa)" - }; - for (auto &column : columns) - { - statistics.set_precision (column, 8); - statistics.set_scientific (column, true); - } - } - - std::ostringstream output; - output.precision(4); - output << top_pressure << " Pa, " - << bottom_pressure << " Pa"; - - return std::pair ("Pressure at top/bottom of domain:", - output.str()); - } - - template - double - BoundaryPressures::pressure_at_top() const - { - return top_pressure; - } - - template - double - BoundaryPressures::pressure_at_bottom() const - { - return bottom_pressure; - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(BoundaryPressures, - "boundary pressures", - "A postprocessor that computes the laterally averaged " - "pressure at the top and bottom of the domain.") - } -} diff --git a/source/postprocess/boundary_strain_rate_residual_statistics.cc.bak b/source/postprocess/boundary_strain_rate_residual_statistics.cc.bak deleted file mode 100644 index 251880b9451..00000000000 --- a/source/postprocess/boundary_strain_rate_residual_statistics.cc.bak +++ /dev/null @@ -1,332 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - - -#include -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - void - BoundaryStrainRateResidualStatistics::initialize () - { - strain_rate_data_lookup = std::make_unique>(1, scale_factor); - strain_rate_data_lookup->load_file(data_directory + data_file_name, this->get_mpi_communicator()); - } - - - - template - double - BoundaryStrainRateResidualStatistics::get_data_surface_strain_rate (const Point &p) const - { - Point internal_position = p; - - if (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical) - { - const std::array spherical_position = this->get_geometry_model(). - cartesian_to_natural_coordinates(p); - - for (unsigned int d = 0; d < dim; ++d) - internal_position[d] = spherical_position[d]; - } - - const double data_surface_strain_rate = strain_rate_data_lookup->get_data(internal_position, 0); - - return data_surface_strain_rate; - } - - - - template - std::pair - BoundaryStrainRateResidualStatistics::execute (TableHandler &statistics) - { - // create a quadrature formula for the velocity. - const Quadrature &quadrature_formula = this->introspection().face_quadratures.velocities; - - FEFaceValues fe_face_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_gradients | - update_JxW_values | - update_quadrature_points); - - // This variable stores the strain rates computed at the quadrature points. - std::vector> strain_rate (fe_face_values.n_quadrature_points); - - std::map local_max_eii; - std::map local_min_eii; - std::map local_eii_square_integral; - std::map local_boundary_area; - - std::set boundary_indicators; - boundary_indicators.insert(this->get_geometry_model().translate_symbolic_boundary_name_to_id("top")); - - AssertThrow (boundary_indicators.size() == 1, - ExcMessage("The plugin is only tested " - "to work correctly for a single boundary indicator, " - "but more than one was specified.")); - - for (const auto boundary_id : boundary_indicators) - { - local_max_eii[boundary_id] = std::numeric_limits::lowest(); - local_min_eii[boundary_id] = std::numeric_limits::max(); - } - - // for every face that is part of the selected geometry boundary - // and that is owned by this processor, - // compute the maximum, minimum, and squared*area strain rate invariant residual - // magnitude, and the face area. - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - for (const unsigned int f : cell->face_indices()) - for (const auto current_boundary_id : boundary_indicators) - if (cell->face(f)->at_boundary() && cell->face(f)->boundary_id() == current_boundary_id) - { - fe_face_values.reinit (cell, f); - - fe_face_values[this->introspection().extractors.velocities].get_function_symmetric_gradients - (this->get_solution(), strain_rate); - - // determine the max, min, and area integral of squared strain rate residual on the face - // also determine the face area - double local_max = std::numeric_limits::lowest(); - double local_min = std::numeric_limits::max(); - double local_square_strain_rate = 0.0; - double local_fe_face_area = 0.0; - for (unsigned int q=0; q point_at_surface = fe_face_values.quadrature_point(q); - - // Extract the strain rate invariant output here. - const double e_ii = std::sqrt(std::fabs(second_invariant(deviator(strain_rate[q])))); - - // Extract data strain rate invartiant. - double e_ii_data = get_data_surface_strain_rate(point_at_surface); - - if (this->convert_output_to_years() == true) - e_ii_data = e_ii_data/year_in_seconds; - - // The strain rate invariant residual is calculated here. Ignore the computation if we - // encounter nan or 1e300 in the input data. - double strain_invariant_residual = 0; - if (e_ii_data < 1e300 || !std::isnan(e_ii_data)) - strain_invariant_residual = std::abs(e_ii_data - e_ii); - else - continue; - - local_max = std::max(strain_invariant_residual, - local_max); - local_min = std::min(strain_invariant_residual, - local_min); - local_square_strain_rate += ((strain_invariant_residual * strain_invariant_residual) * fe_face_values.JxW(q)); - local_fe_face_area += fe_face_values.JxW(q); - } - // then merge them with the min/max/squared strain rates - // and face areas we found for other faces with the same boundary indicator - local_max_eii[current_boundary_id] = std::max(local_max, - local_max_eii[current_boundary_id]); - local_min_eii[current_boundary_id] = std::min(local_min, - local_min_eii[current_boundary_id]); - local_eii_square_integral[current_boundary_id] += local_square_strain_rate; - local_boundary_area[current_boundary_id] += local_fe_face_area; - } - - // now communicate to get the global values - std::map global_max_eii; - std::map global_min_eii; - std::map global_rms_eii; - { - // first collect local values in the same order in which they are listed - // in the set of boundary indicators - std::vector local_max_values; - std::vector local_min_values; - std::vector local_eii_square_integral_values; - std::vector local_boundary_area_values; - - for (const auto p : boundary_indicators) - { - local_max_values.push_back (local_max_eii[p]); - local_min_values.push_back (local_min_eii[p]); - - local_eii_square_integral_values.push_back (local_eii_square_integral[p]); - local_boundary_area_values.push_back (local_boundary_area[p]); - } - - // then collect contributions from all processors - std::vector global_max_values (local_max_values.size()); - Utilities::MPI::max (local_max_values, this->get_mpi_communicator(), global_max_values); - std::vector global_min_values (local_min_values.size()); - Utilities::MPI::min (local_min_values, this->get_mpi_communicator(), global_min_values); - - std::vector global_eii_square_integral_values (local_eii_square_integral_values.size()); - Utilities::MPI::sum(local_eii_square_integral_values,this->get_mpi_communicator(),global_eii_square_integral_values); - std::vector global_boundary_area_values (local_boundary_area_values.size()); - Utilities::MPI::sum(local_boundary_area_values,this->get_mpi_communicator(),global_boundary_area_values); - - // and now take them apart into the global map again - // At the same time, calculate the rms strain rate invariant for each boundary - unsigned int index = 0; - for (const auto boundary_id: boundary_indicators) - { - global_max_eii[boundary_id] = global_max_values[index]; - global_min_eii[boundary_id] = global_min_values[index]; - global_rms_eii[boundary_id] = std::sqrt(global_eii_square_integral_values[index] / global_boundary_area_values[index]); - ++index; - } - } - - // now add the computed max, min, and rms strain rates to the statistics object - // and create a single string that can be output to the screen - const std::string units = (this->convert_output_to_years() == true) ? "1/yr" : "1/s"; - const double unit_scale_factor = (this->convert_output_to_years() == true) ? year_in_seconds : 1.0; - std::ostringstream screen_text; - unsigned int index = 0; - - for (std::map::const_iterator - max_eii = global_max_eii.begin(), min_eii = global_min_eii.begin(), rms = global_rms_eii.begin(); - max_eii != global_max_eii.end() && min_eii != global_min_eii.end() && rms != global_rms_eii.end(); - ++max_eii, ++min_eii, ++rms, ++index) - { - const std::string name_max = "Maximum strain rate invariant residual magnitude on boundary with indicator " - + Utilities::int_to_string(max_eii->first) - + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() - .translate_id_to_symbol_name (max_eii->first)) - + " (" + units + ")"; - statistics.add_value (name_max, max_eii->second*unit_scale_factor); - const std::string name_min = "Minimum strain rate invariant residual magnitude on boundary with indicator " - + Utilities::int_to_string(min_eii->first) - + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() - .translate_id_to_symbol_name (min_eii->first)) - + " (" + units + ")"; - statistics.add_value (name_min, min_eii->second*unit_scale_factor); - const std::string name_rms = "RMS strain rate invariant residual on boundary with indicator " - + Utilities::int_to_string(rms->first) - + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() - .translate_id_to_symbol_name (rms->first)) - + " (" + units + ")"; - statistics.add_value (name_rms, rms->second*unit_scale_factor); - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - statistics.set_precision (name_max, 8); - statistics.set_scientific (name_max, true); - statistics.set_precision (name_min, 8); - statistics.set_scientific (name_min, true); - statistics.set_precision (name_rms, 8); - statistics.set_scientific (name_rms, true); - - screen_text << max_eii->second *unit_scale_factor << " " << units << ", " - << min_eii->second *unit_scale_factor << " " << units << ", " - << rms->second *unit_scale_factor << " " << units - << (index == global_max_eii.size()-1 ? "" : ", "); - - } - - return std::pair ("Max, min, and RMS residual strain rate invariant along boundary parts:", - screen_text.str()); - } - - - - template - void - BoundaryStrainRateResidualStatistics::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Boundary strain rate residual statistics"); - { - prm.declare_entry ("Data directory", - "$ASPECT_SOURCE_DIR/data/postprocess/boundary-strain-rate-residual/", - Patterns::DirectoryName (), - "The name of a directory that contains the ascii data. " - "This path may either be absolute (if starting with a " - "`/') or relative to the current directory. The path may also " - "include the special text `$ASPECT_SOURCE_DIR' which will be " - "interpreted as the path in which the ASPECT source files were " - "located when ASPECT was compiled. This interpretation allows, " - "for example, to reference files located in the `data/' subdirectory " - "of ASPECT."); - prm.declare_entry ("Data file name", "box_3d_boundary_strain_rate.txt", - Patterns::Anything (), - "The file name of the input surface strain rate an ascii data. " - "The file has one column in addition to the coordinate columns " - "corresponding to the second invariant of strain rate. "); - prm.declare_entry ("Scale factor", "1.", - Patterns::Double (), - "Scalar factor, which is applied to the model data. " - "You might want to use this to scale the input to a " - "reference model."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - - template - void - BoundaryStrainRateResidualStatistics::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Boundary strain rate residual statistics"); - { - // Get the path to the data files. If it contains a reference - // to $ASPECT_SOURCE_DIR, replace it by what CMake has given us - // as a #define - data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get ("Data directory")); - data_file_name = prm.get ("Data file name"); - scale_factor = prm.get_double ("Scale factor"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(BoundaryStrainRateResidualStatistics, - "boundary strain rate residual statistics", - "A postprocessor that computes some statistics about " - "the surface strain rate residual along the top boundary. The residual " - "is the difference between the second invariant of the model strain rate and " - "the second strain rate invariant read from the input data file. " - "Currently, the strain residual statistics, i.e., min, max and the rms magnitude, " - "are computed at the top surface.") - } -} diff --git a/source/postprocess/boundary_velocity_residual_statistics.cc.bak b/source/postprocess/boundary_velocity_residual_statistics.cc.bak deleted file mode 100644 index 2390c4e7be6..00000000000 --- a/source/postprocess/boundary_velocity_residual_statistics.cc.bak +++ /dev/null @@ -1,376 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - - -#include -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - void - BoundaryVelocityResidualStatistics::initialize () - { - if (use_ascii_data) - { - // The input ascii table contains dim data columns (velocity components) in addition to the coordinate columns. - data_lookup = std::make_unique>(dim, scale_factor); - data_lookup->load_file(data_directory + data_file_name, this->get_mpi_communicator()); - } - else - { - // The two points are used in GPlates to find the 2d plane in which - // the model lies. These values are not used for 3d geometries and - // are thus set to the default. - Point<2> point_one(numbers::PI/2., 0.); - Point<2> point_two(numbers::PI/2., numbers::PI/2.); - - gplates_lookup = std::make_unique> ( - point_one, point_two); - - gplates_lookup->load_file(data_directory + data_file_name, this->get_mpi_communicator()); - } - } - - - - template - Tensor<1,dim> - BoundaryVelocityResidualStatistics::get_data_velocity (const Point &p) const - { - Tensor<1,dim> data_velocity; - if (use_ascii_data) - { - Point internal_position = p; - - if (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical) - { - const std::array spherical_position = this->get_geometry_model(). - cartesian_to_natural_coordinates(p); - - for (unsigned int d = 0; d < dim; ++d) - internal_position[d] = spherical_position[d]; - } - - for (unsigned int d = 0; d < dim; ++d) - data_velocity[d] = data_lookup->get_data(internal_position, d); - if (use_spherical_unit_vectors == true) - data_velocity = Utilities::Coordinates::spherical_to_cartesian_vector(data_velocity, p); - } - else - { - data_velocity = gplates_lookup->surface_velocity(p); - } - - return data_velocity; - } - - - - template - std::pair - BoundaryVelocityResidualStatistics::execute (TableHandler &statistics) - { - // create a quadrature formula for the velocity. - const Quadrature &quadrature_formula = this->introspection().face_quadratures.velocities; - - FEFaceValues fe_face_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_JxW_values | - update_quadrature_points); - - std::vector> velocities (fe_face_values.n_quadrature_points); - - std::map local_max_vel; - std::map local_min_vel; - std::map local_velocity_square_integral; - std::map local_boundary_area; - - std::set boundary_indicators; - boundary_indicators.insert(this->get_geometry_model().translate_symbolic_boundary_name_to_id("top")); - - AssertThrow (boundary_indicators.size() == 1, - ExcMessage("The plugin is only tested " - "to work correctly for a single boundary indicator, " - "but more than one was specified.")); - - for (const auto p : boundary_indicators) - { - local_max_vel[p] = std::numeric_limits::lowest(); - local_min_vel[p] = std::numeric_limits::max(); - } - - // for every face that is part of the selected geometry boundary - // and that is owned by this processor, - // compute the maximum, minimum, and squared*area velocity residual - // magnitude and the face area. - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - for (const unsigned int f : cell->face_indices()) - for (const auto current_boundary_id : boundary_indicators) - if (cell->face(f)->at_boundary() && cell->face(f)->boundary_id() == current_boundary_id) - { - fe_face_values.reinit (cell, f); - - fe_face_values[this->introspection().extractors.velocities].get_function_values (this->get_solution(), - velocities); - - // determine the max, min, and squared velocity residual on the face - // also determine the face area - double local_max = std::numeric_limits::lowest(); - double local_min = std::numeric_limits::max(); - double local_sqvel = 0.0; - double local_fe_face_area = 0.0; - for (unsigned int q=0; q point_at_surface = fe_face_values.quadrature_point(q); - // Extract data velocity. - Tensor<1,dim> data_velocity = get_data_velocity(point_at_surface); - - if (this->convert_output_to_years() == true) - data_velocity = data_velocity/year_in_seconds; - - // The velocity residual is calculated here. - const double vel_residual_mag = (velocities[q] - data_velocity).norm(); - - local_max = std::max(vel_residual_mag, - local_max); - local_min = std::min(vel_residual_mag, - local_min); - local_sqvel += ((vel_residual_mag * vel_residual_mag) * fe_face_values.JxW(q)); - local_fe_face_area += fe_face_values.JxW(q); - } - - // then merge them with the min/max/squared velocities - // and face areas we found for other faces with the same boundary indicator - local_max_vel[current_boundary_id] = std::max(local_max, - local_max_vel[current_boundary_id]); - local_min_vel[current_boundary_id] = std::min(local_min, - local_min_vel[current_boundary_id]); - local_velocity_square_integral[current_boundary_id] += local_sqvel; - local_boundary_area[current_boundary_id] += local_fe_face_area; - } - - // now communicate to get the global values - std::map global_max_vel; - std::map global_min_vel; - std::map global_rms_vel; - { - // first collect local values in the same order in which they are listed - // in the set of boundary indicators - std::vector local_max_values; - std::vector local_min_values; - std::vector local_velocity_square_integral_values; - std::vector local_boundary_area_values; - - for (const auto p : boundary_indicators) - { - local_max_values.push_back (local_max_vel[p]); - local_min_values.push_back (local_min_vel[p]); - - local_velocity_square_integral_values.push_back (local_velocity_square_integral[p]); - local_boundary_area_values.push_back (local_boundary_area[p]); - } - - // then collect contributions from all processors - std::vector global_max_values (local_max_values.size()); - Utilities::MPI::max (local_max_values, this->get_mpi_communicator(), global_max_values); - std::vector global_min_values (local_min_values.size()); - Utilities::MPI::min (local_min_values, this->get_mpi_communicator(), global_min_values); - - std::vector global_velocity_square_integral_values (local_velocity_square_integral_values.size()); - Utilities::MPI::sum(local_velocity_square_integral_values,this->get_mpi_communicator(),global_velocity_square_integral_values); - std::vector global_boundary_area_values (local_boundary_area_values.size()); - Utilities::MPI::sum(local_boundary_area_values,this->get_mpi_communicator(),global_boundary_area_values); - - // and now take them apart into the global map again - // At the same time, calculate the rms velocity for each boundary - unsigned int index = 0; - for (const auto boundary_id: boundary_indicators) - { - global_max_vel[boundary_id] = global_max_values[index]; - global_min_vel[boundary_id] = global_min_values[index]; - global_rms_vel[boundary_id] = std::sqrt(global_velocity_square_integral_values[index] / global_boundary_area_values[index]); - ++index; - } - } - - // now add the computed max, min, and rms velocities to the statistics object - // and create a single string that can be output to the screen - const std::string units = (this->convert_output_to_years() == true) ? "m/year" : "m/s"; - const double unit_scale_factor = (this->convert_output_to_years() == true) ? year_in_seconds : 1.0; - std::ostringstream screen_text; - unsigned int index = 0; - - for (std::map::const_iterator - max_velocity = global_max_vel.begin(), min_velocity = global_min_vel.begin(), rms = global_rms_vel.begin(); - max_velocity != global_max_vel.end() && min_velocity != global_min_vel.end() && rms != global_rms_vel.end(); - ++max_velocity, ++min_velocity, ++rms, ++index) - { - const std::string name_max = "Maximum velocity residual magnitude on boundary with indicator " - + Utilities::int_to_string(max_velocity->first) - + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() - .translate_id_to_symbol_name (max_velocity->first)) - + " (" + units + ")"; - statistics.add_value (name_max, max_velocity->second*unit_scale_factor); - const std::string name_min = "Minimum velocity residual magnitude on boundary with indicator " - + Utilities::int_to_string(min_velocity->first) - + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() - .translate_id_to_symbol_name (min_velocity->first)) - + " (" + units + ")"; - statistics.add_value (name_min, min_velocity->second*unit_scale_factor); - const std::string name_rms = "RMS velocity residual on boundary with indicator " - + Utilities::int_to_string(rms->first) - + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() - .translate_id_to_symbol_name (rms->first)) - + " (" + units + ")"; - statistics.add_value (name_rms, rms->second*unit_scale_factor); - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - statistics.set_precision (name_max, 8); - statistics.set_scientific (name_max, true); - statistics.set_precision (name_min, 8); - statistics.set_scientific (name_min, true); - statistics.set_precision (name_rms, 8); - statistics.set_scientific (name_rms, true); - - // finally have something for the screen - screen_text.precision(4); - screen_text << max_velocity->second *unit_scale_factor << ' ' << units << ", " - << min_velocity->second *unit_scale_factor << ' ' << units << ", " - << rms->second *unit_scale_factor << ' ' << units - << (index == global_max_vel.size()-1 ? "" : ", "); - } - - return std::pair ("Max, min, and RMS residual velocity along boundary parts:", - screen_text.str()); - } - - - - template - void - BoundaryVelocityResidualStatistics::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Boundary velocity residual statistics"); - { - prm.declare_entry ("Data directory", - "$ASPECT_SOURCE_DIR/data/boundary-velocity/gplates/", - Patterns::DirectoryName (), - "The name of a directory that contains the GPlates model or the " - "ascii data. This path may either be absolute (if starting with a " - "`/') or relative to the current directory. The path may also " - "include the special text `$ASPECT_SOURCE_DIR' which will be " - "interpreted as the path in which the ASPECT source files were " - "located when ASPECT was compiled. This interpretation allows, " - "for example, to reference files located in the `data/' subdirectory " - "of ASPECT."); - prm.declare_entry ("Data file name", "current_day.gpml", - Patterns::Anything (), - "The file name of the input velocity as a GPlates model or an ascii data. " - "For the GPlates model, provide file in the same format as described " - "in the 'gplates' boundary velocity plugin. " - "For the ascii data, provide file in the same format as described in " - " 'ascii data' initial composition plugin." ); - prm.declare_entry ("Scale factor", "1.", - Patterns::Double (), - "Scalar factor, which is applied to the model data. " - "You might want to use this to scale the input to a " - "reference model. Another way to use this factor is to " - "convert units of the input files. For instance, if you " - "provide velocities in cm/year set this factor to 0.01."); - prm.declare_entry ("Use spherical unit vectors", "false", - Patterns::Bool (), - "Specify velocity as r, phi, and theta components " - "instead of x, y, and z. Positive velocities point up, east, " - "and north (in 3d) or out and clockwise (in 2d). " - "This setting only makes sense for spherical geometries." - "GPlates data is always interpreted to be in east and north directions " - "and is not affected by this parameter."); - prm.declare_entry ("Use ascii data", "false", - Patterns::Bool (), - "Use ascii data files (e.g., GPS) for computing residual velocities " - "instead of GPlates data."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - - template - void - BoundaryVelocityResidualStatistics::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Boundary velocity residual statistics"); - { - // Get the path to the data files. If it contains a reference - // to $ASPECT_SOURCE_DIR, replace it by what CMake has given us - // as a #define - data_directory = Utilities::expand_ASPECT_SOURCE_DIR(prm.get ("Data directory")); - data_file_name = prm.get ("Data file name"); - scale_factor = prm.get_double ("Scale factor"); - - use_spherical_unit_vectors = prm.get_bool("Use spherical unit vectors"); - use_ascii_data = prm.get_bool("Use ascii data"); - - if (use_spherical_unit_vectors) - AssertThrow (this->get_geometry_model().natural_coordinate_system() == Utilities::Coordinates::spherical, - ExcMessage ("Spherical unit vectors should not be used " - "when geometry model is not spherical.")); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(BoundaryVelocityResidualStatistics, - "boundary velocity residual statistics", - "A postprocessor that computes some statistics about " - "the velocity residual along the top boundary. The velocity residual " - "is the difference between the model solution velocities and the input " - "velocities (GPlates model or ascii data). Currently, the velocity residual " - "statistics, i.e., min, max and the rms magnitude, is computed at the top " - "surface.") - } -} diff --git a/source/postprocess/command.cc.bak b/source/postprocess/command.cc.bak deleted file mode 100644 index 9160c73fea3..00000000000 --- a/source/postprocess/command.cc.bak +++ /dev/null @@ -1,131 +0,0 @@ -/* - Copyright (C) 2016 - 2018 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - -#include - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - Command::execute (TableHandler &) - { - if (on_all_processes || - (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0)) - { - - // Check if a command-processor is available by calling system() with a - // null pointer. System is guaranteed to return non-zero if it finds - // a terminal and zero if there is none (like on the compute nodes of - // some cluster architectures, e.g. IBM BlueGene/Q) - AssertThrow(system(nullptr) != 0, - ExcMessage("The \"command\" postprocessor required a command-processor, " - "which appears to be unavailable on this system.")); - - const int error = system(command.c_str()); - - if (error != 0) - { - std::string err_str = (error<0 ? "-" : "") + - Utilities::int_to_string(std::abs(error)); - - - if (terminate_on_failure) - { - AssertThrow(false, ExcMessage("Command <" + - command + - "> failed with error code: " + - err_str + - ". Terminating process.")); - } - else - { - std::cerr << "*** WARNING: Command <" << command - << "> failed with error code: " - << err_str - << ". Continuing anyway." - << std::endl; - } - } - } - - return std::make_pair (std::string("Running command:"), - command); - } - - template - void - Command::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Command"); - { - prm.declare_entry ("Terminate on failure", "false", - Patterns::Bool(), - "Select whether \\aspect{} should terminate if the " - "command returns a non-zero exit status."); - - prm.declare_entry ("Run on all processes", "false", - Patterns::Bool(), - "Whether to run command from all processes (true), " - "or only on process 0 (false)."); - - prm.declare_entry ("Command", "", - Patterns::Anything(), - "Command to execute."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - Command::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Command"); - { - terminate_on_failure = prm.get_bool ("Terminate on failure"); - on_all_processes = prm.get_bool ("Run on all processes"); - command = prm.get ("Command"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(Command, - "command", - "A postprocessor that executes a command line " - "process.") - } -} diff --git a/source/postprocess/composition_statistics.cc.bak b/source/postprocess/composition_statistics.cc.bak deleted file mode 100644 index d0073fcf11c..00000000000 --- a/source/postprocess/composition_statistics.cc.bak +++ /dev/null @@ -1,168 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - CompositionStatistics::execute (TableHandler &statistics) - { - if (this->n_compositional_fields() == 0) - return {"", ""}; - - // create a quadrature formula based on the compositional element alone. - const Quadrature &quadrature_formula = this->introspection().quadratures.compositional_fields; - const unsigned int n_q_points = quadrature_formula.size(); - - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_quadrature_points | - update_JxW_values); - - std::vector compositional_values(n_q_points); - - std::vector local_compositional_integrals (this->n_compositional_fields()); - - // compute the integral quantities by quadrature - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit (cell); - - for (unsigned int c=0; cn_compositional_fields(); ++c) - { - fe_values[this->introspection().extractors.compositional_fields[c]].get_function_values (this->get_solution(), - compositional_values); - for (unsigned int q=0; q global_compositional_integrals (local_compositional_integrals.size()); - Utilities::MPI::sum (local_compositional_integrals, - this->get_mpi_communicator(), - global_compositional_integrals); - - // compute min/max by simply - // looping over the elements of the - // solution vector. - std::vector local_min_compositions (this->n_compositional_fields(), - std::numeric_limits::max()); - std::vector local_max_compositions (this->n_compositional_fields(), - std::numeric_limits::lowest()); - - for (unsigned int c=0; cn_compositional_fields(); ++c) - { - IndexSet range = this->get_solution().block(this->introspection().block_indices.compositional_fields[c]).locally_owned_elements(); - for (unsigned int i=0; iget_solution().block(this->introspection().block_indices.compositional_fields[c])(idx); - - local_min_compositions[c] = std::min (local_min_compositions[c], val); - local_max_compositions[c] = std::max (local_max_compositions[c], val); - } - - } - - // now do the reductions over all processors - std::vector global_min_compositions (this->n_compositional_fields(), - std::numeric_limits::max()); - std::vector global_max_compositions (this->n_compositional_fields(), - std::numeric_limits::lowest()); - { - Utilities::MPI::min (local_min_compositions, - this->get_mpi_communicator(), - global_min_compositions); - Utilities::MPI::max (local_max_compositions, - this->get_mpi_communicator(), - global_max_compositions); - } - - // finally produce something for the statistics file - for (unsigned int c=0; cn_compositional_fields(); ++c) - { - statistics.add_value ("Minimal value for composition " + this->introspection().name_for_compositional_index(c), - global_min_compositions[c]); - statistics.add_value ("Maximal value for composition " + this->introspection().name_for_compositional_index(c), - global_max_compositions[c]); - statistics.add_value ("Global mass for composition " + this->introspection().name_for_compositional_index(c), - global_compositional_integrals[c]); - } - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - for (unsigned int c=0; cn_compositional_fields(); ++c) - { - const std::string columns[] = { "Minimal value for composition " + this->introspection().name_for_compositional_index(c), - "Maximal value for composition " + this->introspection().name_for_compositional_index(c), - "Global mass for composition " + this->introspection().name_for_compositional_index(c) - }; - for (const auto &col : columns) - { - statistics.set_precision (col, 8); - statistics.set_scientific (col, true); - } - } - - std::ostringstream output; - output.precision(4); - for (unsigned int c=0; cn_compositional_fields(); ++c) - { - output << global_min_compositions[c] << '/' - << global_max_compositions[c] << '/' - << global_compositional_integrals[c]; - if (c+1 != this->n_compositional_fields()) - output << " // "; - } - - return std::pair ("Compositions min/max/mass:", - output.str()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(CompositionStatistics, - "composition statistics", - "A postprocessor that computes some statistics about " - "the compositional fields, if present in this simulation. " - "In particular, it computes maximal and minimal values of " - "each field, as well as the total mass contained in this " - "field as defined by the integral " - "$m_i(t) = \\int_\\Omega c_i(\\mathbf x,t) \\; \\text{d}x$.") - } -} diff --git a/source/postprocess/composition_velocity_statistics.cc.bak b/source/postprocess/composition_velocity_statistics.cc.bak deleted file mode 100644 index ce2244a748c..00000000000 --- a/source/postprocess/composition_velocity_statistics.cc.bak +++ /dev/null @@ -1,205 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - CompositionVelocityStatistics::execute (TableHandler &statistics) - { - const QGauss quadrature_formula (this->get_fe() - .base_element(this->introspection().base_elements.velocities).degree+1); - const unsigned int n_q_points = quadrature_formula.size(); - - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_quadrature_points | - update_JxW_values); - - std::vector> velocity_values(n_q_points); - std::vector compositional_values(n_q_points); - - std::vector local_velocity_square_integral(this->n_compositional_fields()); - std::vector local_area_integral(this->n_compositional_fields()); - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit (cell); - fe_values[this->introspection().extractors.velocities].get_function_values (this->get_solution(), - velocity_values); - - for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) - { - fe_values[this->introspection().extractors.compositional_fields[c]].get_function_values(this->get_solution(), - compositional_values); - - for (unsigned int q = 0; q < n_q_points; ++q) - { - if (compositional_values[q] >= 0.5) - { - local_velocity_square_integral[c] += ((velocity_values[q] * velocity_values[q]) * - fe_values.JxW(q)); - local_area_integral[c] += fe_values.JxW(q); - } - } - } - } - - std::vector global_velocity_square_integral(local_velocity_square_integral.size()); - Utilities::MPI::sum(local_velocity_square_integral, this->get_mpi_communicator(), global_velocity_square_integral); - std::vector global_area_integral(local_area_integral.size()); - Utilities::MPI::sum(local_area_integral, this->get_mpi_communicator(), global_area_integral); - - // compute the RMS velocity for each compositional field and for the selected compositonal fields combined - std::vector vrms_per_composition(local_area_integral.size()); - double velocity_square_integral_selected_fields = 0., area_integral_selected_fields = 0.; - for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) - { - vrms_per_composition[c] = std::sqrt(global_velocity_square_integral[c]) / - std::sqrt(global_area_integral[c]); - - const std::vector::iterator selected_field_it = std::find(selected_fields.begin(), selected_fields.end(), this->introspection().name_for_compositional_index(c)); - if (selected_field_it != selected_fields.end()) - { - velocity_square_integral_selected_fields += global_velocity_square_integral[c]; - area_integral_selected_fields += global_area_integral[c]; - } - } - - const double vrms_selected_fields = std::sqrt(velocity_square_integral_selected_fields) / std::sqrt(area_integral_selected_fields); - - const std::string unit = (this->convert_output_to_years()) ? "m/year" : "m/s"; - const double time_scaling = (this->convert_output_to_years()) ? year_in_seconds : 1.0; - - // finally produce something for the statistics file - for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) - { - statistics.add_value("RMS velocity (" + unit + ") for composition " + this->introspection().name_for_compositional_index(c), - time_scaling * vrms_per_composition[c]); - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - const std::string columns[] = {"RMS velocity (" + unit + ") for composition " + - this->introspection().name_for_compositional_index(c) - }; - - for (const auto &column : columns) - { - statistics.set_precision(column, 8); - statistics.set_scientific(column, true); - } - } - - // Also output the selected fields vrms - statistics.add_value("RMS velocity (" + unit + ") for the selected field ", - time_scaling * vrms_selected_fields); - - const std::string column = {"RMS velocity (" + unit + ") for the selected field "}; - - statistics.set_precision(column, 8); - statistics.set_scientific(column, true); - - std::ostringstream output; - output.precision(4); - - for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) - { - output << time_scaling *vrms_per_composition[c] - << " " << unit; - output << " // "; - } - output << time_scaling *vrms_selected_fields; - - return std::pair("RMS velocity for compositions and combined selected fields:", - output.str()); - } - - - - template - void - CompositionVelocityStatistics::declare_parameters(ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Composition velocity statistics"); - { - prm.declare_entry("Names of selected compositional fields", "", - Patterns::List(Patterns::Anything()), - "A list of names for each of the compositional fields that " - "you want to compute the combined RMS velocity for."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - - template - void - CompositionVelocityStatistics::parse_parameters(ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Composition velocity statistics"); - { - selected_fields = Utilities::split_string_list(prm.get("Names of selected compositional fields")); - - AssertThrow((selected_fields.size() > 0) && - (selected_fields.size() <= this->n_compositional_fields()), - ExcMessage("The length of the list of names for the compositional " - "fields for which the RMS velocity is to be summed must be larger than zero " - "and smaller or equal to the number of compositional fields.")); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(CompositionVelocityStatistics, - "composition velocity statistics", - "A postprocessor that computes the root mean square velocity " - "over the area spanned by each compositional field (i.e. where " - "the field values are larger or equal to 0.5.") - } -} diff --git a/source/postprocess/core_statistics.cc.bak b/source/postprocess/core_statistics.cc.bak deleted file mode 100644 index 1179c83a4ff..00000000000 --- a/source/postprocess/core_statistics.cc.bak +++ /dev/null @@ -1,236 +0,0 @@ -/* - Copyright (C) 2011 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file doc/COPYING. If not see - . -*/ - - -#include -#include -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - CoreStatistics::CoreStatistics() - { - core_data.is_initialized = false; - } - - template - std::pair - CoreStatistics::execute (TableHandler &statistics) - { - // now add all of the computed heat fluxes to the statistics object - // and create a single string that can be output to the screen - std::ostringstream screen_text; - - const BoundaryTemperature::DynamicCore &dynamic_core = - this->get_boundary_temperature_manager().template get_matching_boundary_temperature_model>(); - - core_data = dynamic_core.get_core_data(); - - // now add core mantle boundary heat flux to the statistics object - // and create a single string that can be output to the screen - const std::string name = "CMB heat flux out of the core (TW)"; - statistics.add_value (name, -core_data.Q/1e12); - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - statistics.set_precision (name, 3); - statistics.set_scientific (name, true); - - // finally have something for the screen - screen_text.precision(3); - screen_text << -core_data.Q/1e12 << " TW,"; - - - const std::string name1 = "CMB Temperature (K)"; - statistics.add_value (name1, core_data.Ti); - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - statistics.set_precision (name1, 2); - statistics.set_scientific (name1, false); - - const std::string name2 = "Inner core radius (km)"; - statistics.add_value (name2, core_data.Ri*1e-3); - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - statistics.set_precision (name2, 2); - statistics.set_scientific (name2, false); - - const std::string name3 = "Light element concentration (%)"; - statistics.add_value (name3, core_data.Xi*100); - statistics.set_precision (name3, 4); - statistics.set_scientific (name3, false); - - if (excess_entropy_only) - { - const std::string name4 = "Excess entropy (W/K)"; - const double delta_E = core_data.Es*core_data.dT_dt - + core_data.Er - + core_data.Eh*core_data.dR_dt - + core_data.El*core_data.dR_dt - + core_data.Eg*core_data.dR_dt - - core_data.Ek; - statistics.add_value (name4, delta_E); - statistics.set_precision (name4, 3); - statistics.set_scientific (name4, true); - } - else - { - const std::string name5 = "Es (W/K)"; - statistics.add_value (name5, core_data.Es*core_data.dT_dt); - statistics.set_precision (name5, 3); - statistics.set_scientific (name5, true); - - const std::string name6 = "Er (W/K)"; - statistics.add_value (name6, core_data.Er); - statistics.set_precision (name6, 3); - statistics.set_scientific (name6, true); - - const std::string name7 = "Eh (W/K)"; - statistics.add_value (name7, core_data.Eh*core_data.dR_dt); - statistics.set_precision (name7, 3); - statistics.set_scientific (name7, true); - - const std::string name8 = "El (W/K)"; - statistics.add_value (name8, core_data.El*core_data.dR_dt); - statistics.set_precision (name8, 3); - statistics.set_scientific (name8, true); - - const std::string name9 = "Eg (W/K)"; - statistics.add_value (name9, core_data.Eg*core_data.dR_dt); - statistics.set_precision (name9, 3); - statistics.set_scientific (name9, true); - - const std::string name10 = "Ek (W/K)"; - statistics.add_value (name10, core_data.Ek); - statistics.set_precision (name10, 3); - statistics.set_scientific (name10, true); - } - - if (dynamic_core.is_OES_used()) - { - const std::string name11 = "Other energy source (W)"; - statistics.add_value (name11, core_data.Q_OES); - statistics.set_precision (name11, 3); - statistics.set_scientific (name11, true); - } - - return std::pair ("CMB heat flux out of the core", - screen_text.str()); - } - - template - void - CoreStatistics::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Dynamic core statistics"); - { - prm.declare_entry("Excess entropy only","false", - Patterns::Bool(), - "Output the excess entropy only instead the each entropy terms."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - void - CoreStatistics::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Dynamic core statistics"); - { - excess_entropy_only = prm.get_bool("Excess entropy only"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - template - const BoundaryTemperature::internal::CoreData & - CoreStatistics::get_core_data() const - { - return core_data; - } - - template - template - void CoreStatistics::serialize (Archive &ar, const unsigned int) - { - ar &(core_data.Ti); - ar &(core_data.Ri); - ar &(core_data.Xi); - ar &(core_data.Q); - ar &(core_data.dR_dt); - ar &(core_data.dT_dt); - ar &(core_data.dX_dt); - ar &(core_data.is_initialized); - } - - template - void CoreStatistics::save (std::map &status_strings) const - { - std::ostringstream os; - aspect::oarchive oa (os); - oa << (*this); - - status_strings["CoreStatistics"] = os.str(); - } - - template - void CoreStatistics::load (const std::map &status_strings) - { - // see if something was saved - if (status_strings.find("CoreStatistics") != status_strings.end()) - { - std::istringstream is (status_strings.find("CoreStatistics")->second); - aspect::iarchive ia (is); - ia >> (*this); - } - } - - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(CoreStatistics, - "core statistics", - "A postprocessor that computes some statistics about " - "the core evolution. (Working only with dynamic core boundary temperature plugin)") - } -} diff --git a/source/postprocess/crystal_preferred_orientation.cc.bak b/source/postprocess/crystal_preferred_orientation.cc.bak deleted file mode 100644 index 974ffa07e79..00000000000 --- a/source/postprocess/crystal_preferred_orientation.cc.bak +++ /dev/null @@ -1,870 +0,0 @@ -/* - Copyright (C) 2022 by the authors of the ASPECT code. - This file is part of ASPECT. - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - ASPECT 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 General Public License for more details. - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - -namespace aspect -{ - namespace Postprocess - { - template - CrystalPreferredOrientation::CrystalPreferredOrientation () - : - // the following value is later read from the input file - output_interval (0), - // initialize this to a nonsensical value; set it to the actual time - // the first time around we get to check it - last_output_time (std::numeric_limits::quiet_NaN()), - output_file_number (numbers::invalid_unsigned_int), - group_files(0), - write_in_background_thread(false) - {} - - - - template - CrystalPreferredOrientation::~CrystalPreferredOrientation () - { - // make sure a thread that may still be running in the background, - // writing data, finishes - if (background_thread_main.joinable()) - background_thread_main.join (); - - if (background_thread_content_raw.joinable()) - background_thread_content_raw.join (); - - if (background_thread_content_draw_volume_weighting.joinable()) - background_thread_content_draw_volume_weighting.join (); - } - - - - template - void - CrystalPreferredOrientation::initialize () - { - const unsigned int my_rank = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); - this->random_number_generator.seed(random_number_seed+my_rank); - } - - - - template - std::list - CrystalPreferredOrientation::required_other_postprocessors () const - { - return {"particles"}; - } - - - - template - // We need to pass the arguments by value, as this function can be called on a separate thread: - void CrystalPreferredOrientation::writer (const std::string &filename, - const std::string &temporary_output_location, - const std::string &file_contents, - const bool compress_contents) - { - std::string tmp_filename = filename; - if (temporary_output_location != "") - { - tmp_filename = temporary_output_location + "/aspect.tmp.XXXXXX"; - - // Create the temporary file; get at the actual filename - // by using a C-style string that mkstemp will then overwrite - std::vector tmp_filename_x (tmp_filename.size()+1); - std::strcpy(tmp_filename_x.data(), tmp_filename.c_str()); - const int tmp_file_desc = mkstemp(tmp_filename_x.data()); - tmp_filename = tmp_filename_x.data(); - - // If we failed to create the temp file, just write directly to the target file. - // We also provide a warning about this fact. There are places where - // this fails *on every node*, so we will get a lot of warning messages - // into the output; in these cases, just writing multiple pieces to - // std::cerr will produce an unreadable mass of text; rather, first - // assemble the error message completely, and then output it atomically - if (tmp_file_desc == -1) - { - const std::string x = ("***** WARNING: could not create temporary file <" - + - tmp_filename - + - ">, will output directly to final location. This may negatively " - "affect performance. (On processor " - + Utilities::int_to_string(Utilities::MPI::this_mpi_process (MPI_COMM_WORLD)) - + ".)\n"); - - std::cerr << x << std::flush; - - tmp_filename = filename; - } - else - close(tmp_file_desc); - } - - std::ofstream out(tmp_filename.c_str(), std::ofstream::binary); - - AssertThrow (out, ExcMessage(std::string("Trying to write to file <") + - filename + - ">, but the file can't be opened!")); - - // now write and then move the tmp file to its final destination - // if necessary - if (compress_contents) - { - namespace bio = boost::iostreams; - - std::stringstream origin(file_contents); - - bio::filtering_streambuf compress_out; - compress_out.push(bio::zlib_compressor()); - compress_out.push(origin); - bio::copy(compress_out, out); - } - else - { - out << file_contents; - } - - out.close (); - - if (tmp_filename != filename) - { - std::string command = std::string("mv ") + tmp_filename + " " + filename; - int error = system(command.c_str()); - - AssertThrow(error == 0, - ExcMessage("Could not move " + tmp_filename + " to " - + filename + ". On processor " - + Utilities::int_to_string(Utilities::MPI::this_mpi_process (MPI_COMM_WORLD)) + ".")); - } - } - - - - template - std::pair - CrystalPreferredOrientation::execute (TableHandler &statistics) - { - - const Particle::Property::Manager &manager = this->get_particle_world(0).get_property_manager(); - const Particle::Property::ParticleHandler &particle_handler = this->get_particle_world(0).get_particle_handler(); - - const bool cpo_elastic_decomposition_plugin_exists = manager.plugin_name_exists("elastic tensor decomposition"); - - // Get a reference to the CPO particle property. - const Particle::Property::CrystalPreferredOrientation &cpo_particle_property = - manager.template get_matching_property>(); - - const unsigned int n_grains = cpo_particle_property.get_number_of_grains(); - const unsigned int n_minerals = cpo_particle_property.get_number_of_minerals(); - - // if this is the first time we get here, set the last output time - // to the current time - output_interval. this makes sure we - // always produce data during the first time step - if (std::isnan(last_output_time)) - last_output_time = this->get_time() - output_interval; - - // If it's not time to generate an output file or we do not write output - // return early. - if (this->get_time() < last_output_time + output_interval && this->get_time() != end_time) - return std::make_pair("",""); - - if (output_file_number == numbers::invalid_unsigned_int) - output_file_number = 0; - else - ++output_file_number; - - // Now prepare everything for writing the output - std::string particle_file_prefix_main = this->get_output_directory() + "particles_cpo/particles-" + Utilities::int_to_string (output_file_number, 5); - std::string particle_file_prefix_content_raw = this->get_output_directory() + "particles_cpo/CPO-" + Utilities::int_to_string (output_file_number, 5); - std::string particle_file_prefix_content_draw_volume_weighting = this->get_output_directory() + "particles_cpo/weighted_CPO-" + Utilities::int_to_string (output_file_number, 5); - - std::stringstream string_stream_main; - std::stringstream string_stream_content_raw; - std::stringstream string_stream_content_draw_volume_weighting; - - string_stream_main << "id x y" << (dim == 3 ? " z" : "") << " olivine_deformation_type" - << (cpo_elastic_decomposition_plugin_exists ? (std::string(" full_norm_square ") - + "triclinic_norm_square_p1 triclinic_norm_square_p2 triclinic_norm_square_p3 " - + "monoclinic_norm_square_p1 monoclinic_norm_square_p2 monoclinic_norm_square_p3 " - + "orthohombic_norm_square_p1 orthohombic_norm_square_p2 orthohombic_norm_square_p3 " - + "tetragonal_norm_square_p1 tetragonal_norm_square_p2 tetragonal_norm_square_p3 " - + "hexagonal_norm_square_p1 hexagonal_norm_square_p2 hexagonal_norm_square_p3 " - + "isotropic_norm_square") : "") << std::endl; - - // get particle data - const Particle::Property::ParticlePropertyInformation &property_information = this->get_particle_world(0).get_property_manager().get_data_info(); - - AssertThrow(property_information.fieldname_exists("cpo mineral 0 type") , - ExcMessage("No CPO particle properties found. Make sure that the CPO particle property plugin is selected.")); - - - - const unsigned int cpo_data_position = property_information.n_fields() == 0 - ? - 0 - : - property_information.get_position_by_field_name("cpo mineral 0 type"); - - std::vector>> rotation_matrices (n_minerals, {n_grains,Tensor<2,3>()}); - std::vector>> euler_angles(n_minerals, {n_grains,{{0}}}); - - // write unweighted header - if (write_raw_cpo.size() != 0) - { - string_stream_content_raw << "id" << " " << std::setprecision(12); - for (unsigned int property_i = 0; property_i < write_raw_cpo.size(); ++property_i) - { - switch (write_raw_cpo[property_i].second) - { - case Output::VolumeFraction: - string_stream_content_raw << "mineral_" << write_raw_cpo[property_i].first << "_volume_fraction" << " "; - break; - - case Output::RotationMatrix: - string_stream_content_raw << "mineral_" << write_raw_cpo[property_i].first << "_RM_0" << " " - << "mineral_" << write_raw_cpo[property_i].first << "_RM_1" << " " - << "mineral_" << write_raw_cpo[property_i].first << "_RM_2" << " " - << "mineral_" << write_raw_cpo[property_i].first << "_RM_3" << " " - << "mineral_" << write_raw_cpo[property_i].first << "_RM_4" << " " - << "mineral_" << write_raw_cpo[property_i].first << "_RM_5" << " " - << "mineral_" << write_raw_cpo[property_i].first << "_RM_6" << " " - << "mineral_" << write_raw_cpo[property_i].first << "_RM_7" << " " - << "mineral_" << write_raw_cpo[property_i].first << "_RM_8" << " "; - break; - - case Output::EulerAngles: - string_stream_content_raw << "mineral_" << write_raw_cpo[property_i].first << "_EA_phi" << " " - << "mineral_" << write_raw_cpo[property_i].first << "_EA_theta" << " " - << "mineral_" << write_raw_cpo[property_i].first << "_EA_z" << " "; - break; - default: - Assert(false, ExcMessage("Internal error: raw CPO postprocess case not found.")); - break; - } - } - string_stream_content_raw << std::endl; - } - - - // write weighted header - if (write_draw_volume_weighted_cpo.size() != 0) - { - string_stream_content_draw_volume_weighting << "id" << " "; - for (unsigned int property_i = 0; property_i < write_draw_volume_weighted_cpo.size(); ++property_i) - { - switch (write_draw_volume_weighted_cpo[property_i].second) - { - case Output::VolumeFraction: - string_stream_content_draw_volume_weighting << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_volume_fraction" << " "; - break; - - case Output::RotationMatrix: - string_stream_content_draw_volume_weighting << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_0" << " " - << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_1" << " " - << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_2" << " " - << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_3" << " " - << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_4" << " " - << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_5" << " " - << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_6" << " " - << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_7" << " " - << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_RM_8" << " "; - break; - - case Output::EulerAngles: - string_stream_content_draw_volume_weighting << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_EA_phi" << " " - << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_EA_theta" << " " - << "mineral_" << write_draw_volume_weighted_cpo[property_i].first << "_EA_z" << " "; - break; - default: - Assert(false, ExcMessage("Internal error: raw CPO postprocess case not found.")); - break; - } - } - string_stream_content_draw_volume_weighting << std::endl; - - } - - for (const auto &particle: particle_handler) - { - AssertThrow(particle.has_properties(), - ExcMessage("No particle properties found. Make sure that the CPO particle property plugin is selected.")); - - const unsigned int id = particle.get_id(); - const ArrayView properties = particle.get_properties(); - - const Point position = particle.get_location(); - - // always make a vector of rotation matrices - for (unsigned int mineral = 0; mineral < n_minerals; ++mineral) - { - rotation_matrices[mineral].resize(n_grains); - for (unsigned int i_grain = 0; i_grain < n_grains; ++i_grain) - { - rotation_matrices[mineral][i_grain] = cpo_particle_property.get_rotation_matrix_grains( - cpo_data_position, - properties, - mineral, - i_grain); - } - } - - const unsigned int lpo_hex_data_position = property_information.n_fields() == 0 || cpo_elastic_decomposition_plugin_exists == false - ? - 0 - : - property_information.get_position_by_field_name("cpo elastic axis e1"); - - // write main file - string_stream_main << id << " " << position << " " << properties[cpo_data_position]; - - if (cpo_elastic_decomposition_plugin_exists == true) - { - string_stream_main << " " << properties[lpo_hex_data_position+12] << " " << properties[lpo_hex_data_position+13] - << " " << properties[lpo_hex_data_position+14] << " " << properties[lpo_hex_data_position+15] - << " " << properties[lpo_hex_data_position+16] << " " << properties[lpo_hex_data_position+17] - << " " << properties[lpo_hex_data_position+18] << " " << properties[lpo_hex_data_position+19] - << " " << properties[lpo_hex_data_position+20] << " " << properties[lpo_hex_data_position+21] - << " " << properties[lpo_hex_data_position+22] << " " << properties[lpo_hex_data_position+23] - << " " << properties[lpo_hex_data_position+24] << " " << properties[lpo_hex_data_position+25] - << " " << properties[lpo_hex_data_position+26] << " " << properties[lpo_hex_data_position+27] - << " " << properties[lpo_hex_data_position+28]; - } - string_stream_main << std::endl; - - // write content file - if (compute_raw_euler_angles == true) - { - euler_angles.resize(n_minerals); - for (unsigned int mineral = 0; mineral < n_minerals; ++mineral) - { - euler_angles[mineral].resize(n_grains); - for (unsigned int i_grain = 0; i_grain < n_grains; ++i_grain) - { - euler_angles[mineral][i_grain] = Utilities::zxz_euler_angles_from_rotation_matrix( - rotation_matrices[mineral][i_grain]); - } - } - } - - if (write_raw_cpo.size() != 0) - { - // write unweighted data - for (unsigned int grain = 0; grain < n_grains; ++grain) - { - string_stream_content_raw << id << " "; - for (unsigned int property_i = 0; property_i < write_raw_cpo.size(); ++property_i) - { - switch (write_raw_cpo[property_i].second) - { - case Output::VolumeFraction: - string_stream_content_raw << cpo_particle_property.get_volume_fractions_grains( - cpo_data_position, - properties, - write_raw_cpo[property_i].first, - grain) << " "; - break; - - case Output::RotationMatrix: - string_stream_content_raw << rotation_matrices[write_raw_cpo[property_i].first][grain]<< " "; - break; - - case Output::EulerAngles: - Assert(compute_raw_euler_angles == true, - ExcMessage("Internal error: writing out raw Euler angles, without them being computed.")); - string_stream_content_raw << euler_angles[write_raw_cpo[property_i].first][grain][0] << " " - << euler_angles[write_raw_cpo[property_i].first][grain][1] << " " - << euler_angles[write_raw_cpo[property_i].first][grain][2] << " "; - break; - default: - Assert(false, ExcMessage("Internal error: raw CPO postprocess case not found.")); - break; - } - } - string_stream_content_raw << std::endl; - } - - } - - if (write_draw_volume_weighted_cpo.size() != 0) - { - std::vector>> weighted_rotation_matrices; - std::vector>> weighted_euler_angles; - - weighted_euler_angles.resize(n_minerals); - weighted_rotation_matrices.resize(n_minerals); - std::vector> volume_fractions_grains(n_minerals,std::vector(n_grains,-1.)); - for (unsigned int mineral = 0; mineral < n_minerals; ++mineral) - { - for (unsigned int i_grain = 0; i_grain < n_grains; ++i_grain) - { - weighted_euler_angles[mineral].resize(n_grains); - weighted_rotation_matrices[mineral].resize(n_grains); - volume_fractions_grains[mineral][i_grain] = cpo_particle_property.get_volume_fractions_grains( - cpo_data_position, - properties, - mineral, - i_grain); - } - weighted_rotation_matrices[mineral] = Utilities::rotation_matrices_random_draw_volume_weighting(volume_fractions_grains[mineral], rotation_matrices[mineral], n_grains, this->random_number_generator); - - Assert(weighted_rotation_matrices[mineral].size() == euler_angles[mineral].size(), - ExcMessage("Weighted rotation matrices vector (size = " + std::to_string(weighted_rotation_matrices[mineral].size()) + - ") has different size from input angles (size = " + std::to_string(euler_angles[mineral].size()) + ").")); - - for (unsigned int i_grain = 0; i_grain < n_grains; ++i_grain) - { - weighted_euler_angles[mineral][i_grain] = Utilities::zxz_euler_angles_from_rotation_matrix( - weighted_rotation_matrices[mineral][i_grain]); - } - } - string_stream_content_draw_volume_weighting << std::endl; - - // write data - for (unsigned int grain = 0; grain < n_grains; ++grain) - { - string_stream_content_draw_volume_weighting << id << " "; - for (unsigned int property_i = 0; property_i < write_draw_volume_weighted_cpo.size(); ++property_i) - { - switch (write_draw_volume_weighted_cpo[property_i].second) - { - case Output::VolumeFraction: - string_stream_content_draw_volume_weighting << volume_fractions_grains[write_draw_volume_weighted_cpo[property_i].first][grain] << " "; - break; - - case Output::RotationMatrix: - string_stream_content_draw_volume_weighting << weighted_rotation_matrices[write_draw_volume_weighted_cpo[property_i].first][grain] << " "; - break; - - case Output::EulerAngles: - Assert(compute_raw_euler_angles == true, - ExcMessage("Internal error: writing out raw Euler angles, without them being computed.")); - string_stream_content_draw_volume_weighting << weighted_euler_angles[write_draw_volume_weighted_cpo[property_i].first][grain][0] << " " - << weighted_euler_angles[write_draw_volume_weighted_cpo[property_i].first][grain][1] << " " - << weighted_euler_angles[write_draw_volume_weighted_cpo[property_i].first][grain][2] << " "; - break; - - default: - Assert(false, ExcMessage("Internal error: raw CPO postprocess case not found.")); - break; - } - } - string_stream_content_draw_volume_weighting << std::endl; - } - } - } - - std::string filename_main = particle_file_prefix_main + "." + Utilities::int_to_string(dealii::Utilities::MPI::this_mpi_process (this->get_mpi_communicator()),4) + ".dat"; - std::string filename_raw = particle_file_prefix_content_raw + "." + Utilities::int_to_string(dealii::Utilities::MPI::this_mpi_process (this->get_mpi_communicator()),4) + ".dat"; - std::string filename_draw_volume_weighting = particle_file_prefix_content_draw_volume_weighting + "." + Utilities::int_to_string(dealii::Utilities::MPI::this_mpi_process (this->get_mpi_communicator()),4) + ".dat"; - - std::unique_ptr file_contents_main = std::make_unique(string_stream_main.str()); - std::unique_ptr file_contents_raw = std::make_unique(string_stream_content_raw.str()); - std::unique_ptr file_contents_draw_volume_weighting = std::make_unique(string_stream_content_draw_volume_weighting.str()); - - if (write_in_background_thread) - { - // Wait for all previous write operations to finish, should - // any be still active, - if (background_thread_main.joinable()) - background_thread_main.join (); - - // then continue with writing the main file - background_thread_main - = std::thread([ my_filename = std::move(filename_main), - my_temporary_output_location = temporary_output_location, - my_file_contents = std::move(file_contents_main)]() - { - writer (my_filename, my_temporary_output_location, *my_file_contents, false); - }); - - if (write_raw_cpo.size() != 0) - { - // Wait for all previous write operations to finish, should - // any be still active, - if (background_thread_content_raw.joinable()) - background_thread_content_raw.join (); - - // then continue with writing our own data. - background_thread_content_raw - = std::thread([ my_filename = std::move(filename_raw), - my_temporary_output_location = temporary_output_location, - my_file_contents = std::move(file_contents_raw), - my_compress_cpo_data_files = compress_cpo_data_files]() - { - writer (my_filename, my_temporary_output_location, *my_file_contents, my_compress_cpo_data_files); - }); - } - - if (write_draw_volume_weighted_cpo.size() != 0) - { - // Wait for all previous write operations to finish, should - // any be still active, - if (background_thread_content_draw_volume_weighting.joinable()) - background_thread_content_draw_volume_weighting.join (); - - // then continue with writing our own data. - background_thread_content_draw_volume_weighting - = std::thread([ my_filename = std::move(filename_draw_volume_weighting), - my_temporary_output_location = temporary_output_location, - my_file_contents = std::move(file_contents_draw_volume_weighting), - my_compress_cpo_data_files = compress_cpo_data_files]() - { - writer (my_filename, my_temporary_output_location, *my_file_contents, my_compress_cpo_data_files); - }); - } - } - else - { - writer(filename_main,temporary_output_location,*file_contents_main, false); - if (write_raw_cpo.size() != 0) - writer(filename_raw,temporary_output_location,*file_contents_raw, compress_cpo_data_files); - if (write_draw_volume_weighted_cpo.size() != 0) - writer(filename_draw_volume_weighting,temporary_output_location,*file_contents_draw_volume_weighting, compress_cpo_data_files); - } - - - // up the next time we need output - set_last_output_time (this->get_time()); - - const std::string &particles_cpo_output = particle_file_prefix_content_raw; - - // record the file base file name in the output file - statistics.add_value ("Particle CPO file name", particles_cpo_output); - return std::make_pair("Writing particle cpo output:", particles_cpo_output); - } - - - - template - void - CrystalPreferredOrientation::set_last_output_time (const double current_time) - { - // if output_interval is positive, then update the last supposed output - // time - if (output_interval > 0) - { - // We need to find the last time output was supposed to be written. - // this is the last_output_time plus the largest positive multiple - // of output_intervals that passed since then. We need to handle the - // edge case where last_output_time+output_interval==current_time, - // we did an output and std::floor sadly rounds to zero. This is done - // by forcing std::floor to round 1.0-eps to 1.0. - const double magic = 1.0+2.0*std::numeric_limits::epsilon(); - last_output_time = last_output_time + std::floor((current_time-last_output_time)/output_interval*magic) * output_interval/magic; - } - } - - - - template - typename CrystalPreferredOrientation::Output - CrystalPreferredOrientation::string_to_output_enum(const std::string &string) - { - // olivine volume fraction, olivine rotation matrix, olivine Euler angles, enstatite volume fraction, enstatite rotation matrix, enstatite Euler angles - if (string == "volume fraction") - return Output::VolumeFraction; - if (string == "rotation matrix") - return Output::RotationMatrix; - if (string == "Euler angles") - return Output::EulerAngles; - return Output::not_found; - } - - - - template - void - CrystalPreferredOrientation::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Crystal Preferred Orientation"); - { - prm.declare_entry ("Time between data output", "1e8", - Patterns::Double (0), - "The time interval between each generation of " - "output files. A value of zero indicates that " - "output should be generated every time step.\n\n" - "Units: years if the " - "'Use years in output instead of seconds' parameter is set; " - "seconds otherwise."); - - prm.declare_entry ("Random number seed", "1", - Patterns::Integer (0), - "The seed used to generate random numbers. This will make sure that " - "results are reproducible as long as the problem is run with the " - "same amount of MPI processes. It is implemented as final seed = " - "random number seed + MPI Rank. "); - - prm.declare_entry ("Write in background thread", "false", - Patterns::Bool(), - "File operations can potentially take a long time, blocking the " - "progress of the rest of the model run. Setting this variable to " - "`true' moves this process into background threads, while the " - "rest of the model continues."); - - prm.declare_entry ("Temporary output location", "", - Patterns::Anything(), - "On large clusters it can be advantageous to first write the " - "output to a temporary file on a local file system and later " - "move this file to a network file system. If this variable is " - "set to a non-empty string it will be interpreted as a " - "temporary storage location."); - - prm.declare_entry ("Write out raw cpo data", - "olivine volume fraction,olivine Euler angles,enstatite volume fraction,enstatite Euler angles", - Patterns::List(Patterns::Anything()), - "A list containing what particle cpo data needs " - "to be written out after the particle id. This writes out the raw " - "cpo data files for each MPI process. It can write out the following data: " - "olivine volume fraction, olivine rotation matrix, olivine Euler angles, " - "enstatite volume fraction, enstatite rotation matrix, enstatite Euler angles. \n" - "Note that the rotation matrix and Euler angles both contain the same " - "information, but in a different format. Euler angles are recommended " - "over the rotation matrix since they only require to write 3 values instead " - "of 9. If the list is empty, this file will not be written." - "Furthermore, the entries will be written out in the order given, " - "and if entries are entered multiple times, they will be written " - "out multiple times."); - - prm.declare_entry ("Write out draw volume weighted cpo data", - "olivine Euler angles,enstatite Euler angles", - Patterns::List(Patterns::Anything()), - "A list containing the what part of the random draw volume " - "weighted particle cpo data needs to be written out after " - "the particle id. after using a random draw volume weighting. " - "The random draw volume weigthing uses a uniform random distribution " - "This writes out the raw cpo data files for " - "each MPI process. It can write out the following data: " - "olivine volume fraction, olivine rotation matrix, olivine Euler angles, " - "enstatite volume fraction, enstatite rotation matrix, enstatite Euler angles. \n" - "Note that the rotation matrix and Euler angles both contain the same " - "information, but in a different format. Euler angles are recommended " - "over the rotation matrix since they only require to write 3 values instead " - "of 9. If the list is empty, this file will not be written. " - "Furthermore, the entries will be written out in the order given, " - "and if entries are entered multiple times, they will be written " - "out multiple times."); - prm.declare_entry ("Compress cpo data files", "true", - Patterns::Bool(), - "Whether to compress the raw and weighted cpo data output files with zlib."); - } - prm.leave_subsection (); - } - prm.leave_subsection (); - - } - - - - template - void - CrystalPreferredOrientation::parse_parameters (ParameterHandler &prm) - { - end_time = prm.get_double ("End time"); - if (this->convert_output_to_years()) - end_time *= year_in_seconds; - - unsigned int n_minerals; - - prm.enter_subsection("Particles"); - { - prm.enter_subsection("Crystal Preferred Orientation"); - { - prm.enter_subsection("Initial grains"); - { - // Static variable of CPO has not been initialize yet, so we need to get it directly. - n_minerals = dealii::Utilities::split_string_list(prm.get("Minerals")).size(); - } - prm.leave_subsection(); - } - prm.leave_subsection (); - } - prm.leave_subsection (); - - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Crystal Preferred Orientation"); - { - output_interval = prm.get_double ("Time between data output"); - if (this->convert_output_to_years()) - output_interval *= year_in_seconds; - - random_number_seed = prm.get_integer ("Random number seed"); - - AssertThrow(this->get_parameters().run_postprocessors_on_nonlinear_iterations == false, - ExcMessage("Postprocessing nonlinear iterations in models with " - "particles is currently not supported.")); - - aspect::Utilities::create_directory (this->get_output_directory() + "particles_cpo/", - this->get_mpi_communicator(), - true); - - write_in_background_thread = prm.get_bool("Write in background thread"); - temporary_output_location = prm.get("Temporary output location"); - - if (temporary_output_location != "") - { - // Check if a command-processor is available by calling system() with a - // null pointer. System is guaranteed to return non-zero if it finds - // a terminal and zero if there is none (like on the compute nodes of - // some cluster architectures, e.g. IBM BlueGene/Q) - AssertThrow(system((char *)nullptr) != 0, - ExcMessage("Usage of a temporary storage location is only supported if " - "there is a terminal available to move the files to their final location " - "after writing. The system() command did not succeed in finding such a terminal.")); - } - - std::vector write_raw_cpo_list = Utilities::split_string_list(prm.get("Write out raw cpo data")); - write_raw_cpo.resize(write_raw_cpo_list.size()); - bool found_euler_angles = false; - for (unsigned int i = 0; i < write_raw_cpo_list.size(); ++i) - { - std::vector split_raw_cpo_instructions = Utilities::split_string_list(write_raw_cpo_list[i],':'); - - AssertThrow(split_raw_cpo_instructions.size() == 2, - ExcMessage("Value \""+ write_raw_cpo_list[i] +"\", set in \"Write out raw cpo data\", is not a correct option " - + "because it should contain a mineral identification and a output specifier separated by a colon (:). This entry " - + "does not follow those rules.")); - - // get mineral number - std::vector mineral_instructions = Utilities::split_string_list(split_raw_cpo_instructions[0],' '); - AssertThrow(mineral_instructions.size() == 2, - ExcMessage("Value \""+ write_raw_cpo_list[i] +"\", set in \"Write out raw cpo data\", is not a correct option " - + "because the mineral identification part should contain two elements, the word mineral and a number.")); - - AssertThrow(mineral_instructions[0] == "mineral", - ExcMessage("Value \""+ write_raw_cpo_list[i] +"\", set in \"Write out raw cpo data\", is not a correct option " - + "because the mineral identification part should start with the word mineral and it starts with \"" - + mineral_instructions[0] + "\".")); - - int mineral_number = Utilities::string_to_int(mineral_instructions[1]); - Assert(mineral_number >= 0, ExcMessage("Internal error: mineral_number is negative: " + std::to_string(mineral_number) + ".")); - - AssertThrow((unsigned int) mineral_number < n_minerals, - ExcMessage("Value \""+ write_raw_cpo_list[i] +"\", set in \"Write out raw cpo data\", is not a correct option " - + "because the mineral number (" + std::to_string(mineral_number) + ") is larger than the number of minerals " - + "provided in the CPO subsection (" + std::to_string(n_minerals) + ").")); - - // get mineral fabric/deformation type - Output cpo_fabric_instruction = string_to_output_enum(split_raw_cpo_instructions[1]); - - AssertThrow(cpo_fabric_instruction != Output::not_found, - ExcMessage("Value \""+ write_raw_cpo_list[i] +"\", set in \"Write out raw cpo data\", is not a correct option.")); - - if (cpo_fabric_instruction == Output::EulerAngles) - found_euler_angles = true; - - write_raw_cpo[i] = std::make_pair(mineral_number,cpo_fabric_instruction); - } - - std::vector write_draw_volume_weighted_cpo_list = Utilities::split_string_list(prm.get("Write out draw volume weighted cpo data")); - write_draw_volume_weighted_cpo.resize(write_draw_volume_weighted_cpo_list.size()); - bool found_rotation_matrix = false; - for (unsigned int i = 0; i < write_draw_volume_weighted_cpo_list.size(); ++i) - { - std::vector split_draw_volume_weighted_cpo_instructions = Utilities::split_string_list(write_draw_volume_weighted_cpo_list[i],':'); - - AssertThrow(split_draw_volume_weighted_cpo_instructions.size() == 2, - ExcMessage("Value \""+ write_draw_volume_weighted_cpo_list[i] +"\", set in \"Write out draw volume weighted cpo data\", is not a correct option " - + "because it should contain a mineral identification and a output specifier separated by a colon (:). This entry " - + "does not follow those rules.")); - - // get mineral number - std::vector mineral_instructions = Utilities::split_string_list(split_draw_volume_weighted_cpo_instructions[0],' '); - AssertThrow(mineral_instructions.size() == 2, - ExcMessage("Value \""+ write_draw_volume_weighted_cpo_list[i] +"\", set in \"Write out draw volume weighted cpo data\", is not a correct option " - + "because the mineral identification part should contain two elements, the word mineral and a number.")); - - AssertThrow(mineral_instructions[0] == "mineral", - ExcMessage("Value \""+ write_draw_volume_weighted_cpo_list[i] +"\", set in \"Write out draw volume weighted cpo data\", is not a correct option " - + "because the mineral identification part should start with the word mineral and it starts with \"" - + mineral_instructions[0] + "\".")); - - int mineral_number = Utilities::string_to_int(mineral_instructions[1]); - Assert(mineral_number >= 0, ExcMessage("Internal error: mineral_number is negative: " + std::to_string(mineral_number) + ".")); - - AssertThrow((unsigned int) mineral_number < n_minerals, - ExcMessage("Value \""+ write_raw_cpo_list[i] +"\", set in \"Write out raw cpo data\", is not a correct option " - + "because the mineral number (" + std::to_string(mineral_number) + ") is larger than the number of minerals " - + "provided in the CPO subsection (" + std::to_string(n_minerals) + ").")); - - // get mineral fabric/deformation type - Output cpo_fabric_instruction = string_to_output_enum(split_draw_volume_weighted_cpo_instructions[1]); - - AssertThrow(cpo_fabric_instruction != Output::not_found, - ExcMessage("Value \""+ write_draw_volume_weighted_cpo_list[i] +"\", set in \"Write out draw volume weighted cpo data\", is not a correct option.")); - - if (cpo_fabric_instruction == Output::RotationMatrix) - found_rotation_matrix = true; - - write_draw_volume_weighted_cpo[i] = std::make_pair(mineral_number,cpo_fabric_instruction); - } - - if (write_draw_volume_weighted_cpo_list.size() != 0 || found_euler_angles == true) - compute_raw_euler_angles = true; - else - compute_raw_euler_angles = false; - - if (write_draw_volume_weighted_cpo_list.size() != 0 && found_rotation_matrix == true) - compute_weighted_rotation_matrix = true; - else - compute_weighted_rotation_matrix = false; - - compress_cpo_data_files = prm.get_bool("Compress cpo data files"); - } - prm.leave_subsection (); - } - prm.leave_subsection (); - - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(CrystalPreferredOrientation, - "crystal preferred orientation", - "A Postprocessor that writes out CPO specific particle data." - "It can write out the CPO data as it is stored (raw) and/or as a" - "random draw volume weighted representation. The latter one" - "is recommended for plotting against real data. For both representations" - "the specific output fields and their order can be set." - "The work of this postprocessor should better be done by the main particles " - "postprocessor, however we need to be able to process the data before outputting it, " - "which does not work with that postprocessor. If this is added to the other " - "postprocessor in the future this one becomes obsolete.") - } -} diff --git a/source/postprocess/depth_average.cc.bak b/source/postprocess/depth_average.cc.bak deleted file mode 100644 index c753fef2467..00000000000 --- a/source/postprocess/depth_average.cc.bak +++ /dev/null @@ -1,517 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - -#include - -namespace aspect -{ - namespace Postprocess - { - template - template - void DepthAverage::DataPoint::serialize (Archive &ar, - const unsigned int) - { - ar &time &values; - } - - - template - DepthAverage::DepthAverage () - : - // the following value is later read from the input file - output_interval (0), - // initialize this to a nonsensical value; set it to the actual time - // the first time around we get to check it - last_output_time (std::numeric_limits::quiet_NaN()), - n_depth_zones (numbers::invalid_unsigned_int) - {} - - - - template - std::pair - DepthAverage::execute (TableHandler &) - { - // if this is the first time we get here, set the next output time - // to the current time. this makes sure we always produce data during - // the first time step - if (std::isnan(last_output_time)) - last_output_time = this->get_time() - output_interval; - - // see if output is requested at this time - if (this->get_time() < last_output_time + output_interval) - return {"", ""}; - - DataPoint data_point; - data_point.time = this->get_time(); - - // Add all the requested fields - data_point.values = this->get_lateral_averaging().compute_lateral_averages(depth_bounds,variables); - entries.push_back (data_point); - - // On the root process, write out the file. do this using the DataOutStack - // class on a piece-wise constant finite element space on - // a 1d mesh with the correct subdivisions - const std::string filename_prefix (this->get_output_directory() + "depth_average"); - if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - Triangulation<1> mesh; - const Point<1> p(depth_bounds[0]); - std::vector> spacing(1,std::vector(depth_bounds.size()-1,0.0)); - for (unsigned int i=0; i material_id(spacing[0].size()); - - GridGenerator::subdivided_hyper_rectangle(mesh, spacing, p, material_id); - - FE_DGQ<1> fe(0); - DoFHandler<1> dof_handler (mesh); - dof_handler.distribute_dofs(fe); - Assert (dof_handler.n_dofs() == n_depth_zones, ExcInternalError()); - - DataOutStack<1> data_out_stack; - - for (const auto &output_format_string: output_formats) - { - if (output_format_string != "txt") - { - for (const auto &variable : variables) - data_out_stack.declare_data_vector (variable, - DataOutStack<1>::cell_vector); - - for (unsigned int i=0; iconvert_output_to_years() - ? - entries[i].time / year_in_seconds - : - entries[i].time), - // declare the time step, which here is the difference - // between successive output times. we don't have anything - // for the first time step, however. we could do a zero - // delta, but that leads to invisible output. rather, we - // use an artificial value of one tenth of the first interval, - // if available - (i == 0 ? - (entries.size() > 1 ? (entries[1].time - entries[0].time)/10 : 0) : - entries[i].time - entries[i-1].time) / - (this->convert_output_to_years() - ? - year_in_seconds - : - 1)); - - data_out_stack.attach_dof_handler (dof_handler); - - Vector tmp(n_depth_zones); - for (unsigned int j=0; j did not succeed in the `point values' " - "postprocessor.")); - } - else - { - const std::string filename (this->get_output_directory() + "depth_average.txt"); - std::ofstream f(filename, std::ofstream::out); - - // Write the header - f << "# time" << " depth"; - for (const auto &variable : variables) - f << ' ' << variable; - f << std::endl; - - // Output each data point in the entries object - for (const auto &point : entries) - { - for (unsigned int d = 0; d < point.values[0].size(); ++d) - { - const double depth = (depth_bounds[d] + depth_bounds[d+1]) / 2.0; - f << std::setw(12) - << (this->convert_output_to_years() ? point.time/year_in_seconds : point.time) - << ' ' << std::setw(12) << depth; - for ( unsigned int i = 0; i < variables.size(); ++i ) - f << ' ' << std::setw(12) << point.values[i][d]; - f << std::endl; - } - } - - AssertThrow (f, ExcMessage("Writing data to <" + filename + - "> did not succeed in the `point values' " - "postprocessor.")); - } - } - } - - set_last_output_time (this->get_time()); - - // return what should be printed to the screen. note that we had - // just incremented the number, so use the previous value - return std::make_pair (std::string ("Writing depth average:"), - filename_prefix); - } - - - template - void - DepthAverage::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Depth average"); - { - prm.declare_entry ("Time between graphical output", "1e8", - Patterns::Double (0.), - "The time interval between each generation of " - "graphical output files. A value of zero indicates " - "that output should be generated in each time step. " - "Units: years if the " - "'Use years in output instead of seconds' parameter is set; " - "seconds otherwise."); - prm.declare_entry ("Number of zones", "10", - Patterns::Integer (1), - "The number of zones in depth direction within which we " - "are to compute averages. By default, we subdivide the entire " - "domain into 10 depth zones and compute temperature and other " - "averages within each of these zones. However, if you have a " - "very coarse mesh, it may not make much sense to subdivide " - "the domain into so many zones and you may wish to choose " - "less than this default. It may also make computations slightly " - "faster. On the other hand, if you have an extremely highly " - "resolved mesh, choosing more zones might also make sense."); - prm.declare_entry ("Depth boundaries of zones", "", - Patterns::List (Patterns::Double()), - "The depth boundaries of zones within which we " - "are to compute averages. By default this list is empty " - "and we subdivide the entire " - "domain into equidistant depth zones and compute " - "averages within each of these zones. If this list is not " - "empty it has to contain one more entry " - "than the 'Number of zones' parameter, representing the upper " - "and lower depth boundary of each zone. It is not necessary to " - "cover the whole depth-range (i.e. you can select to only average in " - "a single layer by choosing 2 arbitrary depths as the boundaries " - "of that layer)."); - prm.declare_entry ("Output format", "gnuplot, txt", - Patterns::MultipleSelection(DataOutBase::get_output_format_names().append("|txt")), - "A list of formats in which the output shall be produced. The " - "format in which the output is generated also determines " - "the extension of the file into which data is written. " - "The list of possible output formats that can be given " - "here is documented in the appendix of the manual where " - "the current parameter is described. By default the output " - "is written as gnuplot file (for plotting), and as a simple " - "text file."); - const std::string variables = - "all|temperature|composition|" - "adiabatic temperature|adiabatic pressure|adiabatic density|adiabatic density derivative|" - "velocity magnitude|sinking velocity|rising velocity|Vs|Vp|log viscosity|" - "viscosity|vertical heat flux|vertical mass flux|composition mass"; - prm.declare_entry("List of output variables", "all", - Patterns::MultipleSelection(variables), - "A comma separated list which specifies which quantities to " - "average in each depth slice. It defaults to averaging all " - "available quantities, but this can be an expensive operation, " - "so you may want to select only a few.\n\n" - "Specifically, the sinking velocity is defined as the scalar " - "product of the velocity and a unit vector in the direction of " - "gravity, if positive (being zero if this product is negative, " - "which would correspond to an upward velocity). " - "The rising velocity is the opposite: the scalar product of " - "the velocity and a unit vector in the direction opposite of " - "gravity, if positive (being zero for downward velocities). " - "\n\n" - "List of options:\n" - +variables); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - template - void - DepthAverage::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Depth average"); - { - n_depth_zones = prm.get_integer ("Number of zones"); - depth_bounds = Utilities::string_to_double(Utilities::split_string_list( - prm.get("Depth boundaries of zones"))); - - AssertThrow(depth_bounds.size() == 0 || depth_bounds.size() == n_depth_zones + 1, - ExcMessage("The parameter 'Depth boundaries of zones' has to be either empty, or have exactly " - "one more entry than the 'Number of zones' parameter.")); - - if (depth_bounds.size() == 0) - { - const double maximal_depth = this->get_geometry_model().maximal_depth(); - depth_bounds.resize(n_depth_zones+1); - - // Leave index 0 at 0.0, and generate an increasing range of equidistant depth bounds - for (unsigned int i=1; idepth_bounds[i-1], - ExcMessage("The entries in the parameter 'Depth boundaries of zones' have " - "to be sorted in increasing order.")); - } - - output_interval = prm.get_double ("Time between graphical output"); - if (this->convert_output_to_years()) - output_interval *= year_in_seconds; - - if (output_interval > 0.0) - { - // since we increase the time indicating when to write the next graphical output - // every time we execute the depth average postprocessor, there is no good way to - // figure out when to write graphical output for the nonlinear iterations if we do - // not want to output every time step - AssertThrow(this->get_parameters().run_postprocessors_on_nonlinear_iterations == false, - ExcMessage("Postprocessing nonlinear iterations is only supported if every time " - "step is visualized, or in other words, if the 'Time between graphical " - "output' in the Depth average postprocessor is set to zero.")); - } - - std::vector output_variables = Utilities::split_string_list(prm.get("List of output variables")); - AssertThrow(Utilities::has_unique_entries(output_variables), - ExcMessage("The list of strings for the parameter " - "'Postprocess/Depth average/List of output variables' contains entries more than once. " - "This is not allowed. Please check your parameter file.")); - - bool output_all_variables = false; - if ( std::find( output_variables.begin(), output_variables.end(), "all") != output_variables.end()) - output_all_variables = true; - - // we have to parse the list in this order to match the output columns - { - if (output_all_variables || std::find( output_variables.begin(), output_variables.end(), "temperature") != output_variables.end() ) - variables.emplace_back("temperature"); - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "composition") != output_variables.end() ) - for (unsigned int c=0; cn_compositional_fields(); ++c) - variables.emplace_back(this->introspection().name_for_compositional_index(c)); - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "adiabatic temperature") != output_variables.end() ) - variables.emplace_back("adiabatic_temperature"); - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "adiabatic pressure") != output_variables.end() ) - variables.emplace_back("adiabatic_pressure"); - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "adiabatic density") != output_variables.end() ) - variables.emplace_back("adiabatic_density"); - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "adiabatic density derivative") != output_variables.end() ) - variables.emplace_back("adiabatic_density_derivative"); - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "velocity magnitude") != output_variables.end() ) - variables.emplace_back("velocity_magnitude"); - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "sinking velocity") != output_variables.end() ) - variables.emplace_back("sinking_velocity"); - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "rising velocity") != output_variables.end() ) - variables.emplace_back("rising_velocity"); - - // handle seismic velocities, because they may, or may not be provided by the material model - { - MaterialModel::MaterialModelOutputs out(1, this->n_compositional_fields()); - this->get_material_model().create_additional_named_outputs(out); - - const bool material_model_provides_seismic_output = - (out.template get_additional_output>() != nullptr); - - const bool output_vs = std::find( output_variables.begin(), output_variables.end(), "Vs") != output_variables.end(); - const bool output_vp = std::find( output_variables.begin(), output_variables.end(), "Vp") != output_variables.end(); - - if (output_vs || output_vp) - AssertThrow(material_model_provides_seismic_output, - ExcMessage("You requested seismic velocities from the 'Depth average' postprocessor, " - "but the material model does not provide seismic velocities. Either remove 'Vs' and " - "'Vp' from the 'List of output variables' parameter, or use a material model that " - "provides these velocities.")); - - if (output_all_variables && material_model_provides_seismic_output) - { - variables.emplace_back("Vs"); - variables.emplace_back("Vp"); - } - - if (output_vs) - variables.emplace_back("Vs"); - - if (output_vp) - variables.emplace_back("Vp"); - } - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "viscosity") != output_variables.end() ) - variables.emplace_back("viscosity"); - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "log viscosity") != output_variables.end() ) - variables.emplace_back("log_viscosity"); - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "vertical heat flux") != output_variables.end() ) - variables.emplace_back("vertical_heat_flux"); - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "vertical mass flux") != output_variables.end() ) - variables.emplace_back("vertical_mass_flux"); - - if ( output_all_variables || std::find( output_variables.begin(), output_variables.end(), "composition mass") != output_variables.end() ) - for (unsigned int c=0; cn_compositional_fields(); ++c) - variables.emplace_back(this->introspection().name_for_compositional_index(c) + std::string("_mass")); - } - - output_formats = Utilities::split_string_list(prm.get("Output format")); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - template - template - void DepthAverage::serialize (Archive &ar, const unsigned int) - { - ar &last_output_time - & entries; - } - - - template - void - DepthAverage::save (std::map &status_strings) const - { - std::ostringstream os; - aspect::oarchive oa (os); - oa << (*this); - - status_strings["DepthAverage"] = os.str(); - } - - - template - void - DepthAverage::load (const std::map &status_strings) - { - // see if something was saved - if (status_strings.find("DepthAverage") != status_strings.end()) - { - std::istringstream is (status_strings.find("DepthAverage")->second); - aspect::iarchive ia (is); - ia >> (*this); - } - } - - - template - void - DepthAverage::set_last_output_time (const double current_time) - { - // if output_interval is positive, then set the next output interval to - // a positive multiple. - if (output_interval > 0) - { - // We need to find the last time output was supposed to be written. - // this is the last_output_time plus the largest positive multiple - // of output_intervals that passed since then. We need to handle the - // edge case where last_output_time+output_interval==current_time, - // we did an output and std::floor sadly rounds to zero. This is done - // by forcing std::floor to round 1.0-eps to 1.0. - const double magic = 1.0+2.0*std::numeric_limits::epsilon(); - last_output_time = last_output_time + std::floor((current_time-last_output_time)/output_interval*magic) * output_interval/magic; - } - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(DepthAverage, - "depth average", - "A postprocessor that computes depth averaged " - "quantities and writes them into a file " - "in the output directory, where the extension of the file " - "is determined by the output format you select. In addition " - "to the output format, a number of other parameters also influence " - "this postprocessor, and they can be set in the section " - "\\texttt{Postprocess/Depth average} in the input file." - "\n\n" - "In the output files, the $x$-value of each data point corresponds " - "to the depth, whereas the $y$-value corresponds to the " - "simulation time. The time is provided in seconds or, if the " - "global ``Use years in output instead of seconds'' parameter is " - "set, in years.") - } -} diff --git a/source/postprocess/domain_volume_statistics.cc.bak b/source/postprocess/domain_volume_statistics.cc.bak deleted file mode 100644 index c6220190fd3..00000000000 --- a/source/postprocess/domain_volume_statistics.cc.bak +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - DomainVolume::execute (TableHandler &statistics) - { - // Retrieve the current domain volume - const double global_volume = this->get_volume(); - - // add the volume to the statistics object - const std::string unit = (dim == 2) ? "m^2" : "m^3"; - const std::string name = "Model domain volume (" + unit + ")"; - statistics.add_value (name, global_volume); - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - statistics.set_precision (name, 8); - statistics.set_scientific (name, true); - - // create a single string to output to the screen - std::ostringstream screen_text; - screen_text.precision(4); - screen_text << global_volume << " " << unit; - - return std::pair ("Model domain volume:", - screen_text.str()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(DomainVolume, - "domain volume statistics", - "A postprocessor that computes the total area (in 2d) " - "or volume (in 3d) of the computational domain. ") - } -} diff --git a/source/postprocess/dynamic_topography.cc.bak b/source/postprocess/dynamic_topography.cc.bak deleted file mode 100644 index 8751c8f9463..00000000000 --- a/source/postprocess/dynamic_topography.cc.bak +++ /dev/null @@ -1,548 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - -#include -#include - -#include - -#include -#include - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - DynamicTopography::execute (TableHandler &) - { - const Postprocess::BoundaryPressures &boundary_pressures = - this->get_postprocess_manager().template get_matching_postprocessor>(); - - // Get the average pressure at the top and bottom boundaries. - // This will be used to compute the dynamic pressure at the boundaries. - const double surface_pressure = boundary_pressures.pressure_at_top(); - const double bottom_pressure = boundary_pressures.pressure_at_bottom(); - - const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); - const types::boundary_id bottom_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); - - // If the gravity vector is pointed *up*, as determined by representative points - // at the surface and at depth, then we are running backwards advection, and need - // to reverse the dynamic topography values. - const bool backward_advection = (this->get_gravity_model().gravity_vector(this->get_geometry_model().representative_point(0.)) * - (this->get_geometry_model().representative_point(0.) - - this->get_geometry_model().representative_point(this->get_geometry_model().maximal_depth()))) >= 0.; - - const unsigned int quadrature_degree = this->get_fe().base_element(this->introspection().base_elements.velocities).degree+1; - // Gauss quadrature in the interior for best accuracy. - const QGauss quadrature_formula(quadrature_degree); - // GLL quadrature on the surface to get a diagonal mass matrix. - const QGaussLobatto quadrature_formula_face(quadrature_degree); - - const unsigned int dofs_per_cell = this->get_fe().dofs_per_cell; - const unsigned int dofs_per_face = this->get_fe().dofs_per_face; - const unsigned int n_q_points = quadrature_formula.size(); - const unsigned int n_face_q_points = quadrature_formula_face.size(); - - // The CBF method involves both boundary and volume integrals on the - // cells at the boundary. Construct FEValues objects for each of these integrations. - FEValues fe_volume_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_gradients | - update_quadrature_points | - update_JxW_values); - - FEFaceValues fe_face_values (this->get_mapping(), - this->get_fe(), - quadrature_formula_face, - update_JxW_values | - update_values | - update_gradients | - update_quadrature_points); - - // Storage for shape function values for the current solution. - // Used for constructing the known side of the CBF system. - std::vector> phi_u (dofs_per_cell); - std::vector> epsilon_phi_u (dofs_per_cell); - std::vector div_phi_u (dofs_per_cell); - std::vector div_solution(n_q_points); - - // Vectors for solving CBF system. - Vector local_vector(dofs_per_cell); - Vector local_mass_matrix(dofs_per_cell); - - LinearAlgebra::BlockVector rhs_vector(this->introspection().index_sets.system_partitioning, this->get_mpi_communicator()); - // The mass matrix may be stored in a vector as it is a - // diagonal matrix. - LinearAlgebra::BlockVector mass_matrix(this->introspection().index_sets.system_partitioning, this->get_mpi_communicator()); - - LinearAlgebra::BlockVector distributed_topo_vector(this->introspection().index_sets.system_partitioning, this->get_mpi_communicator()); - - topo_vector.reinit(this->introspection().index_sets.system_partitioning, - this->introspection().index_sets.system_relevant_partitioning, - this->get_mpi_communicator()); - distributed_topo_vector = 0.; - topo_vector = 0.; - - // Possibly keep track of the dynamic topography values for - // later surface output. - std::vector, double>> stored_values_surface; - std::vector, double>> stored_values_bottom; - visualization_values.reinit(this->get_triangulation().n_active_cells()); - visualization_values = 0.; - - // Loop over all of the surface cells and if one less than h/3 away from - // one of the top or bottom boundaries, assemble CBF system for it. - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned() && cell->at_boundary()) - { - // see if the cell is at the *top* or *bottom* boundary, not just any boundary - unsigned int face_idx = numbers::invalid_unsigned_int; - for (const unsigned int f : cell->face_indices()) - { - if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) - { - // If the cell is at the top boundary, assign face_idx. - face_idx = f; - break; - } - else if (cell->at_boundary(f) && cell->face(f)->boundary_id() == bottom_boundary_id) - { - // If the cell is at the bottom boundary, assign face_idx. - face_idx = f; - break; - } - } - // If the cell is not at the boundary, jump to the next cell. - if (face_idx == numbers::invalid_unsigned_int) - continue; - - fe_volume_values.reinit (cell); - fe_face_values.reinit (cell, face_idx); - - local_vector = 0.; - local_mass_matrix = 0.; - - // Evaluate the material model in the cell volume. - MaterialModel::MaterialModelInputs in_volume(fe_volume_values, cell, this->introspection(), this->get_solution()); - MaterialModel::MaterialModelOutputs out_volume(fe_volume_values.n_quadrature_points, this->n_compositional_fields()); - in_volume.requested_properties = MaterialModel::MaterialProperties::density | MaterialModel::MaterialProperties::viscosity; - this->get_material_model().evaluate(in_volume, out_volume); - - // Get solution values for the divergence of the velocity, which is not - // computed by the material model. - fe_volume_values[this->introspection().extractors.velocities].get_function_divergences (this->get_solution(), div_solution); - - for (unsigned int q=0; qget_material_model().is_compressible(); - const Tensor<1,dim> gravity = this->get_gravity_model().gravity_vector(in_volume.position[q]); - - // Set up shape function values - for (unsigned int k=0; kintrospection().extractors.velocities].value(k,q); - epsilon_phi_u[k] = fe_volume_values[this->introspection().extractors.velocities].symmetric_gradient(k,q); - div_phi_u[k] = fe_volume_values[this->introspection().extractors.velocities].divergence (k, q); - } - - for (unsigned int i = 0; iintrospection().extractors.velocities].value(i,q) * - fe_face_values[this->introspection().extractors.velocities].value(i,q) * - fe_face_values.JxW(q); - - cell->distribute_local_to_global(local_vector, rhs_vector); - cell->distribute_local_to_global(local_mass_matrix, mass_matrix); - } - - rhs_vector.compress(VectorOperation::add); - mass_matrix.compress(VectorOperation::add); - - // Since the mass matrix is diagonal, we can just solve for the stress vector by dividing. - const IndexSet local_elements = mass_matrix.locally_owned_elements(); - for (unsigned int k=0; k 1.e-15) - distributed_topo_vector[global_index] = rhs_vector[global_index]/mass_matrix[global_index]; - } - distributed_topo_vector.compress(VectorOperation::insert); - topo_vector = distributed_topo_vector; - - // Now loop over the cells again and solve for the dynamic topography. - // We solve for it on the support points of the system, since it can be - // directly put into a system vector of the right size. - std::vector> face_support_points = this->get_fe().base_element(this->introspection().base_elements.temperature).get_unit_face_support_points(); - Quadrature support_quadrature(face_support_points); - FEFaceValues fe_support_values (this->get_mapping(), - this->get_fe(), - support_quadrature, - update_values | update_normal_vectors - | update_gradients | update_quadrature_points); - - std::vector> stress_support_values( support_quadrature.size() ); - std::vector topo_values( support_quadrature.size() ); - std::vector face_dof_indices (dofs_per_face); - - // Also construct data structures for getting the dynamic topography at the cell face - // midpoints. This is a more practical thing for text output and visualization. - const QGauss output_quadrature(quadrature_degree); - FEFaceValues fe_output_values (this->get_mapping(), - this->get_fe(), - output_quadrature, - update_values | update_normal_vectors | update_gradients | - update_quadrature_points | update_JxW_values); - std::vector> stress_output_values( output_quadrature.size() ); - - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned() && cell->at_boundary()) - { - // see if the cell is at the *top* boundary, not just any boundary - unsigned int face_idx = numbers::invalid_unsigned_int; - // if the face is at the upper surface 'at_upper_surface' will be true, if - // it is at the lower surface 'at_upper_surface' will be false. The default - // is true and will be changed to false if it's at the lower boundary. If the - // cell is at neither boundary the loop will continue to the next cell. - bool at_upper_surface = true; - for (const unsigned int f : cell->face_indices()) - { - if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) - { - // If the cell is at the top boundary, assign face_idx. - face_idx = f; - at_upper_surface = true; - break; - } - else if (cell->at_boundary(f) && cell->face(f)->boundary_id() == bottom_boundary_id) - { - // If the cell is at the bottom boundary, assign face_idx. - face_idx = f; - at_upper_surface = false; - break; - } - } - // If the cell is not at the boundary, jump to the next cell. - if (face_idx == numbers::invalid_unsigned_int) - continue; - - fe_support_values.reinit (cell, face_idx); - - // Evaluate the material model on the cell face. - MaterialModel::MaterialModelInputs in_support(fe_support_values, cell, this->introspection(), this->get_solution()); - MaterialModel::MaterialModelOutputs out_support(fe_support_values.n_quadrature_points, this->n_compositional_fields()); - in_support.requested_properties = MaterialModel::MaterialProperties::density; - this->get_material_model().evaluate(in_support, out_support); - - fe_support_values[this->introspection().extractors.velocities].get_function_values(topo_vector, stress_support_values); - cell->face(face_idx)->get_dof_indices (face_dof_indices); - for (unsigned int i = 0; i < face_dof_indices.size(); ++i) - { - // Given the face dof, we get the component and overall cell dof index. - const std::pair component_index = this->get_fe().face_system_to_component_index(i); - const unsigned int component = component_index.first; - const unsigned int support_index = component_index.second; - // Dynamic topography is stored in the temperature component. - if (component == this->introspection().component_indices.temperature) - { - // Compute the local gravity at the support point. - const Point point = fe_support_values.quadrature_point(support_index); - const double gravity_norm = this->get_gravity_model().gravity_vector(point).norm(); - const Tensor<1,dim> normal = fe_support_values.normal_vector(support_index); - - // Compute the dynamic topography, formulae are slightly different - // for upper and lower boundaries. - double dynamic_topography; - if (at_upper_surface) - { - const double delta_rho = out_support.densities[support_index] - density_above; - AssertThrow(std::abs(delta_rho) > std::numeric_limits::min(), - ExcMessage("delta_rho is close or equal to zero at the surface.")); - dynamic_topography = (-stress_support_values[support_index]*normal - surface_pressure) - / delta_rho / gravity_norm; - } - else - { - const double delta_rho = out_support.densities[support_index] - density_below; - AssertThrow(std::abs(delta_rho) > std::numeric_limits::min(), - ExcMessage("delta_rho is close or equal to zero at the bottom.")); - dynamic_topography = (-stress_support_values[support_index]*normal - bottom_pressure) - / delta_rho / gravity_norm; - } - distributed_topo_vector[face_dof_indices[i]] = dynamic_topography * (backward_advection ? -1. : 1.); - } - } - - // Also evaluate the dynamic topography on the cell faces. This is more convenient - // for ASCII output, as well as for use with the visualization postprocessor. - fe_output_values.reinit(cell, face_idx); - - // Evaluate the material model on the cell face. - MaterialModel::MaterialModelInputs in_output(fe_output_values, cell, this->introspection(), this->get_solution()); - MaterialModel::MaterialModelOutputs out_output(fe_output_values.n_quadrature_points, this->n_compositional_fields()); - in_output.requested_properties = MaterialModel::MaterialProperties::density; - this->get_material_model().evaluate(in_output, out_output); - - fe_output_values[this->introspection().extractors.velocities].get_function_values(topo_vector, stress_output_values); - - // Compute the average dynamic topography at the cell face. - double face_area = 0.; - double dynamic_topography = 0.; - for (unsigned int q=0; q < output_quadrature.size(); ++q) - { - const Point point = fe_output_values.quadrature_point(q); - const Tensor<1,dim> normal = fe_output_values.normal_vector(q); - const double gravity_norm = this->get_gravity_model().gravity_vector(point).norm(); - - if (at_upper_surface) - { - const double delta_rho = out_output.densities[q] - density_above; - dynamic_topography += (-stress_output_values[q]*normal - surface_pressure) - / delta_rho / gravity_norm * fe_output_values.JxW(q); - } - else - { - const double delta_rho = out_output.densities[q] - density_below; - - dynamic_topography += (-stress_output_values[q]*normal - bottom_pressure) - / delta_rho / gravity_norm * fe_output_values.JxW(q); - } - face_area += fe_output_values.JxW(q); - } - // Get the average dynamic topography for the cell - dynamic_topography = dynamic_topography * (backward_advection ? -1. : 1.) / face_area; - - // Maybe keep track of surface output vector. - const bool respect_manifold = true; - if (output_surface && at_upper_surface) - stored_values_surface.push_back(std::make_pair(cell->face(face_idx)->center(respect_manifold), dynamic_topography)); - // Maybe keep track of bottom output vector. - if (output_bottom && !at_upper_surface) - stored_values_bottom.push_back(std::make_pair(cell->face(face_idx)->center(respect_manifold), dynamic_topography)); - - // Add the value to the vector for the visualization postprocessor. - visualization_values(cell->active_cell_index()) = dynamic_topography; - } - distributed_topo_vector.compress(VectorOperation::insert); - topo_vector = distributed_topo_vector; - - // Possibly output the result to file. - if (output_surface) - output_to_file(top_boundary_id, stored_values_surface); - if (output_bottom) - output_to_file(bottom_boundary_id, stored_values_bottom); - - return std::pair("Computing dynamic topography", ""); - } - - /** - * Return the topography vector as calculated by CBF formulation - */ - template - const LinearAlgebra::BlockVector & - DynamicTopography:: - topography_vector() const - { - return topo_vector; - } - - /** - * Return the cellwise topography vector as calculated by CBF formulation - */ - template - const Vector & - DynamicTopography:: - cellwise_topography() const - { - return visualization_values; - } - - /** - * Register the other postprocessor that we need: BoundaryPressures - */ - template - std::list - DynamicTopography::required_other_postprocessors() const - { - return {"boundary pressures"}; - } - - - /** - * Output the dynamic topography solution to - * a file. - */ - template - void - DynamicTopography::output_to_file(const types::boundary_id boundary_id, - const std::vector,double>> &position_and_topography) - { - // get boundary name and avoid spaces for file output - std::string boundary_name = this->get_geometry_model().translate_id_to_symbol_name(boundary_id); - std::replace(boundary_name.begin(), boundary_name.end(), ' ', '_'); - - std::ostringstream output; - - // On processor 0, write header lines - if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - output << "# " - << ((dim==2)? "x y " : "x y z ") - << "dynamic_topography_" << boundary_name << std::endl; - } - - for (unsigned int i = 0; i < position_and_topography.size(); ++i) - { - output << std::setprecision(10) - << position_and_topography[i].first - << ' ' - << std::setprecision(10) - << position_and_topography[i].second - << std::endl; - } - - std::string filename = this->get_output_directory() + - "dynamic_topography_" + boundary_name + "." + - Utilities::int_to_string(this->get_timestep_number(), 5); - if (this->get_parameters().run_postprocessors_on_nonlinear_iterations) - filename.append("." + Utilities::int_to_string (this->get_nonlinear_iteration(), 4)); - - Utilities::collect_and_write_file_content(filename, output.str(), this->get_mpi_communicator()); - } - - - /** - * Declare the parameters for the postprocessor. - */ - template - void - DynamicTopography:: - declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Dynamic topography"); - { - prm.declare_entry ("Density above","0.", - Patterns::Double (0.), - "Dynamic topography is calculated as the excess or lack of mass that is supported by mantle flow. " - "This value depends on the density of material that is moved up or down, i.e. crustal rock, and the " - "density of the material that is displaced (generally water or air). While the density of crustal rock " - "is part of the material model, this parameter `Density above' allows the user to specify the density " - "value of material that is displaced above the solid surface. By default this material is assumed to " - "be air, with a density of 0. " - "Units: \\si{\\kilogram\\per\\meter\\cubed}."); - prm.declare_entry ("Density below","9900.", - Patterns::Double (0.), - "Dynamic topography is calculated as the excess or lack of mass that is supported by mantle flow. " - "This value depends on the density of material that is moved up or down, i.e. mantle above CMB, and the " - "density of the material that is displaced (generally outer core material). While the density of mantle rock " - "is part of the material model, this parameter `Density below' allows the user to specify the density " - "value of material that is displaced below the solid surface. By default this material is assumed to " - "be outer core material with a density of 9900. " - "Units: \\si{\\kilogram\\per\\meter\\cubed}."); - prm.declare_entry ("Output surface", "true", - Patterns::Bool(), - "Whether to output a file containing the surface dynamic topography."); - prm.declare_entry ("Output bottom", "true", - Patterns::Bool(), - "Whether to output a file containing the bottom (i.e., CMB) dynamic topography."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - /** - * Declare the parameters for the postprocessor. - */ - template - void - DynamicTopography::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Dynamic topography"); - { - density_above = prm.get_double ("Density above"); - density_below = prm.get_double ("Density below"); - output_surface = prm.get_bool ("Output surface"); - output_bottom = prm.get_bool ("Output bottom"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(DynamicTopography, - "dynamic topography", - "A postprocessor that computes a measure of dynamic topography " - "based on the stress at the boundary. The data is written into text " - "files named `dynamic\\_topography_\\X.NNNNN' in the output directory, " - "where X is the name of the boundary and NNNNN is the number of the time step." - "\n\n" - "The exact approach works as follows: At each selected boundary, we compute " - "the traction that acts normal to the boundary faces using the " - "consistent boundary flux method as described in " - "``Gresho, Lee, Sani, Maslanik, Eaton (1987). " - "The consistent Galerkin FEM for computing derived boundary " - "quantities in thermal and or fluids problems. International " - "Journal for Numerical Methods in Fluids, 7(4), 371-394.'' " - "From this traction, the dynamic topography is computed using the formula " - "$h=\\frac{\\sigma_{n}}{g \\rho}$ where $g$ is the norm of the gravity and $\\rho$ " - "is the density. For the bottom surface we chose the convention " - "that positive values are up and negative values are down, analogous to " - "the deformation of the upper surface. Note that this implementation takes " - "the direction of gravity into account, which means that reversing the flow " - "in backward advection calculations will not reverse the instantaneous topography " - "because the reverse flow will be divided by the reverse surface gravity. " - "\n" - "The file format then consists of lines with Euclidean coordinates " - "followed by the corresponding topography value.") - } -} diff --git a/source/postprocess/entropy_viscosity_statistics.cc.bak b/source/postprocess/entropy_viscosity_statistics.cc.bak deleted file mode 100644 index 0df4a943994..00000000000 --- a/source/postprocess/entropy_viscosity_statistics.cc.bak +++ /dev/null @@ -1,118 +0,0 @@ -/* - Copyright (C) 2019 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - EntropyViscosityStatistics::execute (TableHandler &statistics) - { - Vector entropy_viscosity(this->get_triangulation().n_active_cells()); - this->get_artificial_viscosity(entropy_viscosity); - - // The entropy viscosity is cell-wise constant, so a simple midpoint quadrature - // will be sufficient to integrate the value over cells. - const QMidpoint quadrature_formula; - const unsigned int n_q_points = quadrature_formula.size(); - - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_JxW_values); - - double local_maximum_viscosity = 0.0; - double local_integrated_viscosity = 0.0; - double local_volume = 0.0; - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit (cell); - - for (unsigned int q = 0; q < n_q_points; ++q) - { - const double entropy_viscosity_cell = entropy_viscosity[cell->active_cell_index()]; - local_maximum_viscosity = std::max(local_maximum_viscosity,entropy_viscosity_cell); - local_volume += fe_values.JxW(q); - local_integrated_viscosity += entropy_viscosity_cell * fe_values.JxW(q); - } - } - - const double global_integrated_viscosity - = Utilities::MPI::sum (local_integrated_viscosity, this->get_mpi_communicator()); - const double global_integrated_volume - = Utilities::MPI::sum (local_volume, this->get_mpi_communicator()); - const double global_maximum_viscosity - = Utilities::MPI::max (local_maximum_viscosity, this->get_mpi_communicator()); - - const double average_viscosity = global_integrated_viscosity / global_integrated_volume; - - statistics.add_value ("Max entropy viscosity (W/(m*K))", - global_maximum_viscosity); - statistics.add_value ("Average entropy viscosity (W/(m*K))", - average_viscosity); - - // also make sure that the columns filled by this plugin - // show up with sufficient accuracy and in scientific notation - const char *columns[] = { "Max entropy viscosity (W/(m*K))", - "Average entropy viscosity (W/(m*K))" - }; - for (auto &column : columns) - { - statistics.set_precision (column, 8); - statistics.set_scientific (column, true); - } - - std::ostringstream output; - output.precision(3); - output << global_maximum_viscosity - << " W/(m*K), " - << average_viscosity - << " W/(m*K)"; - - - return std::pair ("Max / average entropy viscosity:", - output.str()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(EntropyViscosityStatistics, - "entropy viscosity statistics", - "A postprocessor that computes the maximum and volume averaged" - "entropy viscosity stabilization for the temperature field.") - } -} diff --git a/source/postprocess/geoid.cc.bak b/source/postprocess/geoid.cc.bak deleted file mode 100644 index 96789262ce4..00000000000 --- a/source/postprocess/geoid.cc.bak +++ /dev/null @@ -1,1060 +0,0 @@ -/* - Copyright (C) 2015 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair,std::vector> - Geoid::to_spherical_harmonic_coefficients(const std::vector> &spherical_function) const - { - std::vector cosi(spherical_function.size(),0); - std::vector sini(spherical_function.size(),0); - std::vector coecos; - std::vector coesin; - - for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) - { - for (unsigned int iord = 0; iord < ideg+1; ++iord) - { - // Do the spherical harmonic expansion. - for (unsigned int ds_num = 0; ds_num < spherical_function.size(); ++ds_num) - { - // Normalization after Dahlen and Tromp (1986) Appendix B.6. - const std::pair sph_harm_vals = aspect::Utilities::real_spherical_harmonic(ideg,iord,spherical_function.at(ds_num).at(0),spherical_function.at(ds_num).at(1)); - const double cos_component = sph_harm_vals.first; // real / cos part - const double sin_component = sph_harm_vals.second; // imaginary / sin part - - cosi.at(ds_num) = (spherical_function.at(ds_num).at(3) * cos_component); - sini.at(ds_num) = (spherical_function.at(ds_num).at(3) * sin_component); - } - // Integrate the contribution of each spherical infinitesimal. - double cosii = 0; - double sinii = 0; - for (unsigned int ds_num = 0; ds_num < spherical_function.size(); ++ds_num) - { - cosii += cosi.at(ds_num) * spherical_function.at(ds_num).at(2); - sinii += sini.at(ds_num) * spherical_function.at(ds_num).at(2); - } - coecos.push_back(cosii); - coesin.push_back(sinii); - } - } - // Sum over each processor. - dealii::Utilities::MPI::sum (coecos,this->get_mpi_communicator(),coecos); - dealii::Utilities::MPI::sum (coesin,this->get_mpi_communicator(),coesin); - - return std::make_pair(coecos,coesin); - } - - template - std::pair,std::vector> - Geoid::density_contribution (const double &/*outer_radius*/) const - { - Assert(false, ExcNotImplemented()); - return std::make_pair(std::vector(), std::vector()); - - } - - template <> - std::pair,std::vector> - Geoid<3>::density_contribution (const double &outer_radius) const - { - const unsigned int quadrature_degree = this->introspection().polynomial_degree.temperature; - - // Need to evaluate density contribution of each volume quadrature point. - const QGauss<3> quadrature_formula(quadrature_degree); - - FEValues<3> fe_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_quadrature_points | - update_JxW_values | - update_gradients); - - MaterialModel::MaterialModelInputs<3> in(fe_values.n_quadrature_points, this->n_compositional_fields()); - MaterialModel::MaterialModelOutputs<3> out(fe_values.n_quadrature_points, this->n_compositional_fields()); - in.requested_properties = MaterialModel::MaterialProperties::density; - - std::vector> - composition_values(this->n_compositional_fields(), std::vector(quadrature_formula.size())); - - // Directly do the global 3d integral over each quadrature point of every cell (different from traditional way to do layer integral). - // This is necessary because of ASPECT's adaptive mesh refinement feature. - std::vector SH_density_coecos; - std::vector SH_density_coesin; - for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) - { - for (unsigned int iord = 0; iord < ideg+1; ++iord) - { - // Initialization of the density contribution integral per degree, order. - double integrated_density_cos_component = 0; - double integrated_density_sin_component = 0; - - // Loop over all of the cells. - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit (cell); - // Set use_strain_rates to false since we don't need viscosity. - in.reinit(fe_values, cell, this->introspection(), this->get_solution()); - - this->get_material_model().evaluate(in, out); - - // Compute the integral of the density function - // over the cell, by looping over all quadrature points. - for (unsigned int q=0; q scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(in.position[q]); - - // Normalization after Dahlen and Tromp (1986) Appendix B.6. - const std::pair sph_harm_vals = aspect::Utilities::real_spherical_harmonic(ideg,iord,scoord[2],scoord[1]); - const double cos_component = sph_harm_vals.first; // real / cos part - const double sin_component = sph_harm_vals.second; // imaginary / sin part - - const double density = out.densities[q]; - const double r_q = in.position[q].norm(); - - integrated_density_cos_component += density * (1./r_q) * std::pow(r_q/outer_radius,ideg+1) * cos_component * fe_values.JxW(q); - integrated_density_sin_component += density * (1./r_q) * std::pow(r_q/outer_radius,ideg+1) * sin_component * fe_values.JxW(q); - } - } - SH_density_coecos.push_back(integrated_density_cos_component); - SH_density_coesin.push_back(integrated_density_sin_component); - } - } - // Sum over each processor. - dealii::Utilities::MPI::sum (SH_density_coecos,this->get_mpi_communicator(),SH_density_coecos); - dealii::Utilities::MPI::sum (SH_density_coesin,this->get_mpi_communicator(),SH_density_coesin); - - return std::make_pair(SH_density_coecos,SH_density_coesin); - } - - template - std::pair,std::vector>>, std::pair,std::vector>>> - Geoid::topography_contribution(const double &/*outer_radius*/, - const double &/*inner_radius*/) const - { - Assert(false, ExcNotImplemented()); - std::pair,std::vector>> temp; - return std::make_pair(temp, temp); - } - - template <> - std::pair,std::vector>>, std::pair,std::vector>>> - Geoid<3>::topography_contribution(const double &outer_radius, - const double &inner_radius) const - { - // Get a pointer to the boundary densities postprocessor. - const Postprocess::BoundaryDensities<3> &boundary_densities = - this->get_postprocess_manager().template get_matching_postprocessor>(); - - const double top_layer_average_density = boundary_densities.density_at_top(); - const double bottom_layer_average_density = boundary_densities.density_at_bottom(); - - const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); - const types::boundary_id bottom_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); - - const unsigned int quadrature_degree = this->introspection().polynomial_degree.temperature; - const QGauss<2> quadrature_formula_face(quadrature_degree); - - FEFaceValues<3> fe_face_values (this->get_mapping(), - this->get_fe(), - quadrature_formula_face, - update_values | - update_quadrature_points | - update_JxW_values); - - // Vectors to store the location, infinitesimal area, and topography associated with each quadrature point of each surface and bottom cell respectively. - std::vector,std::pair>> surface_stored_values; - std::vector,std::pair>> CMB_stored_values; - - // Loop over all of the boundary cells and if one is at - // surface or CMB, evaluate the topography vector there. - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned() && cell->at_boundary()) - { - unsigned int face_idx = numbers::invalid_unsigned_int; - bool at_upper_surface = false; - { - for (const unsigned int f : cell->face_indices()) - { - if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) - { - // If the cell is at the top boundary, assign face_idx. - face_idx = f; - at_upper_surface = true; - break; - } - else if (cell->at_boundary(f) && cell->face(f)->boundary_id() == bottom_boundary_id) - { - // If the cell is at the bottom boundary, assign face_idx. - face_idx = f; - at_upper_surface = false; - break; - } - } - // If the cell is not at the boundary, jump to the next cell. - if (face_idx == numbers::invalid_unsigned_int) - continue; - } - - // Focus on the boundary cell's upper face if on the top boundary and lower face if on the bottom boundary. - fe_face_values.reinit(cell, face_idx); - - // Topography is evaluated at each quadrature - // point on every top/bottom cell's boundary face. The - // reason to do this -- as opposed to using a single - // value per boundary face -- is that later in the - // spherical harmonic expansion, we will calculate - // sin(theta)*d_theta*d_phi by - // infinitesimal_area/radius^2. The accuracy of this - // transfer gets better as infinitesimal_area gets - // closer to zero, so using every boundary quadrature - // point's associated area (in the form of - // FEFaceValues::JxW) will lead to better accuracy in - // spherical harmonic expansion compared to using just - // one average value per face, especially in the coarse - // meshes. - - // If the cell is at the top boundary, add its contributions to the topography surface storage vector. - if (at_upper_surface) - { - if (include_surface_topo_contribution == true) - { - if (use_free_surface_topography == true) - { - for (unsigned int q=0; q current_position = fe_face_values.quadrature_point(q); - const double topography = this->get_geometry_model().height_above_reference_surface(current_position); - surface_stored_values.emplace_back (current_position, std::make_pair(fe_face_values.JxW(q), topography)); - } - } - else - { - // Get a reference to the dynamic topography postprocessor. - const Postprocess::DynamicTopography<3> &dynamic_topography = - this->get_postprocess_manager().template get_matching_postprocessor>(); - - // Get the already-computed dynamic topography solution. - const LinearAlgebra::BlockVector &topo_vector = dynamic_topography.topography_vector(); - - std::vector topo_values(quadrature_formula_face.size()); - - fe_face_values[this->introspection().extractors.temperature].get_function_values(topo_vector, topo_values); - - for (unsigned int q=0; q current_position = fe_face_values.quadrature_point(q); - const double topography = this->get_geometry_model().height_above_reference_surface(current_position) + (outer_radius - inner_radius); - CMB_stored_values.emplace_back (current_position, std::make_pair(fe_face_values.JxW(q), topography)); - } - } - else - { - // Get a reference to the dynamic topography postprocessor. - const Postprocess::DynamicTopography<3> &dynamic_topography = - this->get_postprocess_manager().template get_matching_postprocessor>(); - - // Get the already-computed dynamic topography solution. - const LinearAlgebra::BlockVector &topo_vector = dynamic_topography.topography_vector(); - - std::vector topo_values(quadrature_formula_face.size()); - - fe_face_values[this->introspection().extractors.temperature].get_function_values(topo_vector, topo_values); - - for (unsigned int q=0; q> surface_topo_spherical_function; - std::vector> CMB_topo_spherical_function; - - for (const auto &surface_stored_value : surface_stored_values) - { - const std::array scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(surface_stored_value.first); - - // Calculate spherical infinitesimal sin(theta)*d_theta*d_phi by infinitesimal_area/radius^2 - const double infinitesimal = surface_stored_value.second.first/(outer_radius*outer_radius); - - // Theta, phi, spherical infinitesimal, and surface topography - surface_topo_spherical_function.emplace_back(std::vector {scoord[2], - scoord[1], - infinitesimal, - surface_stored_value.second.second - }); - } - - for (const auto &CMB_stored_value : CMB_stored_values) - { - const std::array scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(CMB_stored_value.first); - - // Calculate spherical infinitesimal sin(theta)*d_theta*d_phi by infinitesimal_area/radius^2 - const double infinitesimal = CMB_stored_value.second.first/(inner_radius*inner_radius); - - // Theta, phi, spherical infinitesimal, and CMB dynamic topography - CMB_topo_spherical_function.emplace_back(std::vector {scoord[2], - scoord[1], - infinitesimal, - CMB_stored_value.second.second - }); - } - - std::pair,std::vector>> SH_surface_topo_coes - = std::make_pair(top_layer_average_density,to_spherical_harmonic_coefficients(surface_topo_spherical_function)); - std::pair,std::vector>> SH_CMB_topo_coes - = std::make_pair(bottom_layer_average_density,to_spherical_harmonic_coefficients(CMB_topo_spherical_function)); - return std::make_pair(SH_surface_topo_coes,SH_CMB_topo_coes); - } - - - template - std::pair - Geoid::execute (TableHandler &) - { - // Current geoid code only works for spherical shell geometry. - AssertThrow (Plugins::plugin_type_matches>(this->get_geometry_model()) - && - dim == 3, - ExcMessage("The geoid postprocessor is currently only implemented for the 3d spherical shell geometry model.")); - - const GeometryModel::SphericalShell &geometry_model = - Plugins::get_plugin_as_type> (this->get_geometry_model()); - - // Get the value of the outer radius and inner radius. - const double outer_radius = geometry_model.outer_radius(); - const double inner_radius = geometry_model.inner_radius(); - - const types::boundary_id top_boundary_id = geometry_model.translate_symbolic_boundary_name_to_id("top"); - - // Get the value of the surface gravity acceleration from the gravity model. - Point surface_point; - surface_point[0] = outer_radius; - const double surface_gravity = this->get_gravity_model().gravity_vector(surface_point).norm(); - - // Get the value of the universal gravitational constant. - const double G = aspect::constants::big_g; - - // Get the spherical harmonic coefficients of the density contribution. - std::pair,std::vector> SH_density_coes = density_contribution(outer_radius); - std::pair,std::vector>> SH_surface_topo_coes; - std::pair,std::vector>> SH_CMB_topo_coes; - - // Initialize the surface and CMB density contrasts with NaNs because they may be unused in case of no topography contribution. - double surface_delta_rho = numbers::signaling_nan(); - double CMB_delta_rho = numbers::signaling_nan(); - - // Get the spherical harmonic coefficients of the surface and CMB topography. - std::pair,std::vector>>, std::pair,std::vector>>> SH_topo_coes; - SH_topo_coes = topography_contribution(outer_radius,inner_radius); - SH_surface_topo_coes = SH_topo_coes.first; - SH_CMB_topo_coes = SH_topo_coes.second; - - // Get the density contrast at the surface and CMB to replace the initialized NaN values. - // The surface and CMB density contrasts will be used later to calculate geoid, - // and the spherical harmonic output of the surface and CMB topography contribution to geoid. - surface_delta_rho = SH_surface_topo_coes.first - density_above; - CMB_delta_rho = density_below - SH_CMB_topo_coes.first; - - // Compute the spherical harmonic coefficients of geoid anomaly. - std::vector density_anomaly_contribution_coecos; - std::vector density_anomaly_contribution_coesin; - std::vector surface_topo_contribution_coecos; - std::vector surface_topo_contribution_coesin; - std::vector CMB_topo_contribution_coecos; - std::vector CMB_topo_contribution_coesin; - geoid_coecos.clear(); - geoid_coesin.clear(); - - // First compute the spherical harmonic contributions from density anomaly, surface topography and CMB topography. - int ind = 0; // coefficients index - for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) - { - for (unsigned int iord = 0; iord < ideg+1; ++iord) - { - double coecos_density_anomaly = (4 * numbers::PI * G / (surface_gravity * (2 * ideg + 1))) * SH_density_coes.first.at(ind); - double coesin_density_anomaly = (4 * numbers::PI * G / (surface_gravity * (2 * ideg + 1))) * SH_density_coes.second.at(ind); - density_anomaly_contribution_coecos.push_back(coecos_density_anomaly); - density_anomaly_contribution_coesin.push_back(coesin_density_anomaly); - - if (include_surface_topo_contribution == true || include_CMB_topo_contribution == true) - { - const double coecos_surface_topo = (4 * numbers::PI * G / (surface_gravity * (2 * ideg + 1))) - * surface_delta_rho*SH_surface_topo_coes.second.first.at(ind)*outer_radius; - const double coesin_surface_topo = (4 * numbers::PI * G / (surface_gravity * (2 * ideg + 1))) - * surface_delta_rho*SH_surface_topo_coes.second.second.at(ind)*outer_radius; - surface_topo_contribution_coecos.push_back(coecos_surface_topo); - surface_topo_contribution_coesin.push_back(coesin_surface_topo); - - const double coecos_CMB_topo = (4 * numbers::PI * G / (surface_gravity * (2 * ideg + 1))) - * CMB_delta_rho*SH_CMB_topo_coes.second.first.at(ind)*inner_radius*std::pow(inner_radius/outer_radius,ideg+1); - const double coesin_CMB_topo = (4 * numbers::PI * G / (surface_gravity * (2 * ideg + 1))) - * CMB_delta_rho*SH_CMB_topo_coes.second.second.at(ind)*inner_radius*std::pow(inner_radius/outer_radius,ideg+1); - CMB_topo_contribution_coecos.push_back(coecos_CMB_topo); - CMB_topo_contribution_coesin.push_back(coesin_CMB_topo); - - } - - ++ind; - } - } - - // Then sum the three contributions together to get the spherical harmonic coefficients of geoid anomaly. - ind = 0; // coefficients index - for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) - { - for (unsigned int iord = 0; iord < ideg+1; ++iord) - { - if (include_surface_topo_contribution == true || include_CMB_topo_contribution == true) - { - geoid_coecos.push_back(density_anomaly_contribution_coecos.at(ind)+surface_topo_contribution_coecos.at(ind)+CMB_topo_contribution_coecos.at(ind)); - geoid_coesin.push_back(density_anomaly_contribution_coesin.at(ind)+surface_topo_contribution_coesin.at(ind)+CMB_topo_contribution_coesin.at(ind)); - } - else - { - geoid_coecos.push_back(density_anomaly_contribution_coecos.at(ind)); - geoid_coesin.push_back(density_anomaly_contribution_coesin.at(ind)); - } - - ind += 1; - } - } - - const QMidpoint quadrature_formula_face_center; - Assert(quadrature_formula_face_center.size() == 1, ExcInternalError()); - FEFaceValues fe_face_center_values (this->get_mapping(), - this->get_fe(), - quadrature_formula_face_center, - update_values | - update_quadrature_points| - update_JxW_values); - - // Define a vector to store the location of the cells along the surface. - std::vector> surface_cell_locations; - - // Loop over all the cells to get the locations of the surface cells to prepare for the geoid computation. - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned() && cell->at_boundary()) - { - // If the cell is at the top boundary, store the cell's upper face midpoint location. - for (const unsigned int f : cell->face_indices()) - if (cell->at_boundary(f) && cell->face(f)->boundary_id() == top_boundary_id) - { - fe_face_center_values.reinit(cell,f); - const Point midpoint_at_top_face = fe_face_center_values.get_quadrature_points().at(0); - surface_cell_locations.push_back(midpoint_at_top_face); - break; - } - } - - // Transfer the geocentric coordinates of the surface cells to the surface spherical coordinates (theta,phi) - std::vector> surface_cell_spherical_coordinates; - for (unsigned int i=0; i scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(surface_cell_locations.at(i)); - const double phi = scoord[1]; - const double theta = scoord[2]; - surface_cell_spherical_coordinates.emplace_back(theta,phi); - } - - // Compute the grid geoid anomaly based on spherical harmonics. - std::vector geoid_anomaly; - for (const auto &surface_cell_spherical_coordinate : surface_cell_spherical_coordinates) - { - int ind = 0; - double geoid_value = 0; - for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) - { - for (unsigned int iord = 0; iord < ideg+1; ++iord) - { - // Normalization after Dahlen and Tromp (1986) Appendix B.6. - const std::pair sph_harm_vals = aspect::Utilities::real_spherical_harmonic(ideg,iord,surface_cell_spherical_coordinate.first,surface_cell_spherical_coordinate.second); - const double cos_component = sph_harm_vals.first; // real / cos part - const double sin_component = sph_harm_vals.second; // imaginary / sin part - - geoid_value += geoid_coecos.at(ind)*cos_component+geoid_coesin.at(ind)*sin_component; - ++ind; - } - } - geoid_anomaly.push_back(geoid_value); - } - - // The user can get the spherical harmonic coefficients of the density anomaly contribution if needed - if (output_density_anomaly_contribution_SH_coes == true) - { - // Have a stream into which we write the SH coefficients data from density anomaly contribution. - // The text stream is then later sent to processor 0. - std::ostringstream output_density_anomaly_contribution_SH_coes; - - // Prepare the output SH coefficients data from density anomaly contribution. - unsigned int SH_coes_ind = 0; - for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) - { - for (unsigned int iord = 0; iord < ideg+1; ++iord) - { - output_density_anomaly_contribution_SH_coes << ideg - << ' ' - << iord - << ' ' - << density_anomaly_contribution_coecos.at(SH_coes_ind) - << ' ' - << density_anomaly_contribution_coesin.at(SH_coes_ind) - << std::endl; - ++SH_coes_ind; - } - } - - const std::string density_anomaly_contribution_SH_coes_filename = this->get_output_directory() + - "density_anomaly_contribution_SH_coefficients." + - dealii::Utilities::int_to_string(this->get_timestep_number(), 5); - - // Because each processor already held all the SH coefficients from density anomaly contribution, we only need to stop by the processor 0 to get the data. - // On processor 0, collect all the data and put them into the output density anomaly contribution SH coefficients file. - if (dealii::Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - std::ofstream density_anomaly_contribution_SH_coes_file (density_anomaly_contribution_SH_coes_filename); - density_anomaly_contribution_SH_coes_file << "# " - << "degree order cosine_coefficient sine_coefficient" - << std::endl; - - // Write out the data on processor 0. - density_anomaly_contribution_SH_coes_file << output_density_anomaly_contribution_SH_coes.str(); - } - } - - // The user can get the spherical harmonic coefficients of the surface topography contribution if needed - if (output_surface_topo_contribution_SH_coes == true) - { - // Have a stream into which we write the SH coefficients data from surface topography contribution. - // The text stream is then later sent to processor 0. - std::ostringstream output_surface_topo_contribution_SH_coes; - - // Prepare the output SH coefficients data from surface topography contribution. - unsigned int SH_coes_ind = 0; - for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) - { - for (unsigned int iord = 0; iord < ideg+1; ++iord) - { - output_surface_topo_contribution_SH_coes << ideg - << ' ' - << iord - << ' ' - << surface_topo_contribution_coecos.at(SH_coes_ind) - << ' ' - << surface_topo_contribution_coesin.at(SH_coes_ind) - << std::endl; - ++SH_coes_ind; - } - } - - const std::string surface_topo_contribution_SH_coes_filename = this->get_output_directory() + - "surface_topography_contribution_SH_coefficients." + - dealii::Utilities::int_to_string(this->get_timestep_number(), 5); - - // Because each processor already held all the SH coefficients from surface topography contribution, - // we only need to stop by the processor 0 to get the data. On processor 0, collect all the data - // and put them into the output surface topography contribution SH coefficients file. - if (dealii::Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - std::ofstream surface_topo_contribution_SH_coes_file (surface_topo_contribution_SH_coes_filename); - surface_topo_contribution_SH_coes_file << "# " - << "degree order cosine_coefficient sine_coefficient" - << std::endl; - std::ostringstream output_surface_delta_rho; - output_surface_delta_rho << surface_delta_rho; - surface_topo_contribution_SH_coes_file << "surface density contrast(kg/m^3): " - << output_surface_delta_rho.str() - << std::endl; - // Write out the data on processor 0 - surface_topo_contribution_SH_coes_file << output_surface_topo_contribution_SH_coes.str(); - } - } - - // The user can get the spherical harmonic coefficients of the CMB topography contribution if needed. - if (output_CMB_topo_contribution_SH_coes == true) - { - // Have a stream into which we write the SH coefficients data from CMB topography contribution. - // The text stream is then later sent to processor 0. - std::ostringstream output_CMB_topo_contribution_SH_coes; - - // Prepare the output SH coefficients data from CMB topography contribution. - unsigned int SH_coes_ind = 0; - for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) - { - for (unsigned int iord = 0; iord < ideg+1; ++iord) - { - output_CMB_topo_contribution_SH_coes << ideg - << ' ' - << iord - << ' ' - << CMB_topo_contribution_coecos.at(SH_coes_ind) - << ' ' - << CMB_topo_contribution_coesin.at(SH_coes_ind) - << std::endl; - ++SH_coes_ind; - } - } - - const std::string CMB_topo_contribution_SH_coes_filename = this->get_output_directory() + - "CMB_topography_contribution_SH_coefficients." + - dealii::Utilities::int_to_string(this->get_timestep_number(), 5); - - // Because each processor already held all the SH coefficients from CMB topography contribution, we only need to stop by the processor 0 - // to get the data. On processor 0, collect all the data and put them into the output CMB topography contribution SH coefficients file. - if (dealii::Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - std::ofstream CMB_topo_contribution_SH_coes_file (CMB_topo_contribution_SH_coes_filename); - CMB_topo_contribution_SH_coes_file << "# " - << "degree order cosine_coefficient sine_coefficient" - << std::endl; - std::ostringstream output_CMB_delta_rho; - output_CMB_delta_rho << CMB_delta_rho; - CMB_topo_contribution_SH_coes_file << "CMB density contrast(kg/m^3): " - << output_CMB_delta_rho.str() - << std::endl; - // Write out the data on processor 0 - CMB_topo_contribution_SH_coes_file << output_CMB_topo_contribution_SH_coes.str(); - } - } - - // The user can get the spherical harmonic coefficients of the geoid anomaly if needed. - if (output_geoid_anomaly_SH_coes == true) - { - // Have a stream into which we write the geoid anomaly SH coefficients data. - // The text stream is then later sent to processor 0. - std::ostringstream output_geoid_anomaly_SH_coes; - - // Prepare the output geoid anomaly SH coefficients data. - unsigned int SH_coes_ind = 0; - for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) - { - for (unsigned int iord = 0; iord < ideg+1; ++iord) - { - output_geoid_anomaly_SH_coes << ideg - << ' ' - << iord - << ' ' - << geoid_coecos.at(SH_coes_ind) - << ' ' - << geoid_coesin.at(SH_coes_ind) - << std::endl; - ++SH_coes_ind; - } - } - - const std::string geoid_anomaly_SH_coes_filename = this->get_output_directory() + - "geoid_anomaly_SH_coefficients." + - dealii::Utilities::int_to_string(this->get_timestep_number(), 5); - - // Because each processor already held all the geoid anomaly SH coefficients, we only need to stop by the processor 0 to get the data. - // On processor 0, collect all the data and put them into the output geoid anomaly SH coefficients file. - if (dealii::Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - std::ofstream geoid_anomaly_SH_coes_file (geoid_anomaly_SH_coes_filename); - geoid_anomaly_SH_coes_file << "# " - << "degree order cosine_coefficient sine_coefficient" - << std::endl; - - // Write out the data on processor 0. - geoid_anomaly_SH_coes_file << output_geoid_anomaly_SH_coes.str(); - } - } - - // Have a stream into which we write the geoid height data. the text stream is then - // later sent to processor 0. - std::ostringstream output; - - // On processor 0, write the header lines - if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - output << "# " - << ((output_in_lat_lon == true)? "longitude latitude" : "x y z") - << " geoid_anomaly" << std::endl; - } - - // Prepare the output data. - if (output_in_lat_lon == true) - { - double lon, lat; - for (unsigned int i=0; iget_output_directory() + - "geoid_anomaly." + - dealii::Utilities::int_to_string(this->get_timestep_number(), 5); - - Utilities::collect_and_write_file_content(filename, output.str(), this->get_mpi_communicator()); - - // Prepare the free-air gravity anomaly output. - if (output_gravity_anomaly == true) - { - // Have a stream into which we write the gravity anomaly data. the text stream is then - // later sent to processor 0. - std::ostringstream output_gravity_anomaly; - - // On processor 0, write the header lines: - if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - output_gravity_anomaly << "# " - << ((output_in_lat_lon == true)? "longitude latitude" : "x y z") - << " gravity_anomaly" << std::endl; - } - - // Compute the grid gravity anomaly based on spherical harmonics. - std::vector gravity_anomaly; - gravity_anomaly.reserve(surface_cell_spherical_coordinates.size()); - - for (const auto &surface_cell_spherical_coordinate : surface_cell_spherical_coordinates) - { - int ind = 0; - double gravity_value = 0; - for (unsigned int ideg = min_degree; ideg < max_degree+1; ++ideg) - { - for (unsigned int iord = 0; iord < ideg+1; ++iord) - { - // Normalization after Dahlen and Tromp (1986) Appendix B.6. - const std::pair sph_harm_vals = aspect::Utilities::real_spherical_harmonic(ideg,iord,surface_cell_spherical_coordinate.first,surface_cell_spherical_coordinate.second); - const double cos_component = sph_harm_vals.first; // real / cos part - const double sin_component = sph_harm_vals.second; // imaginary / sin part - - // The conversion from geoid to gravity anomaly is given by gravity_anomaly = (l-1)*g/R_surface * geoid_anomaly - // based on Forte (2007) equation [97]. - gravity_value += (geoid_coecos.at(ind)*cos_component+geoid_coesin.at(ind)*sin_component) * (ideg - 1) * surface_gravity / outer_radius; - ++ind; - } - } - gravity_anomaly.push_back(gravity_value); - } - - // Prepare the output data. - if (output_in_lat_lon == true) - { - double lon, lat; - for (unsigned int i=0; iget_output_directory() + - "gravity_anomaly." + - dealii::Utilities::int_to_string(this->get_timestep_number(), 5); - - Utilities::collect_and_write_file_content(filename, output_gravity_anomaly.str(), this->get_mpi_communicator()); - } - - return std::pair("Writing geoid anomaly:", - filename); - } - - template - std::list - Geoid::required_other_postprocessors() const - { - std::list deps; - - if ( (include_surface_topo_contribution == true && use_free_surface_topography == false) || (include_CMB_topo_contribution == true && use_free_CMB_topography == false) ) - deps.emplace_back("dynamic topography"); - - deps.emplace_back("boundary densities"); - - return deps; - } - - template - double - Geoid::evaluate (const Point &/*p*/) const - { - Assert(false, ExcNotImplemented()); - return 0; - } - - template <> - double - Geoid<3>::evaluate (const Point<3> &p) const - { - const std::array scoord = aspect::Utilities::Coordinates::cartesian_to_spherical_coordinates(p); - const double theta = scoord[2]; - const double phi = scoord[1]; - double value = 0.; - - for (unsigned int ideg=min_degree, k=0; ideg < max_degree+1; ++ideg) - for (unsigned int iord = 0; iord < ideg+1; ++iord, ++k) - { - std::pair val = aspect::Utilities::real_spherical_harmonic( ideg, iord, theta, phi ); - - value += geoid_coecos[k] * val.first + - geoid_coesin[k] * val.second; - - } - return value; - } - - template - void - Geoid::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Geoid"); - { - prm.declare_entry("Include surface topography contribution", "true", - Patterns::Bool(), - "Option to include the contribution from surface topography on geoid. The default is true."); - prm.declare_entry("Include CMB topography contribution", "true", - Patterns::Bool(), - "Option to include the contribution from CMB topography on geoid. The default is true."); - prm.declare_entry("Maximum degree","20", - Patterns::Integer (0), - "This parameter can be a random positive integer. However, the value normally should not exceed the maximum " - "degree of the initial perturbed temperature field. For example, if the initial temperature uses S40RTS, the " - "maximum degree should not be larger than 40."); - prm.declare_entry("Minimum degree","2", - Patterns::Integer (0), - "This parameter normally is set to 2 since the perturbed gravitational potential at degree 1 always vanishes " - "in a reference frame with the planetary center of mass same as the center of figure."); - prm.declare_entry("Output data in geographical coordinates", "false", - Patterns::Bool(), - "Option to output the geoid anomaly in geographical coordinates (latitude and longitude). " - "The default is false, so the postprocessor will output the data in geocentric coordinates (x,y,z) as normally."); - prm.declare_entry("Density above","0.", - Patterns::Double (0.), - "The density value above the surface boundary."); - prm.declare_entry("Density below","9900.", - Patterns::Double (0.), - "The density value below the CMB boundary."); - prm.declare_entry("Output geoid anomaly coefficients", "false", - Patterns::Bool(), - "Option to output the spherical harmonic coefficients of the geoid anomaly up to the maximum degree. " - "The default is false, so the postprocessor will only output the geoid anomaly in grid format. "); - prm.declare_entry("Output surface topography contribution coefficients", "false", - Patterns::Bool(), - "Option to output the spherical harmonic coefficients of the surface topography contribution " - "to the maximum degree. The default is false. "); - prm.declare_entry("Output CMB topography contribution coefficients", "false", - Patterns::Bool(), - "Option to output the spherical harmonic coefficients of the CMB topography contribution " - "to the maximum degree. The default is false. "); - prm.declare_entry("Output density anomaly contribution coefficients", "false", - Patterns::Bool(), - "Option to output the spherical harmonic coefficients of the density anomaly contribution to the " - "maximum degree. The default is false. "); - prm.declare_entry("Output gravity anomaly", "false", - Patterns::Bool(), - "Option to output the free-air gravity anomaly up to the maximum degree. " - "The unit of the output is in SI, hence $m/s^2$ ($1mgal = 10^-5 m/s^2$). The default is false. "); - - prm.declare_alias("Output geoid anomaly coefficients","Also output the spherical harmonic coefficients of geoid anomaly"); - prm.declare_alias("Output surface topography contribution coefficients","Also output the spherical harmonic coefficients of surface dynamic topography contribution"); - prm.declare_alias("Output CMB topography contribution coefficients","Also output the spherical harmonic coefficients of CMB dynamic topography contribution"); - prm.declare_alias("Output density anomaly contribution coefficients","Also output the spherical harmonic coefficients of density anomaly contribution"); - prm.declare_alias("Output gravity anomaly","Also output the gravity anomaly"); - } - prm.leave_subsection (); - } - prm.leave_subsection (); - } - - template - void - Geoid::parse_parameters (ParameterHandler &prm) - { - CitationInfo::add("geoid"); - - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Geoid"); - { - include_surface_topo_contribution = prm.get_bool ("Include surface topography contribution"); - include_CMB_topo_contribution = prm.get_bool ("Include CMB topography contribution"); - max_degree = prm.get_integer ("Maximum degree"); - min_degree = prm.get_integer ("Minimum degree"); - output_in_lat_lon = prm.get_bool ("Output data in geographical coordinates"); - density_above = prm.get_double ("Density above"); - density_below = prm.get_double ("Density below"); - output_geoid_anomaly_SH_coes = prm.get_bool ("Output geoid anomaly coefficients"); - output_surface_topo_contribution_SH_coes = prm.get_bool ("Output surface topography contribution coefficients"); - output_CMB_topo_contribution_SH_coes = prm.get_bool ("Output CMB topography contribution coefficients"); - output_density_anomaly_contribution_SH_coes = prm.get_bool ("Output density anomaly contribution coefficients"); - output_gravity_anomaly = prm.get_bool ("Output gravity anomaly"); - } - prm.leave_subsection (); - } - prm.leave_subsection (); - } - - template - void - Geoid::initialize () - { - // Find if the included boundaries are active free surfaces - if (include_surface_topo_contribution == true || include_CMB_topo_contribution == true) - { - if (this->get_parameters().mesh_deformation_enabled == true) - { - const types::boundary_id surface_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); - const types::boundary_id bottom_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("bottom"); - - const std::set mesh_deformation_boundaries = this->get_mesh_deformation_handler().get_active_mesh_deformation_boundary_indicators(); - - use_free_surface_topography = mesh_deformation_boundaries.find(surface_id) != mesh_deformation_boundaries.end(); - use_free_CMB_topography = mesh_deformation_boundaries.find(bottom_id) != mesh_deformation_boundaries.end(); - } - } - } - - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(Geoid, - "geoid", - "A postprocessor that computes a representation of " - "the geoid based on the density structure in the mantle, " - "as well as the topography at the surface and " - "core mantle boundary (CMB) if desired. The topography is based on the " - "dynamic topography postprocessor in case of no free surface, " - "and based on the real surface from the geometry model in case " - "of a free surface. The geoid is computed " - "from a spherical harmonic expansion, so the geometry " - "of the domain must be a 3d spherical shell.") - } -} diff --git a/source/postprocess/global_statistics.cc.bak b/source/postprocess/global_statistics.cc.bak deleted file mode 100644 index aae8dd2e811..00000000000 --- a/source/postprocess/global_statistics.cc.bak +++ /dev/null @@ -1,324 +0,0 @@ -/* - Copyright (C) 2017 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -namespace aspect -{ - namespace Postprocess - { - template - void - GlobalStatistics::initialize() - { - this->get_signals().post_stokes_solver.connect( - [&](const SimulatorAccess &/*simulator_access*/, - const unsigned int number_S_iterations, - const unsigned int number_A_iterations, - const SolverControl &solver_control_cheap, - const SolverControl &solver_control_expensive) - { - this->store_stokes_solver_history(number_S_iterations, - number_A_iterations, - solver_control_cheap, - solver_control_expensive); - }); - - this->get_signals().post_advection_solver.connect( - [&](const SimulatorAccess &/*simulator_access*/, - const bool solved_temperature_field, - const unsigned int compositional_index, - const SolverControl &solver_control) - { - this->store_advection_solver_history(solved_temperature_field, - compositional_index, - solver_control); - }); - - // delete the data after the initial refinement steps, to not mix it up - // with the first time step - if (!this->get_parameters().run_postprocessors_on_initial_refinement) - this->get_signals().post_set_initial_state.connect( - [&] (const SimulatorAccess &) - { - this->clear_data(); - }); - } - - - - template - void - GlobalStatistics::clear_data() - { - list_of_S_iterations.clear(); - list_of_A_iterations.clear(); - stokes_iterations_cheap.clear(); - stokes_iterations_expensive.clear(); - advection_iterations.clear(); - } - - - - template - void - GlobalStatistics::store_stokes_solver_history(const unsigned int number_S_iterations, - const unsigned int number_A_iterations, - const SolverControl &solver_control_cheap, - const SolverControl &solver_control_expensive) - { - list_of_S_iterations.push_back(number_S_iterations); - list_of_A_iterations.push_back(number_A_iterations); - stokes_iterations_cheap.push_back(solver_control_cheap.last_step()); - stokes_iterations_expensive.push_back(solver_control_expensive.last_step()); - } - - - - template - void - GlobalStatistics::store_advection_solver_history(const bool solved_temperature_field, - const unsigned int compositional_index, - const SolverControl &solver_control) - { - const std::string column_name = (solved_temperature_field) ? - "Iterations for temperature solver" - : - "Iterations for composition solver " + Utilities::int_to_string(compositional_index+1); - - unsigned int column_position = numbers::invalid_unsigned_int; - - for (unsigned int i=0; i(1,solver_control.last_step())); - else - advection_iterations[column_position].second.push_back(solver_control.last_step()); - } - - - - template - std::pair - GlobalStatistics::execute (TableHandler &statistics) - { - // We would like to know how many nonlinear iterations were performed since - // the last call to execute(). Unfortunately some solver schemes iterate only the - // Stokes equation, some Stokes and advection, and some do not even call the - // Stokes or advection solver. Therefore, the best estimate for the number - // of nonlinear iterations since the last call is the maximum size of the - // vectors in which we store our data. - unsigned int nonlinear_iterations = stokes_iterations_cheap.size(); - - for (const auto &advection_iteration : advection_iterations) - nonlinear_iterations = std::max(nonlinear_iterations, static_cast (advection_iteration.second.size())); - - if (one_line_per_iteration) - for (unsigned int iteration = 0; iteration < nonlinear_iterations; ++iteration) - { - generate_global_statistics(statistics); - - statistics.add_value("Nonlinear iteration number", - iteration); - - for (const auto &advection_iteration : advection_iterations) - if (iteration < advection_iteration.second.size()) - statistics.add_value(advection_iteration.first, - advection_iteration.second[iteration]); - - if (iteration < stokes_iterations_cheap.size()) - { - statistics.add_value("Iterations for Stokes solver", - stokes_iterations_cheap[iteration] + stokes_iterations_expensive[iteration]); - statistics.add_value("Velocity iterations in Stokes preconditioner", - list_of_A_iterations[iteration]); - statistics.add_value("Schur complement iterations in Stokes preconditioner", - list_of_S_iterations[iteration]); - } - - } - else - { - generate_global_statistics(statistics); - - unsigned int A_iterations = 0; - unsigned int S_iterations = 0; - unsigned int Stokes_outer_iterations = 0; - std::vector advection_outer_iterations(advection_iterations.size(),0); - - for (unsigned int iteration = 0; iteration < nonlinear_iterations; ++iteration) - { - for (unsigned int column=0; columnget_parameters().nonlinear_solver == Parameters::NonlinearSolver::single_Advection_single_Stokes - || this->get_parameters().nonlinear_solver == Parameters::NonlinearSolver::single_Advection_no_Stokes)) - statistics.add_value("Number of nonlinear iterations", - nonlinear_iterations); - - // Only output statistics columns if the solver actually signaled at least one - // successful solve. Some solver schemes might need no advection or Stokes solver - for (unsigned int column=0; column 0) - { - statistics.add_value("Iterations for Stokes solver", - Stokes_outer_iterations); - statistics.add_value("Velocity iterations in Stokes preconditioner", - A_iterations); - statistics.add_value("Schur complement iterations in Stokes preconditioner", - S_iterations); - } - } - - clear_data(); - - return std::make_pair (std::string(),std::string()); - } - - - - template - void - GlobalStatistics::generate_global_statistics(TableHandler &statistics) - { - // set global statistics about this time step - statistics.add_value("Time step number", this->get_timestep_number()); - - if (this->convert_output_to_years() == true) - { - statistics.add_value("Time (years)", this->get_time() / year_in_seconds); - statistics.set_precision("Time (years)", 12); - statistics.set_scientific("Time (years)", true); - - statistics.add_value("Time step size (years)", this->get_timestep() / year_in_seconds); - statistics.set_precision("Time step size (years)", 12); - statistics.set_scientific("Time step size (years)", true); - } - else - { - statistics.add_value("Time (seconds)", this->get_time()); - statistics.set_precision("Time (seconds)", 12); - statistics.set_scientific("Time (seconds)", true); - - statistics.add_value("Time step size (seconds)", this->get_timestep()); - statistics.set_precision("Time step size (seconds)", 12); - statistics.set_scientific("Time step size (seconds)", true); - } - - // set global statistics about the mesh and problem size - statistics.add_value("Number of mesh cells", - this->get_triangulation().n_global_active_cells()); - - types::global_dof_index n_stokes_dofs = this->introspection().system_dofs_per_block[0]; - if (this->introspection().block_indices.velocities != this->introspection().block_indices.pressure) - n_stokes_dofs += this->introspection().system_dofs_per_block[this->introspection().block_indices.pressure]; - - statistics.add_value("Number of Stokes degrees of freedom", n_stokes_dofs); - statistics.add_value("Number of temperature degrees of freedom", - this->introspection().system_dofs_per_block[this->introspection().block_indices.temperature]); - if (this->n_compositional_fields() > 0) - statistics.add_value("Number of degrees of freedom for all compositions", - static_cast(this->n_compositional_fields()) - * this->introspection().system_dofs_per_block[this->introspection().block_indices.compositional_fields[0]]); - } - - - - template - void - GlobalStatistics::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Global statistics"); - { - prm.declare_entry ("Write statistics for each nonlinear iteration", "false", - Patterns::Bool (), - "Whether to put every nonlinear iteration into a separate " - "line in the statistics file (if true), or to output only " - "one line per time step that contains the total number of " - "iterations of the Stokes and advection linear system solver."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - - template - void - GlobalStatistics::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Global statistics"); - { - one_line_per_iteration = prm.get_bool("Write statistics for each nonlinear iteration"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(GlobalStatistics, - "global statistics", - "A postprocessor that outputs all the global statistics " - "information, e.g. the time of the simulation, the timestep " - "number, number of degrees of freedom and solver iterations " - "for each timestep. The postprocessor can output different " - "formats, the first printing one line in the statistics file " - "per nonlinear solver iteration (if a nonlinear solver scheme " - "is selected). The second prints one line per timestep, " - "summing the information about all nonlinear iterations in " - "this line. Note that this postprocessor is always active " - "independent on whether or not it is selected in the " - "parameter file.") - } -} diff --git a/source/postprocess/gravity_point_values.cc.bak b/source/postprocess/gravity_point_values.cc.bak deleted file mode 100644 index 4371292ea51..00000000000 --- a/source/postprocess/gravity_point_values.cc.bak +++ /dev/null @@ -1,850 +0,0 @@ -/* - Copyright (C) 2018 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - - template - GravityPointValues::GravityPointValues () - : - // the following value is later read from the input file - output_interval (0), - // initialize this to a nonsensical value; set it to the actual time - // the first time around we get to check it - last_output_time (std::numeric_limits::quiet_NaN()), - maximum_timesteps_between_outputs (std::numeric_limits::max()), - last_output_timestep (numbers::invalid_unsigned_int), - output_file_number (numbers::invalid_unsigned_int) - {} - - - - template - void - GravityPointValues::initialize () - { - // Get the value of the outer radius and inner radius: - if (Plugins::plugin_type_matches> (this->get_geometry_model())) - { - model_outer_radius = Plugins::get_plugin_as_type> - (this->get_geometry_model()).outer_radius(); - model_inner_radius = Plugins::get_plugin_as_type> - (this->get_geometry_model()).inner_radius(); - } - else if (Plugins::plugin_type_matches> (this->get_geometry_model())) - { - model_outer_radius = Plugins::get_plugin_as_type> - (this->get_geometry_model()).outer_radius(); - model_inner_radius = Plugins::get_plugin_as_type> - (this->get_geometry_model()).inner_radius(); - } - else if (Plugins::plugin_type_matches> (this->get_geometry_model())) - { - model_outer_radius = Plugins::get_plugin_as_type> - (this->get_geometry_model()).radius(); - model_inner_radius = 0; - } - else - { - model_outer_radius = 1; - model_inner_radius = 0; - } - - - // *** First calculate the number of satellites according to the sampling scheme: - unsigned int n_satellites; - if (sampling_scheme == fibonacci_spiral) - n_satellites = n_points_spiral * n_points_radius; - else if (sampling_scheme == map) - n_satellites = n_points_radius * n_points_longitude * n_points_latitude; - else if (sampling_scheme == list_of_points) - n_satellites = longitude_list.size(); - else n_satellites = 1; - - // *** Second assign the coordinates of all satellites: - satellite_positions_spherical.resize(n_satellites); - if (sampling_scheme == map) - { - unsigned int p = 0; - for (unsigned int h=0; h < n_points_radius; ++h) - { - for (unsigned int i=0; i < n_points_longitude; ++i) - { - for (unsigned int j=0; j < n_points_latitude; ++j) - { - if (n_points_radius > 1) - satellite_positions_spherical[p][0] = minimum_radius + ((maximum_radius - minimum_radius) / (n_points_radius - 1)) * h; - else - satellite_positions_spherical[p][0] = minimum_radius; - if (n_points_longitude > 1) - satellite_positions_spherical[p][1] = (minimum_colongitude + ((maximum_colongitude - minimum_colongitude) / - (n_points_longitude - 1)) * i) * constants::degree_to_radians; - else - satellite_positions_spherical[p][1] = minimum_colongitude * constants::degree_to_radians; - if (n_points_latitude > 1) - satellite_positions_spherical[p][2] = (minimum_colatitude + ((maximum_colatitude - minimum_colatitude) / - (n_points_latitude - 1)) * j) * constants::degree_to_radians; - else - satellite_positions_spherical[p][2] = minimum_colatitude * constants::degree_to_radians; - ++p; - } - } - } - } - if (sampling_scheme == fibonacci_spiral) - { - const double golden_ratio = (1. + std::sqrt(5.))/2.; - const double golden_angle = 2. * numbers::PI * (1. - 1./golden_ratio); - unsigned int p = 0; - for (unsigned int h=0; h < n_points_radius; ++h) - { - for (unsigned int s=0; s < n_points_spiral; ++s) - { - if (n_points_radius > 1) - satellite_positions_spherical[p][0] = minimum_radius + ((maximum_radius - minimum_radius) / (n_points_radius - 1)) * h; - else - satellite_positions_spherical[p][0] = minimum_radius; - satellite_positions_spherical[p][2] = std::acos(1. - 2. * s / (n_points_spiral - 1.)); - satellite_positions_spherical[p][1] = std::fmod((s*golden_angle), 2.*numbers::PI); - ++p; - } - } - } - if (sampling_scheme == list_of_points) - { - for (unsigned int p=0; p < n_satellites; ++p) - { - if (radius_list.size() == 1) - satellite_positions_spherical[p][0] = radius_list[0]; - else - satellite_positions_spherical[p][0] = radius_list[p]; - if (longitude_list[p] < 0) - satellite_positions_spherical[p][1] = (360 + longitude_list[p]) * constants::degree_to_radians; - else - satellite_positions_spherical[p][1] = (longitude_list[p]) * constants::degree_to_radians; - satellite_positions_spherical[p][2] = (90 - latitude_list[p]) * constants::degree_to_radians; - } - } - - // The spherical coordinates are shifted into cartesian to allow simplification - // in the mathematical equation. - satellite_positions_cartesian.resize (n_satellites); - for (unsigned int p=0; p(satellite_positions_spherical[p]); - } - - - - template - std::pair - GravityPointValues::execute (TableHandler &) - { - AssertThrow(false, ExcNotImplemented()); - return {"", ""}; - } - - - - template <> - std::pair - GravityPointValues<3>::execute (TableHandler &statistics) - { - const int dim = 3; - - // Check time to see if we output gravity - if (std::isnan(last_output_time)) - { - last_output_time = this->get_time() - output_interval; - last_output_timestep = this->get_timestep_number(); - } - if ((this->get_time() < last_output_time + output_interval) - && (this->get_timestep_number() < last_output_timestep + maximum_timesteps_between_outputs) - && (this->get_timestep_number() != 0)) - return {}; - - // Up the counter of the number of the file by one, but not in - // the very first output step. if we run postprocessors on all - // iterations, only increase file number in the first nonlinear iteration - const bool increase_file_number = (this->get_nonlinear_iteration() == 0) || - (!this->get_parameters().run_postprocessors_on_nonlinear_iterations); - if (output_file_number == numbers::invalid_unsigned_int) - output_file_number = 0; - else if (increase_file_number) - ++output_file_number; - - const std::string file_prefix = "gravity-" + Utilities::int_to_string (output_file_number, 5); - const std::string filename = (this->get_output_directory() - + "output_gravity/" - + file_prefix); - - // Get quadrature formula and increase the degree of quadrature over the velocity - // element degree. - const unsigned int degree = this->get_fe().base_element(this->introspection() - .base_elements.velocities).degree - + quadrature_degree_increase; - const QGauss quadrature_formula (degree); - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_gradients | - update_quadrature_points | - update_JxW_values); - - - // Get the value of the universal gravitational constant: - const double G = aspect::constants::big_g; - - const unsigned int n_quadrature_points_per_cell = quadrature_formula.size(); - - const unsigned int n_satellites = satellite_positions_spherical.size(); - - - // This is the main loop which computes gravity acceleration, potential and - // gradients at a point located at the spherical coordinate [r, phi, theta]. - // This loop corresponds to the 3 integrals of Newton law: - std::vector local_g_potential (n_satellites); - std::vector> local_g (n_satellites); - std::vector> local_g_anomaly (n_satellites); - std::vector> local_g_gradient (n_satellites); - - std::vector G_times_density_times_JxW (n_quadrature_points_per_cell); - std::vector G_times_density_anomaly_times_JxW (n_quadrature_points_per_cell); - - MaterialModel::MaterialModelInputs in(quadrature_formula.size(), - this->n_compositional_fields()); - MaterialModel::MaterialModelOutputs out(quadrature_formula.size(), - this->n_compositional_fields()); - in.requested_properties = MaterialModel::MaterialProperties::density; - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - // Evaluate the solution at the quadrature points of this cell - fe_values.reinit (cell); - - in.reinit(fe_values, cell, this->introspection(), this->get_solution()); - this->get_material_model().evaluate(in, out); - - // Pull some computations that are independent of the - // satellite position out of the following loop. This is - // because we may have a very large number of satellites, - // so even just one multiplication that is unnecessarily - // repeated can be expensive. - for (unsigned int q = 0; q < n_quadrature_points_per_cell; ++q) - { - G_times_density_times_JxW[q] = G * out.densities[q] * - fe_values.JxW(q); - G_times_density_anomaly_times_JxW[q] = G * (out.densities[q]-reference_density) * - fe_values.JxW(q); - } - - - for (unsigned int p=0; p < n_satellites; ++p) - { - const Point satellite_position = satellite_positions_cartesian[p]; - - for (unsigned int q = 0; q < n_quadrature_points_per_cell; ++q) - { - const Tensor<1,dim> r_vector = satellite_position - fe_values.quadrature_point(q); - - const double r_squared = r_vector.norm_square(); - const double r = std::sqrt(r_squared); - const double r_cubed = r * r_squared; - const double one_over_r_cubed = 1. / r_cubed; - const double r_to_the_5 = r_squared * r_cubed; - - const double G_density_JxW = G_times_density_times_JxW[q]; - - // For gravity acceleration: - const double KK = - G_density_JxW * one_over_r_cubed; - local_g[p] += KK * r_vector; - - // For gravity anomalies: - const double KK_anomalies = - G_times_density_anomaly_times_JxW[q] * one_over_r_cubed; - local_g_anomaly[p] += KK_anomalies * r_vector; - - // For gravity potential: - local_g_potential[p] -= G_density_JxW / r; - - // For gravity gradient: - const double grad_KK = G_density_JxW / r_to_the_5; - for (unsigned int e=0; e g_potential(n_satellites); - Utilities::MPI::sum (make_const_array_view(local_g_potential), - this->get_mpi_communicator(), - make_array_view(g_potential)); - - const auto tensor_sum - = [] (const auto &v1, const auto &v2) - { - AssertDimension (v1.size(), v2.size()); - - using element_type = typename std::remove_reference::type::value_type; - - std::vector result (v1.size()); - for (unsigned int i=0; i> - g = Utilities::MPI::all_reduce - (local_g, - this->get_mpi_communicator(), - tensor_sum); - - const std::vector> - g_anomaly = Utilities::MPI::all_reduce - (local_g_anomaly, - this->get_mpi_communicator(), - tensor_sum); - - const std::vector> - g_gradient = Utilities::MPI::all_reduce - (local_g_gradient, - this->get_mpi_communicator(), - tensor_sum); - - double sum_g = 0; - double min_g = std::numeric_limits::max(); - double max_g = std::numeric_limits::lowest(); - double sum_g_potential = 0; - double min_g_potential = std::numeric_limits::max(); - double max_g_potential = std::numeric_limits::lowest(); - - for (unsigned int p=0; p < n_satellites; ++p) - { - // sum gravity components for all n_satellites: - sum_g += g[p].norm(); - sum_g_potential += g_potential[p]; - max_g = std::max(g[p].norm(), max_g); - min_g = std::min(g[p].norm(), min_g); - max_g_potential = std::max(g_potential[p], max_g_potential); - min_g_potential = std::min(g_potential[p], min_g_potential); - } - - - // Now also compute theoretical values. These are output only - // on process zero and, for now, also only computed on process zero. - std::vector g_theory(n_satellites); - std::vector g_potential_theory(n_satellites); - std::vector> g_gradient_theory(n_satellites); - - const unsigned int my_rank - = Utilities::MPI::this_mpi_process(this->get_mpi_communicator()); - const unsigned int n_ranks - = Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()); - - for (unsigned int p=0; p < n_satellites; ++p) - if (p % n_ranks == my_rank) - { - const Point satellite_position = satellite_positions_cartesian[p]; - - // analytical solution to calculate the theoretical gravity and its derivatives - // from a uniform density model. Can only be used if concentric density profile. - if (satellite_positions_spherical[p][0] <= model_inner_radius) - { - // We are inside the inner radius - g_theory[p] = 0; - g_potential_theory[p] = 2.0 * G * numbers::PI * reference_density * - ((model_inner_radius * model_inner_radius) - (model_outer_radius * model_outer_radius)); - } - else if ((satellite_positions_spherical[p][0] > model_inner_radius) - && (satellite_positions_spherical[p][0] < model_outer_radius)) - { - // We are in the spherical shell - g_theory[p] = G * numbers::PI * 4./3. * reference_density * - (satellite_positions_spherical[p][0] - - ((model_inner_radius * model_inner_radius * model_inner_radius) - / (satellite_positions_spherical[p][0] * satellite_positions_spherical[p][0]))); - g_potential_theory[p] = G * numbers::PI * 4./3. * reference_density * - (((satellite_positions_spherical[p][0] * satellite_positions_spherical[p][0])/2.0) + - ((model_inner_radius * model_inner_radius * model_inner_radius) / satellite_positions_spherical[p][0])) - - - G * numbers::PI * 2.0 * reference_density * - (model_outer_radius * model_outer_radius); - } - else - { - const double common_factor = G * numbers::PI * 4./3. * reference_density - * ((model_outer_radius * model_outer_radius * model_outer_radius) - (model_inner_radius * model_inner_radius * model_inner_radius)); - const double r = satellite_positions_spherical[p][0]; - - g_theory[p] = common_factor / (r * r); - g_potential_theory[p] = - common_factor / r; - - // For the gradient of g, start with the common part of - // the diagonal elements: - g_gradient_theory[p][0][0] = - g_gradient_theory[p][1][1] = - g_gradient_theory[p][2][2] = -1./(r * r * r); - - // Then do the off-diagonal elements: - for (unsigned int e=0; e - (g_theory, - this->get_mpi_communicator(), - tensor_sum); - - g_potential_theory = Utilities::MPI::all_reduce - (g_potential_theory, - this->get_mpi_communicator(), - tensor_sum); - - g_gradient_theory = Utilities::MPI::all_reduce - (g_gradient_theory, - this->get_mpi_communicator(), - tensor_sum); - - // open the file on rank 0 and write the headers - if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - // First put all of our output into a string buffer: - std::ostringstream output; - output << "# 1: position_satellite_r" << '\n' - << "# 2: position_satellite_phi" << '\n' - << "# 3: position_satellite_theta" << '\n' - << "# 4: position_satellite_x" << '\n' - << "# 5: position_satellite_y" << '\n' - << "# 6: position_satellite_z" << '\n' - << "# 7: gravity_x" << '\n' - << "# 8: gravity_y" << '\n' - << "# 9: gravity_z" << '\n' - << "# 10: gravity_norm" << '\n' - << "# 11: gravity_theory" << '\n' - << "# 12: gravity_potential" << '\n' - << "# 13: gravity_potential_theory" << '\n' - << "# 14: gravity_anomaly_x" << '\n' - << "# 15: gravity_anomaly_y" << '\n' - << "# 16: gravity_anomaly_z" << '\n' - << "# 17: gravity_anomaly_norm" << '\n' - << "# 18: gravity_gradient_xx" << '\n' - << "# 19: gravity_gradient_yy" << '\n' - << "# 20: gravity_gradient_zz" << '\n' - << "# 21: gravity_gradient_xy" << '\n' - << "# 22: gravity_gradient_xz" << '\n' - << "# 23: gravity_gradient_yz" << '\n' - << "# 24: gravity_gradient_theory_xx" << '\n' - << "# 25: gravity_gradient_theory_yy" << '\n' - << "# 26: gravity_gradient_theory_zz" << '\n' - << "# 27: gravity_gradient_theory_xy" << '\n' - << "# 28: gravity_gradient_theory_xz" << '\n' - << "# 29: gravity_gradient_theory_yz" << '\n' - << '\n'; - - for (unsigned int p=0; p < n_satellites; ++p) - { - const Point satellite_position = satellite_positions_cartesian[p]; - - // write output. - // g_gradient is here given in eotvos E (1E = 1e-9 per square seconds): - output << satellite_positions_spherical[p][0] << ' ' - << satellite_positions_spherical[p][1] * constants::radians_to_degree << ' ' - << satellite_positions_spherical[p][2] * constants::radians_to_degree << ' ' - << satellite_position[0] << ' ' - << satellite_position[1] << ' ' - << satellite_position[2] << ' ' - << std::setprecision(precision) - << g[p] << ' ' - << g[p].norm() << ' ' - << g_theory[p] << ' ' - << g_potential[p] << ' ' - << g_potential_theory[p] << ' ' - << g_anomaly[p] << ' ' - << g_anomaly[p].norm() << ' ' - << g_gradient[p][0][0] *1e9 << ' ' - << g_gradient[p][1][1] *1e9 << ' ' - << g_gradient[p][2][2] *1e9 << ' ' - << g_gradient[p][0][1] *1e9 << ' ' - << g_gradient[p][0][2] *1e9 << ' ' - << g_gradient[p][1][2] *1e9 << ' ' - << g_gradient_theory[p][0][0] *1e9 << ' ' - << g_gradient_theory[p][1][1] *1e9 << ' ' - << g_gradient_theory[p][2][2] *1e9 << ' ' - << g_gradient_theory[p][0][1] *1e9 << ' ' - << g_gradient_theory[p][0][2] *1e9 << ' ' - << g_gradient_theory[p][1][2] *1e9 << ' ' - << '\n'; - } - - // Now push the entire buffer into the output file in one swoop fell: - std::ofstream output_file(filename); - AssertThrow(output_file, - ExcMessage("Unable to open file for writing: " + filename +".")); - output_file << output.str(); - } - - // write quantities in the statistic file - const std::string name2("Average gravity acceleration (m/s^2)"); - statistics.add_value (name2, sum_g/n_satellites); - statistics.set_precision (name2, precision); - statistics.set_scientific (name2, true); - - const std::string name3("Minimum gravity acceleration (m/s^2)"); - statistics.add_value (name3, min_g); - statistics.set_precision (name3, precision); - statistics.set_scientific (name3, true); - - const std::string name4("Maximum gravity acceleration (m/s^2)"); - statistics.add_value (name4, max_g); - statistics.set_precision (name4, precision); - statistics.set_scientific (name4, true); - - const std::string name5("Average gravity potential (m^2/s^2)"); - statistics.add_value (name5, sum_g_potential/n_satellites); - statistics.set_precision (name5, precision); - statistics.set_scientific (name5, true); - - const std::string name6("Minimum gravity potential (m^2/s^2)"); - statistics.add_value (name6, min_g_potential); - statistics.set_precision (name6, precision); - statistics.set_scientific (name6, true); - - const std::string name7("Maximum gravity potential (m^2/s^2)"); - statistics.add_value (name7, max_g_potential); - statistics.set_precision (name7, precision); - statistics.set_scientific (name7, true); - - // up the next time we need output: - set_last_output_time (this->get_time()); - last_output_timestep = this->get_timestep_number(); - return std::pair ("Writing gravity output:", filename); - } - - - - template - void - GravityPointValues::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection ("Postprocess"); - { - prm.enter_subsection ("Gravity calculation"); - { - prm.declare_entry ("Sampling scheme", "map", - Patterns::Selection ("map|list|list of points|fibonacci spiral"), - "Choose the sampling scheme. By default, the map produces a " - "grid of equally angled points between a minimum and maximum " - "radius, longitude, and latitude. A list of points contains " - "the specific coordinates of the satellites. The fibonacci " - "spiral sampling scheme produces a uniformly distributed map " - "on the surface of sphere defined by a minimum and/or " - "maximum radius."); - prm.declare_entry ("Number points fibonacci spiral", "200", - Patterns::Integer (0), - "Parameter for the fibonacci spiral sampling scheme: " - "This specifies the desired number of satellites per radius " - "layer. The default value is 200. Note that sampling " - "becomes more uniform with increasing number of satellites"); - prm.declare_entry ("Quadrature degree increase", "0", - Patterns::Integer (-1), - "Quadrature degree increase over the velocity element " - "degree may be required when gravity is calculated near " - "the surface or inside the model. An increase in the " - "quadrature element adds accuracy to the gravity " - "solution from noise due to the model grid."); - prm.declare_entry ("Number points radius", "1", - Patterns::Integer (0), - "Parameter for the map sampling scheme: " - "This specifies the number of points along " - "the radius (e.g. depth profile) between a minimum and " - "maximum radius."); - prm.declare_entry ("Number points longitude", "1", - Patterns::Integer (0), - "Parameter for the map sampling scheme: " - "This specifies the number of points along " - "the longitude (e.g. gravity map) between a minimum and " - "maximum longitude."); - prm.declare_entry ("Number points latitude", "1", - Patterns::Integer (0), - "Parameter for the map sampling scheme: " - "This specifies the number of points along " - "the latitude (e.g. gravity map) between a minimum and " - "maximum latitude."); - prm.declare_entry ("Minimum radius", "0.", - Patterns::Double (0.0), - "Parameter for the map sampling scheme: " - "Minimum radius may be defined in or outside the model. " - "Prescribe a minimum radius for a sampling coverage at a " - "specific height."); - prm.declare_entry ("Maximum radius", "0.", - Patterns::Double (0.0), - "Parameter for the map sampling scheme: " - "Maximum radius can be defined in or outside the model."); - prm.declare_entry ("Minimum longitude", "-180.", - Patterns::Double (-180.0, 180.0), - "Parameter for the uniform distribution sampling scheme: " - "Gravity may be calculated for a sets of points along " - "the longitude between a minimum and maximum longitude."); - prm.declare_entry ("Minimum latitude", "-90.", - Patterns::Double (-90.0, 90.0), - "Parameter for the uniform distribution sampling scheme: " - "Gravity may be calculated for a sets of points along " - "the latitude between a minimum and maximum latitude."); - prm.declare_entry ("Maximum longitude", "180.", - Patterns::Double (-180.0, 180.0), - "Parameter for the uniform distribution sampling scheme: " - "Gravity may be calculated for a sets of points along " - "the longitude between a minimum and maximum longitude."); - prm.declare_entry ("Maximum latitude", "90", - Patterns::Double (-90.0, 90.0), - "Parameter for the uniform distribution sampling scheme: " - "Gravity may be calculated for a sets of points along " - "the latitude between a minimum and maximum latitude."); - prm.declare_entry ("Reference density", "3300.", - Patterns::Double (0.0), - "Gravity anomalies may be computed using density " - "anomalies relative to a reference density."); - prm.declare_entry ("Precision in gravity output", "12", - Patterns::Integer (1), - "Set the precision of gravity acceleration, potential " - "and gradients in the gravity output and statistics file."); - prm.declare_entry ("List of radius", "", - Patterns::List (Patterns::Double (0.)), - "Parameter for the list of points sampling scheme: " - "List of satellite radius coordinates. Just specify one " - "radius if all points values have the same radius. If " - "not, make sure there are as many radius as longitude " - "and latitude"); - prm.declare_entry ("List of longitude", "", - Patterns::List (Patterns::Double(-180.0, 180.0)), - "Parameter for the list of points sampling scheme: " - "List of satellite longitude coordinates."); - prm.declare_entry ("List of latitude", "", - Patterns::List (Patterns::Double(-90.0, 90.0)), - "Parameter for the list of points sampling scheme: " - "List of satellite latitude coordinates."); - prm.declare_entry ("Time between gravity output", "1e8", - Patterns::Double(0.0), - "The time interval between each generation of " - "gravity output files. A value of 0 indicates " - "that output should be generated in each time step. " - "Units: years if the " - "'Use years in output instead of seconds' parameter is set; " - "seconds otherwise."); - prm.declare_entry ("Time steps between gravity output", boost::lexical_cast(std::numeric_limits::max()), - Patterns::Integer(0,std::numeric_limits::max()), - "The maximum number of time steps between each generation of " - "gravity output files."); - - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - - template - void - GravityPointValues::parse_parameters (ParameterHandler &prm) - { - std::string gravity_subdirectory = this->get_output_directory() + "output_gravity/"; - Utilities::create_directory (gravity_subdirectory, - this->get_mpi_communicator(), - true); - - end_time = prm.get_double ("End time"); - if (this->convert_output_to_years()) - end_time *= year_in_seconds; - - prm.enter_subsection ("Postprocess"); - { - prm.enter_subsection ("Gravity calculation"); - { - if ( (prm.get ("Sampling scheme") == "uniform distribution") || (prm.get ("Sampling scheme") == "map") ) - sampling_scheme = map; - else if ( (prm.get ("Sampling scheme") == "list of points") || (prm.get ("Sampling scheme") == "list") ) - sampling_scheme = list_of_points; - else if (prm.get ("Sampling scheme") == "fibonacci spiral") - sampling_scheme = fibonacci_spiral; - else - AssertThrow (false, ExcMessage ("Not a valid sampling scheme.")); - quadrature_degree_increase = prm.get_integer ("Quadrature degree increase"); - n_points_spiral = prm.get_integer("Number points fibonacci spiral"); - n_points_radius = prm.get_integer("Number points radius"); - n_points_longitude = prm.get_integer("Number points longitude"); - n_points_latitude = prm.get_integer("Number points latitude"); - minimum_radius = prm.get_double ("Minimum radius"); - maximum_radius = prm.get_double ("Maximum radius"); - minimum_colongitude = prm.get_double ("Minimum longitude") + 180.; - maximum_colongitude = prm.get_double ("Maximum longitude") + 180.; - minimum_colatitude = prm.get_double ("Minimum latitude") + 90.; - maximum_colatitude = prm.get_double ("Maximum latitude") + 90.; - reference_density = prm.get_double ("Reference density"); - precision = prm.get_integer ("Precision in gravity output"); - radius_list = Utilities::string_to_double(Utilities::split_string_list(prm.get("List of radius"))); - longitude_list = Utilities::string_to_double(Utilities::split_string_list(prm.get("List of longitude"))); - latitude_list = Utilities::string_to_double(Utilities::split_string_list(prm.get("List of latitude"))); - AssertThrow (longitude_list.size() == latitude_list.size(), - ExcMessage ("Make sure you have the same number of point coordinates in the list sampling scheme.")); - AssertThrow (Plugins::plugin_type_matches> (this->get_geometry_model()) || - Plugins::plugin_type_matches> (this->get_geometry_model()) || - Plugins::plugin_type_matches> (this->get_geometry_model()), - ExcMessage ("This postprocessor can only be used if the geometry is a sphere, spherical shell or spherical chunk.")); - AssertThrow (! this->get_material_model().is_compressible(), - ExcMessage("This postprocessor was only tested for incompressible models so far.")); - AssertThrow (dim==3, - ExcMessage("This postprocessor was only tested for 3d models.")); - output_interval = prm.get_double ("Time between gravity output"); - if (this->convert_output_to_years()) - output_interval *= year_in_seconds; - maximum_timesteps_between_outputs = prm.get_integer("Time steps between gravity output"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - - template - template - void GravityPointValues::serialize (Archive &ar, const unsigned int) - { - // This deals with having the correct behavior during checkpoint/restart cycles: - ar &last_output_time - & last_output_timestep - & output_file_number - ; - } - - - - template - void - GravityPointValues::set_last_output_time (const double current_time) - { - // if output_interval is positive, then update the last supposed output time: - if (output_interval > 0) - { - // We need to find the last time output was supposed to be written. - // this is the last_output_time plus the largest positive multiple - // of output_intervals that passed since then. We need to handle the - // edge case where last_output_time+output_interval==current_time, - // we did an output and std::floor sadly rounds to zero. This is done - // by forcing std::floor to round 1.0-eps to 1.0. - const double magic = 1.0+2.0*std::numeric_limits::epsilon(); - last_output_time = last_output_time + std::floor((current_time-last_output_time)/output_interval*magic) * output_interval/magic; - } - } - - - - template - void - GravityPointValues::save (std::map &status_strings) const - { - std::ostringstream os; - aspect::oarchive oa (os); - oa << (*this); - - status_strings["GravityPointValues"] = os.str(); - } - - - - template - void - GravityPointValues::load (const std::map &status_strings) - { - // see if something was saved - if (status_strings.find("GravityPointValues") != status_strings.end()) - { - std::istringstream is (status_strings.find("GravityPointValues")->second); - aspect::iarchive ia (is); - ia >> (*this); - } - } - - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(GravityPointValues, - "gravity calculation", - "A postprocessor that computes gravity, gravity anomalies, gravity " - "potential and gravity gradients for a set of points (e.g. satellites) " - "in or above the model surface for either a user-defined range of " - "latitudes, longitudes and radius or a list of point coordinates." - "Spherical coordinates in the output file are radius, colatitude " - "and colongitude. Gravity is here based on the density distribution " - "from the material model (and non adiabatic). This means that the " - "density may come directly from an ascii file. This postprocessor also " - "computes theoretical gravity and its derivatives, which corresponds to " - "the analytical solution of gravity in the same geometry but filled " - "with a reference density. The reference density is also used to " - "determine density anomalies for computing gravity anomalies. Thus " - "one must carefully evaluate the meaning of the gravity anomaly output, " - "because the solution may not reflect the actual gravity anomaly (due to " - "differences in the assumed reference density). On way to guarantee correct " - "gravity anomalies is to subtract gravity of a certain point from the average " - "gravity on the map. Another way is to directly use density anomalies for this " - "postprocessor." - "The average- minimum- and maximum gravity acceleration and potential are " - "written into the statistics file.") - } -} diff --git a/source/postprocess/heat_flux_densities.cc.bak b/source/postprocess/heat_flux_densities.cc.bak deleted file mode 100644 index d4c715f8716..00000000000 --- a/source/postprocess/heat_flux_densities.cc.bak +++ /dev/null @@ -1,157 +0,0 @@ -/* - Copyright (C) 2016 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - HeatFluxDensities::execute (TableHandler &statistics) - { - const char *unit = (dim==2)? "W/m" : "W/m^2"; - - std::vector>> heat_flux_and_area = - internal::compute_heat_flux_through_boundary_faces (*this); - - std::map local_boundary_fluxes; - std::map local_areas; - - // Compute the area and heat flux of each boundary that lives on this processor. - // Finally, sum over the processors and compute the ratio between the - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - for (const unsigned int f : cell->face_indices()) - if (cell->at_boundary(f)) - { - const types::boundary_id boundary_indicator - = cell->face(f)->boundary_id(); - local_boundary_fluxes[boundary_indicator] += heat_flux_and_area[cell->active_cell_index()][f].first; - local_areas[boundary_indicator] += heat_flux_and_area[cell->active_cell_index()][f].second; - } - - // now communicate to get the global values - std::map global_boundary_flux_densities; - { - // first collect local values in the same order in which they are listed - // in the set of boundary indicators - const std::set - boundary_indicators - = this->get_geometry_model().get_used_boundary_indicators (); - std::vector local_boundary_fluxes_vector; - std::vector local_areas_vector; - for (const auto id : boundary_indicators) - { - local_boundary_fluxes_vector.push_back (local_boundary_fluxes[id]); - local_areas_vector.push_back (local_areas[id]); - } - - // then collect contributions from all processors - std::vector global_values (local_boundary_fluxes_vector.size()); - std::vector global_areas (local_areas_vector.size()); - Utilities::MPI::sum (local_boundary_fluxes_vector, this->get_mpi_communicator(), global_values); - Utilities::MPI::sum (local_areas_vector, this->get_mpi_communicator(), global_areas); - - // and now take them apart into the global map again and compute ratios - unsigned int index = 0; - for (const auto id : boundary_indicators) - { - global_boundary_flux_densities[id] = global_values[index]/global_areas[index]; - ++index; - } - } - - // now add all of the computed heat fluxes to the statistics object - // and create a single string that can be output to the screen - std::ostringstream screen_text; - unsigned int index = 0; - for (std::map::const_iterator - p = global_boundary_flux_densities.begin(); - p != global_boundary_flux_densities.end(); ++p, ++index) - { - const std::string name = "Outward heat flux density for boundary with id " - + Utilities::int_to_string(p->first) - + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() - .translate_id_to_symbol_name (p->first)) - + " (" + unit +")"; - statistics.add_value (name, p->second); - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - statistics.set_precision (name, 8); - statistics.set_scientific (name, true); - - // finally have something for the screen - screen_text.precision(4); - screen_text << p->second << ' ' << unit - << (index == global_boundary_flux_densities.size()-1 ? "" : ", "); - } - - return std::pair ("Heat flux densities for boundaries:", - screen_text.str()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(HeatFluxDensities, - "heat flux densities", - "A postprocessor that computes some statistics " - "about the heat flux density for each boundary id. " - "The heat flux density across each boundary " - "is computed in outward " - "direction, i.e., from the domain to the " - "outside. The heat flux is computed as sum " - "of advective heat flux and conductive heat " - "flux through Neumann boundaries, both " - "computed as integral over the boundary area, " - "and conductive heat flux through Dirichlet " - "boundaries, which is computed using the " - "consistent boundary flux method as described " - "in ``Gresho, Lee, Sani, Maslanik, Eaton (1987). " - "The consistent Galerkin FEM for computing " - "derived boundary quantities in thermal and or " - "fluids problems. International Journal for " - "Numerical Methods in Fluids, 7(4), 371-394.''" - "\n\n" - "Note that the ``heat flux statistics'' " - "postprocessor computes the same quantity as " - "the one here, but not divided by the area of " - "the surface. In other words, it computes the " - "\\textit{total} heat flux through each boundary." - ) - } -} diff --git a/source/postprocess/heat_flux_map.cc.bak b/source/postprocess/heat_flux_map.cc.bak deleted file mode 100644 index c565d3cdcad..00000000000 --- a/source/postprocess/heat_flux_map.cc.bak +++ /dev/null @@ -1,565 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace aspect -{ - namespace Postprocess - { - namespace internal - { - template - LinearAlgebra::BlockVector - compute_dirichlet_boundary_heat_flux_solution_vector (const SimulatorAccess &simulator_access) - { - // Quadrature degree for assembling the consistent boundary flux equation, see Simulator::assemble_advection_system() - // for a justification of the chosen quadrature degree. - const unsigned int quadrature_degree = simulator_access.get_parameters().temperature_degree - + - (simulator_access.get_parameters().stokes_velocity_degree+1)/2; - - // Gauss quadrature in the interior for best accuracy. - const QGauss quadrature_formula(quadrature_degree); - // GLL quadrature on the faces to get a diagonal mass matrix. - const QGaussLobatto quadrature_formula_face(quadrature_degree); - - // The CBF method involves both boundary and volume integrals on the - // cells at the boundary. Construct FEValues objects for each of these integrations. - FEValues fe_volume_values (simulator_access.get_mapping(), - simulator_access.get_fe(), - quadrature_formula, - update_values | - update_gradients | - update_quadrature_points | - update_JxW_values); - - FEFaceValues fe_face_values (simulator_access.get_mapping(), - simulator_access.get_fe(), - quadrature_formula_face, - update_JxW_values | - update_values | - update_gradients | - update_normal_vectors | - update_quadrature_points); - - const unsigned int dofs_per_cell = simulator_access.get_fe().dofs_per_cell; - const unsigned int n_q_points = quadrature_formula.size(); - const unsigned int n_face_q_points = quadrature_formula_face.size(); - - // Vectors for solving CBF system. Since we are using GLL - // quadrature, the mass matrix will be diagonal, and we can just assemble it into a vector. - Vector local_rhs(dofs_per_cell); - Vector local_mass_matrix(dofs_per_cell); - - // The mass matrix may be stored in a vector as it is a diagonal matrix: - // it is computed based on quadrature over faces, and we use a node-location - // based quadrature formula above, so phi_i(x_q)=delta_{iq} where the - // x_q are the node points of the finite element shape functions on the face. - LinearAlgebra::BlockVector mass_matrix(simulator_access.introspection().index_sets.system_partitioning, - simulator_access.get_mpi_communicator()); - LinearAlgebra::BlockVector distributed_heat_flux_vector(simulator_access.introspection().index_sets.system_partitioning, - simulator_access.get_mpi_communicator()); - LinearAlgebra::BlockVector heat_flux_vector(simulator_access.introspection().index_sets.system_partitioning, - simulator_access.introspection().index_sets.system_relevant_partitioning, - simulator_access.get_mpi_communicator()); - LinearAlgebra::BlockVector rhs_vector(simulator_access.introspection().index_sets.system_partitioning, - simulator_access.get_mpi_communicator()); - - distributed_heat_flux_vector = 0.; - heat_flux_vector = 0.; - - typename MaterialModel::Interface::MaterialModelInputs - in(fe_volume_values.n_quadrature_points, simulator_access.n_compositional_fields()); - typename MaterialModel::Interface::MaterialModelOutputs - out(fe_volume_values.n_quadrature_points, simulator_access.n_compositional_fields()); - - HeatingModel::HeatingModelOutputs - heating_out(fe_volume_values.n_quadrature_points, simulator_access.n_compositional_fields()); - - typename MaterialModel::Interface::MaterialModelInputs - face_in(fe_face_values.n_quadrature_points, simulator_access.n_compositional_fields()); - typename MaterialModel::Interface::MaterialModelOutputs - face_out(fe_face_values.n_quadrature_points, simulator_access.n_compositional_fields()); - - std::vector old_temperatures (n_q_points); - std::vector old_old_temperatures (n_q_points); - std::vector> temperature_gradients (n_q_points); - - const double time_step = simulator_access.get_timestep(); - const double old_time_step = simulator_access.get_old_timestep(); - - const std::set &fixed_temperature_boundaries = - simulator_access.get_boundary_temperature_manager().get_fixed_temperature_boundary_indicators(); - - const std::set &fixed_heat_flux_boundaries = - simulator_access.get_parameters().fixed_heat_flux_boundary_indicators; - - Vector artificial_viscosity(simulator_access.get_triangulation().n_active_cells()); - simulator_access.get_artificial_viscosity(artificial_viscosity, true); - - // loop over all of the surface cells and evaluate the heat flux - for (const auto &cell : simulator_access.get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned() && cell->at_boundary()) - { - fe_volume_values.reinit (cell); - in.reinit(fe_volume_values, cell, simulator_access.introspection(), simulator_access.get_solution()); - simulator_access.get_material_model().evaluate(in, out); - - if (simulator_access.get_parameters().formulation_temperature_equation == - Parameters::Formulation::TemperatureEquation::reference_density_profile) - { - for (unsigned int q=0; q 1) - { - Assert(time_step > 0.0 && old_time_step > 0.0, - ExcMessage("The heat flux postprocessor found a time step length of 0. " - "This is not supported, because it needs to compute the time derivative of the " - "temperature. Either use a positive timestep, or modify the postprocessor to " - "ignore the time derivative.")); - - temperature_time_derivative = (1.0/time_step) * - (in.temperature[q] * - (2*time_step + old_time_step) / (time_step + old_time_step) - - - old_temperatures[q] * - (1 + time_step/old_time_step) - + - old_old_temperatures[q] * - (time_step * time_step) / (old_time_step * (time_step + old_time_step))); - } - else if (simulator_access.get_timestep_number() == 1) - { - Assert(time_step > 0.0, - ExcMessage("The heat flux postprocessor found a time step length of 0. " - "This is not supported, because it needs to compute the time derivative of the " - "temperature. Either use a positive timestep, or modify the postprocessor to " - "ignore the time derivative.")); - - temperature_time_derivative = - (in.temperature[q] - old_temperatures[q]) / time_step; - } - else - temperature_time_derivative = 0.0; - - const double JxW = fe_volume_values.JxW(q); - - const double density_c_P = out.densities[q] * out.specific_heat[q]; - const double latent_heat_LHS = heating_out.lhs_latent_heat_terms[q]; - const double material_prefactor = density_c_P + latent_heat_LHS; - - const double artificial_viscosity_cell = static_cast(artificial_viscosity(cell->active_cell_index())); - - // The SUPG parameter tau does not have the physical dimensions of a thermal conductivity and as such should not be included in heat flux calculations - // By default, ASPECT includes the artificial viscosity in the thermal conductivity when calculating boundary heat flux. - const double diffusion_constant = (simulator_access.get_parameters().advection_stabilization_method == - Parameters::AdvectionStabilizationMethod::supg) ? - out.thermal_conductivities[q] - : - std::max(out.thermal_conductivities[q], - artificial_viscosity_cell); - - for (unsigned int i = 0; iface_indices()) - { - if (!cell->at_boundary(f)) - continue; - - fe_face_values.reinit (cell, f); - - const unsigned int boundary_id = cell->face(f)->boundary_id(); - - // Compute heat flux through Dirichlet boundary using CBF method - if (fixed_temperature_boundaries.find(boundary_id) != fixed_temperature_boundaries.end()) - { - // Assemble the mass matrix for cell face. Because the quadrature - // formula is chosen as co-located with the nodes of shape functions, - // the resulting matrix is diagonal. - for (unsigned int q=0; q::Formulation::TemperatureEquation::reference_density_profile) - { - for (unsigned int q=0; q> heat_flux(n_face_q_points); - heat_flux = simulator_access.get_boundary_heat_flux().heat_flux( - boundary_id, - face_in, - face_out, - fe_face_values.get_normal_vectors() - ); - - // For inhomogeneous Neumann boundaries we know the heat flux across the boundary at each point, - // and can thus simply integrate it for each cell. However, we still need to assemble the - // boundary terms for the CBF method, because there could be Dirichlet boundaries on the - // same cell (e.g. a different face in a corner). Therefore, do the integration into - // heat_flux_and_area, and assemble the CBF term into local_rhs. - for (unsigned int q=0; q < n_face_q_points; ++q) - { - for (unsigned int i = 0; idistribute_local_to_global(local_mass_matrix, mass_matrix); - cell->distribute_local_to_global(local_rhs, rhs_vector); - } - - mass_matrix.compress(VectorOperation::add); - rhs_vector.compress(VectorOperation::add); - - const IndexSet local_elements = mass_matrix.locally_owned_elements(); - for (unsigned int k=0; k 1.e-15) - distributed_heat_flux_vector[global_index] = rhs_vector[global_index] / mass_matrix[global_index]; - } - - distributed_heat_flux_vector.compress(VectorOperation::insert); - heat_flux_vector = distributed_heat_flux_vector; - - return heat_flux_vector; - } - - - - template - std::vector>> - compute_heat_flux_through_boundary_faces (const SimulatorAccess &simulator_access) - { - std::vector>> - heat_flux_and_area(simulator_access.get_triangulation().n_active_cells()); - - // Quadrature degree for assembling the consistent boundary flux equation, see Simulator::assemble_advection_system() - // for a justification of the chosen quadrature degree. - const unsigned int quadrature_degree = simulator_access.get_parameters().temperature_degree - + - (simulator_access.get_parameters().stokes_velocity_degree+1)/2; - - // GLL quadrature on the faces to get a diagonal mass matrix. - const QGaussLobatto quadrature_formula_face(quadrature_degree); - - FEFaceValues fe_face_values (simulator_access.get_mapping(), - simulator_access.get_fe(), - quadrature_formula_face, - update_JxW_values | - update_values | - update_gradients | - update_normal_vectors | - update_quadrature_points); - - const unsigned int n_face_q_points = quadrature_formula_face.size(); - - typename MaterialModel::Interface::MaterialModelInputs face_in(fe_face_values.n_quadrature_points, simulator_access.n_compositional_fields()); - typename MaterialModel::Interface::MaterialModelOutputs face_out(fe_face_values.n_quadrature_points, simulator_access.n_compositional_fields()); - - const std::set &fixed_temperature_boundaries = - simulator_access.get_boundary_temperature_manager().get_fixed_temperature_boundary_indicators(); - - const std::set &fixed_heat_flux_boundaries = - simulator_access.get_parameters().fixed_heat_flux_boundary_indicators; - - const std::set &tangential_velocity_boundaries = - simulator_access.get_boundary_velocity_manager().get_tangential_boundary_velocity_indicators(); - - const std::set &zero_velocity_boundaries = - simulator_access.get_boundary_velocity_manager().get_zero_boundary_velocity_indicators(); - - const LinearAlgebra::BlockVector heat_flux_vector = compute_dirichlet_boundary_heat_flux_solution_vector(simulator_access); - std::vector heat_flux_values(n_face_q_points); - - // loop over all of the surface cells and evaluate the heat flux - for (const auto &cell : simulator_access.get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned() && cell->at_boundary()) - { - for (const unsigned int f : cell->face_indices()) - if (cell->at_boundary(f)) - { - // See if this is the first face on this cell we visit, and if - // so resize the output array. - if (heat_flux_and_area[cell->active_cell_index()].size() == 0) - heat_flux_and_area[cell->active_cell_index()] - .resize (cell->n_faces(), std::pair(0.0,0.0)); - else - Assert (heat_flux_and_area[cell->active_cell_index()].size() == cell->n_faces(), - ExcInternalError()); - - // Determine the type of boundary - const unsigned int boundary_id = cell->face(f)->boundary_id(); - const bool prescribed_temperature = fixed_temperature_boundaries.find(boundary_id) != fixed_temperature_boundaries.end(); - const bool prescribed_heat_flux = fixed_heat_flux_boundaries.find(boundary_id) != fixed_heat_flux_boundaries.end(); - const bool non_tangential_velocity = - tangential_velocity_boundaries.find(boundary_id) == tangential_velocity_boundaries.end() && - zero_velocity_boundaries.find(boundary_id) == zero_velocity_boundaries.end(); - - fe_face_values.reinit (cell, f); - - // Integrate the face area - for (unsigned int q=0; qactive_cell_index()][f].second += fe_face_values.JxW(q); - - // Compute heat flux through Dirichlet boundaries by integrating the CBF solution vector - if (prescribed_temperature) - { - fe_face_values[simulator_access.introspection().extractors.temperature].get_function_values(heat_flux_vector, heat_flux_values); - - for (unsigned int q=0; qactive_cell_index()][f].first += heat_flux_values[q] * - fe_face_values.JxW(q); - } - - // if necessary, compute material properties for this face - if (prescribed_heat_flux || non_tangential_velocity) - { - face_in.reinit(fe_face_values, cell, simulator_access.introspection(), simulator_access.get_solution()); - simulator_access.get_material_model().evaluate(face_in, face_out); - - if (simulator_access.get_parameters().formulation_temperature_equation == - Parameters::Formulation::TemperatureEquation::reference_density_profile) - { - for (unsigned int q=0; q> heat_flux(n_face_q_points); - heat_flux = simulator_access.get_boundary_heat_flux().heat_flux( - boundary_id, - face_in, - face_out, - fe_face_values.get_normal_vectors() - ); - - for (unsigned int q=0; q < n_face_q_points; ++q) - { - const double normal_heat_flux = heat_flux[q] * fe_face_values.normal_vector(q); - const double JxW = fe_face_values.JxW(q); - heat_flux_and_area[cell->active_cell_index()][f].first += normal_heat_flux * JxW; - } - } - - // Compute advective heat flux - if (non_tangential_velocity) - { - for (unsigned int q=0; qactive_cell_index()][f].first += face_out.densities[q] * - face_out.specific_heat[q] * face_in.temperature[q] * - face_in.velocity[q] * fe_face_values.normal_vector(q) * - fe_face_values.JxW(q); - } - } - } - } - return heat_flux_and_area; - } - } - - - - template - std::pair - HeatFluxMap::execute (TableHandler &) - { - std::vector>> heat_flux_and_area = - internal::compute_heat_flux_through_boundary_faces (*this); - - const auto boundary_ids = this->get_geometry_model().get_used_boundary_indicators(); - for (const auto &boundary_id: boundary_ids) - if (this->get_geometry_model().translate_id_to_symbol_name(boundary_id) == "top" || - this->get_geometry_model().translate_id_to_symbol_name(boundary_id) == "bottom") - output_to_file(boundary_id, heat_flux_and_area); - - std::string placeholder_name = this->get_output_directory() + "heat_flux." + Utilities::int_to_string(this->get_timestep_number(), 5); - if (this->get_parameters().run_postprocessors_on_nonlinear_iterations) - placeholder_name.append("." + Utilities::int_to_string (this->get_nonlinear_iteration(), 4)); - - return std::pair("Writing heat flux map", - placeholder_name); - } - - - - template - void - HeatFluxMap::output_to_file(const types::boundary_id boundary_id, - const std::vector>> &heat_flux_and_area) - { - // get boundary name and avoid spaces for file output - std::string boundary_name = this->get_geometry_model().translate_id_to_symbol_name(boundary_id); - std::replace(boundary_name.begin(), boundary_name.end(), ' ', '_'); - - std::ostringstream output; - - // write the file header. note that we only do so on processor 0 - if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - output << "# " - << ((dim==2)? "x y" : "x y z") - << " heat_flux_" << boundary_name << std::endl; - } - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - for (const unsigned int f: cell->face_indices()) - if (cell->at_boundary(f) && - (cell->face(f)->boundary_id() == boundary_id)) - { - // evaluate position of heat flow to write into output file - const bool respect_manifold = true; - const Point midpoint_at_surface = cell->face(f)->center(respect_manifold); - - const double flux_density = heat_flux_and_area[cell->active_cell_index()][f].first / - heat_flux_and_area[cell->active_cell_index()][f].second; - - output << std::setprecision(10) - << midpoint_at_surface - << ' ' - << std::setprecision(10) - << flux_density - << std::endl; - } - - std::string filename = this->get_output_directory() + - "heat_flux_" + boundary_name + "." + - Utilities::int_to_string(this->get_timestep_number(), 5); - if (this->get_parameters().run_postprocessors_on_nonlinear_iterations) - filename.append("." + Utilities::int_to_string (this->get_nonlinear_iteration(), 4)); - - Utilities::collect_and_write_file_content(filename, output.str(), this->get_mpi_communicator()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - namespace internal - { -#define INSTANTIATE(dim) \ - template LinearAlgebra::BlockVector compute_dirichlet_boundary_heat_flux_solution_vector (const SimulatorAccess &simulator_access); - - ASPECT_INSTANTIATE(INSTANTIATE) - -#undef INSTANTIATE - } - - ASPECT_REGISTER_POSTPROCESSOR(HeatFluxMap, - "heat flux map", - "A postprocessor that computes the heat flux " - "density across each boundary in outward " - "direction, i.e., from the domain to the " - "outside. The heat flux is computed as sum " - "of advective heat flux and conductive heat " - "flux through Neumann boundaries, both " - "computed as integral over the boundary area, " - "and conductive heat flux through Dirichlet " - "boundaries, which is computed using the " - "consistent boundary flux method as described " - "in ``Gresho, Lee, Sani, Maslanik, Eaton (1987). " - "The consistent Galerkin FEM for computing " - "derived boundary quantities in thermal and or " - "fluids problems. International Journal for " - "Numerical Methods in Fluids, 7(4), 371-394.''") - } -} diff --git a/source/postprocess/heat_flux_statistics.cc.bak b/source/postprocess/heat_flux_statistics.cc.bak deleted file mode 100644 index e1c4110c748..00000000000 --- a/source/postprocess/heat_flux_statistics.cc.bak +++ /dev/null @@ -1,160 +0,0 @@ -/* - Copyright (C) 2011 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - HeatFluxStatistics::execute (TableHandler &statistics) - { - std::vector>> heat_flux_and_area = - internal::compute_heat_flux_through_boundary_faces (*this); - - std::map local_boundary_fluxes; - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - for (const unsigned int f : cell->face_indices()) - if (cell->at_boundary(f)) - { - const types::boundary_id boundary_indicator - = cell->face(f)->boundary_id(); - local_boundary_fluxes[boundary_indicator] += heat_flux_and_area[cell->active_cell_index()][f].first; - } - - // now communicate to get the global values - std::map global_boundary_fluxes; - { - // first collect local values in the same order in which they are listed - // in the set of boundary indicators - const std::set - boundary_indicators - = this->get_geometry_model().get_used_boundary_indicators (); - std::vector local_values; - local_values.reserve(boundary_indicators.size()); - for (const auto p : boundary_indicators) - local_values.emplace_back (local_boundary_fluxes[p]); - - // then collect contributions from all processors - std::vector global_values (local_values.size()); - Utilities::MPI::sum (local_values, this->get_mpi_communicator(), global_values); - - // and now take them apart into the global map again - unsigned int index = 0; - for (std::set::const_iterator - p = boundary_indicators.begin(); - p != boundary_indicators.end(); ++p, ++index) - global_boundary_fluxes[*p] = global_values[index]; - } - - // now add all of the computed heat fluxes to the statistics object - // and create a single string that can be output to the screen - std::ostringstream screen_text; - unsigned int index = 0; - for (std::map::const_iterator - p = global_boundary_fluxes.begin(); - p != global_boundary_fluxes.end(); ++p, ++index) - { - const std::string name = "Outward heat flux through boundary with indicator " - + Utilities::int_to_string(p->first) - + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() - .translate_id_to_symbol_name (p->first)) - + " (W)"; - statistics.add_value (name, p->second); - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - statistics.set_precision (name, 8); - statistics.set_scientific (name, true); - - // finally have something for the screen - screen_text.precision(4); - screen_text << p->second << " W" - << (index == global_boundary_fluxes.size()-1 ? "" : ", "); - } - - return std::pair ("Heat fluxes through boundary parts:", - screen_text.str()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(HeatFluxStatistics, - "heat flux statistics", - "A postprocessor that computes some " - "statistics about the heat flux " - "density across each boundary in outward " - "direction, i.e., from the domain to the " - "outside. The heat flux is computed as sum " - "of advective heat flux and conductive heat " - "flux through Neumann boundaries, both " - "computed as integral over the boundary area, " - "and conductive heat flux through Dirichlet " - "boundaries, which is computed using the " - "consistent boundary flux method as described " - "in ``Gresho, Lee, Sani, Maslanik, Eaton (1987). " - "The consistent Galerkin FEM for computing " - "derived boundary quantities in thermal and or " - "fluids problems. International Journal for " - "Numerical Methods in Fluids, 7(4), 371-394.''" - "The point-wise heat flux can be obtained from the heat flux map postprocessor, " - "which outputs the heat flux to a file, or the heat flux map " - "visualization postprocessor, which outputs the heat flux for " - "visualization. " - "\n\n" - "As stated, this postprocessor computes the \\textit{outbound} heat " - "flux. If you " - "are interested in the opposite direction, for example from " - "the core into the mantle when the domain describes the " - "mantle, then you need to multiply the result by -1." - "\n\n" - ":::{note}\n" - "In geodynamics, the term ``heat flux'' is often understood " - "to be the quantity $- k \\nabla T$, which is really a heat " - "flux \\textit{density}, i.e., a vector-valued field. In contrast " - "to this, the current postprocessor only computes the integrated " - "flux over each part of the boundary. Consequently, the units of " - "the quantity computed here are $W=\\frac{J}{s}$.\n" - ":::" - "\n\n" - "The ``heat flux densities'' postprocessor computes the same " - "quantity as the one here, but divided by the area of " - "the surface.") - } -} diff --git a/source/postprocess/heating_statistics.cc.bak b/source/postprocess/heating_statistics.cc.bak deleted file mode 100644 index 92d4e91a3a5..00000000000 --- a/source/postprocess/heating_statistics.cc.bak +++ /dev/null @@ -1,166 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - - -#include -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - HeatingStatistics::execute (TableHandler &statistics) - { - // create a quadrature formula based on the temperature element alone. - const Quadrature &quadrature_formula = this->introspection().quadratures.temperature; - const unsigned int n_q_points = quadrature_formula.size(); - - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_gradients | - update_quadrature_points | - update_JxW_values); - - MaterialModel::MaterialModelInputs in(fe_values.n_quadrature_points, this->n_compositional_fields()); - MaterialModel::MaterialModelOutputs out(fe_values.n_quadrature_points, this->n_compositional_fields()); - this->get_heating_model_manager().create_additional_material_model_inputs_and_outputs(in, out); - - std::vector> composition_values (this->n_compositional_fields(),std::vector (quadrature_formula.size())); - - const auto &heating_model_objects = this->get_heating_model_manager().get_active_heating_models(); - const std::vector &heating_model_names = this->get_heating_model_manager().get_active_heating_model_names(); - - HeatingModel::HeatingModelOutputs heating_model_outputs(n_q_points, this->n_compositional_fields()); - - std::ostringstream output; - output.precision(4); - - double average_heating_integral = 0.0; - double total_heating_integral = 0.0; - - std::vector local_heating_integrals (heating_model_objects.size()); - double local_mass = 0.0; - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit (cell); - in.reinit(fe_values, cell, this->introspection(), this->get_solution()); - - this->get_material_model().fill_additional_material_model_inputs(in, this->get_solution(), fe_values, this->introspection()); - this->get_material_model().evaluate(in, out); - - if (this->get_parameters().formulation_temperature_equation - == Parameters::Formulation::TemperatureEquation::reference_density_profile) - { - // Overwrite the density by the reference density coming from the - // adiabatic conditions as required by the formulation - for (unsigned int q=0; qget_adiabatic_conditions().density(in.position[q]); - } - else if (this->get_parameters().formulation_temperature_equation - == Parameters::Formulation::TemperatureEquation::real_density) - { - // use real density - } - else - AssertThrow(false, ExcNotImplemented()); - - for (unsigned int q=0; q>>::const_iterator - heating_model = heating_model_objects.begin(); - heating_model != heating_model_objects.end(); ++heating_model, ++index) - { - (*heating_model)->evaluate(in, out, heating_model_outputs); - - for (unsigned int q=0; q global_heating_integrals (heating_model_objects.size()); - double global_mass = 0.0; - - // compute the sum over all processors - Utilities::MPI::sum (local_heating_integrals, - this->get_mpi_communicator(), - global_heating_integrals); - global_mass = Utilities::MPI::sum (local_mass, this->get_mpi_communicator()); - - unsigned int index = 0; - for (typename std::list>>::const_iterator - heating_model = heating_model_objects.begin(); - heating_model != heating_model_objects.end(); ++heating_model, ++index) - { - // finally produce something for the statistics file - const std::string name1("Average " + heating_model_names[index] + " rate (W/kg)"); - statistics.add_value (name1, global_heating_integrals[index]/global_mass); - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - statistics.set_precision (name1, 8); - statistics.set_scientific (name1, true); - - const std::string name2("Total " + heating_model_names[index] + " rate (W)"); - statistics.add_value (name2, global_heating_integrals[index]); - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - statistics.set_precision (name2, 8); - statistics.set_scientific (name2, true); - - total_heating_integral += global_heating_integrals[index]; - } - - average_heating_integral = total_heating_integral/global_mass; - - output << average_heating_integral << " W/kg, " - << total_heating_integral << " W"; - - return std::pair ("Heating rate (average/total): ", - output.str()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(HeatingStatistics, - "heating statistics", - "A postprocessor that computes some statistics about " - "heating, averaged by volume. ") - } -} diff --git a/source/postprocess/interface.cc.bak b/source/postprocess/interface.cc.bak deleted file mode 100644 index 40ae8ab7c28..00000000000 --- a/source/postprocess/interface.cc.bak +++ /dev/null @@ -1,414 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include - - -namespace aspect -{ - namespace Postprocess - { -// ------------------------------ Interface ----------------------------- - - template - std::list - Interface::required_other_postprocessors() const - { - return {}; - } - - - - template - void - Interface::save (std::map &) const - {} - - - - template - void - Interface::load (const std::map &) - {} - - - -// ------------------------------ Manager ----------------------------- - - - template - std::list> - Manager::execute (TableHandler &statistics) - { - // call the execute() functions of all postprocessor objects we have - // here in turns - std::list> output_list; - for (const auto &p : this->plugin_objects) - { - try - { - // first call the update() function. - p->update(); - - // call the execute() function. if it produces any output - // then add it to the list - std::pair output - = p->execute (statistics); - - if (output.first.size() + output.second.size() > 0) - output_list.push_back (output); - } - // postprocessors that throw exceptions usually do not result in - // anything good because they result in an unwinding of the stack - // and, if only one processor triggers an exception, the - // destruction of objects often causes a deadlock. thus, if - // an exception is generated, catch it, print an error message, - // and abort the program - catch (std::exception &exc) - { - std::cerr << std::endl << std::endl - << "----------------------------------------------------" - << std::endl; - std::cerr << "Exception on MPI process <" - << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) - << "> while running postprocessor <" - << typeid(*p).name() - << ">: " << std::endl - << exc.what() << std::endl - << "Aborting!" << std::endl - << "----------------------------------------------------" - << std::endl; - - // terminate the program! - MPI_Abort (MPI_COMM_WORLD, 1); - } - catch (...) - { - std::cerr << std::endl << std::endl - << "----------------------------------------------------" - << std::endl; - std::cerr << "Exception on MPI process <" - << Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) - << "> while running postprocessor <" - << typeid(*p).name() - << ">: " << std::endl; - std::cerr << "Unknown exception!" << std::endl - << "Aborting!" << std::endl - << "----------------------------------------------------" - << std::endl; - - // terminate the program! - MPI_Abort (MPI_COMM_WORLD, 1); - } - } - - return output_list; - } - - -// -------------------------------- Deal with registering postprocessors and automating -// -------------------------------- their setup and selection at run time - - namespace - { - std::tuple - >, - aspect::internal::Plugins::PluginList>> registered_plugins; - } - - - - template - void - Manager::declare_parameters (ParameterHandler &prm) - { - // first declare the postprocessors we know about to - // choose from - prm.enter_subsection("Postprocess"); - { - // construct a string for Patterns::MultipleSelection that - // contains the names of all registered postprocessors - const std::string pattern_of_names - = std::get(registered_plugins).get_pattern_of_names (); - prm.declare_entry("List of postprocessors", - "", - Patterns::MultipleSelection(pattern_of_names), - "A comma separated list of postprocessor objects that should be run " - "at the end of each time step. Some of these postprocessors will " - "declare their own parameters which may, for example, include that " - "they will actually do something only every so many time steps or " - "years. Alternatively, the text `all' indicates that all available " - "postprocessors should be run after each time step.\n\n" - "The following postprocessors are available:\n\n" - + - std::get(registered_plugins).get_description_string()); - } - prm.leave_subsection(); - - // now declare the parameters of each of the registered - // postprocessors in turn - std::get(registered_plugins).declare_parameters (prm); - } - - - - template - void - Manager::parse_parameters (ParameterHandler &prm) - { - Assert (std::get(registered_plugins).plugins != nullptr, - ExcMessage ("No postprocessors registered!?")); - - // first find out which postprocessors are requested - std::vector postprocessor_names; - prm.enter_subsection("Postprocess"); - { - postprocessor_names - = Utilities::split_string_list(prm.get("List of postprocessors")); - AssertThrow(Utilities::has_unique_entries(postprocessor_names), - ExcMessage("The list of strings for the parameter " - "'Postprocess/List of postprocessors' contains entries more than once. " - "This is not allowed. Please check your parameter file.")); - } - prm.leave_subsection(); - - // see if 'all' was selected (or is part of the list). if so - // simply replace the list with one that contains all names - if (std::find (postprocessor_names.begin(), - postprocessor_names.end(), - "all") != postprocessor_names.end()) - { - postprocessor_names.clear(); - for (typename std::list>::PluginInfo>::const_iterator - p = std::get(registered_plugins).plugins->begin(); - p != std::get(registered_plugins).plugins->end(); ++p) - postprocessor_names.push_back (std::get<0>(*p)); - } - - // see if the user specified "global statistics" somewhere; if so, remove - // it from the list because we will *always* want to have it and so - // whether or not it has been explicitly provided by the user makes no - // difference. - std::vector::iterator new_end - = std::remove (postprocessor_names.begin(), - postprocessor_names.end(), - "global statistics"); - if (new_end != postprocessor_names.end()) - postprocessor_names.erase (new_end, postprocessor_names.end()); - - // in any case, put the global statistics postprocessor at the front: - postprocessor_names.insert(postprocessor_names.begin(), "global statistics"); - - // then go through the list, create objects and let them parse - // their own parameters - for (unsigned int name=0; nameplugin_objects.push_back (std::unique_ptr> - (std::get(registered_plugins) - .create_plugin (postprocessor_names[name], - "Postprocessor plugins"))); - if (SimulatorAccess *sim = dynamic_cast*>(&*this->plugin_objects.back())) - sim->initialize_simulator (this->get_simulator()); - - this->plugin_objects.back()->parse_parameters (prm); - this->plugin_objects.back()->initialize (); - - // now see if the newly created postprocessor relies on others. if so, - // go through the list of the ones we already have and if the required - // ones are new, add them to the end of the list we work through - const std::list additional_postprocessors - = this->plugin_objects.back()->required_other_postprocessors (); - - for (const auto &p : additional_postprocessors) - { - AssertThrow (Patterns::Selection(std::get(registered_plugins).get_pattern_of_names ()) - .match (p) == true, - ExcMessage ("Postprocessor <" + postprocessor_names[name] + - "> states that it depends on another postprocessor, <" - + p + - ">, but the latter is not a valid name.")); - - bool already_present = false; - for (const auto &postprocessor_name : postprocessor_names) - if (postprocessor_name == p) - { - already_present = true; - break; - } - - if (already_present == false) - postprocessor_names.push_back (p); - } - } - Assert (postprocessor_names.size() == this->plugin_objects.size(), - ExcInternalError()); - - // we now have matching lists 'this->plugin_objects' and 'postprocessor_names' - // that define which postprocessors we have. we just need to bring them - // into an order so that dependencies run first, and dependents after - // them. the algorithm for creating a sorted list for this works as follows: - // - // while there are postprocessors not yet added to the sorted list: - // - go through the list - // - if we encounter a postprocessor that has not yet been added yet: - // . if all of its dependencies are in the list, add it to the end - // . if at least one of its dependencies are not yet in the list, - // skip it - // - // if we go through a loop where we do not add a postprocessor to the list - // but there are still ones that haven't been added to the list, then we - // have found a cycle in the dependencies and that is clearly a problem - std::vector already_assigned (this->plugin_objects.size(), false); - std::vector sorted_names; - std::list>> sorted_postprocessors; - while (sorted_names.size() < this->plugin_objects.size()) - { - bool at_least_one_element_added = false; - - { - typename std::list>>::iterator - pp = this->plugin_objects.begin(); - for (unsigned int i=0; i deps = (*pp)->required_other_postprocessors(); - bool unmet_dependencies = false; - for (const auto &p : deps) - if (std::find (sorted_names.begin(), - sorted_names.end(), - p) == sorted_names.end()) - { - unmet_dependencies = true; - break; - } - - // if we have unmet dependencies, there is nothing we can do - // right now for this postprocessor (but we will come back for it) - // - // if there are none, add this postprocessor. using move semantics - // removes the postprocessor from the 'this->plugin_objects' array, - // which is ok since we will swap the two arrays at the end of the - // function. - if (unmet_dependencies == false) - { - sorted_names.push_back (postprocessor_names[i]); - sorted_postprocessors.emplace_back (std::move(*pp)); - already_assigned[i] = true; - at_least_one_element_added = true; - } - } - } - - // check that we have added at least one element; if not, there is a cycle - if (at_least_one_element_added == false) - { - std::ostringstream out; - out << "While sorting postprocessors by their dependencies, " - "ASPECT encountered a cycle in dependencies. The following " - "postprocessors are involved:\n"; - typename std::list>>::const_iterator - pp = this->plugin_objects.begin(); - for (unsigned int i=0; i "; - const std::list deps = (*pp)->required_other_postprocessors(); - for (const auto &p : deps) - out << "'" << p << "' "; - out << std::endl; - } - AssertThrow (false, ExcMessage(out.str())); - } - } - Assert (postprocessor_names.size() == sorted_names.size(), - ExcInternalError()); - Assert (sorted_postprocessors.size() == sorted_names.size(), - ExcInternalError()); - Assert (std::find (already_assigned.begin(), already_assigned.end(), false) == already_assigned.end(), - ExcInternalError()); - - // finally swap the unsorted list with the sorted list and only - // keep the latter - this->plugin_objects.swap (sorted_postprocessors); - } - - - template - void - Manager::register_postprocessor (const std::string &name, - const std::string &description, - void (*declare_parameters_function) (ParameterHandler &), - std::unique_ptr> (*factory_function) ()) - { - std::get(registered_plugins).register_plugin (name, - description, - declare_parameters_function, - factory_function); - } - - - - template - void - Manager::write_plugin_graph (std::ostream &out) - { - std::get(registered_plugins).write_plugin_graph ("Postprocessor interface", - out); - } - - } -} - - -// explicit instantiations -namespace aspect -{ - namespace internal - { - namespace Plugins - { - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - template <> - std::list>::PluginInfo> * - internal::Plugins::PluginList>::plugins = nullptr; - } - } - - namespace Postprocess - { -#define INSTANTIATE(dim) \ - template class Interface; \ - template class Manager; - - ASPECT_INSTANTIATE(INSTANTIATE) - -#undef INSTANTIATE - } -} diff --git a/source/postprocess/load_balance_statistics.cc.bak b/source/postprocess/load_balance_statistics.cc.bak deleted file mode 100644 index 2749d974c50..00000000000 --- a/source/postprocess/load_balance_statistics.cc.bak +++ /dev/null @@ -1,111 +0,0 @@ -/* - Copyright (C) 2016 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file doc/COPYING. If not see - . -*/ - - -#include - -#include - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - LoadBalanceStatistics::execute (TableHandler &statistics) - { - const unsigned int locally_owned_active_cells = this->get_triangulation().n_locally_owned_active_cells(); - const dealii::Utilities::MPI::MinMaxAvg cell_distribution - = dealii::Utilities::MPI::min_max_avg(locally_owned_active_cells, - this->get_mpi_communicator()); - - statistics.add_value ("Minimal cells per process", - static_cast(cell_distribution.min)); - statistics.add_value ("Maximal cells per process", - static_cast(cell_distribution.max)); - statistics.add_value ("Average cells per process", - cell_distribution.avg); - - if (this->n_particle_worlds() > 0) - { - const unsigned int locally_owned_particles = this->get_particle_world(0). - get_particle_handler().n_locally_owned_particles(); - const dealii::Utilities::MPI::MinMaxAvg particles_per_process = - dealii::Utilities::MPI::min_max_avg(locally_owned_particles,this->get_mpi_communicator()); - - statistics.add_value ("Minimal particles per process", - static_cast(particles_per_process.min)); - statistics.add_value ("Maximal particles per process", - static_cast(particles_per_process.max)); - statistics.add_value ("Average particles per process", - particles_per_process.avg); - - const double local_ratio = (locally_owned_active_cells != 0) - ? - static_cast(locally_owned_particles) - / static_cast(locally_owned_active_cells) - : - 0.0; - - const dealii::Utilities::MPI::MinMaxAvg particle_to_cell_ratio - = dealii::Utilities::MPI::min_max_avg(local_ratio, - this->get_mpi_communicator()); - - statistics.add_value ("Minimal local particle to cell ratio", particle_to_cell_ratio.min); - statistics.add_value ("Maximal local particle to cell ratio", particle_to_cell_ratio.max); - statistics.add_value ("Average local particle to cell ratio", particle_to_cell_ratio.avg); - } - - std::ostringstream output; - output.precision(4); - output << cell_distribution.min << '/' - << cell_distribution.max << '/' - << cell_distribution.avg; - - return std::pair ("Cells per process min/max/avg:", - output.str()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(LoadBalanceStatistics, - "load balance statistics", - "A postprocessor that computes statistics about " - "the distribution of cells, and if present particles " - "across subdomains. " - "In particular, it computes maximal, average and " - "minimal number of cells across all ranks. " - "If there are particles it also computes the " - "maximal, average, and minimum number of particles across " - "all ranks, and maximal, average, and minimal ratio " - "between local number of particles and local number " - "of cells across all processes. All of these numbers " - "can be useful to assess the load balance between " - "different MPI ranks, as the difference between the " - "minimal and maximal load should be as small as " - "possible.") - } -} diff --git a/source/postprocess/mass_flux_statistics.cc.bak b/source/postprocess/mass_flux_statistics.cc.bak deleted file mode 100644 index 55f09956ba6..00000000000 --- a/source/postprocess/mass_flux_statistics.cc.bak +++ /dev/null @@ -1,188 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - MassFluxStatistics::execute (TableHandler &statistics) - { - const std::string unit = (this->convert_output_to_years()) - ? - "kg/yr" - : - "kg/s"; - const double in_years = (this->convert_output_to_years()) - ? - year_in_seconds - : - 1.0; - - // create a quadrature formula based on the temperature element alone. - const Quadrature &quadrature_formula = this->introspection().face_quadratures.velocities; - - FEFaceValues fe_face_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | update_gradients | - update_normal_vectors | - update_quadrature_points | update_JxW_values); - - std::vector> composition_values (this->n_compositional_fields(),std::vector (quadrature_formula.size())); - - std::map local_boundary_fluxes; - - MaterialModel::MaterialModelInputs in(fe_face_values.n_quadrature_points, this->n_compositional_fields()); - MaterialModel::MaterialModelOutputs out(fe_face_values.n_quadrature_points, this->n_compositional_fields()); - in.requested_properties = MaterialModel::MaterialProperties::density; - - // for every surface face on which it makes sense to compute a - // mass flux and that is owned by this processor, - // integrate the normal mass flux given by the formula - // j = \rho * v * n - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - for (const unsigned int f : cell->face_indices()) - if (cell->at_boundary(f)) - { - fe_face_values.reinit (cell, f); - // Set use_strain_rates to false since we don't need viscosity - in.reinit(fe_face_values, cell, this->introspection(), this->get_solution()); - - this->get_material_model().evaluate(in, out); - - - double local_normal_flux = 0; - for (unsigned int q=0; qface(f)->boundary_id(); - local_boundary_fluxes[boundary_indicator] += local_normal_flux * in_years; - } - - // now communicate to get the global values - std::map global_boundary_fluxes; - { - // first collect local values in the same order in which they are listed - // in the set of boundary indicators - const std::set - boundary_indicators - = this->get_geometry_model().get_used_boundary_indicators (); - std::vector local_values; - local_values.reserve(boundary_indicators.size()); - for (const auto p : boundary_indicators) - local_values.push_back (local_boundary_fluxes[p]); - - // then collect contributions from all processors - std::vector global_values (local_values.size()); - Utilities::MPI::sum (local_values, this->get_mpi_communicator(), global_values); - - // and now take them apart into the global map again - unsigned int index = 0; - for (std::set::const_iterator - p = boundary_indicators.begin(); - p != boundary_indicators.end(); ++p, ++index) - global_boundary_fluxes[*p] = global_values[index]; - } - - // now add all of the computed mass fluxes to the statistics object - // and create a single string that can be output to the screen - std::ostringstream screen_text; - unsigned int index = 0; - for (std::map::const_iterator - p = global_boundary_fluxes.begin(); - p != global_boundary_fluxes.end(); ++p, ++index) - { - const std::string name = "Outward mass flux through boundary with indicator " - + Utilities::int_to_string(p->first) - + aspect::Utilities::parenthesize_if_nonempty(this->get_geometry_model() - .translate_id_to_symbol_name (p->first)) - + " (" + unit + ")"; - statistics.add_value (name, p->second); - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - statistics.set_precision (name, 8); - statistics.set_scientific (name, true); - - // finally have something for the screen - screen_text.precision(4); - screen_text << p->second << ' ' << unit - << (index == global_boundary_fluxes.size()-1 ? "" : ", "); - } - - return std::pair ("Mass fluxes through boundary parts:", - screen_text.str()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(MassFluxStatistics, - "mass flux statistics", - "A postprocessor that computes some statistics about " - "the mass flux across boundaries. For each boundary " - "indicator (see your geometry description for which boundary " - "indicators are used), the mass flux is computed in outward " - "direction, i.e., from the domain to the outside, using the " - "formula $\\int_{\\Gamma_i} \\rho \\mathbf v \\cdot \\mathbf n$ " - "where $\\Gamma_i$ is the part of the boundary with indicator $i$, " - "$\\rho$ is the density as reported by the material model, " - "$\\mathbf v$ is the velocity, and $\\mathbf n$ is the outward normal. " - "\n\n" - "As stated, this postprocessor computes the \\textit{outbound} mass " - "flux. If you " - "are interested in the opposite direction, for example from " - "the core into the mantle when the domain describes the " - "mantle, then you need to multiply the result by -1." - "\n\n" - ":::{note}\n" - "In geodynamics, the term ``mass flux'' is often understood " - "to be the quantity $\\rho \\mathbf v$, which is really a mass " - "flux \\textit{density}, i.e., a vector-valued field. In contrast " - "to this, the current postprocessor only computes the integrated " - "flux over each part of the boundary. Consequently, the units of " - "the quantity computed here are $\\frac{kg}{s}$.\n" - ":::") - } -} diff --git a/source/postprocess/material_statistics.cc.bak b/source/postprocess/material_statistics.cc.bak deleted file mode 100644 index 9c7f6157417..00000000000 --- a/source/postprocess/material_statistics.cc.bak +++ /dev/null @@ -1,128 +0,0 @@ -/* - Copyright (C) 2018 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - MaterialStatistics::execute (TableHandler &statistics) - { - // create a quadrature formula based on the temperature element alone. - const Quadrature &quadrature_formula = this->introspection().quadratures.temperature; - const unsigned int n_q_points = quadrature_formula.size(); - - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_gradients | - update_quadrature_points | - update_JxW_values); - - MaterialModel::MaterialModelInputs in(fe_values.n_quadrature_points, this->n_compositional_fields()); - MaterialModel::MaterialModelOutputs out(fe_values.n_quadrature_points, this->n_compositional_fields()); - in.requested_properties = MaterialModel::MaterialProperties::density | MaterialModel::MaterialProperties::viscosity; - - double local_volume = 0.0; - double local_mass = 0.0; - double local_viscosity = 0.0; - - // compute the integral quantities by quadrature - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit (cell); - in.reinit(fe_values, cell, this->introspection(), this->get_solution()); - - this->get_material_model().fill_additional_material_model_inputs(in, this->get_solution(), fe_values, this->introspection()); - this->get_material_model().evaluate(in, out); - - for (unsigned int q=0; qget_mpi_communicator()); - const double global_viscosity = Utilities::MPI::sum (local_viscosity, this->get_mpi_communicator()); - const double global_volume = Utilities::MPI::sum (local_volume, this->get_mpi_communicator()); - const double average_density = global_mass / global_volume; - const double average_viscosity = global_viscosity / global_volume; - - const std::string name1("Average density (kg/m^3)"); - statistics.add_value (name1, average_density); - statistics.set_precision (name1, 8); - statistics.set_scientific (name1, true); - - const std::string name2("Average viscosity (Pa s)"); - statistics.add_value (name2, average_viscosity); - statistics.set_precision (name2, 8); - statistics.set_scientific (name2, true); - - const std::string name3("Total mass (kg)"); - statistics.add_value (name3, global_mass); - statistics.set_precision (name3, 8); - statistics.set_scientific (name3, true); - - std::ostringstream output; - output.precision(4); - - output << average_density << " kg/m^3, " - << average_viscosity << " Pa s, " - << global_mass << " kg"; - - return std::pair ("Average density / Average viscosity / Total mass: ", - output.str()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(MaterialStatistics, - "material statistics", - "A postprocessor that computes some statistics about " - "the material properties. In particular, it computes the " - "volume-averages of the density and viscosity, and the " - "total mass in the model. Specifically, it implements " - "the following formulas in each time step: " - "$\\left<\\rho\\right> = \\frac{1}{|\\Omega|} \\int_\\Omega \\rho(\\mathbf x) \\, \\text{d}x$, " - "$\\left<\\eta\\right> = \\frac{1}{|\\Omega|} \\int_\\Omega \\eta(\\mathbf x) \\, \\text{d}x$, " - "$M = \\int_\\Omega \\rho(\\mathbf x) \\, \\text{d}x$, " - "where $|\\Omega|$ is the volume of the domain.") - } -} diff --git a/source/postprocess/matrix_statistics.cc.bak b/source/postprocess/matrix_statistics.cc.bak deleted file mode 100644 index 89409b70b32..00000000000 --- a/source/postprocess/matrix_statistics.cc.bak +++ /dev/null @@ -1,119 +0,0 @@ -/* - Copyright (C) 2016 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include - -#include -#include - - -namespace -{ - const std::string - get_stats(const aspect::LinearAlgebra::BlockSparseMatrix &matrix, - const std::string &matrix_name, - const MPI_Comm comm) - { - std::ostringstream output; - - // convert from bytes into Mb - const double mb = 1024*1024; - // sum up local matrix memory usage - double global_matrix_memory_consumption = dealii::Utilities::MPI::sum(matrix.memory_consumption(), - comm); - output << "\nTotal " << matrix_name << " memory consumption: " - << std::fixed << std::setprecision(2) << global_matrix_memory_consumption/mb - << " MB." << std::endl; - - // output number of nonzero elements in matrix. Do so with 1000s separator - // since they are frequently large; this was previously done by using the empty - // string locale, but creating std::locale with an empty string caused problems - // on some platforms, so the functionality to catch the exception and ignore - // is kept here, even though explicitly setting a facet should always work. - try - { - // Imbue the stream with a locale that does the right thing. The - // locale is responsible for later deleting the object pointed - // to by the last argument (the "facet"), see - // https://en.cppreference.com/w/cpp/locale/locale/locale - output.imbue(std::locale(std::locale(), - new aspect::Utilities::ThousandSep)); - } - catch (const std::runtime_error &e) - { - // If the locale doesn't work, just give up - } - - - output << "Total " << matrix_name << " nnz: " - << matrix.n_nonzero_elements() << std::endl; - - // output number of nonzero elements in each matrix block - output << matrix_name << " nnz by block: " << std::endl; - for (unsigned int i=0; i - std::pair - MatrixStatistics::execute (TableHandler &) - { - std::ostringstream output; - output << get_stats(this->get_system_matrix(), - "system matrix", - this->get_mpi_communicator()); - output << get_stats(this->get_system_preconditioner_matrix(), - "system preconditioner matrix", - this->get_mpi_communicator()); - - return std::pair ("", - output.str()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(MatrixStatistics, - "matrix statistics", - "A postprocessor that computes some statistics about " - "the matrices. " - "In particular, it outputs total memory consumption, " - "total non-zero elements, and non-zero elements per " - "block, for system matrix and system preconditioner matrix.") - } -} diff --git a/source/postprocess/max_depth_field.cc.bak b/source/postprocess/max_depth_field.cc.bak deleted file mode 100644 index d0cba1d2a56..00000000000 --- a/source/postprocess/max_depth_field.cc.bak +++ /dev/null @@ -1,131 +0,0 @@ -/* - Copyright (C) 2021 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file doc/COPYING. If not see - . -*/ - - -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - MaxDepthField::execute (TableHandler &statistics) - { - // create a quadrature formula based on the compositional element alone. - // be defensive about determining that a compositional field actually exists - AssertThrow(this->n_compositional_fields() > 0, - ExcMessage("This postprocessor cannot be used without compositional fields.")); - const Quadrature &quadrature_formula = this->introspection().quadratures.compositional_fields; - - const unsigned int n_q_points = quadrature_formula.size(); - - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_quadrature_points); - - std::vector compositional_values(n_q_points); - std::vector> position_values(n_q_points); - - std::vector local_max_depth(this->n_compositional_fields(), std::numeric_limits::lowest()); - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit (cell); - - position_values = fe_values.get_quadrature_points(); - - for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) - { - fe_values[this->introspection().extractors.compositional_fields[c]].get_function_values(this->get_solution(), compositional_values); - - for (unsigned int q = 0; q < n_q_points; ++q) - { - const double depth = this->get_geometry_model().depth(position_values[q]); - if (compositional_values[q] >= 0.5 && depth > local_max_depth[c]) - local_max_depth[c] = depth; - } - } - } - - // compute the max over all processors - std::vector global_max_depth(this->n_compositional_fields()); - Utilities::MPI::max (local_max_depth, - this->get_mpi_communicator(), - global_max_depth); - - // finally produce something for the statistics file - for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) - { - statistics.add_value("Max depth [m] for composition " + this->introspection().name_for_compositional_index(c), - global_max_depth[c]); - } - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) - { - const std::string columns[] = {"Max depth [m] for composition " + this->introspection().name_for_compositional_index(c)}; - for (const auto &col: columns) - { - statistics.set_precision(col, 8); - statistics.set_scientific(col, true); - } - } - - std::ostringstream output; - output.precision(4); - for (unsigned int c = 0; c < this->n_compositional_fields(); ++c) - { - output << global_max_depth[c]; - if (c + 1 != this->n_compositional_fields()) - output << " // "; - } - return std::pair("Compositions max depth [m]:", - output.str()); - - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(MaxDepthField, - "maximum depth of field", - "A postprocessor that for each compositional field " - "outputs the largest depth at which " - "a quadrature point is found where the field " - "has a value of 0.5 or larger. For fields that do not " - "represent materials, but for example track a certain quantity " - "like strain, this value of 0.5 does not necessarily make sense. ") - } -} diff --git a/source/postprocess/melt_statistics.cc.bak b/source/postprocess/melt_statistics.cc.bak deleted file mode 100644 index 22bb2ce3829..00000000000 --- a/source/postprocess/melt_statistics.cc.bak +++ /dev/null @@ -1,152 +0,0 @@ -/* - Copyright (C) 2015 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - - -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - MeltStatistics::execute (TableHandler &statistics) - { - // create a quadrature formula based on the temperature element alone. - const Quadrature &quadrature_formula = this->introspection().quadratures.temperature; - const unsigned int n_q_points = quadrature_formula.size(); - std::vector> composition_values (this->n_compositional_fields(), - std::vector (n_q_points)); - - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_gradients | - update_quadrature_points | - update_JxW_values); - - MaterialModel::MaterialModelInputs in(fe_values.n_quadrature_points, this->n_compositional_fields()); - - std::ostringstream output; - output.precision(4); - - double local_melt_integral = 0.0; - double local_min_melt = std::numeric_limits::max(); - double local_max_melt = std::numeric_limits::lowest(); - - // compute the integral quantities by quadrature - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - // fill material model inputs - fe_values.reinit (cell); - in.reinit(fe_values, cell, this->introspection(), this->get_solution()); - - // we can only postprocess melt fractions if the material model that is used - // in the simulation has implemented them - // otherwise, set them to zero - std::vector melt_fractions(n_q_points, 0.0); - if (MaterialModel::MeltFractionModel::is_melt_fraction_model(this->get_material_model())) - MaterialModel::MeltFractionModel::as_melt_fraction_model(this->get_material_model()) - .melt_fractions(in, melt_fractions); - - for (unsigned int q=0; qget_mpi_communicator()); - double global_min_melt = 0; - double global_max_melt = 0; - - // now do the reductions that are - // min/max operations. do them in - // one communication by multiplying - // one value by -1 - { - double local_values[2] = { -local_min_melt, local_max_melt }; - double global_values[2]; - - Utilities::MPI::max (local_values, this->get_mpi_communicator(), global_values); - - global_min_melt = -global_values[0]; - global_max_melt = global_values[1]; - } - - - // finally produce something for the statistics file - statistics.add_value ("Minimal melt fraction", - global_min_melt); - statistics.add_value ("Total melt volume", - global_melt_integral); - statistics.add_value ("Maximal melt fraction", - global_max_melt); - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - { - const char *columns[] = { "Minimal melt fraction", - "Total melt volume", - "Maximal melt fraction" - }; - for (auto &column : columns) - { - statistics.set_precision (column, 8); - statistics.set_scientific (column, true); - } - } - - output << global_min_melt << ", " - << global_melt_integral << ", " - << global_max_melt; - - return std::pair ("Melt fraction min/total/max:", - output.str()); - - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(MeltStatistics, - "melt statistics", - "A postprocessor that computes some statistics about " - "the melt (volume) fraction. If the material model " - "does not implement a melt fraction function, the output is " - "set to zero.") - } -} diff --git a/source/postprocess/memory_statistics.cc.bak b/source/postprocess/memory_statistics.cc.bak deleted file mode 100644 index 4bab32297b7..00000000000 --- a/source/postprocess/memory_statistics.cc.bak +++ /dev/null @@ -1,141 +0,0 @@ -/* - Copyright (C) 2016 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - - -#include -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - MemoryStatistics::execute (TableHandler &statistics) - { - // memory consumption: - const double mb = 1024*1024; // convert from bytes into mb - - statistics.add_value ("System matrix memory consumption (MB) ", this->get_system_matrix().memory_consumption()/mb); - statistics.add_value ("Triangulation memory consumption (MB) ", this->get_triangulation().memory_consumption()/mb); - statistics.add_value ("p4est memory consumption (MB) ", this->get_triangulation().memory_consumption_p4est()/mb); - - double dof_handler_mem = this->get_dof_handler().memory_consumption(); - double constraints_mem = this->get_current_constraints().memory_consumption(); - if (this->is_stokes_matrix_free()) - { - dof_handler_mem += this->get_stokes_matrix_free().get_dof_handler_v().memory_consumption() - + this->get_stokes_matrix_free().get_dof_handler_p().memory_consumption(); - - dof_handler_mem += this->get_stokes_matrix_free().get_dof_handler_projection().memory_consumption(); - - constraints_mem += this->get_stokes_matrix_free().get_constraints_v().memory_consumption() - + this->get_stokes_matrix_free().get_constraints_p().memory_consumption(); - } - statistics.add_value ("DoFHandler memory consumption (MB) ", dof_handler_mem/mb); - statistics.add_value ("AffineConstraints memory consumption (MB) ", constraints_mem/mb); - - statistics.add_value ("Solution vector memory consumption (MB) ", this->get_solution().memory_consumption()/mb); - - if (this->is_stokes_matrix_free()) - { - const double mg_transfer_mem = this->get_stokes_matrix_free().get_mg_transfer_A().memory_consumption() - + this->get_stokes_matrix_free().get_mg_transfer_S().memory_consumption(); - statistics.add_value ("MGTransfer memory consumption (MB) ", mg_transfer_mem/mb); - - const double cell_data_mem = this->get_stokes_matrix_free().get_cell_data_memory_consumption(); - statistics.add_value ("Matrix-free cell data memory consumption (MB) ", cell_data_mem/mb); - } - - if (output_vmpeak) - { - // allow disabling of the output because this is not stable in automated tests: - dealii::Utilities::System::MemoryStats stats; - dealii::Utilities::System::get_memory_stats(stats); - const double max_vmpeak = dealii::Utilities::MPI::max(stats.VmPeak/1024.0, this->get_mpi_communicator()); - statistics.add_value ("Peak virtual memory usage (VmPeak) (MB) ", max_vmpeak); - } - - std::ostringstream output; - output << std::fixed << std::setprecision(2) << this->get_system_matrix().memory_consumption()/mb << " MB"; - - return std::pair ("System matrix memory consumption: ", - output.str()); - - } - - - - - template - void - MemoryStatistics::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Memory statistics"); - { - prm.declare_entry ("Output peak virtual memory (VmPeak)", "true", - Patterns::Bool(), - "If set to 'true', also output the peak virtual memory " - "usage (computed as the maximum over all processors)."); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - - - template - void - MemoryStatistics::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Memory statistics"); - { - output_vmpeak = prm.get_bool ("Output peak virtual memory (VmPeak)"); - } - prm.leave_subsection(); - } - prm.leave_subsection(); - } - } -} - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(MemoryStatistics, - "memory statistics", - "A postprocessor that computes some statistics about " - "the memory consumption. " - "In particular, it computes the memory usage of the " - "system matrix, triangulation, p4est, " - "DoFHandler, current constraints, solution vector, " - "and peak virtual memory usage, all in MB. " - "It also outputs the memory usage of the system " - "matrix to the screen.") - } -} diff --git a/source/postprocess/mobility_statistics.cc.bak b/source/postprocess/mobility_statistics.cc.bak deleted file mode 100644 index f403f11a98c..00000000000 --- a/source/postprocess/mobility_statistics.cc.bak +++ /dev/null @@ -1,156 +0,0 @@ -/* - Copyright (C) 2011 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - MobilityStatistics::execute (TableHandler &statistics) - { - // create a quadrature formula for the velocity for the volume of cells - const Quadrature &quadrature_formula = this->introspection().quadratures.velocities; - const unsigned int n_q_points = quadrature_formula.size(); - - FEValues fe_values (this->get_mapping(), - this->get_fe(), - quadrature_formula, - update_values | - update_quadrature_points | - update_JxW_values); - - std::vector> velocity_values(n_q_points); - - // create a quadrature formula for the velocity for the surface of cells - const Quadrature &quadrature_formula_face - = this->introspection().face_quadratures.velocities; - const unsigned int n_q_points_face = quadrature_formula_face.size(); - - FEFaceValues fe_face_values (this->get_mapping(), - this->get_fe(), - quadrature_formula_face, - update_values | - update_JxW_values | - update_quadrature_points); - - std::vector> surface_velocity_values (n_q_points_face); - - double local_velocity_square_integral = 0; - double local_velocity_square_integral_top_boundary = 0; - double local_top_boundary_area = 0; - - const std::set - boundary_indicators - = this->get_geometry_model().get_used_boundary_indicators (); - const types::boundary_id top_boundary_id = this->get_geometry_model().translate_symbolic_boundary_name_to_id("top"); - - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - fe_values.reinit (cell); - // extract velocities - fe_values[this->introspection().extractors.velocities].get_function_values (this->get_solution(), - velocity_values); - for (unsigned int q = 0; q < n_q_points; ++q) - { - local_velocity_square_integral += velocity_values[q].norm_square() * - fe_values.JxW(q); - } - - // now for the surface cells only - for (const unsigned int f : cell->face_indices()) - if (cell->face(f)->boundary_id() == top_boundary_id) - { - fe_face_values.reinit (cell, f); - // extract velocities - fe_face_values[this->introspection().extractors.velocities].get_function_values (this->get_solution(), - surface_velocity_values); - - // determine the squared velocity on the face - for (unsigned int q = 0; q < n_q_points_face; ++q) - { - const double JxW = fe_face_values.JxW(q); - local_velocity_square_integral_top_boundary += surface_velocity_values[q].norm_square() * JxW; - local_top_boundary_area += JxW; - } - } - } - - // now communicate to get the global values and convert to rms - const double global_velocity_square_integral - = Utilities::MPI::sum (local_velocity_square_integral, this->get_mpi_communicator()); - - const double global_rms_vel = std::sqrt(global_velocity_square_integral) / - std::sqrt(this->get_volume()); - - const double global_top_velocity_square_integral = Utilities::MPI::sum(local_velocity_square_integral_top_boundary, this->get_mpi_communicator()); - const double global_top_boundary_area_integral = Utilities::MPI::sum(local_top_boundary_area, this->get_mpi_communicator()); - - const double global_top_rms_vel = std::sqrt(global_top_velocity_square_integral) / - std::sqrt(global_top_boundary_area_integral); - - // now add the computed rms velocities to the statistics object - // and create a single string that can be output to the screen - const double mobility = global_top_rms_vel / global_rms_vel; - const std::string name_mobility = "Mobility"; - - statistics.add_value (name_mobility, - mobility); - - // also make sure that the other columns filled by this object - // all show up with sufficient accuracy and in scientific notation - statistics.set_precision (name_mobility, 8); - statistics.set_scientific (name_mobility, true); - - std::ostringstream output; - output.precision(3); - output << mobility; - - return std::pair ("Mobility:", - output.str()); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(MobilityStatistics, - "mobility statistics", - "A postprocessor that computes some statistics about mobility " - "following Tackley (2000) and Lourenco et al. (2020).") - } -} diff --git a/source/postprocess/particle_count_statistics.cc.bak b/source/postprocess/particle_count_statistics.cc.bak deleted file mode 100644 index 8b2ca0c952b..00000000000 --- a/source/postprocess/particle_count_statistics.cc.bak +++ /dev/null @@ -1,97 +0,0 @@ -/* - Copyright (C) 2016 - 2021 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include - -#include -#include - - -namespace aspect -{ - namespace Postprocess - { - template - std::pair - ParticleCountStatistics::execute (TableHandler &statistics) - { - const Particle::ParticleHandler &particle_handler = - this->get_particle_world(0).get_particle_handler(); - - unsigned int local_min_particles = std::numeric_limits::max(); - unsigned int local_max_particles = 0; - const Particle::types::particle_index global_particles = this->get_particle_world(0).n_global_particles(); - - // compute local min/max - for (const auto &cell : this->get_dof_handler().active_cell_iterators()) - if (cell->is_locally_owned()) - { - const unsigned int particles_in_cell = particle_handler.n_particles_in_cell(cell); - local_min_particles = std::min(local_min_particles,particles_in_cell); - local_max_particles = std::max(local_max_particles,particles_in_cell); - } - - // now do the reductions over all processors - const unsigned int global_min_particles = Utilities::MPI::min (local_min_particles, - this->get_mpi_communicator()); - const unsigned int global_max_particles = Utilities::MPI::max (local_max_particles, - this->get_mpi_communicator()); - - // finally produce something for the statistics file - statistics.add_value ("Minimal particles per cell: ", global_min_particles); - statistics.add_value ("Average particles per cell: ", global_particles / this->get_triangulation().n_global_active_cells()); - statistics.add_value ("Maximal particles per cell: ", global_max_particles); - - std::ostringstream output; - output << global_min_particles << ", " - << global_particles / this->get_triangulation().n_global_active_cells() << ", " - << global_max_particles; - - return std::pair ("Particle count per cell min/avg/max:", - output.str()); - } - - - - template - std::list - ParticleCountStatistics::required_other_postprocessors() const - { - return {"particles"}; - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - ASPECT_REGISTER_POSTPROCESSOR(ParticleCountStatistics, - "particle count statistics", - "A postprocessor that computes some statistics about " - "the particle distribution, if present in this simulation. " - "In particular, it computes minimal, average and maximal " - "values of particles per cell in the global domain.") - } -} diff --git a/source/postprocess/particles.cc.bak b/source/postprocess/particles.cc.bak deleted file mode 100644 index 126f6a1f607..00000000000 --- a/source/postprocess/particles.cc.bak +++ /dev/null @@ -1,758 +0,0 @@ -/* - Copyright (C) 2011 - 2023 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . - */ - -#include -#include -#include -#include - -#include -#include - -#include -#include - -namespace aspect -{ - namespace Postprocess - { - namespace internal - { - template - void - ParticleOutput::build_patches(const dealii::Particles::ParticleHandler &particle_handler, - const aspect::Particle::Property::ParticlePropertyInformation &property_information, - const std::vector &exclude_output_properties, - const bool only_group_3d_vectors) - { - // First store the names of the data fields that should be written - dataset_names.reserve(property_information.n_components()+1); - dataset_names.emplace_back("id"); - - // This is a map from an index for the particle property vector to an index in the output - // vector. Values equal 0 indicate a property will not be written, values bigger 0 - // indicate into which output entry the property value should be written. - std::vector property_index_to_output_index(property_information.n_components(),0); - - if (std::find(exclude_output_properties.begin(), - exclude_output_properties.end(), - "all") - == exclude_output_properties.end()) - { - // Start the output index from 1, because 0 is occupied by the "id" - unsigned int output_index = 1; - for (unsigned int field_index = 0; field_index < property_information.n_fields(); ++field_index) - { - // Determine some info about the field. - const unsigned n_components = property_information.get_components_by_field_index(field_index); - const std::string field_name = property_information.get_field_name_by_index(field_index); - const unsigned int field_position = property_information.n_fields() == 0 - ? - 0 - : - property_information.get_position_by_field_index(field_index); - - // HDF5 only supports 3d vector output, therefore only treat output fields as vector if we - // have a dimension of 3 and 3 components. - const bool field_is_vector = (only_group_3d_vectors == false - ? - n_components == dim - : - dim == 3 && n_components == 3); - - // Determine if this field should be excluded, if so, skip it - bool exclude_property = false; - for (const auto &property : exclude_output_properties) - if (field_name.find(property) != std::string::npos) - { - exclude_property = true; - break; - } - - if (exclude_property == false) - { - // For each component record its name and position in output vector - for (unsigned int component_index=0; component_index::particle_iterator particle = particle_handler.begin(); - - for (unsigned int i=0; particle != particle_handler.end(); ++particle, ++i) - { - patches[i].vertices[0] = particle->get_location(); - patches[i].patch_index = i; - - patches[i].data.reinit(dataset_names.size(),1); - - patches[i].data(0,0) = particle->get_id(); - - if (particle->has_properties()) - { - const ArrayView properties = particle->get_properties(); - - for (unsigned int property_index = 0; property_index < properties.size(); ++property_index) - { - if (property_index_to_output_index[property_index] > 0) - patches[i].data(property_index_to_output_index[property_index],0) = properties[property_index]; - } - } - } - } - - template - const std::vector> & - ParticleOutput::get_patches () const - { - return patches; - } - - template - std::vector - ParticleOutput::get_dataset_names () const - { - return dataset_names; - } - - template - std::vector< - std::tuple> - ParticleOutput::get_nonscalar_data_ranges () const - { - return vector_datasets; - } - } - - template - Particles::Particles () - : - // the following value is later read from the input file - output_interval (0), - // initialize this to a nonsensical value; set it to the actual time - // the first time around we get to check it - last_output_time (std::numeric_limits::quiet_NaN()) - ,output_file_number (numbers::invalid_unsigned_int), - group_files(0), - write_in_background_thread(false) - {} - - - - template - Particles::~Particles () - { - // make sure a thread that may still be running in the background, - // writing data, finishes - if (background_thread.joinable()) - background_thread.join (); - } - - - - template - // We need to pass the arguments by value, as this function can be called on a separate thread: - void Particles::writer (const std::string &filename, //NOLINT(performance-unnecessary-value-param) - const std::string &temporary_output_location, //NOLINT(performance-unnecessary-value-param) - const std::string &file_contents) - { - std::string tmp_filename = filename; - if (temporary_output_location != "") - { - tmp_filename = temporary_output_location + "/aspect.tmp.XXXXXX"; - - // Create the temporary file; get at the actual filename - // by using a C-style string that mkstemp will then overwrite - std::vector tmp_filename_x (tmp_filename.size()+1); - std::strcpy(tmp_filename_x.data(), tmp_filename.c_str()); - const int tmp_file_desc = mkstemp(tmp_filename_x.data()); - tmp_filename = tmp_filename_x.data(); - - // If we failed to create the temp file, just write directly to the target file. - // We also provide a warning about this fact. There are places where - // this fails *on every node*, so we will get a lot of warning messages - // into the output; in these cases, just writing multiple pieces to - // std::cerr will produce an unreadable mass of text; rather, first - // assemble the error message completely, and then output it atomically - if (tmp_file_desc == -1) - { - const std::string x = ("***** WARNING: could not create temporary file <" - + - tmp_filename - + - ">, will output directly to final location. This may negatively " - "affect performance. (On processor " - + Utilities::int_to_string(Utilities::MPI::this_mpi_process (MPI_COMM_WORLD)) - + ".)\n"); - - std::cerr << x << std::flush; - - tmp_filename = filename; - } - else - close(tmp_file_desc); - } - - std::ofstream out(tmp_filename); - - AssertThrow (out, ExcMessage(std::string("Trying to write to file <") + - filename + - ">, but the file can't be opened!")); - - // now write and then move the tmp file to its final destination - // if necessary - out << file_contents; - out.close (); - - if (tmp_filename != filename) - { - std::string command = std::string("mv ") + tmp_filename + " " + filename; - int error = system(command.c_str()); - - AssertThrow(error == 0, - ExcMessage("Could not move " + tmp_filename + " to " - + filename + ". On processor " - + Utilities::int_to_string(Utilities::MPI::this_mpi_process (MPI_COMM_WORLD)) + ".")); - } - } - - template - void - Particles::write_description_files (const internal::ParticleOutput &data_out, - const std::string &solution_file_prefix, - const std::vector &filenames) - { - const double time_in_years_or_seconds = (this->convert_output_to_years() ? - this->get_time() / year_in_seconds : - this->get_time()); - const std::string pvtu_filename = (solution_file_prefix + - ".pvtu"); - std::ofstream pvtu_file (this->get_output_directory() + "particles/" + - pvtu_filename); - data_out.write_pvtu_record (pvtu_file, filenames); - - // now also generate a .pvd file that matches simulation - // time and corresponding .pvtu record - times_and_pvtu_file_names.emplace_back(time_in_years_or_seconds, "particles/"+pvtu_filename); - - const std::string pvd_filename = (this->get_output_directory() + "particles.pvd"); - std::ofstream pvd_file (pvd_filename); - - DataOutBase::write_pvd_record (pvd_file, times_and_pvtu_file_names); - - // finally, do the same for VisIt via the .visit file for this - // time step, as well as for all time steps together - const std::string visit_filename = (this->get_output_directory() - + "particles/" - + solution_file_prefix - + ".visit"); - std::ofstream visit_file (visit_filename); - - DataOutBase::write_visit_record (visit_file, filenames); - - { - // the global .visit file needs the relative path because it sits a - // directory above - std::vector filenames_with_path; - filenames_with_path.reserve(filenames.size()); - for (const auto &filename : filenames) - { - filenames_with_path.push_back("particles/" + filename); - } - - output_file_names_by_timestep.push_back (filenames_with_path); - } - - std::ofstream global_visit_file (this->get_output_directory() + - "particles.visit"); - - std::vector>> times_and_output_file_names; - for (unsigned int timestep=0; timestep - std::pair - Particles::execute (TableHandler &statistics) - { - // if this is the first time we get here, set the last output time - // to the current time - output_interval. this makes sure we - // always produce data during the first time step - if (std::isnan(last_output_time)) - last_output_time = this->get_time() - output_interval; - - const Particle::World &world = this->get_particle_world(0); - - statistics.add_value("Number of advected particles",world.n_global_particles()); - - // If it's not time to generate an output file - // return early with the number of particles that were advected - if (this->get_time() < last_output_time + output_interval) - return std::make_pair("Number of advected particles:", - Utilities::int_to_string(world.n_global_particles())); - - // If we do not write output - // return early with the number of particles that were advected - if (output_formats.size() == 0 || output_formats[0] == "none") - { - // Up the next time we need output. This is relevant to correctly - // write output after a restart if the format is changed. - set_last_output_time (this->get_time()); - - return std::make_pair("Number of advected particles:", - Utilities::int_to_string(world.n_global_particles())); - } - - if (output_file_number == numbers::invalid_unsigned_int) - output_file_number = 0; - else - ++output_file_number; - - // Create the particle output - const bool output_hdf5 = std::find(output_formats.begin(), output_formats.end(),"hdf5") != output_formats.end(); - internal::ParticleOutput data_out; - data_out.build_patches(world.get_particle_handler(), - world.get_property_manager().get_data_info(), - exclude_output_properties, - output_hdf5); - - // Now prepare everything for writing the output and choose output format - std::string particle_file_prefix = "particles-" + Utilities::int_to_string (output_file_number, 5); - - const double time_in_years_or_seconds = (this->convert_output_to_years() ? - this->get_time() / year_in_seconds : - this->get_time()); - - for (const auto &output_format : output_formats) - { - // this case was handled above - Assert(output_format != "none", ExcInternalError()); - - if (output_format == "hdf5") - { - const std::string particle_file_name = "particles/" + particle_file_prefix + ".h5"; - const std::string xdmf_filename = "particles.xdmf"; - - // Do not filter redundant values, there are no duplicate particles - DataOutBase::DataOutFilter data_filter(DataOutBase::DataOutFilterFlags(false, true)); - - data_out.write_filtered_data(data_filter); - data_out.write_hdf5_parallel(data_filter, - this->get_output_directory()+particle_file_name, - this->get_mpi_communicator()); - - const XDMFEntry new_xdmf_entry = data_out.create_xdmf_entry(data_filter, - particle_file_name, - time_in_years_or_seconds, - this->get_mpi_communicator()); - xdmf_entries.push_back(new_xdmf_entry); - data_out.write_xdmf_file(xdmf_entries, this->get_output_directory() + xdmf_filename, - this->get_mpi_communicator()); - } - else if (output_format == "vtu") - { - // Write descriptive files (.pvtu,.pvd,.visit) on the root process - const int my_id = Utilities::MPI::this_mpi_process(this->get_mpi_communicator()); - - if (my_id == 0) - { - std::vector filenames; - const unsigned int n_processes = Utilities::MPI::n_mpi_processes(this->get_mpi_communicator()); - const unsigned int n_files = (group_files == 0) ? n_processes : std::min(group_files,n_processes); - for (unsigned int i=0; iget_mpi_communicator()); - - const unsigned int my_file_id = (group_files == 0 - ? - my_id - : - my_id % group_files); - const std::string filename = this->get_output_directory() - + "particles/" - + particle_file_prefix - + "." - + Utilities::int_to_string (my_file_id, 4) - + ".vtu"; - - // pass time step number and time as metadata into the output file - DataOutBase::VtkFlags vtk_flags; - vtk_flags.cycle = this->get_timestep_number(); - vtk_flags.time = time_in_years_or_seconds; - - data_out.set_flags (vtk_flags); - - // Write as many files as processes. For this case we support writing in a - // background thread and to a temporary location, so we first write everything - // into a string that is written to disk in a writer function - if ((group_files == 0) || (group_files >= n_processes)) - { - // Put the content we want to write into a string object that - // we can then write in the background - std::unique_ptr file_contents; - { - std::ostringstream tmp; - - data_out.write (tmp, DataOutBase::parse_output_format(output_format)); - file_contents = std::make_unique(tmp.str()); - } - - if (write_in_background_thread) - { - // Wait for all previous write operations to finish, should - // any be still active, ... - if (background_thread.joinable()) - background_thread.join (); - - // ...then continue with writing our own data. - background_thread - = std::thread([ my_filename = filename, // filename is const, so we can not move from it - my_temporary_output_location = temporary_output_location, - my_file_contents = std::move(file_contents)]() - { - writer (my_filename, my_temporary_output_location, *my_file_contents); - }); - } - else - writer(filename,temporary_output_location,*file_contents); - } - // Just write one data file in parallel - else if (group_files == 1) - { - data_out.write_vtu_in_parallel(filename, - this->get_mpi_communicator()); - } - // Write as many output files as 'group_files' groups - else - { - int color = my_id % group_files; - - MPI_Comm comm; - int ierr = MPI_Comm_split(this->get_mpi_communicator(), color, my_id, &comm); - AssertThrowMPI(ierr); - - data_out.write_vtu_in_parallel(filename, comm); - ierr = MPI_Comm_free(&comm); - AssertThrowMPI(ierr); - } - } - // Write in a different format than hdf5 or vtu. This case is supported, but is not - // optimized for parallel output in that every process will write one file directly - // into the output directory. This may or may not affect performance depending on - // the model setup and the network file system type. - else - { - const unsigned int myid = Utilities::MPI::this_mpi_process(this->get_mpi_communicator()); - - const std::string filename = this->get_output_directory() - + "particles/" - + particle_file_prefix - + "." - + Utilities::int_to_string (myid, 4) - + DataOutBase::default_suffix - (DataOutBase::parse_output_format(output_format)); - - std::ofstream out (filename); - - AssertThrow(out, - ExcMessage("Unable to open file for writing: " + filename +".")); - - data_out.write (out, DataOutBase::parse_output_format(output_format)); - } - } - - - // up the next time we need output - set_last_output_time (this->get_time()); - - const std::string particle_output = this->get_output_directory() + "particles/" + particle_file_prefix; - - // record the file base file name in the output file - statistics.add_value ("Particle file name", - particle_output); - return std::make_pair("Writing particle output:", particle_output); - } - - - - template - void - Particles::set_last_output_time (const double current_time) - { - // if output_interval is positive, then update the last supposed output - // time - if (output_interval > 0) - { - // We need to find the last time output was supposed to be written. - // this is the last_output_time plus the largest positive multiple - // of output_intervals that passed since then. We need to handle the - // edge case where last_output_time+output_interval==current_time, - // we did an output and std::floor sadly rounds to zero. This is done - // by forcing std::floor to round 1.0-eps to 1.0. - const double magic = 1.0+2.0*std::numeric_limits::epsilon(); - last_output_time = last_output_time + std::floor((current_time-last_output_time)/output_interval*magic) * output_interval/magic; - } - } - - - template - template - void Particles::serialize (Archive &ar, const unsigned int) - { - ar &last_output_time - & output_file_number - & times_and_pvtu_file_names - & output_file_names_by_timestep - & xdmf_entries - ; - } - - - template - void - Particles::save (std::map &status_strings) const - { - std::ostringstream os; - aspect::oarchive oa (os); - - this->get_particle_world(0).save(os); - oa << (*this); - - status_strings["Particles"] = os.str(); - } - - - template - void - Particles::load (const std::map &status_strings) - { - // see if something was saved - if (status_strings.find("Particles") != status_strings.end()) - { - std::istringstream is (status_strings.find("Particles")->second); - aspect::iarchive ia (is); - - // Load the particle world - this->get_particle_world(0).load(is); - - ia >> (*this); - } - } - - - template - void - Particles::declare_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Particles"); - { - prm.declare_entry ("Time between data output", "1e8", - Patterns::Double (0.), - "The time interval between each generation of " - "output files. A value of zero indicates that " - "output should be generated every time step.\n\n" - "Units: years if the " - "'Use years in output instead of seconds' parameter is set; " - "seconds otherwise."); - - // now also see about the file format we're supposed to write in - // Note: "ascii" is a legacy format used by ASPECT before particle output - // in deal.II was implemented. It is nearly identical to the gnuplot format, thus - // we now simply replace "ascii" by "gnuplot" should it be selected. - prm.declare_entry ("Data output format", "vtu", - Patterns::MultipleSelection (DataOutBase::get_output_format_names ()+"|ascii"), - "A comma separated list of file formats to be used for graphical " - "output. The list of possible output formats that can be given " - "here is documented in the appendix of the manual where the current " - "parameter is described."); - - prm.declare_entry ("Number of grouped files", "16", - Patterns::Integer(0), - "VTU file output supports grouping files from several CPUs " - "into a given number of files using MPI I/O when writing on a parallel " - "filesystem. Select 0 for no grouping. This will disable " - "parallel file output and instead write one file per processor. " - "A value of 1 will generate one big file containing the whole " - "solution, while a larger value will create that many files " - "(at most as many as there are MPI ranks)."); - - prm.declare_entry ("Write in background thread", "false", - Patterns::Bool(), - "File operations can potentially take a long time, blocking the " - "progress of the rest of the model run. Setting this variable to " - "`true' moves this process into a background thread, while the " - "rest of the model continues."); - - prm.declare_entry ("Temporary output location", "", - Patterns::Anything(), - "On large clusters it can be advantageous to first write the " - "output to a temporary file on a local file system and later " - "move this file to a network file system. If this variable is " - "set to a non-empty string it will be interpreted as a " - "temporary storage location."); - - prm.declare_entry ("Exclude output properties", "", - Patterns::Anything(), - "A comma separated list of particle properties that should " - "\\textit{not} be output. If this list contains the " - "entry `all', only the id of particles will be provided in " - "graphical output files."); - } - prm.leave_subsection (); - } - prm.leave_subsection (); - - Particle::World::declare_parameters(prm); - } - - - template - void - Particles::parse_parameters (ParameterHandler &prm) - { - prm.enter_subsection("Postprocess"); - { - prm.enter_subsection("Particles"); - { - output_interval = prm.get_double ("Time between data output"); - if (this->convert_output_to_years()) - output_interval *= year_in_seconds; - - AssertThrow(this->get_parameters().run_postprocessors_on_nonlinear_iterations == false, - ExcMessage("Postprocessing nonlinear iterations in models with " - "particles is currently not supported.")); - - output_formats = Utilities::split_string_list(prm.get ("Data output format")); - AssertThrow(Utilities::has_unique_entries(output_formats), - ExcMessage("The list of strings for the parameter " - "'Postprocess/Particles/Data output format' contains entries more than once. " - "This is not allowed. Please check your parameter file.")); - - AssertThrow ((std::find (output_formats.begin(), - output_formats.end(), - "none") == output_formats.end()) - || - (output_formats.size() == 1), - ExcMessage ("If you specify 'none' for the parameter \"Data output format\", " - "then this needs to be the only value given.")); - - if (std::find (output_formats.begin(), - output_formats.end(), - "none") == output_formats.end()) - aspect::Utilities::create_directory (this->get_output_directory() + "particles/", - this->get_mpi_communicator(), - true); - - // Note: "ascii" is a legacy format used by ASPECT before particle output - // in deal.II was implemented. It is nearly identical to the gnuplot format, thus - // we simply replace "ascii" by "gnuplot" should it be selected. - std::vector::iterator output_format = std::find (output_formats.begin(), - output_formats.end(), - "ascii"); - if (output_format != output_formats.end()) - *output_format = "gnuplot"; - - group_files = prm.get_integer("Number of grouped files"); - write_in_background_thread = prm.get_bool("Write in background thread"); - temporary_output_location = prm.get("Temporary output location"); - - if (temporary_output_location != "") - { - // Check if a command-processor is available by calling system() with a - // null pointer. System is guaranteed to return non-zero if it finds - // a terminal and zero if there is none (like on the compute nodes of - // some cluster architectures, e.g. IBM BlueGene/Q) - AssertThrow(system((char *)nullptr) != 0, - ExcMessage("Usage of a temporary storage location is only supported if " - "there is a terminal available to move the files to their final location " - "after writing. The system() command did not succeed in finding such a terminal.")); - } - - exclude_output_properties = Utilities::split_string_list(prm.get("Exclude output properties")); - - // Never output the integrator properties that are for internal use only - exclude_output_properties.emplace_back("internal: integrator properties"); - } - prm.leave_subsection (); - } - prm.leave_subsection (); - } - } -} - - -// explicit instantiations -namespace aspect -{ - namespace Postprocess - { - namespace internal - { -#define INSTANTIATE(dim) \ - template class ParticleOutput; - - ASPECT_INSTANTIATE(INSTANTIATE) - -#undef INSTANTIATE - } - - ASPECT_REGISTER_POSTPROCESSOR(Particles, - "particles", - "A Postprocessor that creates particles that follow the " - "velocity field of the simulation. The particles can be generated " - "and propagated in various ways and they can carry a number of " - "constant or time-varying properties. The postprocessor can write " - "output positions and properties of all particles at chosen intervals, " - "although this is not mandatory. It also allows other parts of the " - "code to query the particles for information.") - } -} diff --git a/source/postprocess/point_values.cc.bak b/source/postprocess/point_values.cc.bak deleted file mode 100644 index 9b3d7401b72..00000000000 --- a/source/postprocess/point_values.cc.bak +++ /dev/null @@ -1,369 +0,0 @@ -/* - Copyright (C) 2016 - 2022 by the authors of the ASPECT code. - - This file is part of ASPECT. - - ASPECT is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - ASPECT 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with ASPECT; see the file LICENSE. If not see - . -*/ - - -#include -#include -#include -#include -#include -#include - -#include - -namespace aspect -{ - namespace Postprocess - { - template - PointValues::PointValues () - : - // the following value is later read from the input file - output_interval (0), - // initialize this to a nonsensical value; set it to the actual time - // the first time around we get to check it - last_output_time (std::numeric_limits::quiet_NaN()), - evaluation_points_cartesian (std::vector>() ), - point_values (std::vector>>>() ), - use_natural_coordinates (false) - {} - - template - std::pair - PointValues::execute (TableHandler &) - { - // if this is the first time we get here, set the next output time - // to the current time. this makes sure we always produce data during - // the first time step - if (std::isnan(last_output_time)) - last_output_time = this->get_time() - output_interval; - - // see if output is requested at this time - if (this->get_time() < last_output_time + output_interval) - return {"", ""}; - - // evaluate the solution at all of our evaluation points - std::vector> - current_point_values (evaluation_points_cartesian.size(), - Vector (this->introspection().n_components)); - - for (unsigned int p=0; pget_mapping(), - this->get_dof_handler(), - this->get_solution(), - evaluation_points_cartesian[p], - current_point_values[p]); - point_found = true; - } - catch (const VectorTools::ExcPointNotAvailableHere &) - { - // ignore - } - - // ensure that at least one processor found things - const int n_procs = Utilities::MPI::sum (point_found ? 1 : 0, this->get_mpi_communicator()); - AssertThrow (n_procs > 0, - ExcMessage ("While trying to evaluate the solution at point " + - Utilities::to_string(evaluation_points_cartesian[p][0]) + ", " + - Utilities::to_string(evaluation_points_cartesian[p][1]) + - (dim == 3 - ? - ", " + Utilities::to_string(evaluation_points_cartesian[p][2]) - : - "") + "), " + - "no processors reported that the point lies inside the " + - "set of cells they own. Are you trying to evaluate the " + - "solution at a point that lies outside of the domain?" - )); - - // Reduce all collected values into local Vector - Utilities::MPI::sum (current_point_values[p], this->get_mpi_communicator(), - current_point_values[p]); - - // Normalize in cases where points are claimed by multiple processors - if (n_procs > 1) - current_point_values[p] /= n_procs; - } - - // finally push these point values all onto the list we keep - point_values.emplace_back (this->get_time(), current_point_values); - - // now write all of the data to the file of choice. start with a pre-amble that - // explains the meaning of the various fields - const std::string filename = (this->get_output_directory() + - "point_values.txt"); - - if (Utilities::MPI::this_mpi_process(this->get_mpi_communicator()) == 0) - { - - std::ofstream f (filename); - f << ("#